mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-16 06:28:27 +02:00
Finish extraction
- Moves SwiftUI code out of Riot and into RiotSwiftUI which has no dependency on Matrix SDK. - Git wasn't smart enough to see the file moves. Most feature function has remain unchanged. 1 change I did make was remove NotificationSettingsViewModel's dependence on MxPushRule, so that the view model could be moved into RiotSwiftUI. - Add LocaleProvider to abstract VectorL10n's use of Matrix SDK language so it can be used in RiotSwiftUI. - Split Theme into UKit/SwiftUI version to remove RiotSwiftUI's dependence on ThemeService and ThemeV1. - Migrated from ThemeObserver to ThemePublisher. We push updates to ThemePublisher so that we can remove ThemeService as dependency. - Add .DS_Store to .gitignore
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -19,6 +19,7 @@ DerivedData
|
||||
out/
|
||||
.vscode/
|
||||
vendor/
|
||||
.DS_Store
|
||||
|
||||
# CocoaPods
|
||||
#
|
||||
|
||||
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]
|
||||
}
|
||||
@@ -18,58 +18,56 @@ import Foundation
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
|
||||
public protocol DesignKitColorType { }
|
||||
|
||||
extension UIColor: DesignKitColorType { }
|
||||
|
||||
extension Color : DesignKitColorType { }
|
||||
|
||||
/// Colors at https://www.figma.com/file/X4XTH9iS2KGJ2wFKDqkyed/Compound?node-id=1255%3A1104
|
||||
public protocol Colors {
|
||||
|
||||
associatedtype ColorType
|
||||
|
||||
/// - Focused/Active states
|
||||
/// - CTAs
|
||||
var accent: DesignKitColorType { get }
|
||||
var accent: ColorType { get }
|
||||
|
||||
/// - Error messages
|
||||
/// - Content requiring user attention
|
||||
/// - Notification, alerts
|
||||
var alert: DesignKitColorType { get }
|
||||
var alert: ColorType { get }
|
||||
|
||||
/// - Text
|
||||
/// - Icons
|
||||
var primaryContent: DesignKitColorType { get }
|
||||
var primaryContent: ColorType { get }
|
||||
|
||||
/// - Text
|
||||
/// - Icons
|
||||
var secondaryContent: DesignKitColorType { get }
|
||||
var secondaryContent: ColorType { get }
|
||||
|
||||
/// - Text
|
||||
/// - Icons
|
||||
var tertiaryContent: DesignKitColorType { get }
|
||||
var tertiaryContent: ColorType { get }
|
||||
|
||||
/// - Text
|
||||
/// - Icons
|
||||
var quarterlyContent: DesignKitColorType { get }
|
||||
var quarterlyContent: ColorType { get }
|
||||
|
||||
/// - Text
|
||||
/// - Icons
|
||||
var quinaryContent: DesignKitColorType { get }
|
||||
/// - separating lines and other UI components
|
||||
var quinaryContent: ColorType { get }
|
||||
|
||||
/// - System-based areas and backgrounds
|
||||
var system: ColorType { get }
|
||||
|
||||
/// Separating line
|
||||
var separator: DesignKitColorType { get }
|
||||
var separator: ColorType { get }
|
||||
|
||||
// Cards, tiles
|
||||
var tile: DesignKitColorType { get }
|
||||
var tile: ColorType { get }
|
||||
|
||||
/// Top navigation background on iOS
|
||||
var navigation: DesignKitColorType { get }
|
||||
var navigation: ColorType { get }
|
||||
|
||||
/// Background UI color
|
||||
var background: DesignKitColorType { get }
|
||||
var background: ColorType { get }
|
||||
|
||||
/// - Names in chat timeline
|
||||
/// - Avatars default states that include first name letter
|
||||
var namesAndAvatars: [DesignKitColorType] { 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,75 +17,70 @@
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
|
||||
public protocol DesignKitFontType { }
|
||||
|
||||
extension UIFont: DesignKitFontType { }
|
||||
|
||||
extension Font : DesignKitFontType { }
|
||||
|
||||
|
||||
/// Describe fonts used in the application.
|
||||
/// Font names are based on Element typograhy https://www.figma.com/file/X4XTH9iS2KGJ2wFKDqkyed/Compound?node-id=1362%3A0 which is based on Apple font text styles (UIFont.TextStyle): https://developer.apple.com/documentation/uikit/uifonttextstyle
|
||||
/// Create a custom TextStyle enum (like DesignKit.Fonts.TextStyle) is also a possiblity
|
||||
public protocol Fonts {
|
||||
|
||||
associatedtype FontType
|
||||
|
||||
/// The font for large titles.
|
||||
var largeTitle: DesignKitFontType { get }
|
||||
var largeTitle: FontType { get }
|
||||
|
||||
/// `largeTitle` with a Bold weight.
|
||||
var largeTitleB: DesignKitFontType { get }
|
||||
var largeTitleB: FontType { get }
|
||||
|
||||
/// The font for first-level hierarchical headings.
|
||||
var title1: DesignKitFontType { get }
|
||||
var title1: FontType { get }
|
||||
|
||||
/// `title1` with a Bold weight.
|
||||
var title1B: DesignKitFontType { get }
|
||||
var title1B: FontType { get }
|
||||
|
||||
/// The font for second-level hierarchical headings.
|
||||
var title2: DesignKitFontType { get }
|
||||
var title2: FontType { get }
|
||||
|
||||
/// `title2` with a Bold weight.
|
||||
var title2B: DesignKitFontType { get }
|
||||
var title2B: FontType { get }
|
||||
|
||||
/// The font for third-level hierarchical headings.
|
||||
var title3: DesignKitFontType { get }
|
||||
var title3: FontType { get }
|
||||
|
||||
/// `title3` with a Semi Bold weight.
|
||||
var title3SB: DesignKitFontType { get }
|
||||
var title3SB: FontType { get }
|
||||
|
||||
/// The font for headings.
|
||||
var headline: DesignKitFontType { get }
|
||||
var headline: FontType { get }
|
||||
|
||||
/// The font for subheadings.
|
||||
var subheadline: DesignKitFontType { get }
|
||||
var subheadline: FontType { get }
|
||||
|
||||
/// The font for body text.
|
||||
var body: DesignKitFontType { get }
|
||||
var body: FontType { get }
|
||||
|
||||
/// `body` with a Semi Bold weight.
|
||||
var bodySB: DesignKitFontType { get }
|
||||
var bodySB: FontType { get }
|
||||
|
||||
/// The font for callouts.
|
||||
var callout: DesignKitFontType { get }
|
||||
var callout: FontType { get }
|
||||
|
||||
/// `callout` with a Semi Bold weight.
|
||||
var calloutSB: DesignKitFontType { get }
|
||||
var calloutSB: FontType { get }
|
||||
|
||||
/// The font for footnotes.
|
||||
var footnote: DesignKitFontType { get }
|
||||
var footnote: FontType { get }
|
||||
|
||||
/// `footnote` with a Semi Bold weight.
|
||||
var footnoteSB: DesignKitFontType { get }
|
||||
var footnoteSB: FontType { get }
|
||||
|
||||
/// The font for standard captions.
|
||||
var caption1: DesignKitFontType { get }
|
||||
var caption1: FontType { get }
|
||||
|
||||
/// `caption1` with a Semi Bold weight.
|
||||
var caption1SB: DesignKitFontType { get }
|
||||
var caption1SB: FontType { get }
|
||||
|
||||
/// The font for alternate captions.
|
||||
var caption2: DesignKitFontType { get }
|
||||
var caption2: FontType { get }
|
||||
|
||||
/// `caption2` with a Semi Bold weight.
|
||||
var caption2SB: DesignKitFontType { 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 {
|
||||
|
||||
/// Colors object
|
||||
var colors: Colors { get }
|
||||
var colors: ColorsUIKit { get }
|
||||
|
||||
/// Fonts object
|
||||
var fonts: Fonts { get }
|
||||
var fonts: FontsUIKit { get }
|
||||
|
||||
/// may contain more design components in future, like icons, audio files etc.
|
||||
}
|
||||
|
||||
/// Theme v2 for SwiftUI.
|
||||
@available(iOS 14.0, *)
|
||||
public protocol ThemeSwiftUIType {
|
||||
|
||||
/// Colors object
|
||||
var colors: ColorSwiftUI { get }
|
||||
|
||||
/// Fonts object
|
||||
var fonts: FontSwiftUI { get }
|
||||
|
||||
/// may contain more design components in future, like icons, audio files etc.
|
||||
|
||||
}
|
||||
|
||||
@@ -16,43 +16,36 @@
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
|
||||
/// Dark theme colors. Will be a struct when things are more Swifty.
|
||||
public class DarkColors: Colors {
|
||||
|
||||
public let accent: UIColor = UIColor(rgb: 0x0DBD8B)
|
||||
|
||||
public let alert: UIColor = UIColor(rgb: 0xFF4B55)
|
||||
|
||||
public let primaryContent: UIColor = UIColor(rgb: 0xFFFFFF)
|
||||
|
||||
public let secondaryContent: UIColor = UIColor(rgb: 0xA9B2BC)
|
||||
|
||||
public let tertiaryContent: UIColor = UIColor(rgb: 0x8E99A4)
|
||||
|
||||
public let quarterlyContent: UIColor = UIColor(rgb: 0x6F7882)
|
||||
|
||||
public let quinaryContent: UIColor = UIColor(rgb: 0x394049)
|
||||
|
||||
public let separator: UIColor = UIColor(rgb: 0x21262C)
|
||||
|
||||
public let tile: UIColor = UIColor(rgb: 0x394049)
|
||||
|
||||
public let navigation: UIColor = UIColor(rgb: 0x21262C)
|
||||
|
||||
public let background: UIColor = UIColor(rgb: 0x15191E)
|
||||
|
||||
public let namesAndAvatars: [UIColor] = [
|
||||
UIColor(rgb: 0x368BD6),
|
||||
UIColor(rgb: 0xAC3BA8),
|
||||
UIColor(rgb: 0x03B381),
|
||||
UIColor(rgb: 0xE64F7A),
|
||||
UIColor(rgb: 0xFF812D),
|
||||
UIColor(rgb: 0x2DC2C5),
|
||||
UIColor(rgb: 0x5C56F5),
|
||||
UIColor(rgb: 0x74D12C)
|
||||
]
|
||||
|
||||
public init() {}
|
||||
/// Dark theme colors.
|
||||
public class DarkColors {
|
||||
private static let values = ColorValues(
|
||||
accent: UIColor(rgb:0x0DBD8B),
|
||||
alert: UIColor(rgb:0xFF4B55),
|
||||
primaryContent: UIColor(rgb:0xFFFFFF),
|
||||
secondaryContent: UIColor(rgb:0xA9B2BC),
|
||||
tertiaryContent: UIColor(rgb:0x8E99A4),
|
||||
quarterlyContent: UIColor(rgb:0x6F7882),
|
||||
quinaryContent: UIColor(rgb:0x394049),
|
||||
separator: UIColor(rgb:0x21262C),
|
||||
system: UIColor(rgb:0x21262C),
|
||||
tile: UIColor(rgb:0x394049),
|
||||
navigation: UIColor(rgb:0x21262C),
|
||||
background: UIColor(rgb:0x15191E),
|
||||
namesAndAvatars: [
|
||||
UIColor(rgb:0x368BD6),
|
||||
UIColor(rgb:0xAC3BA8),
|
||||
UIColor(rgb:0x03B381),
|
||||
UIColor(rgb:0xE64F7A),
|
||||
UIColor(rgb:0xFF812D),
|
||||
UIColor(rgb:0x2DC2C5),
|
||||
UIColor(rgb:0x5C56F5),
|
||||
UIColor(rgb:0x74D12C)
|
||||
]
|
||||
)
|
||||
|
||||
public static var uiKit = ColorsUIKit(values: values)
|
||||
@available(iOS 14.0, *)
|
||||
public static var swiftUI = ColorSwiftUI(values: values)
|
||||
}
|
||||
|
||||
@@ -16,43 +16,42 @@
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
|
||||
/// Light theme colors. Will be a struct when things are more Swifty.
|
||||
public class LightColors: Colors {
|
||||
|
||||
public let accent: UIColor = UIColor(rgb: 0x0DBD8B)
|
||||
|
||||
public let alert: UIColor = UIColor(rgb: 0xFF4B55)
|
||||
|
||||
public let primaryContent: UIColor = UIColor(rgb: 0x17191C)
|
||||
|
||||
public let secondaryContent: UIColor = UIColor(rgb: 0x737D8C)
|
||||
|
||||
public let tertiaryContent: UIColor = UIColor(rgb: 0x8D97A5)
|
||||
|
||||
public let quarterlyContent: UIColor = UIColor(rgb: 0xC1C6CD)
|
||||
|
||||
public let quinaryContent: UIColor = UIColor(rgb: 0xE3E8F0)
|
||||
|
||||
public let separator: UIColor = UIColor(rgb: 0xE3E8F0)
|
||||
|
||||
public let tile: UIColor = UIColor(rgb: 0xF3F8FD)
|
||||
|
||||
public let navigation: UIColor = UIColor(rgb: 0xF4F6FA)
|
||||
|
||||
public let background: UIColor = UIColor(rgb: 0xFFFFFF)
|
||||
|
||||
public let namesAndAvatars: [UIColor] = [
|
||||
UIColor(rgb: 0x368BD6),
|
||||
UIColor(rgb: 0xAC3BA8),
|
||||
UIColor(rgb: 0x03B381),
|
||||
UIColor(rgb: 0xE64F7A),
|
||||
UIColor(rgb: 0xFF812D),
|
||||
UIColor(rgb: 0x2DC2C5),
|
||||
UIColor(rgb: 0x5C56F5),
|
||||
UIColor(rgb: 0x74D12C)
|
||||
]
|
||||
|
||||
public init() {}
|
||||
/// Light theme colors.
|
||||
public class LightColors {
|
||||
private static let values = ColorValues(
|
||||
accent: UIColor(rgb:0x0DBD8B),
|
||||
alert: UIColor(rgb:0xFF4B55),
|
||||
primaryContent: UIColor(rgb:0x17191C),
|
||||
secondaryContent: UIColor(rgb:0x737D8C),
|
||||
tertiaryContent: UIColor(rgb:0x8D97A5),
|
||||
quarterlyContent: UIColor(rgb:0xC1C6CD),
|
||||
quinaryContent: UIColor(rgb:0xE3E8F0),
|
||||
separator: UIColor(rgb:0xE3E8F0),
|
||||
system: UIColor(rgb:0xF4F6FA),
|
||||
tile: UIColor(rgb:0xF3F8FD),
|
||||
navigation: UIColor(rgb:0xF4F6FA),
|
||||
background: UIColor(rgb:0xFFFFFF),
|
||||
namesAndAvatars: [
|
||||
UIColor(rgb:0x368BD6),
|
||||
UIColor(rgb:0xAC3BA8),
|
||||
UIColor(rgb:0x03B381),
|
||||
UIColor(rgb:0xE64F7A),
|
||||
UIColor(rgb:0xFF812D),
|
||||
UIColor(rgb:0x2DC2C5),
|
||||
UIColor(rgb:0x5C56F5),
|
||||
UIColor(rgb:0x74D12C)
|
||||
]
|
||||
)
|
||||
|
||||
public static var uiKit = ColorsUIKit(values: values)
|
||||
@available(iOS 14.0, *)
|
||||
public static var swiftUI = ColorSwiftUI(values: values)
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -5143,13 +5143,11 @@ extension VectorL10n {
|
||||
static func tr(_ table: String, _ key: String, _ args: CVarArg...) -> String {
|
||||
let format = NSLocalizedString(key, tableName: table, bundle: Bundle(for: BundleToken.self), comment: "")
|
||||
let locale: Locale
|
||||
// if let localeIdentifier = Bundle.mxk_language() {
|
||||
// locale = Locale(identifier: localeIdentifier)
|
||||
// } else if let fallbackLocaleIdentifier = Bundle.mxk_fallbackLanguage() {
|
||||
// locale = Locale(identifier: fallbackLocaleIdentifier)
|
||||
// } else {
|
||||
locale = Locale.current
|
||||
// }
|
||||
if let providedLocale = LocaleProvider.locale {
|
||||
locale = providedLocale
|
||||
} else {
|
||||
locale = Locale.current
|
||||
}
|
||||
|
||||
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 }
|
||||
}
|
||||
@@ -142,12 +142,8 @@ class DarkTheme: NSObject, Theme {
|
||||
}
|
||||
|
||||
/// MARK: - Theme v2
|
||||
var colors: ColorsUIKit = DarkColors.uiKit
|
||||
|
||||
lazy var colors: Colors = {
|
||||
return DarkColors()
|
||||
}()
|
||||
var fonts: FontsUIKit = FontsUIKit(values: ElementFonts())
|
||||
|
||||
lazy var fonts: Fonts = {
|
||||
return ElementFonts()
|
||||
}()
|
||||
}
|
||||
|
||||
@@ -149,12 +149,7 @@ class DefaultTheme: NSObject, Theme {
|
||||
}
|
||||
|
||||
/// MARK: - Theme v2
|
||||
var colors: ColorsUIKit = LightColors.uiKit
|
||||
|
||||
lazy var colors: Colors = {
|
||||
return LightColors()
|
||||
}()
|
||||
|
||||
lazy var fonts: Fonts = {
|
||||
return ElementFonts()
|
||||
}()
|
||||
var fonts: FontsUIKit = FontsUIKit(values: ElementFonts())
|
||||
}
|
||||
|
||||
@@ -103,6 +103,18 @@ final class AppCoordinator: NSObject, AppCoordinatorType {
|
||||
|
||||
private func setupTheme() {
|
||||
ThemeService.shared().themeId = RiotSettings.shared.userInterfaceTheme
|
||||
if #available(iOS 14.0, *) {
|
||||
guard let themeId = ThemeService.shared().themeIdentifier else {
|
||||
MXLog.error("[AppCoordinator] No theme id found to update ThemePublisher")
|
||||
return
|
||||
}
|
||||
ThemePublisher.configure(themeId: themeId)
|
||||
let themeIdPublisher = NotificationCenter.default.publisher(for: Notification.Name.themeServiceDidChangeTheme)
|
||||
.compactMap({ _ in ThemeService.shared().themeIdentifier })
|
||||
.eraseToAnyPublisher()
|
||||
|
||||
ThemePublisher.shared.republish(themeIdPublisher: themeIdPublisher)
|
||||
}
|
||||
}
|
||||
|
||||
private func showAuthentication() {
|
||||
|
||||
@@ -39,24 +39,23 @@ final class RoomNotificationSettingsCoordinator: RoomNotificationSettingsCoordin
|
||||
|
||||
init(room: MXRoom, presentedModally: Bool = true) {
|
||||
let roomNotificationService = RoomNotificationSettingsService(room: room)
|
||||
let avatarData: AvatarInputOption?
|
||||
let avatarData: AvatarType?
|
||||
let showAvatar = presentedModally
|
||||
if #available(iOS 14.0.0, *) {
|
||||
avatarData = showAvatar ? .swiftUI(AvatarInput(
|
||||
avatarData = showAvatar ? AvatarInput(
|
||||
mxContentUri: room.summary.avatar,
|
||||
matrixItemId: room.roomId,
|
||||
displayName: room.summary.displayname
|
||||
)) : nil
|
||||
) : nil
|
||||
} else {
|
||||
avatarData = showAvatar ? .uiKit(RoomAvatarViewData(
|
||||
avatarData = showAvatar ? RoomAvatarViewData(
|
||||
roomId: room.roomId,
|
||||
displayName: room.summary.displayname,
|
||||
avatarUrl: room.summary.avatar,
|
||||
mediaManager: room.mxSession.mediaManager
|
||||
)) : nil
|
||||
) : nil
|
||||
}
|
||||
|
||||
|
||||
let viewModel: RoomNotificationSettingsViewModel
|
||||
let viewController: UIViewController
|
||||
if #available(iOS 14.0.0, *) {
|
||||
|
||||
@@ -144,7 +144,7 @@ final class RoomNotificationSettingsViewController: UIViewController {
|
||||
activityPresenter.removeCurrentActivityIndicator(animated: true)
|
||||
}
|
||||
self.viewState = viewState
|
||||
if case let .uiKit(avatarData) = viewState.avatarData {
|
||||
if let avatarData = viewState.avatarData as? AvatarViewDataProtocol {
|
||||
mainTableView.tableHeaderView = avatarView
|
||||
avatarView.configure(viewData: avatarData)
|
||||
avatarView.update(theme: theme)
|
||||
|
||||
@@ -15,23 +15,26 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import DesignKit
|
||||
|
||||
|
||||
fileprivate extension MXPushRule {
|
||||
/**
|
||||
Conformance of MXPushRule to the abstraction `NotificationPushRule` for use in `NotificationSettingsViewModel`.
|
||||
*/
|
||||
extension MXPushRule: NotificationPushRule {
|
||||
|
||||
/*
|
||||
Given a rule, check it match the actions in the static definition.
|
||||
*/
|
||||
private func maches(targetRule: NotificationStandardActions?) -> Bool {
|
||||
guard let targetRule = targetRule else {
|
||||
func matches(standardActions: NotificationStandardActions?) -> Bool {
|
||||
guard let standardActions = standardActions else {
|
||||
return false
|
||||
}
|
||||
if !enabled && targetRule == .disabled {
|
||||
if !enabled && standardActions == .disabled {
|
||||
return true
|
||||
}
|
||||
|
||||
if enabled,
|
||||
let actions = targetRule.actions,
|
||||
let actions = standardActions.actions,
|
||||
highlight == actions.highlight,
|
||||
sound == actions.sound,
|
||||
notify == actions.notify,
|
||||
@@ -41,14 +44,13 @@ fileprivate extension MXPushRule {
|
||||
return false
|
||||
}
|
||||
|
||||
func getAction(actionType: MXPushRuleActionType, tweakType: String? = nil) -> MXPushRuleAction? {
|
||||
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
|
||||
MXLog.debug("action \(action)")
|
||||
if let tweakType = tweakType,
|
||||
let actionTweak = action.parameters?["set_tweak"] as? String {
|
||||
match = match && (tweakType == actionTweak)
|
||||
|
||||
@@ -26,12 +26,12 @@ class NotificationSettingsService: NotificationSettingsServiceType {
|
||||
@Published private var contentRules = [MXPushRule]()
|
||||
@Published private var rules = [MXPushRule]()
|
||||
|
||||
var rulesPublisher: AnyPublisher<[MXPushRule], Never> {
|
||||
$rules.eraseToAnyPublisher()
|
||||
var rulesPublisher: AnyPublisher<[NotificationPushRule], Never> {
|
||||
$rules.map({ $0.map({ $0 as NotificationPushRule }) }).eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
var contentRulesPublisher: AnyPublisher<[MXPushRule], Never> {
|
||||
$contentRules.eraseToAnyPublisher()
|
||||
var contentRulesPublisher: AnyPublisher<[NotificationPushRule], Never> {
|
||||
$contentRules.map({ $0.map({ $0 as NotificationPushRule }) }).eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
init(session: MXSession) {
|
||||
|
||||
@@ -26,18 +26,6 @@ schemes:
|
||||
- RiotTests
|
||||
|
||||
targets:
|
||||
RiotSwiftUI:
|
||||
type: framework
|
||||
platform: iOS
|
||||
dependencies:
|
||||
- target: DesignKit
|
||||
sources:
|
||||
- path: ModulesSwiftUI
|
||||
- path: Generated/Strings.swift
|
||||
- path: Generated/Images.swift
|
||||
- path: Managers/Theme/Theme.swift
|
||||
- path: Managers/Theme/ThemeIdentifier.swift
|
||||
- path: Categories/UIColor.swift
|
||||
Riot:
|
||||
type: application
|
||||
platform: iOS
|
||||
@@ -47,7 +35,6 @@ targets:
|
||||
- target: SiriIntents
|
||||
- target: RiotNSE
|
||||
- target: DesignKit
|
||||
- target: RiotSwiftUI
|
||||
|
||||
configFiles:
|
||||
Debug: Debug.xcconfig
|
||||
@@ -64,6 +51,10 @@ targets:
|
||||
script: "\"${PODS_ROOT}/SwiftGen/bin/swiftgen\" config run --config \"Tools/SwiftGen/swiftgen-config.yml\"\n"
|
||||
|
||||
sources:
|
||||
- path: ../RiotSwiftUI/Modules
|
||||
# Riot will provide it's own LocaleProviderType so exclude.
|
||||
excludes:
|
||||
- "Common/Locale/LocaleProvider.swift"
|
||||
- path: ../Tools
|
||||
excludes:
|
||||
- "Logs"
|
||||
|
||||
@@ -48,6 +48,8 @@ targets:
|
||||
- path: ../Riot/Modules/SetPinCode/SetupBiometrics/BiometricsAuthenticationPresenter.swift
|
||||
- path: ../Riot/Categories/UNUserNotificationCenter.swift
|
||||
- path: ../Riot/Managers/KeyValueStorage/KeyValueStore.swift
|
||||
- path: ../Riot/Managers/Locale/LocaleProvider.swift
|
||||
- path: ../Riot/Managers/Locale/LocaleProviderType.swift
|
||||
- path: ../Riot/Managers/EncryptionKeyManager/EncryptionKeyManager.swift
|
||||
- path: ../Riot/Categories/Bundle.swift
|
||||
- path: ../Riot/Generated/Strings.swift
|
||||
|
||||
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>
|
||||
@@ -24,7 +24,7 @@ class MockAvatarService: AvatarServiceType {
|
||||
static let example: AvatarServiceType = MockAvatarService()
|
||||
func avatarImage(mxContentUri: String, avatarSize: AvatarSize) -> Future<UIImage, Error> {
|
||||
Future { promise in
|
||||
promise(.success(Asset.Images.appSymbol.image))
|
||||
promise(.success(Asset.Images.appSymbol.image))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,7 @@ import DesignKit
|
||||
@available(iOS 14.0, *)
|
||||
struct AvatarImage: View {
|
||||
|
||||
@Environment(\.theme) var theme: Theme
|
||||
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||
@Environment(\.dependencies) var dependencies: DependencyContainer
|
||||
@StateObject var viewModel = AvatarViewModel()
|
||||
|
||||
@@ -39,7 +39,7 @@ struct AvatarImage: View {
|
||||
.padding(4)
|
||||
.frame(width: CGFloat(size.rawValue), height: CGFloat(size.rawValue))
|
||||
.foregroundColor(.white)
|
||||
.background(Color(theme.avatarColors[colorIndex]))
|
||||
.background(theme.colors.namesAndAvatars[colorIndex])
|
||||
.clipShape(Circle())
|
||||
// Make the text resizable (i.e. Make it large and then allow it to scale down)
|
||||
.font(.system(size: 200))
|
||||
@@ -57,7 +57,7 @@ struct AvatarImage: View {
|
||||
mxContentUri: mxContentUri,
|
||||
matrixItemId: matrixItemId,
|
||||
displayName: displayName,
|
||||
colorCount: theme.avatarColors.count,
|
||||
colorCount: theme.colors.namesAndAvatars.count,
|
||||
avatarSize: size
|
||||
)
|
||||
}
|
||||
@@ -23,17 +23,17 @@ import SwiftUI
|
||||
@available(iOS 14.0, *)
|
||||
struct VectorContentModifier: ViewModifier {
|
||||
|
||||
@StateObject private var themeObserver = ThemeObserver.shared
|
||||
@ObservedObject private var themePublisher = ThemePublisher.shared
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.theme(themeObserver.theme)
|
||||
.theme(themePublisher.theme)
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 14.0, *)
|
||||
extension View {
|
||||
func vectorContent() -> some View {
|
||||
self.modifier(VectorContentModifier())
|
||||
}
|
||||
func vectorContent() -> some View {
|
||||
self.modifier(VectorContentModifier())
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,8 @@
|
||||
|
||||
import Foundation
|
||||
|
||||
enum AvatarInputOption {
|
||||
case swiftUI(AvatarInputType)
|
||||
case uiKit(AvatarViewDataProtocol)
|
||||
class LocaleProvider: LocaleProviderType {
|
||||
static var locale: Locale? {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
@@ -15,22 +15,21 @@
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import DesignKit
|
||||
|
||||
/**
|
||||
Extension to `ThemeIdentifier` for getting the SwiftUI theme.
|
||||
*/
|
||||
@available(iOS 14.0, *)
|
||||
class ThemeObserver: ObservableObject {
|
||||
|
||||
static let shared = ThemeObserver()
|
||||
|
||||
init() {
|
||||
NotificationCenter.default.publisher(for: NSNotification.Name.themeServiceDidChangeTheme).map { _ in
|
||||
ThemeService.shared().theme
|
||||
}.assign(to: &$theme)
|
||||
extension ThemeIdentifier {
|
||||
fileprivate static let defaultTheme = DefaultThemeSwiftUI()
|
||||
fileprivate static let darkTheme = DarkThemeSwiftUI()
|
||||
public var themeSwiftUI: ThemeSwiftUI {
|
||||
switch self {
|
||||
case .light:
|
||||
return Self.defaultTheme
|
||||
case .dark, .black:
|
||||
return Self.darkTheme
|
||||
}
|
||||
}
|
||||
@Published var theme: Theme = ThemeService.shared().theme
|
||||
}
|
||||
|
||||
|
||||
class ThemePublisher: ObservableObject {
|
||||
static let shared = ThemePublisher()
|
||||
}
|
||||
@@ -16,14 +16,16 @@
|
||||
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
import DesignKit
|
||||
|
||||
@available(iOS 14.0, *)
|
||||
private struct ThemeKey: EnvironmentKey {
|
||||
static let defaultValue = ThemeService.shared().theme
|
||||
static let defaultValue = ThemePublisher.shared.theme
|
||||
}
|
||||
|
||||
@available(iOS 14.0, *)
|
||||
extension EnvironmentValues {
|
||||
var theme: Theme {
|
||||
var theme: ThemeSwiftUI {
|
||||
get { self[ThemeKey.self] }
|
||||
set { self[ThemeKey.self] = newValue }
|
||||
}
|
||||
@@ -36,7 +38,7 @@ extension EnvironmentValues {
|
||||
*/
|
||||
@available(iOS 14.0, *)
|
||||
extension View {
|
||||
func theme(_ theme: Theme) -> some View {
|
||||
func theme(_ theme: ThemeSwiftUI) -> some View {
|
||||
environment(\.theme, theme)
|
||||
}
|
||||
}
|
||||
@@ -49,7 +51,6 @@ extension View {
|
||||
@available(iOS 14.0, *)
|
||||
extension View {
|
||||
func theme(_ themeId: ThemeIdentifier) -> some View {
|
||||
let theme = ThemeService.shared().theme(withThemeId: themeId.rawValue)
|
||||
return environment(\.theme, theme)
|
||||
return environment(\.theme, themeId.themeSwiftUI)
|
||||
}
|
||||
}
|
||||
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 calss 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())
|
||||
}
|
||||
@@ -19,11 +19,11 @@ import SwiftUI
|
||||
|
||||
@available(iOS 14.0, *)
|
||||
struct FormItemButtonStyle: ButtonStyle {
|
||||
@Environment(\.theme) var theme: Theme
|
||||
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||
func makeBody(configuration: Self.Configuration) -> some View {
|
||||
configuration.label
|
||||
.background(configuration.isPressed ? Color(theme.selectedBackgroundColor) : Color(theme.backgroundColor))
|
||||
.foregroundColor(Color(theme.textPrimaryColor))
|
||||
.font(Font(theme.fonts.body))
|
||||
.background(configuration.isPressed ? theme.colors.system : theme.colors.background)
|
||||
.foregroundColor(theme.colors.primaryContent)
|
||||
.font(theme.fonts.body)
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ struct FormPickerItem: View {
|
||||
|
||||
typealias TapCallback = () -> Void
|
||||
|
||||
@Environment(\.theme) var theme: Theme
|
||||
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||
|
||||
var title: String
|
||||
var selected: Bool
|
||||
@@ -38,7 +38,7 @@ struct FormPickerItem: View {
|
||||
Spacer()
|
||||
if selected {
|
||||
Image("checkmark")
|
||||
.foregroundColor(Color(theme.tintColor))
|
||||
.foregroundColor(theme.colors.accent)
|
||||
}
|
||||
}
|
||||
.padding(.trailing)
|
||||
@@ -55,6 +55,7 @@ struct FormPickerItem: View {
|
||||
|
||||
@available(iOS 14.0, *)
|
||||
struct FormPickerItem_Previews: PreviewProvider {
|
||||
|
||||
static let items = ["Item 1", "Item 2", "Item 3"]
|
||||
static var selected: String = items[0]
|
||||
static var previews: some View {
|
||||
@@ -19,16 +19,16 @@ import SwiftUI
|
||||
@available(iOS 14.0, *)
|
||||
struct FormSectionFooter: View {
|
||||
|
||||
@Environment(\.theme) var theme: Theme
|
||||
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||
var text: String
|
||||
|
||||
var body: some View {
|
||||
Text(text)
|
||||
.foregroundColor(Color(theme.textSecondaryColor))
|
||||
.foregroundColor(theme.colors.secondaryContent)
|
||||
.padding(.top)
|
||||
.padding(.leading)
|
||||
.padding(.trailing)
|
||||
.font(Font(theme.fonts.callout))
|
||||
.font(theme.fonts.callout)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,16 +19,16 @@ import SwiftUI
|
||||
@available(iOS 14.0, *)
|
||||
struct FormSectionHeader: View {
|
||||
|
||||
@Environment(\.theme) var theme: Theme
|
||||
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||
var text: String
|
||||
|
||||
var body: some View {
|
||||
Text(text)
|
||||
.foregroundColor(Color(theme.textSecondaryColor))
|
||||
.foregroundColor(theme.colors.secondaryContent)
|
||||
.padding(.top, 32)
|
||||
.padding(.leading)
|
||||
.padding(.bottom, 8)
|
||||
.font(Font(theme.fonts.subheadline))
|
||||
.font(theme.fonts.subheadline)
|
||||
.textCase(.uppercase)
|
||||
.frame(maxWidth: .infinity, alignment: .leading)
|
||||
}
|
||||
@@ -41,7 +41,7 @@ struct RoomNotificationSettings: View {
|
||||
|
||||
var body: some View {
|
||||
VectorForm {
|
||||
if case let .swiftUI(avatarData) = viewModel.viewState.avatarData {
|
||||
if let avatarData = viewModel.viewState.avatarData as? AvatarInputType {
|
||||
RoomNotificationSettingsHeader(
|
||||
avatarData: avatarData,
|
||||
displayName: viewModel.viewState.displayName
|
||||
@@ -19,7 +19,7 @@ import SwiftUI
|
||||
@available(iOS 14.0, *)
|
||||
struct RoomNotificationSettingsHeader: View {
|
||||
|
||||
@Environment(\.theme) var theme: Theme
|
||||
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||
var avatarData: AvatarInputType
|
||||
var displayName: String?
|
||||
|
||||
@@ -30,8 +30,8 @@ struct RoomNotificationSettingsHeader: View {
|
||||
AvatarImage(avatarData: avatarData, size: .xxLarge)
|
||||
if let displayName = displayName {
|
||||
Text(displayName)
|
||||
.font(Font(theme.fonts.title3SB))
|
||||
.foregroundColor(Color(theme.textPrimaryColor))
|
||||
.font(theme.fonts.title3SB)
|
||||
.foregroundColor(theme.colors.primaryContent)
|
||||
.textCase(nil)
|
||||
}
|
||||
}
|
||||
@@ -19,7 +19,7 @@ import SwiftUI
|
||||
@available(iOS 14.0, *)
|
||||
struct VectorForm<Content: View>: View {
|
||||
|
||||
@Environment(\.theme) var theme: Theme
|
||||
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||
var content: () -> Content
|
||||
|
||||
init(@ViewBuilder content: @escaping () -> Content) {
|
||||
@@ -37,7 +37,7 @@ struct VectorForm<Content: View>: View {
|
||||
maxHeight: .infinity,
|
||||
alignment: .top
|
||||
)
|
||||
.background(Color(theme.baseColor))
|
||||
.background(theme.colors.system)
|
||||
.edgesIgnoringSafeArea(.bottom)
|
||||
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
import Foundation
|
||||
|
||||
struct MockNotificationPushRule: NotificationPushRule {
|
||||
var ruleId: String
|
||||
var ruleId: String!
|
||||
var enabled: Bool
|
||||
func matches(standardActions: NotificationStandardActions?) -> Bool {
|
||||
return false
|
||||
@@ -17,7 +17,7 @@
|
||||
import Foundation
|
||||
|
||||
protocol NotificationPushRule {
|
||||
var ruleId: String { get }
|
||||
var ruleId: String! { get }
|
||||
var enabled: Bool { get }
|
||||
func matches(standardActions: NotificationStandardActions?) -> Bool
|
||||
}
|
||||
@@ -24,7 +24,7 @@ import SwiftUI
|
||||
@available(iOS 14.0, *)
|
||||
struct BorderedInputFieldStyle: TextFieldStyle {
|
||||
|
||||
@Environment(\.theme) var theme: Theme
|
||||
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||
@Environment(\.isEnabled) var isEnabled: Bool
|
||||
|
||||
var isEditing: Bool = false
|
||||
@@ -32,34 +32,34 @@ struct BorderedInputFieldStyle: TextFieldStyle {
|
||||
|
||||
private var borderColor: Color {
|
||||
if !isEnabled {
|
||||
return Color(theme.colors.quinaryContent)
|
||||
return theme.colors.quinaryContent
|
||||
} else if isError {
|
||||
return Color(theme.colors.alert)
|
||||
return theme.colors.alert
|
||||
} else if isEditing {
|
||||
return Color(theme.colors.accent)
|
||||
return theme.colors.accent
|
||||
}
|
||||
return Color(theme.colors.quarterlyContent)
|
||||
return theme.colors.quarterlyContent
|
||||
}
|
||||
|
||||
private var accentColor: Color {
|
||||
if isError {
|
||||
return Color(theme.colors.alert)
|
||||
return theme.colors.alert
|
||||
}
|
||||
return Color(theme.colors.accent)
|
||||
return theme.colors.accent
|
||||
}
|
||||
|
||||
private var textColor: Color {
|
||||
if !isEnabled {
|
||||
return Color(theme.colors.quarterlyContent)
|
||||
return theme.colors.quarterlyContent
|
||||
}
|
||||
return Color(theme.colors.primaryContent)
|
||||
return theme.colors.primaryContent
|
||||
}
|
||||
|
||||
private var backgroundColor: Color {
|
||||
if !isEnabled && (theme.identifier == ThemeIdentifier.dark.rawValue) {
|
||||
return Color(theme.colors.quinaryContent)
|
||||
if !isEnabled && (theme.identifier == ThemeIdentifier.dark) {
|
||||
return theme.colors.quinaryContent
|
||||
}
|
||||
return Color(theme.colors.background)
|
||||
return theme.colors.background
|
||||
}
|
||||
|
||||
private var borderWidth: CGFloat {
|
||||
@@ -69,7 +69,7 @@ struct BorderedInputFieldStyle: TextFieldStyle {
|
||||
func _body(configuration: TextField<_Label>) -> some View {
|
||||
let rect = RoundedRectangle(cornerRadius: 8)
|
||||
return configuration
|
||||
.font(Font(theme.fonts.callout))
|
||||
.font(theme.fonts.callout)
|
||||
.foregroundColor(textColor)
|
||||
.accentColor(accentColor)
|
||||
.frame(height: 48)
|
||||
@@ -23,21 +23,21 @@ import SwiftUI
|
||||
struct Chip: View {
|
||||
|
||||
@Environment(\.isEnabled) var isEnabled
|
||||
@Environment(\.theme) var theme: Theme
|
||||
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||
|
||||
let title: String
|
||||
let onDelete: () -> Void
|
||||
|
||||
var backgroundColor: Color {
|
||||
if !isEnabled {
|
||||
return Color(theme.colors.quinaryContent)
|
||||
return theme.colors.quinaryContent
|
||||
}
|
||||
return Color(theme.colors.accent)
|
||||
return theme.colors.accent
|
||||
}
|
||||
|
||||
var foregroundColor: Color {
|
||||
if !isEnabled {
|
||||
return Color(theme.colors.tertiaryContent)
|
||||
return theme.colors.tertiaryContent
|
||||
}
|
||||
return Color.white
|
||||
}
|
||||
@@ -45,7 +45,7 @@ struct Chip: View {
|
||||
var body: some View {
|
||||
HStack {
|
||||
Text(title)
|
||||
.font(Font(theme.fonts.body))
|
||||
.font(theme.fonts.body)
|
||||
.lineLimit(1)
|
||||
Button(action: onDelete) {
|
||||
Image(systemName: "xmark.circle.fill")
|
||||
@@ -24,7 +24,7 @@ import SwiftUI
|
||||
@available(iOS 14.0, *)
|
||||
struct ChipsInput: View {
|
||||
|
||||
@Environment(\.theme) var theme: Theme
|
||||
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||
@Environment(\.isEnabled) var isEnabled
|
||||
|
||||
@State private var chipText: String = ""
|
||||
@@ -23,26 +23,26 @@ import SwiftUI
|
||||
@available(iOS 14.0, *)
|
||||
struct FormInputFieldStyle: TextFieldStyle {
|
||||
|
||||
@Environment(\.theme) var theme: Theme
|
||||
@Environment(\.theme) var theme: ThemeSwiftUI
|
||||
@Environment(\.isEnabled) var isEnabled
|
||||
|
||||
private var textColor: Color {
|
||||
if !isEnabled {
|
||||
return Color(theme.colors.quarterlyContent)
|
||||
return theme.colors.quarterlyContent
|
||||
}
|
||||
return Color(theme.colors.primaryContent)
|
||||
return theme.colors.primaryContent
|
||||
}
|
||||
|
||||
private var backgroundColor: Color {
|
||||
if !isEnabled && (theme.identifier == ThemeIdentifier.dark.rawValue) {
|
||||
return Color(theme.colors.quinaryContent)
|
||||
if !isEnabled && theme.identifier == .dark {
|
||||
return theme.colors.quinaryContent
|
||||
}
|
||||
return Color(theme.colors.background)
|
||||
return theme.colors.background
|
||||
}
|
||||
|
||||
func _body(configuration: TextField<_Label>) -> some View {
|
||||
configuration
|
||||
.font(Font(theme.fonts.callout))
|
||||
.font(theme.fonts.callout)
|
||||
.foregroundColor(textColor)
|
||||
.frame(minHeight: 48)
|
||||
.padding(.horizontal)
|
||||
20
RiotSwiftUI/Release.xcconfig
Normal file
20
RiotSwiftUI/Release.xcconfig
Normal file
@@ -0,0 +1,20 @@
|
||||
//
|
||||
// Copyright 2021 Vector Creations Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
// Configuration settings file format documentation can be found at:
|
||||
// https://help.apple.com/xcode/#/dev745c5c974
|
||||
|
||||
#include "Common.xcconfig"
|
||||
40
RiotSwiftUI/target.yml
Normal file
40
RiotSwiftUI/target.yml
Normal file
@@ -0,0 +1,40 @@
|
||||
name: RiotSwiftUI
|
||||
|
||||
schemes:
|
||||
RiotSwiftUI:
|
||||
analyze:
|
||||
config: Debug
|
||||
archive:
|
||||
config: Release
|
||||
build:
|
||||
targets:
|
||||
RiotSwiftUI:
|
||||
- running
|
||||
- profiling
|
||||
- analyzing
|
||||
- archiving
|
||||
profile:
|
||||
config: Release
|
||||
run:
|
||||
config: Debug
|
||||
disableMainThreadChecker: true
|
||||
|
||||
targets:
|
||||
RiotSwiftUI:
|
||||
type: framework
|
||||
platform: iOS
|
||||
dependencies:
|
||||
- target: DesignKit
|
||||
sources:
|
||||
- path: .
|
||||
- path: ../Riot/Generated/Strings.swift
|
||||
- path: ../Riot/Generated/Images.swift
|
||||
- path: ../Riot/Managers/Theme/ThemeIdentifier.swift
|
||||
- path: ../Riot/Managers/Locale/LocaleProviderType.swift
|
||||
- path: ../Riot/Assets/en.lproj/Vector.strings
|
||||
buildPhase: resources
|
||||
- path: ../Riot/Assets/Images.xcassets
|
||||
buildPhase: resources
|
||||
configFiles:
|
||||
Debug: Debug.xcconfig
|
||||
Release: Release.xcconfig
|
||||
@@ -66,12 +66,10 @@ extension {{enumName}} {
|
||||
let format = NSLocalizedString(key, tableName: table, bundle: Bundle(for: BundleToken.self), comment: "")
|
||||
let locale: Locale
|
||||
|
||||
if let localeIdentifier = Bundle.mxk_language() {
|
||||
locale = Locale(identifier: localeIdentifier)
|
||||
} else if let fallbackLocaleIdentifier = Bundle.mxk_fallbackLanguage() {
|
||||
locale = Locale(identifier: fallbackLocaleIdentifier)
|
||||
if let providedLocale = LocaleProvider.locale {
|
||||
locale = providedLocale
|
||||
} else {
|
||||
locale = Locale.current
|
||||
locale = Locale.current
|
||||
}
|
||||
|
||||
return String(format: format, locale: locale, arguments: args)
|
||||
@@ -81,4 +79,4 @@ extension {{enumName}} {
|
||||
private final class BundleToken {}
|
||||
{% else %}
|
||||
// No string found
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
@@ -32,3 +32,4 @@ include:
|
||||
- path: SiriIntents/target.yml
|
||||
- path: RiotNSE/target.yml
|
||||
- path: DesignKit/target.yml
|
||||
- path: RiotSwiftUI/target.yml
|
||||
|
||||
Reference in New Issue
Block a user