mirror of
https://github.com/vector-im/element-ios.git
synced 2024-09-28 23:32:41 +00:00
Merge branch 'develop' into doug/4479_media_size_selection
# Conflicts: # Riot/Managers/Settings/RiotSettings.swift
This commit is contained in:
commit
a300cab626
146 changed files with 1741 additions and 1099 deletions
74
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal file
74
.github/ISSUE_TEMPLATE/bug.yml
vendored
Normal 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
|
31
.github/ISSUE_TEMPLATE/bug_report.md
vendored
31
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
@ -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
36
.github/ISSUE_TEMPLATE/enhancement.yml
vendored
Normal 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
|
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
|
@ -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
1
.gitignore
vendored
|
@ -19,6 +19,7 @@ DerivedData
|
||||||
out/
|
out/
|
||||||
.vscode/
|
.vscode/
|
||||||
vendor/
|
vendor/
|
||||||
|
.DS_Store
|
||||||
|
|
||||||
# CocoaPods
|
# CocoaPods
|
||||||
#
|
#
|
||||||
|
|
31
CHANGES.md
31
CHANGES.md
|
@ -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)
|
## Changes in 1.5.1 (2021-08-12)
|
||||||
|
|
||||||
🐛 Bugfixes
|
🐛 Bugfixes
|
||||||
|
|
|
@ -15,5 +15,5 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
// Version
|
// Version
|
||||||
MARKETING_VERSION = 1.5.2
|
MARKETING_VERSION = 1.5.3
|
||||||
CURRENT_PROJECT_VERSION = 1.5.2
|
CURRENT_PROJECT_VERSION = 1.5.3
|
||||||
|
|
50
DesignKit/Source/ColorValues.swift
Normal file
50
DesignKit/Source/ColorValues.swift
Normal 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]
|
||||||
|
}
|
|
@ -15,54 +15,57 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import UIKit
|
|
||||||
|
|
||||||
/// Colors at https://www.figma.com/file/X4XTH9iS2KGJ2wFKDqkyed/Compound?node-id=1255%3A1104
|
/// 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
|
/// - Focused/Active states
|
||||||
/// - CTAs
|
/// - CTAs
|
||||||
var accent: UIColor { get }
|
var accent: ColorType { get }
|
||||||
|
|
||||||
/// - Error messages
|
/// - Error messages
|
||||||
/// - Content requiring user attention
|
/// - Content requiring user attention
|
||||||
/// - Notification, alerts
|
/// - Notification, alerts
|
||||||
var alert: UIColor { get }
|
var alert: ColorType { get }
|
||||||
|
|
||||||
/// - Text
|
/// - Text
|
||||||
/// - Icons
|
/// - Icons
|
||||||
var primaryContent: UIColor { get }
|
var primaryContent: ColorType { get }
|
||||||
|
|
||||||
/// - Text
|
/// - Text
|
||||||
/// - Icons
|
/// - Icons
|
||||||
var secondaryContent: UIColor { get }
|
var secondaryContent: ColorType { get }
|
||||||
|
|
||||||
/// - Text
|
/// - Text
|
||||||
/// - Icons
|
/// - Icons
|
||||||
var tertiaryContent: UIColor { get }
|
var tertiaryContent: ColorType { get }
|
||||||
|
|
||||||
/// - Text
|
/// - Text
|
||||||
/// - Icons
|
/// - Icons
|
||||||
var quarterlyContent: UIColor { get }
|
var quarterlyContent: ColorType { get }
|
||||||
|
|
||||||
/// - Text
|
/// - separating lines and other UI components
|
||||||
/// - Icons
|
var quinaryContent: ColorType { get }
|
||||||
var quinaryContent: UIColor { get }
|
|
||||||
|
/// - System-based areas and backgrounds
|
||||||
|
var system: ColorType { get }
|
||||||
|
|
||||||
/// Separating line
|
/// Separating line
|
||||||
var separator: UIColor { get }
|
var separator: ColorType { get }
|
||||||
|
|
||||||
// Cards, tiles
|
// Cards, tiles
|
||||||
var tile: UIColor { get }
|
var tile: ColorType { get }
|
||||||
|
|
||||||
/// Top navigation background on iOS
|
/// Top navigation background on iOS
|
||||||
var navigation: UIColor { get }
|
var navigation: ColorType { get }
|
||||||
|
|
||||||
/// Background UI color
|
/// Background UI color
|
||||||
var background: UIColor { get }
|
var background: ColorType { get }
|
||||||
|
|
||||||
/// - Names in chat timeline
|
/// - Names in chat timeline
|
||||||
/// - Avatars default states that include first name letter
|
/// - Avatars default states that include first name letter
|
||||||
var namesAndAvatars: [UIColor] { get }
|
var namesAndAvatars: [ColorType] { get }
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
67
DesignKit/Source/ColorsSwiftUI.swift
Normal file
67
DesignKit/Source/ColorsSwiftUI.swift
Normal 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) })
|
||||||
|
}
|
||||||
|
}
|
67
DesignKit/Source/ColorsUIkit.swift
Normal file
67
DesignKit/Source/ColorsUIkit.swift
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -19,65 +19,67 @@ import UIKit
|
||||||
/// Describe fonts used in the application.
|
/// 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
|
/// 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
|
/// 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.
|
/// The font for large titles.
|
||||||
var largeTitle: UIFont { get }
|
var largeTitle: FontType { get }
|
||||||
|
|
||||||
/// `largeTitle` with a Bold weight.
|
/// `largeTitle` with a Bold weight.
|
||||||
var largeTitleB: UIFont { get }
|
var largeTitleB: FontType { get }
|
||||||
|
|
||||||
/// The font for first-level hierarchical headings.
|
/// The font for first-level hierarchical headings.
|
||||||
var title1: UIFont { get }
|
var title1: FontType { get }
|
||||||
|
|
||||||
/// `title1` with a Bold weight.
|
/// `title1` with a Bold weight.
|
||||||
var title1B: UIFont { get }
|
var title1B: FontType { get }
|
||||||
|
|
||||||
/// The font for second-level hierarchical headings.
|
/// The font for second-level hierarchical headings.
|
||||||
var title2: UIFont { get }
|
var title2: FontType { get }
|
||||||
|
|
||||||
/// `title2` with a Bold weight.
|
/// `title2` with a Bold weight.
|
||||||
var title2B: UIFont { get }
|
var title2B: FontType { get }
|
||||||
|
|
||||||
/// The font for third-level hierarchical headings.
|
/// The font for third-level hierarchical headings.
|
||||||
var title3: UIFont { get }
|
var title3: FontType { get }
|
||||||
|
|
||||||
/// `title3` with a Semi Bold weight.
|
/// `title3` with a Semi Bold weight.
|
||||||
var title3SB: UIFont { get }
|
var title3SB: FontType { get }
|
||||||
|
|
||||||
/// The font for headings.
|
/// The font for headings.
|
||||||
var headline: UIFont { get }
|
var headline: FontType { get }
|
||||||
|
|
||||||
/// The font for subheadings.
|
/// The font for subheadings.
|
||||||
var subheadline: UIFont { get }
|
var subheadline: FontType { get }
|
||||||
|
|
||||||
/// The font for body text.
|
/// The font for body text.
|
||||||
var body: UIFont { get }
|
var body: FontType { get }
|
||||||
|
|
||||||
/// `body` with a Semi Bold weight.
|
/// `body` with a Semi Bold weight.
|
||||||
var bodySB: UIFont { get }
|
var bodySB: FontType { get }
|
||||||
|
|
||||||
/// The font for callouts.
|
/// The font for callouts.
|
||||||
var callout: UIFont { get }
|
var callout: FontType { get }
|
||||||
|
|
||||||
/// `callout` with a Semi Bold weight.
|
/// `callout` with a Semi Bold weight.
|
||||||
var calloutSB: UIFont { get }
|
var calloutSB: FontType { get }
|
||||||
|
|
||||||
/// The font for footnotes.
|
/// The font for footnotes.
|
||||||
var footnote: UIFont { get }
|
var footnote: FontType { get }
|
||||||
|
|
||||||
/// `footnote` with a Semi Bold weight.
|
/// `footnote` with a Semi Bold weight.
|
||||||
var footnoteSB: UIFont { get }
|
var footnoteSB: FontType { get }
|
||||||
|
|
||||||
/// The font for standard captions.
|
/// The font for standard captions.
|
||||||
var caption1: UIFont { get }
|
var caption1: FontType { get }
|
||||||
|
|
||||||
/// `caption1` with a Semi Bold weight.
|
/// `caption1` with a Semi Bold weight.
|
||||||
var caption1SB: UIFont { get }
|
var caption1SB: FontType { get }
|
||||||
|
|
||||||
/// The font for alternate captions.
|
/// The font for alternate captions.
|
||||||
var caption2: UIFont { get }
|
var caption2: FontType { get }
|
||||||
|
|
||||||
/// `caption2` with a Semi Bold weight.
|
/// `caption2` with a Semi Bold weight.
|
||||||
var caption2SB: UIFont { get }
|
var caption2SB: FontType { get }
|
||||||
}
|
}
|
||||||
|
|
88
DesignKit/Source/FontsSwiftUI.swift
Normal file
88
DesignKit/Source/FontsSwiftUI.swift
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
87
DesignKit/Source/FontsUIkit.swift
Normal file
87
DesignKit/Source/FontsUIkit.swift
Normal 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,11 +21,23 @@ import UIKit
|
||||||
@objc public protocol ThemeV2 {
|
@objc public protocol ThemeV2 {
|
||||||
|
|
||||||
/// Colors object
|
/// Colors object
|
||||||
var colors: Colors { get }
|
var colors: ColorsUIKit { get }
|
||||||
|
|
||||||
/// Fonts object
|
/// 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.
|
/// may contain more design components in future, like icons, audio files etc.
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,43 +16,36 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import UIKit
|
import UIKit
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
/// Dark theme colors. Will be a struct when things are more Swifty.
|
/// Dark theme colors.
|
||||||
public class DarkColors: Colors {
|
public class DarkColors {
|
||||||
|
private static let values = ColorValues(
|
||||||
public let accent: UIColor = UIColor(rgb: 0x0DBD8B)
|
accent: UIColor(rgb:0x0DBD8B),
|
||||||
|
alert: UIColor(rgb:0xFF4B55),
|
||||||
public let alert: UIColor = UIColor(rgb: 0xFF4B55)
|
primaryContent: UIColor(rgb:0xFFFFFF),
|
||||||
|
secondaryContent: UIColor(rgb:0xA9B2BC),
|
||||||
public let primaryContent: UIColor = UIColor(rgb: 0xFFFFFF)
|
tertiaryContent: UIColor(rgb:0x8E99A4),
|
||||||
|
quarterlyContent: UIColor(rgb:0x6F7882),
|
||||||
public let secondaryContent: UIColor = UIColor(rgb: 0xA9B2BC)
|
quinaryContent: UIColor(rgb:0x394049),
|
||||||
|
separator: UIColor(rgb:0x21262C),
|
||||||
public let tertiaryContent: UIColor = UIColor(rgb: 0x8E99A4)
|
system: UIColor(rgb:0x21262C),
|
||||||
|
tile: UIColor(rgb:0x394049),
|
||||||
public let quarterlyContent: UIColor = UIColor(rgb: 0x6F7882)
|
navigation: UIColor(rgb:0x21262C),
|
||||||
|
background: UIColor(rgb:0x15191E),
|
||||||
public let quinaryContent: UIColor = UIColor(rgb: 0x394049)
|
namesAndAvatars: [
|
||||||
|
UIColor(rgb:0x368BD6),
|
||||||
public let separator: UIColor = UIColor(rgb: 0x21262C)
|
UIColor(rgb:0xAC3BA8),
|
||||||
|
UIColor(rgb:0x03B381),
|
||||||
public let tile: UIColor = UIColor(rgb: 0x394049)
|
UIColor(rgb:0xE64F7A),
|
||||||
|
UIColor(rgb:0xFF812D),
|
||||||
public let navigation: UIColor = UIColor(rgb: 0x21262C)
|
UIColor(rgb:0x2DC2C5),
|
||||||
|
UIColor(rgb:0x5C56F5),
|
||||||
public let background: UIColor = UIColor(rgb: 0x15191E)
|
UIColor(rgb:0x74D12C)
|
||||||
|
]
|
||||||
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() {}
|
|
||||||
|
|
||||||
|
public static var uiKit = ColorsUIKit(values: values)
|
||||||
|
@available(iOS 14.0, *)
|
||||||
|
public static var swiftUI = ColorSwiftUI(values: values)
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,43 +16,42 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import UIKit
|
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)
|
/// Light theme colors.
|
||||||
|
public class LightColors {
|
||||||
public let tile: UIColor = UIColor(rgb: 0xF3F8FD)
|
private static let values = ColorValues(
|
||||||
|
accent: UIColor(rgb:0x0DBD8B),
|
||||||
public let navigation: UIColor = UIColor(rgb: 0xF4F6FA)
|
alert: UIColor(rgb:0xFF4B55),
|
||||||
|
primaryContent: UIColor(rgb:0x17191C),
|
||||||
public let background: UIColor = UIColor(rgb: 0xFFFFFF)
|
secondaryContent: UIColor(rgb:0x737D8C),
|
||||||
|
tertiaryContent: UIColor(rgb:0x8D97A5),
|
||||||
public let namesAndAvatars: [UIColor] = [
|
quarterlyContent: UIColor(rgb:0xC1C6CD),
|
||||||
UIColor(rgb: 0x368BD6),
|
quinaryContent: UIColor(rgb:0xE3E8F0),
|
||||||
UIColor(rgb: 0xAC3BA8),
|
separator: UIColor(rgb:0xE3E8F0),
|
||||||
UIColor(rgb: 0x03B381),
|
system: UIColor(rgb:0xF4F6FA),
|
||||||
UIColor(rgb: 0xE64F7A),
|
tile: UIColor(rgb:0xF3F8FD),
|
||||||
UIColor(rgb: 0xFF812D),
|
navigation: UIColor(rgb:0xF4F6FA),
|
||||||
UIColor(rgb: 0x2DC2C5),
|
background: UIColor(rgb:0xFFFFFF),
|
||||||
UIColor(rgb: 0x5C56F5),
|
namesAndAvatars: [
|
||||||
UIColor(rgb: 0x74D12C)
|
UIColor(rgb:0x368BD6),
|
||||||
]
|
UIColor(rgb:0xAC3BA8),
|
||||||
|
UIColor(rgb:0x03B381),
|
||||||
public init() {}
|
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
10
Podfile
|
@ -1,3 +1,5 @@
|
||||||
|
source 'https://cdn.cocoapods.org/'
|
||||||
|
|
||||||
# Uncomment this line to define a global platform for your project
|
# Uncomment this line to define a global platform for your project
|
||||||
platform :ios, '11.0'
|
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
|
# - `{ {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
|
# 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 = :local
|
||||||
# $matrixKitVersion = {'develop' => 'develop'}
|
# $matrixKitVersion = {'develop' => 'develop'}
|
||||||
|
|
||||||
|
@ -46,7 +48,7 @@ abstract_target 'RiotPods' do
|
||||||
pod 'GBDeviceInfo', '~> 6.6.0'
|
pod 'GBDeviceInfo', '~> 6.6.0'
|
||||||
pod 'Reusable', '~> 4.1'
|
pod 'Reusable', '~> 4.1'
|
||||||
pod 'KeychainAccess', '~> 4.2.2'
|
pod 'KeychainAccess', '~> 4.2.2'
|
||||||
|
|
||||||
# Piwik for analytics
|
# Piwik for analytics
|
||||||
pod 'MatomoTracker', '~> 7.4.1'
|
pod 'MatomoTracker', '~> 7.4.1'
|
||||||
|
|
||||||
|
@ -103,7 +105,7 @@ post_install do |installer|
|
||||||
# Plus the app does not enable it
|
# Plus the app does not enable it
|
||||||
config.build_settings['ENABLE_BITCODE'] = 'NO'
|
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"
|
config.build_settings["EXCLUDED_ARCHS[sdk=iphonesimulator*]"] = "arm64"
|
||||||
|
|
||||||
# Force ReadMoreTextView to use Swift 5.2 version (as there is no code changes to perform)
|
# 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'
|
config.build_settings['SWIFT_VERSION'] = '5.2'
|
||||||
end
|
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'
|
config.build_settings.delete 'IPHONEOS_DEPLOYMENT_TARGET'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
32
Podfile.lock
32
Podfile.lock
|
@ -37,7 +37,7 @@ PODS:
|
||||||
- DTFoundation/Core
|
- DTFoundation/Core
|
||||||
- DTFoundation/UIKit (1.7.18):
|
- DTFoundation/UIKit (1.7.18):
|
||||||
- DTFoundation/Core
|
- DTFoundation/Core
|
||||||
- ffmpeg-kit-ios-audio (4.4)
|
- ffmpeg-kit-ios-audio (4.4.LTS)
|
||||||
- FLEX (4.4.1)
|
- FLEX (4.4.1)
|
||||||
- FlowCommoniOS (1.10.0)
|
- FlowCommoniOS (1.10.0)
|
||||||
- GBDeviceInfo (6.6.0):
|
- GBDeviceInfo (6.6.0):
|
||||||
|
@ -58,29 +58,29 @@ PODS:
|
||||||
- MatomoTracker (7.4.1):
|
- MatomoTracker (7.4.1):
|
||||||
- MatomoTracker/Core (= 7.4.1)
|
- MatomoTracker/Core (= 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)
|
- Down (~> 0.11.0)
|
||||||
- DTCoreText (~> 1.6.25)
|
- DTCoreText (~> 1.6.25)
|
||||||
- HPGrowingTextView (~> 1.1)
|
- HPGrowingTextView (~> 1.1)
|
||||||
- libPhoneNumber-iOS (~> 0.9.13)
|
- libPhoneNumber-iOS (~> 0.9.13)
|
||||||
- MatrixKit/Core (= 0.15.7)
|
- MatrixKit/Core (= 0.15.8)
|
||||||
- MatrixSDK (= 0.19.7)
|
- MatrixSDK (= 0.19.8)
|
||||||
- MatrixKit/Core (0.15.7):
|
- MatrixKit/Core (0.15.8):
|
||||||
- Down (~> 0.11.0)
|
- Down (~> 0.11.0)
|
||||||
- DTCoreText (~> 1.6.25)
|
- DTCoreText (~> 1.6.25)
|
||||||
- HPGrowingTextView (~> 1.1)
|
- HPGrowingTextView (~> 1.1)
|
||||||
- libPhoneNumber-iOS (~> 0.9.13)
|
- libPhoneNumber-iOS (~> 0.9.13)
|
||||||
- MatrixSDK (= 0.19.7)
|
- MatrixSDK (= 0.19.8)
|
||||||
- MatrixSDK (0.19.7):
|
- MatrixSDK (0.19.8):
|
||||||
- MatrixSDK/Core (= 0.19.7)
|
- MatrixSDK/Core (= 0.19.8)
|
||||||
- MatrixSDK/Core (0.19.7):
|
- MatrixSDK/Core (0.19.8):
|
||||||
- AFNetworking (~> 4.0.0)
|
- AFNetworking (~> 4.0.0)
|
||||||
- GZIP (~> 1.3.0)
|
- GZIP (~> 1.3.0)
|
||||||
- libbase58 (~> 0.1.4)
|
- libbase58 (~> 0.1.4)
|
||||||
- OLMKit (~> 3.2.4)
|
- OLMKit (~> 3.2.4)
|
||||||
- Realm (= 10.7.6)
|
- Realm (= 10.7.6)
|
||||||
- SwiftyBeaver (= 1.9.5)
|
- SwiftyBeaver (= 1.9.5)
|
||||||
- MatrixSDK/JingleCallStack (0.19.7):
|
- MatrixSDK/JingleCallStack (0.19.8):
|
||||||
- JitsiMeetSDK (= 3.5.0)
|
- JitsiMeetSDK (= 3.5.0)
|
||||||
- MatrixSDK/Core
|
- MatrixSDK/Core
|
||||||
- OLMKit (3.2.4):
|
- OLMKit (3.2.4):
|
||||||
|
@ -124,7 +124,7 @@ DEPENDENCIES:
|
||||||
- KeychainAccess (~> 4.2.2)
|
- KeychainAccess (~> 4.2.2)
|
||||||
- KTCenterFlowLayout (~> 1.3.1)
|
- KTCenterFlowLayout (~> 1.3.1)
|
||||||
- MatomoTracker (~> 7.4.1)
|
- MatomoTracker (~> 7.4.1)
|
||||||
- MatrixKit (= 0.15.7)
|
- MatrixKit (= 0.15.8)
|
||||||
- MatrixSDK
|
- MatrixSDK
|
||||||
- MatrixSDK/JingleCallStack
|
- MatrixSDK/JingleCallStack
|
||||||
- OLMKit
|
- OLMKit
|
||||||
|
@ -189,7 +189,7 @@ SPEC CHECKSUMS:
|
||||||
DSWaveformImage: 3c718a0cf99291887ee70d1d0c18d80101d3d9ce
|
DSWaveformImage: 3c718a0cf99291887ee70d1d0c18d80101d3d9ce
|
||||||
DTCoreText: ec749e013f2e1f76de5e7c7634642e600a7467ce
|
DTCoreText: ec749e013f2e1f76de5e7c7634642e600a7467ce
|
||||||
DTFoundation: a53f8cda2489208cbc71c648be177f902ee17536
|
DTFoundation: a53f8cda2489208cbc71c648be177f902ee17536
|
||||||
ffmpeg-kit-ios-audio: ddfc3dac6f574e83d53f8ae33586711162685d3e
|
ffmpeg-kit-ios-audio: 1c365080b8c76aa77b87c926f9f66ac07859b342
|
||||||
FLEX: 7ca2c8cd3a435ff501ff6d2f2141e9bdc934eaab
|
FLEX: 7ca2c8cd3a435ff501ff6d2f2141e9bdc934eaab
|
||||||
FlowCommoniOS: bcdf81a5f30717e711af08a8c812eb045411ba94
|
FlowCommoniOS: bcdf81a5f30717e711af08a8c812eb045411ba94
|
||||||
GBDeviceInfo: ed0db16230d2fa280e1cbb39a5a7f60f6946aaec
|
GBDeviceInfo: ed0db16230d2fa280e1cbb39a5a7f60f6946aaec
|
||||||
|
@ -204,8 +204,8 @@ SPEC CHECKSUMS:
|
||||||
LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d
|
LoggerAPI: ad9c4a6f1e32f518fdb43a1347ac14d765ab5e3d
|
||||||
Logging: beeb016c9c80cf77042d62e83495816847ef108b
|
Logging: beeb016c9c80cf77042d62e83495816847ef108b
|
||||||
MatomoTracker: 24a846c9d3aa76933183fe9d47fd62c9efa863fb
|
MatomoTracker: 24a846c9d3aa76933183fe9d47fd62c9efa863fb
|
||||||
MatrixKit: 5939d1b63bad3e7f709534a8f105b69f84728591
|
MatrixKit: 2945ade22970747defcc4d564cb0c7aedbd4019d
|
||||||
MatrixSDK: c0bbec5b67cc8771cffdf3b494d622bce0a51ceb
|
MatrixSDK: 4d4679b499b4802a11a90b3652f83be496bfaec1
|
||||||
OLMKit: 2d73cd67d149b5c3e3a8eb8ecae93d0b429d8a02
|
OLMKit: 2d73cd67d149b5c3e3a8eb8ecae93d0b429d8a02
|
||||||
ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d
|
ReadMoreTextView: 19147adf93abce6d7271e14031a00303fe28720d
|
||||||
Realm: ed860452717c8db8f4bf832b6807f7f2ce708839
|
Realm: ed860452717c8db8f4bf832b6807f7f2ce708839
|
||||||
|
@ -219,6 +219,6 @@ SPEC CHECKSUMS:
|
||||||
zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c
|
zxcvbn-ios: fef98b7c80f1512ff0eec47ac1fa399fc00f7e3c
|
||||||
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
|
ZXingObjC: fdbb269f25dd2032da343e06f10224d62f537bdb
|
||||||
|
|
||||||
PODFILE CHECKSUM: 605b63b9968e2916d998f4769f162b4b7c2a2577
|
PODFILE CHECKSUM: 7a2c462b09e09029983e15c0e4ad8dcf4d68df69
|
||||||
|
|
||||||
COCOAPODS: 1.10.1
|
COCOAPODS: 1.10.2
|
||||||
|
|
|
@ -4,8 +4,7 @@
|
||||||
version = "1.3">
|
version = "1.3">
|
||||||
<BuildAction
|
<BuildAction
|
||||||
parallelizeBuildables = "YES"
|
parallelizeBuildables = "YES"
|
||||||
buildImplicitDependencies = "YES"
|
buildImplicitDependencies = "YES">
|
||||||
runPostActionsOnFailure = "NO">
|
|
||||||
<BuildActionEntries>
|
<BuildActionEntries>
|
||||||
<BuildActionEntry
|
<BuildActionEntry
|
||||||
buildForTesting = "YES"
|
buildForTesting = "YES"
|
||||||
|
|
|
@ -5155,12 +5155,10 @@ extension VectorL10n {
|
||||||
static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String {
|
static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String {
|
||||||
let format = NSLocalizedString(key, tableName: table, bundle: Bundle(for: BundleToken.self), comment: "")
|
let format = NSLocalizedString(key, tableName: table, bundle: Bundle(for: BundleToken.self), comment: "")
|
||||||
let locale: Locale
|
let locale: Locale
|
||||||
if let localeIdentifier = Bundle.mxk_language() {
|
if let providedLocale = LocaleProvider.locale {
|
||||||
locale = Locale(identifier: localeIdentifier)
|
locale = providedLocale
|
||||||
} else if let fallbackLocaleIdentifier = Bundle.mxk_fallbackLanguage() {
|
|
||||||
locale = Locale(identifier: fallbackLocaleIdentifier)
|
|
||||||
} else {
|
} else {
|
||||||
locale = Locale.current
|
locale = Locale.current
|
||||||
}
|
}
|
||||||
|
|
||||||
return String(format: format, locale: locale, arguments: args)
|
return String(format: format, locale: locale, arguments: args)
|
||||||
|
|
31
Riot/Managers/Locale/LocaleProvider.swift
Normal file
31
Riot/Managers/Locale/LocaleProvider.swift
Normal 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
|
||||||
|
}
|
||||||
|
}
|
24
Riot/Managers/Locale/LocaleProviderType.swift
Normal file
24
Riot/Managers/Locale/LocaleProviderType.swift
Normal 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 }
|
||||||
|
}
|
|
@ -23,72 +23,15 @@ final class RiotSettings: NSObject {
|
||||||
// MARK: - Constants
|
// MARK: - Constants
|
||||||
|
|
||||||
private enum UserDefaultsKeys {
|
private enum UserDefaultsKeys {
|
||||||
static let homeserverUrlString = "homeserverurl"
|
|
||||||
static let identityServerUrlString = "identityserverurl"
|
|
||||||
static let enableCrashReport = "enableCrashReport"
|
static let enableCrashReport = "enableCrashReport"
|
||||||
static let enableRageShake = "enableRageShake"
|
|
||||||
static let userInterfaceTheme = "userInterfaceTheme"
|
|
||||||
static let notificationsShowDecryptedContent = "showDecryptedContent"
|
static let notificationsShowDecryptedContent = "showDecryptedContent"
|
||||||
static let pinRoomsWithMissedNotifications = "pinRoomsWithMissedNotif"
|
|
||||||
static let pinRoomsWithUnreadMessages = "pinRoomsWithUnread"
|
|
||||||
static let allowStunServerFallback = "allowStunServerFallback"
|
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()
|
static let shared = RiotSettings()
|
||||||
|
|
||||||
/// UserDefaults to be used on reads and writes.
|
/// 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 {
|
guard let userDefaults = UserDefaults(suiteName: BuildSettings.applicationGroupIdentifier) else {
|
||||||
fatalError("[RiotSettings] Fail to load shared UserDefaults")
|
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.
|
/// Indicate if UserDefaults suite has been migrated once.
|
||||||
var isUserDefaultsMigrated: Bool {
|
var isUserDefaultsMigrated: Bool {
|
||||||
return defaults.object(forKey: UserDefaultsKeys.notificationsShowDecryptedContent) != nil
|
return RiotSettings.defaults.object(forKey: UserDefaultsKeys.notificationsShowDecryptedContent) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func migrate() {
|
func migrate() {
|
||||||
|
@ -139,321 +57,151 @@ final class RiotSettings: NSObject {
|
||||||
// write values to suite
|
// write values to suite
|
||||||
// remove redundant values from standard
|
// remove redundant values from standard
|
||||||
for (key, value) in dictionary {
|
for (key, value) in dictionary {
|
||||||
defaults.set(value, forKey: key)
|
RiotSettings.defaults.set(value, forKey: key)
|
||||||
UserDefaults.standard.removeObject(forKey: key)
|
UserDefaults.standard.removeObject(forKey: key)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Indicate if encrypted messages content should be displayed in notifications.
|
// MARK: Servers
|
||||||
var showDecryptedContentInNotifications: Bool {
|
|
||||||
get {
|
@UserDefault(key: "homeserverurl", defaultValue: BuildSettings.serverConfigDefaultHomeserverUrlString, storage: defaults)
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.notificationsShowDecryptedContent)
|
var homeserverUrlString
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.notificationsShowDecryptedContent)
|
@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.
|
/// Indicate if rooms with missed notifications should be displayed first on home screen.
|
||||||
var pinRoomsWithMissedNotificationsOnHome: Bool {
|
@UserDefault(key: "pinRoomsWithMissedNotif", defaultValue: false, storage: defaults)
|
||||||
get {
|
var pinRoomsWithMissedNotificationsOnHome
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.pinRoomsWithMissedNotifications)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.pinRoomsWithMissedNotifications)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Indicate if rooms with unread messages should be displayed first on home screen.
|
/// Indicate if rooms with unread messages should be displayed first on home screen.
|
||||||
var pinRoomsWithUnreadMessagesOnHome: Bool {
|
@UserDefault(key: "pinRoomsWithUnread", defaultValue: false, storage: defaults)
|
||||||
get {
|
var pinRoomsWithUnreadMessagesOnHome
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.pinRoomsWithUnreadMessages)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.pinRoomsWithUnreadMessages)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Indicate to show Not Safe For Work public rooms.
|
/// Indicate to show Not Safe For Work public rooms.
|
||||||
var showNSFWPublicRooms: Bool {
|
@UserDefault(key: "showNSFWPublicRooms", defaultValue: false, storage: defaults)
|
||||||
get {
|
var showNSFWPublicRooms
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.showNSFWPublicRooms)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.showNSFWPublicRooms)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: User interface
|
// MARK: User interface
|
||||||
|
|
||||||
var userInterfaceTheme: String? {
|
@UserDefault<String?>(key: "userInterfaceTheme", defaultValue: nil, storage: defaults)
|
||||||
get {
|
var userInterfaceTheme
|
||||||
return defaults.string(forKey: UserDefaultsKeys.userInterfaceTheme)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.userInterfaceTheme)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Other
|
// MARK: Other
|
||||||
|
|
||||||
/// Indicate if `enableCrashReport` settings has been set once.
|
/// Indicate if `enableCrashReport` settings has been set once.
|
||||||
var isEnableCrashReportHasBeenSetOnce: Bool {
|
var isEnableCrashReportHasBeenSetOnce: Bool {
|
||||||
return defaults.object(forKey: UserDefaultsKeys.enableCrashReport) != nil
|
return RiotSettings.defaults.object(forKey: UserDefaultsKeys.enableCrashReport) != nil
|
||||||
}
|
}
|
||||||
|
|
||||||
var enableCrashReport: Bool {
|
@UserDefault(key: UserDefaultsKeys.enableCrashReport, defaultValue: false, storage: defaults)
|
||||||
get {
|
var enableCrashReport
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.enableCrashReport)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.enableCrashReport)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var enableRageShake: Bool {
|
@UserDefault(key: "enableRageShake", defaultValue: false, storage: defaults)
|
||||||
get {
|
var enableRageShake
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.enableRageShake)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.enableRageShake)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Labs
|
// 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.
|
/// 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 {
|
@UserDefault(key: "enableRingingForGroupCalls", defaultValue: false, storage: defaults)
|
||||||
get {
|
var enableRingingForGroupCalls
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.enableRingingForGroupCalls)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.enableRingingForGroupCalls)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Calls
|
// MARK: Calls
|
||||||
|
|
||||||
/// Indicate if `allowStunServerFallback` settings has been set once.
|
/// Indicate if `allowStunServerFallback` settings has been set once.
|
||||||
var isAllowStunServerFallbackHasBeenSetOnce: Bool {
|
var isAllowStunServerFallbackHasBeenSetOnce: Bool {
|
||||||
return defaults.object(forKey: UserDefaultsKeys.allowStunServerFallback) != nil
|
return RiotSettings.defaults.object(forKey: UserDefaultsKeys.allowStunServerFallback) != nil
|
||||||
}
|
|
||||||
|
|
||||||
var allowStunServerFallback: Bool {
|
|
||||||
get {
|
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.allowStunServerFallback)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.allowStunServerFallback)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@UserDefault(key: UserDefaultsKeys.allowStunServerFallback, defaultValue: false, storage: defaults)
|
||||||
|
var allowStunServerFallback
|
||||||
|
|
||||||
// MARK: Key verification
|
// MARK: Key verification
|
||||||
|
|
||||||
var hideVerifyThisSessionAlert: Bool {
|
@UserDefault(key: "hideVerifyThisSessionAlert", defaultValue: false, storage: defaults)
|
||||||
get {
|
var hideVerifyThisSessionAlert
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.hideVerifyThisSessionAlert)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.hideVerifyThisSessionAlert)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var hideReviewSessionsAlert: Bool {
|
@UserDefault(key: "hideReviewSessionsAlert", defaultValue: false, storage: defaults)
|
||||||
get {
|
var hideReviewSessionsAlert
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.hideReviewSessionsAlert)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.hideReviewSessionsAlert)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var matrixApps: Bool {
|
@UserDefault(key: "matrixApps", defaultValue: false, storage: defaults)
|
||||||
get {
|
var matrixApps
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.matrixApps)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.matrixApps)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Rooms Screen
|
// MARK: - Rooms Screen
|
||||||
|
|
||||||
var roomsAllowToJoinPublicRooms: Bool {
|
@UserDefault(key: "roomsAllowToJoinPublicRooms", defaultValue: BuildSettings.roomsAllowToJoinPublicRooms, storage: defaults)
|
||||||
get {
|
var roomsAllowToJoinPublicRooms
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.roomsAllowToJoinPublicRooms) != nil else {
|
|
||||||
return BuildSettings.roomsAllowToJoinPublicRooms
|
|
||||||
}
|
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.roomsAllowToJoinPublicRooms)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.roomsAllowToJoinPublicRooms)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Room Screen
|
// MARK: - Room Screen
|
||||||
|
|
||||||
var roomScreenAllowVoIPForDirectRoom: Bool {
|
@UserDefault(key: "roomScreenAllowVoIPForDirectRoom", defaultValue: BuildSettings.roomScreenAllowVoIPForDirectRoom, storage: defaults)
|
||||||
get {
|
var roomScreenAllowVoIPForDirectRoom
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.roomScreenAllowVoIPForDirectRoom) != nil else {
|
|
||||||
return BuildSettings.roomScreenAllowVoIPForDirectRoom
|
@UserDefault(key: "roomScreenAllowVoIPForNonDirectRoom", defaultValue: BuildSettings.roomScreenAllowVoIPForNonDirectRoom, storage: defaults)
|
||||||
}
|
var roomScreenAllowVoIPForNonDirectRoom
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.roomScreenAllowVoIPForDirectRoom)
|
|
||||||
} set {
|
@UserDefault(key: "roomScreenAllowCameraAction", defaultValue: BuildSettings.roomScreenAllowCameraAction, storage: defaults)
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.roomScreenAllowVoIPForDirectRoom)
|
var roomScreenAllowCameraAction
|
||||||
}
|
|
||||||
}
|
@UserDefault(key: "roomScreenAllowMediaLibraryAction", defaultValue: BuildSettings.roomScreenAllowMediaLibraryAction, storage: defaults)
|
||||||
var roomScreenAllowVoIPForNonDirectRoom: Bool {
|
var roomScreenAllowMediaLibraryAction
|
||||||
get {
|
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.roomScreenAllowVoIPForNonDirectRoom) != nil else {
|
@UserDefault(key: "roomScreenAllowStickerAction", defaultValue: BuildSettings.roomScreenAllowStickerAction, storage: defaults)
|
||||||
return BuildSettings.roomScreenAllowVoIPForNonDirectRoom
|
var roomScreenAllowStickerAction
|
||||||
}
|
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.roomScreenAllowVoIPForNonDirectRoom)
|
@UserDefault(key: "roomScreenAllowFilesAction", defaultValue: BuildSettings.roomScreenAllowFilesAction, storage: defaults)
|
||||||
} set {
|
var roomScreenAllowFilesAction
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Room Contextual Menu
|
// MARK: - Room Contextual Menu
|
||||||
|
|
||||||
var roomContextualMenuShowMoreOptionForMessages: Bool {
|
@UserDefault(key: "roomContextualMenuShowMoreOptionForMessages", defaultValue: BuildSettings.roomContextualMenuShowMoreOptionForMessages, storage: defaults)
|
||||||
get {
|
var roomContextualMenuShowMoreOptionForMessages
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.roomContextualMenuShowMoreOptionForMessages) != nil else {
|
|
||||||
return BuildSettings.roomContextualMenuShowMoreOptionForMessages
|
@UserDefault(key: "roomContextualMenuShowMoreOptionForStates", defaultValue: BuildSettings.roomContextualMenuShowMoreOptionForStates, storage: defaults)
|
||||||
}
|
var roomContextualMenuShowMoreOptionForStates
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.roomContextualMenuShowMoreOptionForMessages)
|
|
||||||
} set {
|
@UserDefault(key: "roomContextualMenuShowReportContentOption", defaultValue: BuildSettings.roomContextualMenuShowReportContentOption, storage: defaults)
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.roomContextualMenuShowMoreOptionForMessages)
|
var roomContextualMenuShowReportContentOption
|
||||||
}
|
|
||||||
}
|
|
||||||
var roomContextualMenuShowMoreOptionForStates: Bool {
|
|
||||||
get {
|
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.roomContextualMenuShowMoreOptionForStates) != nil else {
|
|
||||||
return BuildSettings.roomContextualMenuShowMoreOptionForStates
|
|
||||||
}
|
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.roomContextualMenuShowMoreOptionForStates)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.roomContextualMenuShowMoreOptionForStates)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
var roomContextualMenuShowReportContentOption: Bool {
|
|
||||||
get {
|
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.roomContextualMenuShowReportContentOption) != nil else {
|
|
||||||
return BuildSettings.roomContextualMenuShowReportContentOption
|
|
||||||
}
|
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.roomContextualMenuShowReportContentOption)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.roomContextualMenuShowReportContentOption)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Room Info Screen
|
// MARK: - Room Info Screen
|
||||||
|
|
||||||
var roomInfoScreenShowIntegrations: Bool {
|
@UserDefault(key: "roomInfoScreenShowIntegrations", defaultValue: BuildSettings.roomInfoScreenShowIntegrations, storage: defaults)
|
||||||
get {
|
var roomInfoScreenShowIntegrations
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.roomInfoScreenShowIntegrations) != nil else {
|
|
||||||
return BuildSettings.roomInfoScreenShowIntegrations
|
|
||||||
}
|
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.roomInfoScreenShowIntegrations)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.roomInfoScreenShowIntegrations)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Room Member Screen
|
// MARK: - Room Member Screen
|
||||||
|
|
||||||
var roomMemberScreenShowIgnore: Bool {
|
@UserDefault(key: "roomMemberScreenShowIgnore", defaultValue: BuildSettings.roomMemberScreenShowIgnore, storage: defaults)
|
||||||
get {
|
var roomMemberScreenShowIgnore
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.roomMemberScreenShowIgnore) != nil else {
|
|
||||||
return BuildSettings.roomMemberScreenShowIgnore
|
|
||||||
}
|
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.roomMemberScreenShowIgnore)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.roomMemberScreenShowIgnore)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// MARK: - Room Creation Screen
|
// MARK: - Room Creation Screen
|
||||||
|
|
||||||
var roomCreationScreenAllowEncryptionConfiguration: Bool {
|
@UserDefault(key: "roomCreationScreenAllowEncryptionConfiguration", defaultValue: BuildSettings.roomCreationScreenAllowEncryptionConfiguration, storage: defaults)
|
||||||
get {
|
var roomCreationScreenAllowEncryptionConfiguration
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.roomCreationScreenAllowEncryptionConfiguration) != nil else {
|
|
||||||
return BuildSettings.roomCreationScreenAllowEncryptionConfiguration
|
@UserDefault(key: "roomCreationScreenRoomIsEncrypted", defaultValue: BuildSettings.roomCreationScreenRoomIsEncrypted, storage: defaults)
|
||||||
}
|
var roomCreationScreenRoomIsEncrypted
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.roomCreationScreenAllowEncryptionConfiguration)
|
|
||||||
} set {
|
@UserDefault(key: "roomCreationScreenAllowRoomTypeConfiguration", defaultValue: BuildSettings.roomCreationScreenAllowRoomTypeConfiguration, storage: defaults)
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.roomCreationScreenAllowEncryptionConfiguration)
|
var roomCreationScreenAllowRoomTypeConfiguration
|
||||||
}
|
|
||||||
}
|
@UserDefault(key: "roomCreationScreenRoomIsPublic", defaultValue: BuildSettings.roomCreationScreenRoomIsPublic, storage: defaults)
|
||||||
var roomCreationScreenRoomIsEncrypted: Bool {
|
var roomCreationScreenRoomIsPublic
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: Features
|
// MARK: Features
|
||||||
|
|
||||||
var allowInviteExernalUsers: Bool {
|
@UserDefault(key: "allowInviteExernalUsers", defaultValue: BuildSettings.allowInviteExernalUsers, storage: defaults)
|
||||||
get {
|
var allowInviteExernalUsers
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.allowInviteExernalUsers) != nil else {
|
|
||||||
return BuildSettings.allowInviteExernalUsers
|
|
||||||
}
|
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.allowInviteExernalUsers)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.allowInviteExernalUsers)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// When set to false the original image is sent and a 1080p preset is used for videos.
|
/// 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.
|
/// 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
|
// MARK: - Main Tabs
|
||||||
|
|
||||||
var homeScreenShowFavouritesTab: Bool {
|
@UserDefault(key: "homeScreenShowFavouritesTab", defaultValue: BuildSettings.homeScreenShowFavouritesTab, storage: defaults)
|
||||||
get {
|
var homeScreenShowFavouritesTab
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.homeScreenShowFavouritesTab) != nil else {
|
|
||||||
return BuildSettings.homeScreenShowFavouritesTab
|
@UserDefault(key: "homeScreenShowPeopleTab", defaultValue: BuildSettings.homeScreenShowPeopleTab, storage: defaults)
|
||||||
}
|
var homeScreenShowPeopleTab
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.homeScreenShowFavouritesTab)
|
|
||||||
} set {
|
@UserDefault(key: "homeScreenShowRoomsTab", defaultValue: BuildSettings.homeScreenShowRoomsTab, storage: defaults)
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.homeScreenShowFavouritesTab)
|
var homeScreenShowRoomsTab
|
||||||
}
|
|
||||||
}
|
@UserDefault(key: "homeScreenShowCommunitiesTab", defaultValue: BuildSettings.homeScreenShowCommunitiesTab, storage: defaults)
|
||||||
var homeScreenShowPeopleTab: Bool {
|
var homeScreenShowCommunitiesTab
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: General Settings
|
// MARK: General Settings
|
||||||
|
|
||||||
var settingsScreenShowChangePassword: Bool {
|
@UserDefault(key: "settingsScreenShowChangePassword", defaultValue: BuildSettings.settingsScreenShowChangePassword, storage: defaults)
|
||||||
get {
|
var settingsScreenShowChangePassword
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.settingsScreenShowChangePassword) != nil else {
|
|
||||||
return BuildSettings.settingsScreenShowChangePassword
|
@UserDefault(key: "settingsScreenShowInviteFriends", defaultValue: BuildSettings.settingsScreenShowInviteFriends, storage: defaults)
|
||||||
}
|
var settingsScreenShowInviteFriends
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.settingsScreenShowChangePassword)
|
|
||||||
} set {
|
@UserDefault(key: "settingsScreenShowEnableStunServerFallback", defaultValue: BuildSettings.settingsScreenShowEnableStunServerFallback, storage: defaults)
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.settingsScreenShowChangePassword)
|
var settingsScreenShowEnableStunServerFallback
|
||||||
}
|
|
||||||
}
|
@UserDefault(key: "settingsScreenShowNotificationDecodedContentOption", defaultValue: BuildSettings.settingsScreenShowNotificationDecodedContentOption, storage: defaults)
|
||||||
var settingsScreenShowInviteFriends: Bool {
|
var settingsScreenShowNotificationDecodedContentOption
|
||||||
get {
|
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.settingsScreenShowInviteFriends) != nil else {
|
@UserDefault(key: "settingsScreenShowNsfwRoomsOption", defaultValue: BuildSettings.settingsScreenShowNsfwRoomsOption, storage: defaults)
|
||||||
return BuildSettings.settingsScreenShowInviteFriends
|
var settingsScreenShowNsfwRoomsOption
|
||||||
}
|
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.settingsScreenShowInviteFriends)
|
@UserDefault(key: "settingsSecurityScreenShowSessions", defaultValue: BuildSettings.settingsSecurityScreenShowSessions, storage: defaults)
|
||||||
} set {
|
var settingsSecurityScreenShowSessions
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.settingsScreenShowInviteFriends)
|
|
||||||
}
|
@UserDefault(key: "settingsSecurityScreenShowSetupBackup", defaultValue: BuildSettings.settingsSecurityScreenShowSetupBackup, storage: defaults)
|
||||||
}
|
var settingsSecurityScreenShowSetupBackup
|
||||||
var settingsScreenShowEnableStunServerFallback: Bool {
|
|
||||||
get {
|
@UserDefault(key: "settingsSecurityScreenShowRestoreBackup", defaultValue: BuildSettings.settingsSecurityScreenShowRestoreBackup, storage: defaults)
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.settingsScreenShowInviteFriends) != nil else {
|
var settingsSecurityScreenShowRestoreBackup
|
||||||
return BuildSettings.settingsScreenShowEnableStunServerFallback
|
|
||||||
}
|
@UserDefault(key: "settingsSecurityScreenShowDeleteBackup", defaultValue: BuildSettings.settingsSecurityScreenShowDeleteBackup, storage: defaults)
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.settingsScreenShowEnableStunServerFallback)
|
var settingsSecurityScreenShowDeleteBackup
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.settingsScreenShowEnableStunServerFallback)
|
@UserDefault(key: "settingsSecurityScreenShowCryptographyInfo", defaultValue: BuildSettings.settingsSecurityScreenShowCryptographyInfo, storage: defaults)
|
||||||
}
|
var settingsSecurityScreenShowCryptographyInfo
|
||||||
}
|
|
||||||
var settingsScreenShowNotificationDecodedContentOption: Bool {
|
@UserDefault(key: "settingsSecurityScreenShowCryptographyExport", defaultValue: BuildSettings.settingsSecurityScreenShowCryptographyExport, storage: defaults)
|
||||||
get {
|
var settingsSecurityScreenShowCryptographyExport
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.settingsScreenShowNotificationDecodedContentOption) != nil else {
|
|
||||||
return BuildSettings.settingsScreenShowNotificationDecodedContentOption
|
@UserDefault(key: "settingsSecurityScreenShowAdvancedBlacklistUnverifiedDevices", defaultValue: BuildSettings.settingsSecurityScreenShowAdvancedUnverifiedDevices, storage: defaults)
|
||||||
}
|
var settingsSecurityScreenShowAdvancedUnverifiedDevices
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Room Settings Screen
|
// MARK: - Room Settings Screen
|
||||||
|
|
||||||
var roomSettingsScreenShowLowPriorityOption: Bool {
|
@UserDefault(key: "roomSettingsScreenShowLowPriorityOption", defaultValue: BuildSettings.roomSettingsScreenShowLowPriorityOption, storage: defaults)
|
||||||
get {
|
var roomSettingsScreenShowLowPriorityOption
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.roomSettingsScreenShowLowPriorityOption) != nil else {
|
|
||||||
return BuildSettings.roomSettingsScreenShowLowPriorityOption
|
@UserDefault(key: "roomSettingsScreenShowDirectChatOption", defaultValue: BuildSettings.roomSettingsScreenShowDirectChatOption, storage: defaults)
|
||||||
}
|
var roomSettingsScreenShowDirectChatOption
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.roomSettingsScreenShowLowPriorityOption)
|
|
||||||
} set {
|
@UserDefault(key: "roomSettingsScreenAllowChangingAccessSettings", defaultValue: BuildSettings.roomSettingsScreenAllowChangingAccessSettings, storage: defaults)
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.roomSettingsScreenShowLowPriorityOption)
|
var roomSettingsScreenAllowChangingAccessSettings
|
||||||
}
|
|
||||||
}
|
@UserDefault(key: "roomSettingsScreenAllowChangingHistorySettings", defaultValue: BuildSettings.roomSettingsScreenAllowChangingHistorySettings, storage: defaults)
|
||||||
var roomSettingsScreenShowDirectChatOption: Bool {
|
var roomSettingsScreenAllowChangingHistorySettings
|
||||||
get {
|
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.roomSettingsScreenShowDirectChatOption) != nil else {
|
@UserDefault(key: "roomSettingsScreenShowAddressSettings", defaultValue: BuildSettings.roomSettingsScreenShowAddressSettings, storage: defaults)
|
||||||
return BuildSettings.roomSettingsScreenShowDirectChatOption
|
var roomSettingsScreenShowAddressSettings
|
||||||
}
|
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.roomSettingsScreenShowDirectChatOption)
|
@UserDefault(key: "roomSettingsScreenShowFlairSettings", defaultValue: BuildSettings.roomSettingsScreenShowFlairSettings, storage: defaults)
|
||||||
} set {
|
var roomSettingsScreenShowFlairSettings
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.roomSettingsScreenShowDirectChatOption)
|
|
||||||
}
|
@UserDefault(key: "roomSettingsScreenShowAdvancedSettings", defaultValue: BuildSettings.roomSettingsScreenShowAdvancedSettings, storage: defaults)
|
||||||
}
|
var roomSettingsScreenShowAdvancedSettings
|
||||||
var roomSettingsScreenAllowChangingAccessSettings: Bool {
|
|
||||||
get {
|
@UserDefault(key: "roomSettingsScreenAdvancedShowEncryptToVerifiedOption", defaultValue: BuildSettings.roomSettingsScreenAdvancedShowEncryptToVerifiedOption, storage: defaults)
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.roomSettingsScreenAllowChangingAccessSettings) != nil else {
|
var roomSettingsScreenAdvancedShowEncryptToVerifiedOption
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Unified Search
|
// MARK: - Unified Search
|
||||||
|
|
||||||
var unifiedSearchScreenShowPublicDirectory: Bool {
|
@UserDefault(key: "unifiedSearchScreenShowPublicDirectory", defaultValue: BuildSettings.unifiedSearchScreenShowPublicDirectory, storage: defaults)
|
||||||
get {
|
var unifiedSearchScreenShowPublicDirectory
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.unifiedSearchScreenShowPublicDirectory) != nil else {
|
|
||||||
return BuildSettings.unifiedSearchScreenShowPublicDirectory
|
|
||||||
}
|
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.unifiedSearchScreenShowPublicDirectory)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.unifiedSearchScreenShowPublicDirectory)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Secrets Recovery
|
// MARK: - Secrets Recovery
|
||||||
|
|
||||||
var secretsRecoveryAllowReset: Bool {
|
@UserDefault(key: "secretsRecoveryAllowReset", defaultValue: BuildSettings.secretsRecoveryAllowReset, storage: defaults)
|
||||||
get {
|
var secretsRecoveryAllowReset
|
||||||
guard defaults.object(forKey: UserDefaultsKeys.secretsRecoveryAllowReset) != nil else {
|
|
||||||
return BuildSettings.secretsRecoveryAllowReset
|
|
||||||
}
|
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.secretsRecoveryAllowReset)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.secretsRecoveryAllowReset)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Beta
|
// MARK: - Beta
|
||||||
|
|
||||||
var hideSpaceBetaAnnounce: Bool {
|
@UserDefault(key: "hideSpaceBetaAnnounce", defaultValue: false, storage: defaults)
|
||||||
get {
|
var hideSpaceBetaAnnounce
|
||||||
return defaults.bool(forKey: UserDefaultsKeys.hideSpaceBetaAnnounce)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.hideSpaceBetaAnnounce)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// MARK: - Version check
|
// MARK: - Version check
|
||||||
|
|
||||||
var versionCheckNextDisplayDateTimeInterval: TimeInterval {
|
@UserDefault(key: "versionCheckNextDisplayDateTimeInterval", defaultValue: 0.0, storage: defaults)
|
||||||
get {
|
var versionCheckNextDisplayDateTimeInterval
|
||||||
return defaults.double(forKey: UserDefaultsKeys.versionCheckNextDisplayDateTimeInterval)
|
|
||||||
} set {
|
|
||||||
defaults.set(newValue, forKey: UserDefaultsKeys.versionCheckNextDisplayDateTimeInterval)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -142,12 +142,8 @@ class DarkTheme: NSObject, Theme {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// MARK: - Theme v2
|
/// MARK: - Theme v2
|
||||||
|
var colors: ColorsUIKit = DarkColors.uiKit
|
||||||
|
|
||||||
lazy var colors: Colors = {
|
var fonts: FontsUIKit = FontsUIKit(values: ElementFonts())
|
||||||
return DarkColors()
|
|
||||||
}()
|
|
||||||
|
|
||||||
lazy var fonts: Fonts = {
|
|
||||||
return ElementFonts()
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,12 +149,7 @@ class DefaultTheme: NSObject, Theme {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// MARK: - Theme v2
|
/// MARK: - Theme v2
|
||||||
|
var colors: ColorsUIKit = LightColors.uiKit
|
||||||
|
|
||||||
lazy var colors: Colors = {
|
var fonts: FontsUIKit = FontsUIKit(values: ElementFonts())
|
||||||
return LightColors()
|
|
||||||
}()
|
|
||||||
|
|
||||||
lazy var fonts: Fonts = {
|
|
||||||
return ElementFonts()
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -103,6 +103,18 @@ final class AppCoordinator: NSObject, AppCoordinatorType {
|
||||||
|
|
||||||
private func setupTheme() {
|
private func setupTheme() {
|
||||||
ThemeService.shared().themeId = RiotSettings.shared.userInterfaceTheme
|
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() {
|
private func showAuthentication() {
|
||||||
|
|
|
@ -2040,8 +2040,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||||
|
|
||||||
if (clearCache)
|
if (clearCache)
|
||||||
{
|
{
|
||||||
// clear the media cache
|
[self clearCache];
|
||||||
[MXMediaManager clearCache];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2143,7 +2142,7 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||||
[self.pushNotificationService deregisterRemoteNotifications];
|
[self.pushNotificationService deregisterRemoteNotifications];
|
||||||
|
|
||||||
// Clear cache
|
// Clear cache
|
||||||
[MXMediaManager clearCache];
|
[self clearCache];
|
||||||
|
|
||||||
// Reset key backup banner preferences
|
// Reset key backup banner preferences
|
||||||
[SecureBackupBannerPreferences.shared reset];
|
[SecureBackupBannerPreferences.shared reset];
|
||||||
|
@ -4322,4 +4321,13 @@ NSString *const AppDelegateUniversalLinkDidChangeNotification = @"AppDelegateUni
|
||||||
return [authVC continueSSOLoginWithToken:loginToken txnId:txnId];
|
return [authVC continueSSOLoginWithToken:loginToken txnId:txnId];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma mark - Private
|
||||||
|
|
||||||
|
- (void)clearCache
|
||||||
|
{
|
||||||
|
[MXMediaManager clearCache];
|
||||||
|
[MXKAttachment clearCache];
|
||||||
|
[VoiceMessageAttachmentCacheManagerBridge clearCache];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
|
@ -19,14 +19,6 @@ import MatrixSDK
|
||||||
import Combine
|
import Combine
|
||||||
import DesignKit
|
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 {
|
enum AvatarServiceError: Error {
|
||||||
case pathNotfound
|
case pathNotfound
|
||||||
case loadingImageFailed(Error?)
|
case loadingImageFailed(Error?)
|
|
@ -17,7 +17,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
/// AvatarViewDataProtocol describe a view data that should be given to an AvatarView sublcass
|
/// 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)
|
/// Matrix item identifier (user id or room id)
|
||||||
var matrixItemId: String { get }
|
var matrixItemId: String { get }
|
||||||
|
|
||||||
|
|
|
@ -200,7 +200,7 @@
|
||||||
// Preview the public room
|
// Preview the public room
|
||||||
if (publicRoom.worldReadable)
|
if (publicRoom.worldReadable)
|
||||||
{
|
{
|
||||||
RoomPreviewData *roomPreviewData = [[RoomPreviewData alloc] initWithRoomId:publicRoom.roomId andSession:dataSource.mxSession];
|
RoomPreviewData *roomPreviewData = [[RoomPreviewData alloc] initWithPublicRoom:publicRoom andSession:dataSource.mxSession];
|
||||||
|
|
||||||
[self startActivityIndicator];
|
[self startActivityIndicator];
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,8 @@ class HomeViewControllerWithBannerWrapperViewController: UIViewController, Banne
|
||||||
|
|
||||||
super.init(nibName: nil, bundle: nil)
|
super.init(nibName: nil, bundle: nil)
|
||||||
|
|
||||||
|
extendedLayoutIncludesOpaqueBars = true
|
||||||
|
|
||||||
self.tabBarItem.tag = viewController.tabBarItem.tag
|
self.tabBarItem.tag = viewController.tabBarItem.tag
|
||||||
self.tabBarItem.image = viewController.tabBarItem.image
|
self.tabBarItem.image = viewController.tabBarItem.image
|
||||||
self.accessibilityLabel = viewController.accessibilityLabel
|
self.accessibilityLabel = viewController.accessibilityLabel
|
||||||
|
|
|
@ -19,7 +19,7 @@ import Foundation
|
||||||
class VersionCheckCoordinator: Coordinator, VersionCheckBannerViewDelegate, VersionCheckAlertViewControllerDelegate {
|
class VersionCheckCoordinator: Coordinator, VersionCheckBannerViewDelegate, VersionCheckAlertViewControllerDelegate {
|
||||||
private enum Constants {
|
private enum Constants {
|
||||||
static let osVersionToBeDropped = 11
|
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")
|
static let supportURL = URL(string: "https://support.apple.com/en-gb/guide/iphone/iph3e504502/ios")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -144,7 +144,7 @@ final class RoomNotificationSettingsViewController: UIViewController {
|
||||||
activityPresenter.removeCurrentActivityIndicator(animated: true)
|
activityPresenter.removeCurrentActivityIndicator(animated: true)
|
||||||
}
|
}
|
||||||
self.viewState = viewState
|
self.viewState = viewState
|
||||||
if case let .uiKit(avatarData) = viewState.avatarData {
|
if let avatarData = viewState.avatarData as? AvatarViewDataProtocol {
|
||||||
mainTableView.tableHeaderView = avatarView
|
mainTableView.tableHeaderView = avatarView
|
||||||
avatarView.configure(viewData: avatarData)
|
avatarView.configure(viewData: avatarData)
|
||||||
avatarView.update(theme: theme)
|
avatarView.update(theme: theme)
|
||||||
|
|
|
@ -26,6 +26,7 @@ enum VoiceMessageAttachmentCacheManagerError: Error {
|
||||||
case durationError(Error?)
|
case durationError(Error?)
|
||||||
case invalidNumberOfSamples
|
case invalidNumberOfSamples
|
||||||
case samplingError
|
case samplingError
|
||||||
|
case cancelled
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -51,6 +52,12 @@ struct VoiceMessageAttachmentCacheManagerLoadResult {
|
||||||
let samples: [Float]
|
let samples: [Float]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@objc class VoiceMessageAttachmentCacheManagerBridge: NSObject {
|
||||||
|
@objc static func clearCache() {
|
||||||
|
VoiceMessageAttachmentCacheManager.sharedManager.clearCache()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class VoiceMessageAttachmentCacheManager {
|
class VoiceMessageAttachmentCacheManager {
|
||||||
|
|
||||||
private struct Constants {
|
private struct Constants {
|
||||||
|
@ -67,6 +74,10 @@ class VoiceMessageAttachmentCacheManager {
|
||||||
private let workQueue: DispatchQueue
|
private let workQueue: DispatchQueue
|
||||||
private let operationQueue: OperationQueue
|
private let operationQueue: OperationQueue
|
||||||
|
|
||||||
|
private var temporaryFilesFolderURL: URL {
|
||||||
|
return URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true).appendingPathComponent("VoiceMessages")
|
||||||
|
}
|
||||||
|
|
||||||
private init() {
|
private init() {
|
||||||
workQueue = DispatchQueue(label: "io.element.VoiceMessageAttachmentCacheManager.queue", qos: .userInitiated)
|
workQueue = DispatchQueue(label: "io.element.VoiceMessageAttachmentCacheManager.queue", qos: .userInitiated)
|
||||||
operationQueue = OperationQueue()
|
operationQueue = OperationQueue()
|
||||||
|
@ -76,16 +87,27 @@ class VoiceMessageAttachmentCacheManager {
|
||||||
func loadAttachment(_ attachment: MXKAttachment, numberOfSamples: Int, completion: @escaping (Result<VoiceMessageAttachmentCacheManagerLoadResult, Error>) -> Void) {
|
func loadAttachment(_ attachment: MXKAttachment, numberOfSamples: Int, completion: @escaping (Result<VoiceMessageAttachmentCacheManagerLoadResult, Error>) -> Void) {
|
||||||
guard attachment.type == MXKAttachmentTypeVoiceMessage else {
|
guard attachment.type == MXKAttachmentTypeVoiceMessage else {
|
||||||
completion(Result.failure(VoiceMessageAttachmentCacheManagerError.invalidAttachmentType))
|
completion(Result.failure(VoiceMessageAttachmentCacheManagerError.invalidAttachmentType))
|
||||||
|
MXLog.error("[VoiceMessageAttachmentCacheManager] Invalid attachment type, ignoring request.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard let identifier = attachment.eventId else {
|
guard let identifier = attachment.eventId else {
|
||||||
completion(Result.failure(VoiceMessageAttachmentCacheManagerError.invalidEventId))
|
completion(Result.failure(VoiceMessageAttachmentCacheManagerError.invalidEventId))
|
||||||
|
MXLog.error("[VoiceMessageAttachmentCacheManager] Invalid event id, ignoring request.")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
guard numberOfSamples > 0 else {
|
guard numberOfSamples > 0 else {
|
||||||
completion(Result.failure(VoiceMessageAttachmentCacheManagerError.invalidNumberOfSamples))
|
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
|
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) {
|
private func enqueueLoadAttachment(_ attachment: MXKAttachment, identifier: String, numberOfSamples: Int, completion: @escaping (Result<VoiceMessageAttachmentCacheManagerLoadResult, Error>) -> Void) {
|
||||||
let callbackKey = CompletionCallbackKey(eventIdentifier: identifier, requiredNumberOfSamples: numberOfSamples)
|
let callbackKey = CompletionCallbackKey(eventIdentifier: identifier, requiredNumberOfSamples: numberOfSamples)
|
||||||
|
|
||||||
|
@ -169,8 +208,7 @@ class VoiceMessageAttachmentCacheManager {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
let temporaryDirectoryURL = URL(fileURLWithPath: NSTemporaryDirectory(), isDirectory: true)
|
let newURL = temporaryFilesFolderURL.appendingPathComponent(ProcessInfo().globallyUniqueString).appendingPathExtension("m4a")
|
||||||
let newURL = temporaryDirectoryURL.appendingPathComponent(ProcessInfo().globallyUniqueString).appendingPathExtension("m4a")
|
|
||||||
|
|
||||||
VoiceMessageAudioConverter.convertToMPEG4AAC(sourceURL: URL(fileURLWithPath: filePath), destinationURL: newURL) { result in
|
VoiceMessageAudioConverter.convertToMPEG4AAC(sourceURL: URL(fileURLWithPath: filePath), destinationURL: newURL) { result in
|
||||||
self.workQueue.async {
|
self.workQueue.async {
|
||||||
|
@ -275,4 +313,9 @@ class VoiceMessageAttachmentCacheManager {
|
||||||
|
|
||||||
MXLog.debug("[VoiceMessageAttachmentCacheManager] Failed task with error: \(error)")
|
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)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,8 +75,8 @@
|
||||||
|
|
||||||
- (HomeViewController *)homeViewController
|
- (HomeViewController *)homeViewController
|
||||||
{
|
{
|
||||||
HomeViewControllerWithBannerWrapperViewController *wrapperVC = [self viewControllerForClass:HomeViewControllerWithBannerWrapperViewController.class];
|
UIViewController *wrapperVC = [self viewControllerForClass:HomeViewControllerWithBannerWrapperViewController.class];
|
||||||
return wrapperVC.homeViewController;
|
return [(HomeViewControllerWithBannerWrapperViewController *)wrapperVC homeViewController];
|
||||||
}
|
}
|
||||||
|
|
||||||
- (FavouritesViewController *)favouritesViewController
|
- (FavouritesViewController *)favouritesViewController
|
||||||
|
|
|
@ -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 }
|
||||||
|
}
|
|
@ -51,6 +51,10 @@ targets:
|
||||||
script: "\"${PODS_ROOT}/SwiftGen/bin/swiftgen\" config run --config \"Tools/SwiftGen/swiftgen-config.yml\"\n"
|
script: "\"${PODS_ROOT}/SwiftGen/bin/swiftgen\" config run --config \"Tools/SwiftGen/swiftgen-config.yml\"\n"
|
||||||
|
|
||||||
sources:
|
sources:
|
||||||
|
- path: ../RiotSwiftUI/Modules
|
||||||
|
# Riot will provide it's own LocaleProviderType so exclude.
|
||||||
|
excludes:
|
||||||
|
- "Common/Locale/LocaleProvider.swift"
|
||||||
- path: ../Tools
|
- path: ../Tools
|
||||||
excludes:
|
excludes:
|
||||||
- "Logs"
|
- "Logs"
|
||||||
|
|
|
@ -48,6 +48,8 @@ targets:
|
||||||
- path: ../Riot/Modules/SetPinCode/SetupBiometrics/BiometricsAuthenticationPresenter.swift
|
- path: ../Riot/Modules/SetPinCode/SetupBiometrics/BiometricsAuthenticationPresenter.swift
|
||||||
- path: ../Riot/Categories/UNUserNotificationCenter.swift
|
- path: ../Riot/Categories/UNUserNotificationCenter.swift
|
||||||
- path: ../Riot/Managers/KeyValueStorage/KeyValueStore.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/Managers/EncryptionKeyManager/EncryptionKeyManager.swift
|
||||||
- path: ../Riot/Categories/Bundle.swift
|
- path: ../Riot/Categories/Bundle.swift
|
||||||
- path: ../Riot/Generated/Strings.swift
|
- path: ../Riot/Generated/Strings.swift
|
||||||
|
@ -59,3 +61,4 @@ targets:
|
||||||
- path: ../Riot/Categories/String.swift
|
- path: ../Riot/Categories/String.swift
|
||||||
- path: ../Riot/Categories/Character.swift
|
- path: ../Riot/Categories/Character.swift
|
||||||
- path: ../Riot/Managers/Widgets/WidgetConstants.m
|
- path: ../Riot/Managers/Widgets/WidgetConstants.m
|
||||||
|
- path: ../Riot/PropertyWrappers/UserDefaultsBackedPropertyWrapper.swift
|
||||||
|
|
|
@ -56,6 +56,7 @@ targets:
|
||||||
- path: ../Riot/Categories/UISearchBar.swift
|
- path: ../Riot/Categories/UISearchBar.swift
|
||||||
- path: ../Riot/Categories/String.swift
|
- path: ../Riot/Categories/String.swift
|
||||||
- path: ../Riot/Modules/Common/Recents/CellData/RecentCellData.m
|
- path: ../Riot/Modules/Common/Recents/CellData/RecentCellData.m
|
||||||
|
- path: ../Riot/PropertyWrappers/UserDefaultsBackedPropertyWrapper.swift
|
||||||
- path: ../Riot/Modules/Common/SegmentedViewController/SegmentedViewController.xib
|
- path: ../Riot/Modules/Common/SegmentedViewController/SegmentedViewController.xib
|
||||||
buildPhase: resources
|
buildPhase: resources
|
||||||
- path: ../Riot/Assets/en.lproj/Vector.strings
|
- path: ../Riot/Assets/en.lproj/Vector.strings
|
||||||
|
|
28
RiotSwiftUI/Common.xcconfig
Normal file
28
RiotSwiftUI/Common.xcconfig
Normal 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
|
20
RiotSwiftUI/Debug.xcconfig
Normal file
20
RiotSwiftUI/Debug.xcconfig
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
//
|
||||||
|
// Copyright 2021 Vector Creations Ltd
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Configuration settings file format documentation can be found at:
|
||||||
|
// https://help.apple.com/xcode/#/dev745c5c974
|
||||||
|
|
||||||
|
#include "Common.xcconfig"
|
22
RiotSwiftUI/Info.plist
Normal file
22
RiotSwiftUI/Info.plist
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>$(EXECUTABLE_NAME)</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>$(PRODUCT_NAME)</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>$(MARKETING_VERSION)</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>$(CURRENT_PROJECT_VERSION)</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -17,6 +17,7 @@
|
||||||
import Foundation
|
import Foundation
|
||||||
import Combine
|
import Combine
|
||||||
import DesignKit
|
import DesignKit
|
||||||
|
import UIKit
|
||||||
|
|
||||||
@available(iOS 14.0, *)
|
@available(iOS 14.0, *)
|
||||||
class MockAvatarService: AvatarServiceType {
|
class MockAvatarService: AvatarServiceType {
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
protocol AvatarInputType {
|
protocol AvatarInputType: AvatarType {
|
||||||
var mxContentUri: String? { get }
|
var mxContentUri: String? { get }
|
||||||
var matrixItemId: String { get }
|
var matrixItemId: String { get }
|
||||||
var displayName: String? { get }
|
var displayName: String? { get }
|
||||||
|
@ -27,8 +27,3 @@ struct AvatarInput: AvatarInputType {
|
||||||
var matrixItemId: String
|
var matrixItemId: String
|
||||||
let displayName: String?
|
let displayName: String?
|
||||||
}
|
}
|
||||||
|
|
||||||
enum AvatarInputOption {
|
|
||||||
case swiftUI(AvatarInputType)
|
|
||||||
case uiKit(AvatarViewDataProtocol)
|
|
||||||
}
|
|
19
RiotSwiftUI/Modules/Common/Avatar/Model/AvatarType.swift
Normal file
19
RiotSwiftUI/Modules/Common/Avatar/Model/AvatarType.swift
Normal 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 { }
|
|
@ -20,7 +20,7 @@ import DesignKit
|
||||||
@available(iOS 14.0, *)
|
@available(iOS 14.0, *)
|
||||||
struct AvatarImage: View {
|
struct AvatarImage: View {
|
||||||
|
|
||||||
@Environment(\.theme) var theme: Theme
|
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||||
@Environment(\.dependencies) var dependencies: DependencyContainer
|
@Environment(\.dependencies) var dependencies: DependencyContainer
|
||||||
@StateObject var viewModel = AvatarViewModel()
|
@StateObject var viewModel = AvatarViewModel()
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ struct AvatarImage: View {
|
||||||
.padding(4)
|
.padding(4)
|
||||||
.frame(width: CGFloat(size.rawValue), height: CGFloat(size.rawValue))
|
.frame(width: CGFloat(size.rawValue), height: CGFloat(size.rawValue))
|
||||||
.foregroundColor(.white)
|
.foregroundColor(.white)
|
||||||
.background(Color(theme.avatarColors[colorIndex]))
|
.background(theme.colors.namesAndAvatars[colorIndex])
|
||||||
.clipShape(Circle())
|
.clipShape(Circle())
|
||||||
// Make the text resizable (i.e. Make it large and then allow it to scale down)
|
// Make the text resizable (i.e. Make it large and then allow it to scale down)
|
||||||
.font(.system(size: 200))
|
.font(.system(size: 200))
|
||||||
|
@ -57,7 +57,7 @@ struct AvatarImage: View {
|
||||||
mxContentUri: mxContentUri,
|
mxContentUri: mxContentUri,
|
||||||
matrixItemId: matrixItemId,
|
matrixItemId: matrixItemId,
|
||||||
displayName: displayName,
|
displayName: displayName,
|
||||||
colorCount: theme.avatarColors.count,
|
colorCount: theme.colors.namesAndAvatars.count,
|
||||||
avatarSize: size
|
avatarSize: size
|
||||||
)
|
)
|
||||||
}
|
}
|
|
@ -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>
|
||||||
|
}
|
|
@ -47,7 +47,7 @@ class AvatarViewModel: InjectableObject, ObservableObject {
|
||||||
avatarService.avatarImage(mxContentUri: mxContentUri, avatarSize: avatarSize)
|
avatarService.avatarImage(mxContentUri: mxContentUri, avatarSize: avatarSize)
|
||||||
.sink { completion in
|
.sink { completion in
|
||||||
guard case let .failure(error) = completion else { return }
|
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.
|
// TODO: Report non-fatal error when we have Sentry or similar.
|
||||||
} receiveValue: { image in
|
} receiveValue: { image in
|
||||||
self.viewState = .avatar(image)
|
self.viewState = .avatar(image)
|
|
@ -15,6 +15,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
|
||||||
enum AvatarViewState {
|
enum AvatarViewState {
|
||||||
case empty
|
case empty
|
|
@ -23,17 +23,17 @@ import SwiftUI
|
||||||
@available(iOS 14.0, *)
|
@available(iOS 14.0, *)
|
||||||
struct VectorContentModifier: ViewModifier {
|
struct VectorContentModifier: ViewModifier {
|
||||||
|
|
||||||
@StateObject private var themeObserver = ThemeObserver.shared
|
@ObservedObject private var themePublisher = ThemePublisher.shared
|
||||||
|
|
||||||
func body(content: Content) -> some View {
|
func body(content: Content) -> some View {
|
||||||
content
|
content
|
||||||
.theme(themeObserver.theme)
|
.theme(themePublisher.theme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(iOS 14.0, *)
|
@available(iOS 14.0, *)
|
||||||
extension View {
|
extension View {
|
||||||
func vectorContent() -> some View {
|
func vectorContent() -> some View {
|
||||||
self.modifier(VectorContentModifier())
|
self.modifier(VectorContentModifier())
|
||||||
}
|
}
|
||||||
}
|
}
|
23
RiotSwiftUI/Modules/Common/Locale/LocaleProvider.swift
Normal file
23
RiotSwiftUI/Modules/Common/Locale/LocaleProvider.swift
Normal 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
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,17 +15,21 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import Combine
|
import DesignKit
|
||||||
|
|
||||||
|
/**
|
||||||
|
Extension to `ThemeIdentifier` for getting the SwiftUI theme.
|
||||||
|
*/
|
||||||
@available(iOS 14.0, *)
|
@available(iOS 14.0, *)
|
||||||
class ThemeObserver: ObservableObject {
|
extension ThemeIdentifier {
|
||||||
|
fileprivate static let defaultTheme = DefaultThemeSwiftUI()
|
||||||
static let shared = ThemeObserver()
|
fileprivate static let darkTheme = DarkThemeSwiftUI()
|
||||||
|
public var themeSwiftUI: ThemeSwiftUI {
|
||||||
init() {
|
switch self {
|
||||||
NotificationCenter.default.publisher(for: NSNotification.Name.themeServiceDidChangeTheme).map { _ in
|
case .light:
|
||||||
ThemeService.shared().theme
|
return Self.defaultTheme
|
||||||
}.assign(to: &$theme)
|
case .dark, .black:
|
||||||
|
return Self.darkTheme
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@Published var theme: Theme = ThemeService.shared().theme
|
|
||||||
}
|
}
|
|
@ -16,14 +16,16 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
import SwiftUI
|
import SwiftUI
|
||||||
|
import DesignKit
|
||||||
|
|
||||||
|
@available(iOS 14.0, *)
|
||||||
private struct ThemeKey: EnvironmentKey {
|
private struct ThemeKey: EnvironmentKey {
|
||||||
static let defaultValue = ThemeService.shared().theme
|
static let defaultValue = ThemePublisher.shared.theme
|
||||||
}
|
}
|
||||||
|
|
||||||
@available(iOS 14.0, *)
|
@available(iOS 14.0, *)
|
||||||
extension EnvironmentValues {
|
extension EnvironmentValues {
|
||||||
var theme: Theme {
|
var theme: ThemeSwiftUI {
|
||||||
get { self[ThemeKey.self] }
|
get { self[ThemeKey.self] }
|
||||||
set { self[ThemeKey.self] = newValue }
|
set { self[ThemeKey.self] = newValue }
|
||||||
}
|
}
|
||||||
|
@ -36,7 +38,7 @@ extension EnvironmentValues {
|
||||||
*/
|
*/
|
||||||
@available(iOS 14.0, *)
|
@available(iOS 14.0, *)
|
||||||
extension View {
|
extension View {
|
||||||
func theme(_ theme: Theme) -> some View {
|
func theme(_ theme: ThemeSwiftUI) -> some View {
|
||||||
environment(\.theme, theme)
|
environment(\.theme, theme)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -49,7 +51,6 @@ extension View {
|
||||||
@available(iOS 14.0, *)
|
@available(iOS 14.0, *)
|
||||||
extension View {
|
extension View {
|
||||||
func theme(_ themeId: ThemeIdentifier) -> some View {
|
func theme(_ themeId: ThemeIdentifier) -> some View {
|
||||||
let theme = ThemeService.shared().theme(withThemeId: themeId.rawValue)
|
return environment(\.theme, themeId.themeSwiftUI)
|
||||||
return environment(\.theme, theme)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
51
RiotSwiftUI/Modules/Common/Theme/ThemePublisher.swift
Normal file
51
RiotSwiftUI/Modules/Common/Theme/ThemePublisher.swift
Normal 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)
|
||||||
|
}
|
||||||
|
}
|
23
RiotSwiftUI/Modules/Common/Theme/ThemeSwiftUI.swift
Normal file
23
RiotSwiftUI/Modules/Common/Theme/ThemeSwiftUI.swift
Normal 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 }
|
||||||
|
}
|
|
@ -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())
|
||||||
|
}
|
|
@ -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())
|
||||||
|
}
|
|
@ -38,25 +38,24 @@ final class RoomNotificationSettingsCoordinator: RoomNotificationSettingsCoordin
|
||||||
// MARK: - Setup
|
// MARK: - Setup
|
||||||
|
|
||||||
init(room: MXRoom, presentedModally: Bool = true) {
|
init(room: MXRoom, presentedModally: Bool = true) {
|
||||||
let roomNotificationService = RoomNotificationSettingsService(room: room)
|
let roomNotificationService = MXRoomNotificationSettingsService(room: room)
|
||||||
let avatarData: AvatarInputOption?
|
let avatarData: AvatarType?
|
||||||
let showAvatar = presentedModally
|
let showAvatar = presentedModally
|
||||||
if #available(iOS 14.0.0, *) {
|
if #available(iOS 14.0.0, *) {
|
||||||
avatarData = showAvatar ? .swiftUI(AvatarInput(
|
avatarData = showAvatar ? AvatarInput(
|
||||||
mxContentUri: room.summary.avatar,
|
mxContentUri: room.summary.avatar,
|
||||||
matrixItemId: room.roomId,
|
matrixItemId: room.roomId,
|
||||||
displayName: room.summary.displayname
|
displayName: room.summary.displayname
|
||||||
)) : nil
|
) : nil
|
||||||
} else {
|
} else {
|
||||||
avatarData = showAvatar ? .uiKit(RoomAvatarViewData(
|
avatarData = showAvatar ? RoomAvatarViewData(
|
||||||
roomId: room.roomId,
|
roomId: room.roomId,
|
||||||
displayName: room.summary.displayname,
|
displayName: room.summary.displayname,
|
||||||
avatarUrl: room.summary.avatar,
|
avatarUrl: room.summary.avatar,
|
||||||
mediaManager: room.mxSession.mediaManager
|
mediaManager: room.mxSession.mediaManager
|
||||||
)) : nil
|
) : nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let viewModel: RoomNotificationSettingsViewModel
|
let viewModel: RoomNotificationSettingsViewModel
|
||||||
let viewController: UIViewController
|
let viewController: UIViewController
|
||||||
if #available(iOS 14.0.0, *) {
|
if #available(iOS 14.0.0, *) {
|
|
@ -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 : ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -18,36 +18,12 @@
|
||||||
|
|
||||||
import Foundation
|
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 {
|
protocol RoomNotificationSettingsViewStateType {
|
||||||
var saving: Bool { get }
|
var saving: Bool { get }
|
||||||
var roomEncrypted: Bool { get }
|
var roomEncrypted: Bool { get }
|
||||||
var notificationOptions: [RoomNotificationState] { get }
|
var notificationOptions: [RoomNotificationState] { get }
|
||||||
var notificationState: RoomNotificationState { get }
|
var notificationState: RoomNotificationState { get }
|
||||||
var avatarData: AvatarInputOption? { get }
|
var avatarData: AvatarType? { get }
|
||||||
var displayName: String? { get }
|
var displayName: String? { get }
|
||||||
}
|
}
|
||||||
|
|
||||||
extension RoomNotificationSettingsViewState {
|
|
||||||
var roomEncryptedString: String {
|
|
||||||
roomEncrypted ? VectorL10n.roomNotifsSettingsEncryptedRoomNotice : ""
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
final class RoomNotificationSettingsService: RoomNotificationSettingsServiceType {
|
final class MXRoomNotificationSettingsService: RoomNotificationSettingsServiceType {
|
||||||
|
|
||||||
typealias Completion = () -> Void
|
typealias Completion = () -> Void
|
||||||
|
|
|
@ -19,11 +19,11 @@ import SwiftUI
|
||||||
|
|
||||||
@available(iOS 14.0, *)
|
@available(iOS 14.0, *)
|
||||||
struct FormItemButtonStyle: ButtonStyle {
|
struct FormItemButtonStyle: ButtonStyle {
|
||||||
@Environment(\.theme) var theme: Theme
|
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||||
func makeBody(configuration: Self.Configuration) -> some View {
|
func makeBody(configuration: Self.Configuration) -> some View {
|
||||||
configuration.label
|
configuration.label
|
||||||
.background(configuration.isPressed ? Color(theme.selectedBackgroundColor) : Color(theme.backgroundColor))
|
.background(configuration.isPressed ? theme.colors.system : theme.colors.background)
|
||||||
.foregroundColor(Color(theme.textPrimaryColor))
|
.foregroundColor(theme.colors.primaryContent)
|
||||||
.font(Font(theme.fonts.body))
|
.font(theme.fonts.body)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,7 +21,7 @@ struct FormPickerItem: View {
|
||||||
|
|
||||||
typealias TapCallback = () -> Void
|
typealias TapCallback = () -> Void
|
||||||
|
|
||||||
@Environment(\.theme) var theme: Theme
|
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||||
|
|
||||||
var title: String
|
var title: String
|
||||||
var selected: Bool
|
var selected: Bool
|
||||||
|
@ -38,7 +38,7 @@ struct FormPickerItem: View {
|
||||||
Spacer()
|
Spacer()
|
||||||
if selected {
|
if selected {
|
||||||
Image("checkmark")
|
Image("checkmark")
|
||||||
.foregroundColor(Color(theme.tintColor))
|
.foregroundColor(theme.colors.accent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.padding(.trailing)
|
.padding(.trailing)
|
||||||
|
@ -55,6 +55,7 @@ struct FormPickerItem: View {
|
||||||
|
|
||||||
@available(iOS 14.0, *)
|
@available(iOS 14.0, *)
|
||||||
struct FormPickerItem_Previews: PreviewProvider {
|
struct FormPickerItem_Previews: PreviewProvider {
|
||||||
|
|
||||||
static let items = ["Item 1", "Item 2", "Item 3"]
|
static let items = ["Item 1", "Item 2", "Item 3"]
|
||||||
static var selected: String = items[0]
|
static var selected: String = items[0]
|
||||||
static var previews: some View {
|
static var previews: some View {
|
|
@ -19,16 +19,16 @@ import SwiftUI
|
||||||
@available(iOS 14.0, *)
|
@available(iOS 14.0, *)
|
||||||
struct FormSectionFooter: View {
|
struct FormSectionFooter: View {
|
||||||
|
|
||||||
@Environment(\.theme) var theme: Theme
|
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||||
var text: String
|
var text: String
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text(text)
|
Text(text)
|
||||||
.foregroundColor(Color(theme.textSecondaryColor))
|
.foregroundColor(theme.colors.secondaryContent)
|
||||||
.padding(.top)
|
.padding(.top)
|
||||||
.padding(.leading)
|
.padding(.leading)
|
||||||
.padding(.trailing)
|
.padding(.trailing)
|
||||||
.font(Font(theme.fonts.callout))
|
.font(theme.fonts.callout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,16 +19,16 @@ import SwiftUI
|
||||||
@available(iOS 14.0, *)
|
@available(iOS 14.0, *)
|
||||||
struct FormSectionHeader: View {
|
struct FormSectionHeader: View {
|
||||||
|
|
||||||
@Environment(\.theme) var theme: Theme
|
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||||
var text: String
|
var text: String
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
Text(text)
|
Text(text)
|
||||||
.foregroundColor(Color(theme.textSecondaryColor))
|
.foregroundColor(theme.colors.secondaryContent)
|
||||||
.padding(.top, 32)
|
.padding(.top, 32)
|
||||||
.padding(.leading)
|
.padding(.leading)
|
||||||
.padding(.bottom, 8)
|
.padding(.bottom, 8)
|
||||||
.font(Font(theme.fonts.subheadline))
|
.font(theme.fonts.subheadline)
|
||||||
.textCase(.uppercase)
|
.textCase(.uppercase)
|
||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
}
|
}
|
|
@ -41,7 +41,7 @@ struct RoomNotificationSettings: View {
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
VectorForm {
|
VectorForm {
|
||||||
if case let .swiftUI(avatarData) = viewModel.viewState.avatarData {
|
if let avatarData = viewModel.viewState.avatarData as? AvatarInputType {
|
||||||
RoomNotificationSettingsHeader(
|
RoomNotificationSettingsHeader(
|
||||||
avatarData: avatarData,
|
avatarData: avatarData,
|
||||||
displayName: viewModel.viewState.displayName
|
displayName: viewModel.viewState.displayName
|
||||||
|
@ -75,7 +75,7 @@ struct RoomNotificationSettings_Previews: PreviewProvider {
|
||||||
|
|
||||||
static let mockViewModel = RoomNotificationSettingsSwiftUIViewModel(
|
static let mockViewModel = RoomNotificationSettingsSwiftUIViewModel(
|
||||||
roomNotificationService: MockRoomNotificationSettingsService.example,
|
roomNotificationService: MockRoomNotificationSettingsService.example,
|
||||||
avatarData: .swiftUI(MockAvatarInput.example),
|
avatarData: MockAvatarInput.example,
|
||||||
displayName: MockAvatarInput.example.displayName,
|
displayName: MockAvatarInput.example.displayName,
|
||||||
roomEncrypted: true
|
roomEncrypted: true
|
||||||
)
|
)
|
|
@ -19,7 +19,7 @@ import SwiftUI
|
||||||
@available(iOS 14.0, *)
|
@available(iOS 14.0, *)
|
||||||
struct RoomNotificationSettingsHeader: View {
|
struct RoomNotificationSettingsHeader: View {
|
||||||
|
|
||||||
@Environment(\.theme) var theme: Theme
|
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||||
var avatarData: AvatarInputType
|
var avatarData: AvatarInputType
|
||||||
var displayName: String?
|
var displayName: String?
|
||||||
|
|
||||||
|
@ -30,8 +30,8 @@ struct RoomNotificationSettingsHeader: View {
|
||||||
AvatarImage(avatarData: avatarData, size: .xxLarge)
|
AvatarImage(avatarData: avatarData, size: .xxLarge)
|
||||||
if let displayName = displayName {
|
if let displayName = displayName {
|
||||||
Text(displayName)
|
Text(displayName)
|
||||||
.font(Font(theme.fonts.title3SB))
|
.font(theme.fonts.title3SB)
|
||||||
.foregroundColor(Color(theme.textPrimaryColor))
|
.foregroundColor(theme.colors.primaryContent)
|
||||||
.textCase(nil)
|
.textCase(nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,7 +19,7 @@ import SwiftUI
|
||||||
@available(iOS 14.0, *)
|
@available(iOS 14.0, *)
|
||||||
struct VectorForm<Content: View>: View {
|
struct VectorForm<Content: View>: View {
|
||||||
|
|
||||||
@Environment(\.theme) var theme: Theme
|
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||||
var content: () -> Content
|
var content: () -> Content
|
||||||
|
|
||||||
init(@ViewBuilder content: @escaping () -> Content) {
|
init(@ViewBuilder content: @escaping () -> Content) {
|
||||||
|
@ -37,7 +37,7 @@ struct VectorForm<Content: View>: View {
|
||||||
maxHeight: .infinity,
|
maxHeight: .infinity,
|
||||||
alignment: .top
|
alignment: .top
|
||||||
)
|
)
|
||||||
.background(Color(theme.baseColor))
|
.background(theme.colors.system)
|
||||||
.edgesIgnoringSafeArea(.bottom)
|
.edgesIgnoringSafeArea(.bottom)
|
||||||
|
|
||||||
}
|
}
|
|
@ -55,7 +55,7 @@ class RoomNotificationSettingsViewModel: RoomNotificationSettingsViewModelType {
|
||||||
|
|
||||||
convenience init(
|
convenience init(
|
||||||
roomNotificationService: RoomNotificationSettingsServiceType,
|
roomNotificationService: RoomNotificationSettingsServiceType,
|
||||||
avatarData: AvatarInputOption?,
|
avatarData: AvatarType?,
|
||||||
displayName: String?,
|
displayName: String?,
|
||||||
roomEncrypted: Bool
|
roomEncrypted: Bool
|
||||||
) {
|
) {
|
|
@ -41,7 +41,7 @@ final class NotificationSettingsCoordinator: NotificationSettingsCoordinatorType
|
||||||
|
|
||||||
init(session: MXSession, screen: NotificationSettingsScreen) {
|
init(session: MXSession, screen: NotificationSettingsScreen) {
|
||||||
self.session = session
|
self.session = session
|
||||||
let notificationSettingsService = NotificationSettingsService(session: session)
|
let notificationSettingsService = MXNotificationSettingsService(session: session)
|
||||||
let viewModel = NotificationSettingsViewModel(notificationSettingsService: notificationSettingsService, ruleIds: screen.pushRules)
|
let viewModel = NotificationSettingsViewModel(notificationSettingsService: notificationSettingsService, ruleIds: screen.pushRules)
|
||||||
let viewController: UIViewController
|
let viewController: UIViewController
|
||||||
switch screen {
|
switch screen {
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
Loading…
Reference in a new issue