Repo created

This commit is contained in:
Fr4nz D13trich 2025-11-22 13:58:55 +01:00
parent 4af19165ec
commit 68073add76
12458 changed files with 12350765 additions and 2 deletions

View file

@ -0,0 +1,34 @@
enum BookmarksStyleSheet: String, CaseIterable {
case bookmarksCategoryTextView = "BookmarksCategoryTextView"
case bookmarksCategoryDeleteButton = "BookmarksCategoryDeleteButton"
case bookmarksActionCreateIcon = "BookmarksActionCreateIcon"
case bookmarkSharingLicense = "BookmarkSharingLicense"
}
extension BookmarksStyleSheet: IStyleSheet {
func styleResolverFor(colors: IColors, fonts: IFonts) -> Theme.StyleResolver {
switch self {
case .bookmarksCategoryTextView:
return .add { s in
s.font = fonts.regular16
s.fontColor = colors.blackPrimaryText
s.textContainerInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
case .bookmarksCategoryDeleteButton:
return .add { s in
s.font = fonts.regular17
s.fontColor = colors.red
s.fontColorDisabled = colors.blackHintText
}
case .bookmarksActionCreateIcon:
return .add { s in
s.tintColor = colors.linkBlue
}
case .bookmarkSharingLicense:
return .addFrom(GlobalStyleSheet.termsOfUseLinkText) { s in
s.fontColor = colors.blackSecondaryText
s.font = fonts.regular14
}
}
}
}

View file

@ -0,0 +1,125 @@
class DayColors: IColors {
var clear = UIColor.clear
var primaryDark = UIColor(24, 128, 68, alpha100)
var primary = UIColor.accent
var secondary = UIColor(55, 101, 63, alpha100)
// Light green color
var primaryLight = UIColor(124, 188, 123, alpha100)
var menuBackground = UIColor(255, 255, 255, alpha90)
var tabBarButtonBackground = UIColor(255, 255, 255, alpha70)
var downloadBadgeBackground = UIColor(255, 55, 35, alpha100)
// Background color && press color
var pressBackground = UIColor(245, 245, 245, alpha100)
// Red color (use for status closed in place page)
var red = UIColor(230, 15, 35, alpha100)
var errorPink = UIColor(246, 60, 51, alpha12)
// Orange color (use for status 15 min in place page)
var orange = UIColor(255, 120, 5, alpha100)
// Blue color (use for links and phone numbers)
var linkBlue = UIColor.accent
var linkBlueHighlighted = UIColor.accent
var linkBlueDark = UIColor.accent
var buttonRed = UIColor(244, 67, 67, alpha100)
var buttonRedHighlighted = UIColor(183, 28, 28, alpha100)
var black = UIColor(0, 0, 0, alpha100)
var blackPrimaryText = UIColor(0, 0, 0, alpha87)
var blackSecondaryText = UIColor(0, 0, 0, alpha54)
var blackHintText = UIColor(0, 0, 0, alpha26)
var blackDividers = UIColor(0, 0, 0, alpha08)
var solidDividers = UIColor(224, 224, 224, alpha100)
var white = UIColor(255, 255, 255, alpha100)
var whitePrimaryText = UIColor(255, 255, 255, alpha87);
var whitePrimaryTextHighlighted = UIColor(255, 255, 255, alpha30);
var whiteSecondaryText = UIColor(255, 255, 255, alpha54)
var whiteHintText = UIColor(255, 255, 255, alpha30)
var buttonDisabledBlueText = UIColor(3, 122, 255, alpha26)
var alertBackground = UIColor(255, 255, 255, alpha90)
var blackOpaque = UIColor(0, 0, 0, alpha04)
var toastBackground = UIColor(255, 255, 255, alpha87)
var statusBarBackground = UIColor(255, 255, 255, alpha36)
var searchPromoBackground = UIColor(249, 251, 231, alpha100)
var border = UIColor(0, 0, 0, alpha04)
var bookingBackground = UIColor(25, 69, 125, alpha100)
var opentableBackground = UIColor(218, 55, 67, alpha100)
var transparentGreen = UIColor(233, 244, 233, alpha26)
var ratingRed = UIColor(229, 57, 53, alpha100)
var ratingOrange = UIColor(244, 81, 30, alpha100)
var ratingYellow = UIColor(245, 176, 39, alpha100)
var ratingLightGreen = UIColor(124, 179, 66, alpha100)
var ratingGreen = UIColor(67, 160, 71, alpha100)
var fadeBackground = UIColor(0, 0, 0, alpha80)
var blackStatusBarBackground = UIColor(0, 0, 0, alpha80)
var elevationPreviewTint = UIColor(193, 209, 224, alpha30)
var elevationPreviewSelector = UIColor(red: 0.757, green: 0.82, blue: 0.878, alpha: 1)
var shadow = UIColor(0, 0, 0, alpha100)
var chartLine = UIColor(red: 0.118, green: 0.588, blue: 0.941, alpha: 1)
var chartShadow = UIColor(red: 0.118, green: 0.588, blue: 0.941, alpha: 0.12)
var cityColor = UIColor(red: 0.4, green: 0.225, blue: 0.75, alpha: 1)
var outdoorColor = UIColor(red: 0.235, green: 0.549, blue: 0.235, alpha: 1)
var carplayPlaceholderBackground = UIColor(221, 221, 205, alpha100)
var iconOpaqueGrayTint = UIColor(117, 117, 117, alpha100)
var iconOpaqueGrayBackground = UIColor(231, 231, 231, alpha100)
}
class NightColors: IColors {
var clear = UIColor.clear
var primaryDark = UIColor(25, 30, 35, alpha100)
var primary = UIColor.accent
var secondary = UIColor(0x25, 0x28, 0x2b, alpha100)
// Light green color
var primaryLight = UIColor(65, 70, 75, alpha100)
var menuBackground = UIColor(45, 50, 55, alpha90)
var tabBarButtonBackground = UIColor(60, 64, 68, alpha70)
var downloadBadgeBackground = UIColor(230, 70, 60, alpha100)
// Background color && press color
var pressBackground = UIColor(28, 28, 30, alpha100)
// Red color (use for status closed in place page)
var red = UIColor(230, 70, 60, alpha100)
var errorPink = UIColor(246, 60, 51, alpha26)
// Orange color (use for status 15 min in place page)
var orange = UIColor(250, 190, 10, alpha100)
// Blue color (use for links and phone numbers)
var linkBlue = UIColor.alternativeAccent
var linkBlueHighlighted = UIColor.accent
var linkBlueDark = UIColor.accent
var buttonRed = UIColor(244, 67, 67, alpha100)
var buttonRedHighlighted = UIColor(183, 28, 28, alpha100)
var black = UIColor(255, 255, 255, alpha100)
var blackPrimaryText = UIColor(255, 255, 255, alpha90)
var blackSecondaryText = UIColor(255, 255, 255, alpha70)
var blackHintText = UIColor(255, 255, 255, alpha30)
var blackDividers = UIColor(255, 255, 255, alpha08)
var solidDividers = UIColor(84, 86, 90, alpha100)
var white = UIColor(34, 34, 36, alpha100)
var whitePrimaryText = UIColor(255, 255, 255, alpha87)
var whitePrimaryTextHighlighted = UIColor(255, 255, 255, alpha30)
var whiteSecondaryText = UIColor(0, 0, 0, alpha70)
var whiteHintText = UIColor(0, 0, 0, alpha26)
var buttonDisabledBlueText = UIColor(255, 230, 140, alpha30)
var alertBackground = UIColor(60, 64, 68, alpha90)
var blackOpaque = UIColor(255, 255, 255, alpha04)
var toastBackground = UIColor(0, 0, 0, alpha87)
var statusBarBackground = UIColor(0, 0, 0, alpha32)
var searchPromoBackground = UIColor(71, 75, 79, alpha100)
var border = UIColor(255, 255, 255, alpha04)
var bookingBackground = UIColor(25, 69, 125, alpha100)
var opentableBackground = UIColor(218, 55, 67, alpha100)
var transparentGreen = UIColor(233, 244, 233, alpha26)
var ratingRed = UIColor(229, 57, 53, alpha100)
var ratingOrange = UIColor(244, 81, 30, alpha100)
var ratingYellow = UIColor(245, 176, 39, alpha100)
var ratingLightGreen = UIColor(124, 179, 66, alpha100)
var ratingGreen = UIColor(67, 160, 71, alpha100)
var fadeBackground = UIColor(0, 0, 0, alpha80)
var blackStatusBarBackground = UIColor(0, 0, 0, alpha80)
var elevationPreviewTint = UIColor(0, 0, 0, alpha54)
var elevationPreviewSelector = UIColor(red: 0.404, green: 0.439, blue: 0.475, alpha: 1)
var shadow = UIColor.clear
var chartLine = UIColor(red: 0.294, green: 0.725, blue: 0.902, alpha: 1)
var chartShadow = UIColor(red: 0.294, green: 0.725, blue: 0.902, alpha: 0.12)
var cityColor = UIColor(152, 103, 252, alpha100)
var outdoorColor = UIColor(147, 191, 57, alpha100)
var carplayPlaceholderBackground = UIColor(50, 54, 58, alpha100)
var iconOpaqueGrayTint = UIColor(197, 197, 197, alpha100)
var iconOpaqueGrayBackground = UIColor(84, 86, 90, alpha100)
}

View file

@ -0,0 +1,73 @@
let alpha04: CGFloat = 0.04
let alpha08: CGFloat = 0.08
let alpha12: CGFloat = 0.12
let alpha20: CGFloat = 0.20
let alpha26: CGFloat = 0.26
let alpha30: CGFloat = 0.3
let alpha32: CGFloat = 0.32
let alpha36: CGFloat = 0.36
let alpha40: CGFloat = 0.4
let alpha54: CGFloat = 0.54
let alpha70: CGFloat = 0.7
let alpha80: CGFloat = 0.8
let alpha87: CGFloat = 0.87
let alpha90: CGFloat = 0.9
let alpha100: CGFloat = 1.0
@objc protocol IColors {
var clear: UIColor { get }
var primaryDark: UIColor { get }
var primary: UIColor { get }
var secondary: UIColor { get }
var primaryLight: UIColor { get }
var menuBackground: UIColor { get }
var tabBarButtonBackground: UIColor { get }
var downloadBadgeBackground: UIColor { get }
var pressBackground: UIColor { get }
var red: UIColor { get }
var errorPink: UIColor { get }
var orange: UIColor { get }
var linkBlue: UIColor { get }
var linkBlueHighlighted: UIColor { get }
var linkBlueDark: UIColor { get }
var buttonRed: UIColor { get }
var buttonRedHighlighted: UIColor { get }
var black: UIColor { get }
var blackPrimaryText: UIColor { get }
var blackSecondaryText: UIColor { get }
var blackHintText: UIColor { get }
var blackDividers: UIColor { get }
var solidDividers: UIColor { get }
var white: UIColor { get }
var whitePrimaryText: UIColor { get }
var whitePrimaryTextHighlighted: UIColor { get }
var whiteSecondaryText: UIColor { get }
var whiteHintText: UIColor { get }
var buttonDisabledBlueText: UIColor { get }
var alertBackground: UIColor { get }
var blackOpaque: UIColor { get }
var toastBackground: UIColor { get }
var statusBarBackground: UIColor { get }
var searchPromoBackground: UIColor { get }
var border: UIColor { get }
var bookingBackground: UIColor { get }
var opentableBackground: UIColor { get }
var transparentGreen: UIColor { get }
var ratingRed: UIColor { get }
var ratingOrange: UIColor { get }
var ratingYellow: UIColor { get }
var ratingLightGreen: UIColor { get }
var ratingGreen: UIColor { get }
var fadeBackground: UIColor { get }
var blackStatusBarBackground: UIColor { get }
var elevationPreviewSelector: UIColor { get }
var elevationPreviewTint: UIColor { get }
var shadow: UIColor { get }
var chartLine: UIColor { get }
var chartShadow: UIColor { get }
var cityColor: UIColor { get }
var outdoorColor: UIColor { get }
var carplayPlaceholderBackground: UIColor { get }
var iconOpaqueGrayTint: UIColor { get }
var iconOpaqueGrayBackground: UIColor { get }
}

View file

@ -0,0 +1,60 @@
@objc protocol IFonts {
var regular9: UIFont { get }
var regular10: UIFont { get }
var regular11: UIFont { get }
var regular12: UIFont { get }
var regular13: UIFont { get }
var regular14: UIFont { get }
var regular15: UIFont { get }
var regular16: UIFont { get }
var regular17: UIFont { get }
var regular18: UIFont { get }
var regular20: UIFont { get }
var regular24: UIFont { get }
var regular32: UIFont { get }
var regular52: UIFont { get }
var medium9: UIFont { get }
var medium10: UIFont { get }
var medium12: UIFont { get }
var medium13: UIFont { get }
var medium14: UIFont { get }
var medium16: UIFont { get }
var medium17: UIFont { get }
var medium18: UIFont { get }
var medium20: UIFont { get }
var medium24: UIFont { get }
var medium28: UIFont { get }
var medium36: UIFont { get }
var medium40: UIFont { get }
var medium44: UIFont { get }
var light10: UIFont { get }
var light12: UIFont { get }
var light16: UIFont { get }
var light17: UIFont { get }
var bold12: UIFont { get }
var bold14: UIFont { get }
var bold16: UIFont { get }
var bold17: UIFont { get }
var bold18: UIFont { get }
var bold20: UIFont { get }
var bold22: UIFont { get }
var bold24: UIFont { get }
var bold28: UIFont { get }
var bold34: UIFont { get }
var bold36: UIFont { get }
var bold48: UIFont { get }
var header: UIFont { get }
var heavy17: UIFont { get }
var heavy20: UIFont { get }
var heavy32: UIFont { get }
var heavy38: UIFont { get }
var italic12: UIFont { get }
var italic16: UIFont { get }
var semibold12: UIFont { get }
var semibold14: UIFont { get }
var semibold15: UIFont { get }
var semibold16: UIFont { get }
var semibold18: UIFont { get }
var semibold20: UIFont { get }
}

View file

@ -0,0 +1,9 @@
protocol IStyleSheet: CaseIterable, RawRepresentable, StyleStringRepresentable {
static func register(theme: Theme, colors: IColors, fonts: IFonts)
}
extension IStyleSheet {
static func register(theme: Theme, colors: IColors, fonts: IFonts) {
allCases.forEach { theme.add($0, $0.styleResolverFor(colors: colors, fonts: fonts)) }
}
}

View file

@ -0,0 +1,333 @@
class Style: ExpressibleByDictionaryLiteral {
enum Parameter: Hashable{
case backgroundColor
case borderColor
case borderWidth
case cornerRadius
case maskedCorners
case shadowColor
case shadowOpacity
case shadowOffset
case shadowRadius
case clip
case round
case font
case fontColor
case fontDetailed
case fontColorDetailed
case tintColor
case tintColorDisabled
case onTintColor
case offTintColor
case image
case mwmImage
case color
case attributes
case linkAttributes
case backgroundImage
case backgroundColorSelected
case backgroundColorHighlighted
case backgroundColorDisabled
case fontColorSelected
case fontColorHighlighted
case fontColorDisabled
case barTintColor
case shadowImage
case textAlignment
case textContainerInset
case separatorColor
case pageIndicatorTintColor
case currentPageIndicatorTintColor
case coloring
case colors
case images
case exclusions
case unknown
case gridColor
case previewSelectorColor
case previewTintColor
case infoBackground
}
typealias Key = Parameter
typealias Value = Any?
var params:[Key: Value] = [:]
var isEmpty: Bool {
return params.isEmpty
}
required init(dictionaryLiteral elements: (Style.Parameter, Any?)...) {
for (key, value) in elements {
params[key] = value
}
}
subscript(keyname: Key) -> Value {
get { return params[keyname] ?? nil }
}
func append(_ style: Style) {
params.merge(style.params) { (a, b) -> Style.Value in
return a
}
}
func append(_ styles: [Style]) {
styles.forEach { (style) in
params.merge(style.params) { (a, b) -> Style.Value in
return a
}
}
}
func hasExclusion(view: UIView) -> Bool {
guard let exclusions = exclusions else {
return false
}
var superView:UIView? = view
while (superView != nil) {
if exclusions.contains(String(describing: type(of: superView!))) {
return true
}
superView = superView?.superview
}
return false;
}
}
extension Style {
var backgroundColor: UIColor? {
get { return self[.backgroundColor] as? UIColor }
set { params[.backgroundColor] = newValue }
}
var borderColor: UIColor? {
get { return self[.borderColor] as? UIColor }
set { params[.borderColor] = newValue }
}
var borderWidth: CGFloat? {
get { return self[.borderWidth] as? CGFloat }
set { params[.borderWidth] = newValue }
}
var cornerRadius: CornerRadius? {
get { return self[.cornerRadius] as? CornerRadius }
set { params[.cornerRadius] = newValue }
}
var maskedCorners: CACornerMask? {
get { return self[.maskedCorners] as? CACornerMask }
set { params[.maskedCorners] = newValue }
}
var shadowColor: UIColor? {
get { return self[.shadowColor] as? UIColor }
set { params[.shadowColor] = newValue }
}
var shadowOpacity: Float? {
get { return self[.shadowOpacity] as? Float }
set { params[.shadowOpacity] = newValue }
}
var shadowOffset: CGSize? {
get { return self[.shadowOffset] as? CGSize }
set { params[.shadowOffset] = newValue }
}
var shadowRadius: CGFloat? {
get { return self[.shadowRadius] as? CGFloat }
set { params[.shadowRadius] = newValue }
}
var clip: Bool? {
get { return self[.clip] as? Bool }
set { params[.clip] = newValue }
}
var round: Bool? {
get { return self[.round] as? Bool }
set { params[.round] = newValue }
}
var font: UIFont? {
get { return self[.font] as? UIFont }
set { params[.font] = newValue }
}
var fontColor: UIColor? {
get { return self[.fontColor] as? UIColor }
set { params[.fontColor] = newValue }
}
var fontDetailed: UIFont? {
get { return self[.fontDetailed] as? UIFont }
set { params[.fontDetailed] = newValue }
}
var fontColorDetailed: UIColor? {
get { return self[.fontColorDetailed] as? UIColor }
set { params[.fontColorDetailed] = newValue }
}
var tintColor: UIColor? {
get { return self[.tintColor] as? UIColor }
set { params[.tintColor] = newValue }
}
var tintColorDisabled: UIColor? {
get { return self[.tintColorDisabled] as? UIColor }
set { params[.tintColorDisabled] = newValue }
}
var onTintColor: UIColor? {
get { return self[.onTintColor] as? UIColor }
set { params[.onTintColor] = newValue }
}
var offTintColor: UIColor? {
get { return self[.offTintColor] as? UIColor }
set { params[.offTintColor] = newValue }
}
var image: String? {
get { return self[.image] as? String }
set { params[.image] = newValue }
}
var mwmImage: String? {
get { return self[.mwmImage] as? String }
set { params[.mwmImage] = newValue }
}
var color: UIColor? {
get { return self[.color] as? UIColor }
set { params[.color] = newValue }
}
var attributes: [NSAttributedString.Key : Any]? {
get { return self[.attributes] as? [NSAttributedString.Key : Any] }
set { params[.attributes] = newValue }
}
var linkAttributes: [NSAttributedString.Key : Any]? {
get { return self[.linkAttributes] as? [NSAttributedString.Key : Any] }
set { params[.linkAttributes] = newValue }
}
var backgroundImage: UIImage? {
get { return self[.backgroundImage] as? UIImage }
set { params[.backgroundImage] = newValue }
}
var barTintColor: UIColor? {
get { return self[.barTintColor] as? UIColor }
set { params[.barTintColor] = newValue }
}
var backgroundColorSelected: UIColor? {
get { return self[.backgroundColorSelected] as? UIColor }
set { params[.backgroundColorSelected] = newValue }
}
var backgroundColorHighlighted: UIColor? {
get { return self[.backgroundColorHighlighted] as? UIColor }
set { params[.backgroundColorHighlighted] = newValue }
}
var backgroundColorDisabled: UIColor? {
get { return self[.backgroundColorDisabled] as? UIColor }
set { params[.backgroundColorDisabled] = newValue }
}
var fontColorSelected: UIColor? {
get { return self[.fontColorSelected] as? UIColor }
set { params[.fontColorSelected] = newValue }
}
var fontColorHighlighted: UIColor? {
get { return self[.fontColorHighlighted] as? UIColor }
set { params[.fontColorHighlighted] = newValue }
}
var fontColorDisabled: UIColor? {
get { return self[.fontColorDisabled] as? UIColor }
set { params[.fontColorDisabled] = newValue }
}
var shadowImage: UIImage? {
get { return self[.shadowImage] as? UIImage }
set { params[.shadowImage] = newValue }
}
var textAlignment: NSTextAlignment? {
get { return self[.textAlignment] as? NSTextAlignment }
set { params[.textAlignment] = newValue }
}
var textContainerInset: UIEdgeInsets? {
get { return self[.textContainerInset] as? UIEdgeInsets }
set { params[.textContainerInset] = newValue }
}
var separatorColor: UIColor? {
get { return self[.separatorColor] as? UIColor }
set { params[.separatorColor] = newValue }
}
var pageIndicatorTintColor: UIColor? {
get { return self[.pageIndicatorTintColor] as? UIColor }
set { params[.pageIndicatorTintColor] = newValue }
}
var currentPageIndicatorTintColor: UIColor? {
get { return self[.currentPageIndicatorTintColor] as? UIColor }
set { params[.currentPageIndicatorTintColor] = newValue }
}
var colors: [UIColor]? {
get { return self[.colors] as? [UIColor] }
set { params[.colors] = newValue }
}
var images: [String]? {
get { return self[.images] as? [String] }
set { params[.images] = newValue }
}
var coloring: MWMButtonColoring? {
get { return self[.coloring] as? MWMButtonColoring }
set { params[.coloring] = newValue }
}
var exclusions: Set<String>? {
get { return self[.exclusions] as? Set<String> }
set { params[.exclusions] = newValue }
}
var gridColor: UIColor? {
get { return self[.gridColor] as? UIColor }
set { params[.gridColor] = newValue }
}
var previewSelectorColor: UIColor? {
get { return self[.previewSelectorColor] as? UIColor }
set { params[.previewSelectorColor] = newValue }
}
var previewTintColor: UIColor? {
get { return self[.previewTintColor] as? UIColor }
set { params[.previewTintColor] = newValue }
}
var infoBackground: UIColor? {
get { return self[.infoBackground] as? UIColor }
set { params[.infoBackground] = newValue }
}
}

View file

@ -0,0 +1,80 @@
@objc protocol ThemeListener {
@objc func applyTheme()
}
@objc class StyleManager: NSObject {
@objc static var shared = StyleManager()
@objc private(set) var theme: Theme?
private var listeners: [Weak<ThemeListener>] = []
override private init() {
super.init()
SwizzleStyle.swizzle()
}
func setTheme (_ theme: Theme) {
self.theme = theme;
update()
}
func hasTheme () -> Bool {
return theme != nil
}
func update () {
for scene in UIApplication.shared.connectedScenes {
if let windowsScene = scene as? UIWindowScene {
for window in windowsScene.windows {
updateView(window.rootViewController?.view)
}
}
}
let appDelegate = UIApplication.shared.delegate as! MapsAppDelegate
if let vc = appDelegate.window.rootViewController?.presentedViewController {
vc.applyTheme()
updateView(vc.view)
} else if let vcs = appDelegate.window.rootViewController?.children {
for vc in vcs {
vc.applyTheme()
}
}
for container in listeners {
if let listener = container.value {
listener.applyTheme()
}
}
}
private func updateView(_ view: UIView?) {
guard let view = view else {
return
}
view.isStyleApplied = false
for subview in view.subviews {
self.updateView(subview)
}
view.applyTheme()
view.isStyleApplied = true;
}
func getStyle(_ styleName: String) -> [Style]{
return theme?.get(styleName) ?? [Style]()
}
@objc func addListener(_ themeListener: ThemeListener) {
if theme != nil {
themeListener.applyTheme()
}
if !listeners.contains(where: { themeListener === $0.value }) {
listeners.append(Weak(value: themeListener))
}
}
@objc func removeListener(_ themeListener: ThemeListener) {
listeners.removeAll { (container) -> Bool in
return container.value === themeListener
}
}
}

View file

@ -0,0 +1,76 @@
@objc class Theme: NSObject {
enum ThemeType {
case dark
case light
}
typealias StyleName = String
typealias Resolver = ((Style) -> (Void))
@objc let colors: IColors
@objc let fonts: IFonts
private var themeType: ThemeType
private var components: [StyleName: Style] = [:]
private var resolvers: [StyleName: Resolver] = [:]
private var dependencies: [StyleName: StyleName] = [:]
init (type: ThemeType, colors: IColors, fonts: IFonts) {
self.colors = colors
self.fonts = fonts
self.themeType = type
super.init()
self.register()
}
func registerStyleSheet<U: IStyleSheet> (_ type: U.Type) {
U.register(theme: self, colors: colors, fonts: fonts)
}
func add(styleName: StyleName, _ resolver:@escaping Resolver) {
resolvers[styleName] = resolver
}
func add(styleName: StyleName, from: StyleName, _ resolver:@escaping Resolver) {
resolvers[styleName] = resolver
dependencies[styleName] = from
}
func add(styleName: StyleName, forType: ThemeType, _ resolver:@escaping Resolver) {
guard themeType == forType else {
return
}
resolvers[styleName] = resolver
}
func add(styleName: StyleName, from: StyleName, forType: ThemeType, _ resolver:@escaping Resolver) {
guard themeType == forType else {
return
}
resolvers[styleName] = resolver
dependencies[styleName] = from
}
func get(_ styleName: StyleName) -> [Style] {
let styleNames = styleName.split(separator: ":")
var result = [Style]()
for name in styleNames {
let strName = String(name)
if let style = components[strName] {
result.append(style)
} else if let resolver = resolvers[strName] {
let style = Style()
resolver(style)
if let dependency = dependencies[strName] {
style.append(self.get(dependency))
}
result.append(style)
} else {
assertionFailure("Style Not found:\(name)")
}
}
return result
}
func register() {
fatalError("You should register stylesheets in subclass")
}
}

View file

@ -0,0 +1,103 @@
@objc(MWMThemeManager)
final class ThemeManager: NSObject {
private static let autoUpdatesInterval: TimeInterval = 30 * 60 // 30 minutes in seconds
private static let instance = ThemeManager()
private weak var timer: Timer?
private override init() {
super.init()
}
private func update(theme: MWMTheme) {
updateSystemUserInterfaceStyle(theme)
let actualTheme: MWMTheme = { theme in
let isVehicleRouting = MWMRouter.isRoutingActive() && (MWMRouter.type() == .vehicle) && MWMRouter.hasSavedRoute()
switch theme {
case .day: fallthrough
case .vehicleDay: return isVehicleRouting ? .vehicleDay : .day
case .night: fallthrough
case .vehicleNight: return isVehicleRouting ? .vehicleNight : .night
case .auto:
let isDarkModeEnabled = UIScreen.main.traitCollection.userInterfaceStyle == .dark
guard isVehicleRouting else { return isDarkModeEnabled ? .night : .day }
return isDarkModeEnabled ? .vehicleNight : .vehicleDay
@unknown default:
fatalError()
}
}(theme)
let nightMode = UIColor.isNightMode()
let newNightMode: Bool = { theme in
switch theme {
case .day: fallthrough
case .vehicleDay: return false
case .night: fallthrough
case .vehicleNight: return true
case .auto: assert(false); return false
@unknown default:
fatalError()
}
}(actualTheme)
if Settings.mapAppearance == .light {
if actualTheme == .vehicleDay || actualTheme == .vehicleNight {
FrameworkHelper.setTheme(.vehicleDay)
} else {
FrameworkHelper.setTheme(.day)
}
} else if Settings.mapAppearance == .dark {
if actualTheme == .vehicleDay || actualTheme == .vehicleNight {
FrameworkHelper.setTheme(.vehicleNight)
} else {
FrameworkHelper.setTheme(.night)
}
} else {
FrameworkHelper.setTheme(actualTheme)
}
if nightMode != newNightMode || StyleManager.shared.hasTheme() == false{
UIColor.setNightMode(newNightMode)
if newNightMode {
StyleManager.shared.setTheme(MainTheme(type: .dark, colors: NightColors(), fonts: Fonts()))
} else {
StyleManager.shared.setTheme(MainTheme(type: .light, colors: DayColors(), fonts: Fonts()))
}
}
}
@objc static func invalidate() {
instance.update(theme: SettingsBridge.theme())
}
@available(iOS 13.0, *)
private func updateSystemUserInterfaceStyle(_ theme: MWMTheme) {
let userInterfaceStyle: UIUserInterfaceStyle = { theme in
switch theme {
case .day: fallthrough
case .vehicleDay: return .light
case .night: fallthrough
case .vehicleNight: return .dark
case .auto: return .unspecified
@unknown default:
fatalError()
}
}(theme)
UIApplication.shared.delegate?.window??.overrideUserInterfaceStyle = userInterfaceStyle
}
@available(iOS, deprecated:13.0)
@objc static var autoUpdates: Bool {
get {
return instance.timer != nil
}
set {
if newValue {
instance.timer = Timer.scheduledTimer(timeInterval: autoUpdatesInterval, target: self, selector: #selector(invalidate), userInfo: nil, repeats: true)
} else {
instance.timer?.invalidate()
}
invalidate()
}
}
}

View file

@ -0,0 +1,21 @@
enum CornerRadius {
case modalSheet
case buttonDefault
case buttonDefaultSmall
case buttonSmall
case grabber
case custom(CGFloat)
}
extension CornerRadius {
var value: CGFloat {
switch self {
case .modalSheet: return 12
case .buttonDefault: return 8
case .buttonDefaultSmall: return 6
case .buttonSmall: return 4
case .grabber: return 2.5
case .custom(let value): return value
}
}
}

View file

@ -0,0 +1,46 @@
extension UIColor {
private func convertToHEX(component: CGFloat) -> Int {
return lroundf(Float(component * 255));
}
private var hexColorComponentTemplate: String {
get {
return "%02lX";
}
}
private var hexColorTemplate: String {
get {
return "#\(hexColorComponentTemplate)\(hexColorComponentTemplate)\(hexColorComponentTemplate)";
}
}
var hexString: String {
get {
let cgColorInRGB = cgColor.converted(to: CGColorSpace(name: CGColorSpace.sRGB)!, intent: .defaultIntent, options: nil)!
let colorRef = cgColorInRGB.components
let r = colorRef?[0] ?? 0
let g = colorRef?[1] ?? 0
let b = ((colorRef?.count ?? 0) > 2 ? colorRef?[2] : g) ?? 0
let alpha = cgColor.alpha
var color = String(
format: hexColorTemplate,
convertToHEX(component: r),
convertToHEX(component: g),
convertToHEX(component: b)
)
if (alpha < 1) {
color += String(format: hexColorComponentTemplate, convertToHEX(component: alpha))
}
return color
}
}
var sRGBColor: UIColor {
let cgColorInRGB = cgColor.converted(to: CGColorSpace(name: CGColorSpace.sRGB)!, intent: .defaultIntent, options: nil)!
return UIColor(cgColor: cgColorInRGB)
}
}

View file

@ -0,0 +1,11 @@
extension UIColor {
func getImage() -> UIImage? {
let rect = CGRect(x: 0, y: 0, width: 1, height: 1)
UIGraphicsBeginImageContext(rect.size)
self.setFill()
UIRectFill(rect)
let image = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext()
return image
}
}

View file

@ -0,0 +1,5 @@
extension UIColor {
convenience init(_ r: CGFloat, _ g: CGFloat, _ b :CGFloat, _ a: CGFloat) {
self.init(red: CGFloat(r/255.0), green: CGFloat(g/255.0), blue: CGFloat(b/255.0), alpha: a)
}
}

View file

@ -0,0 +1,18 @@
import UIKit
extension UIFont {
/// Creates a UIFont object with monospaced numbers keeping other font descriptors like size and weight
@objc var monospaced: UIFont {
let attributes: [UIFontDescriptor.AttributeName: Any] = [
.featureSettings: [
[
UIFontDescriptor.FeatureKey.type: kNumberSpacingType,
UIFontDescriptor.FeatureKey.selector: kMonospacedNumbersSelector
]
]
]
let monospacedNumbersFontDescriptor = fontDescriptor.addingAttributes(attributes)
return UIFont(descriptor: monospacedNumbersFontDescriptor, size: pointSize)
}
}

View file

@ -0,0 +1,23 @@
extension UILabel {
func setFontStyle(_ font: FontStyleSheet, color: TextColorStyleSheet? = nil) {
var name = font.rawValue
if let color {
name += ":\(color.rawValue)"
}
styleName = name
}
func setFontStyle(_ color: TextColorStyleSheet) {
styleName = color.rawValue
}
func setFontStyleAndApply(_ font: FontStyleSheet, color: TextColorStyleSheet? = nil) {
setFontStyle(font, color: color)
applyTheme()
}
func setFontStyleAndApply(_ color: TextColorStyleSheet) {
setFontStyle(color)
applyTheme()
}
}

View file

@ -0,0 +1,31 @@
fileprivate struct AssociatedKeys {
static var styleName: UInt8 = 0
static var isStyleApplied: UInt8 = 1
}
@objc extension UINavigationItem: StyleApplicable {
@objc var styleName: String {
get {
isStyleApplied = false
guard let value = objc_getAssociatedObject(self, &AssociatedKeys.styleName) as? String else {
return ""
}
return value
}
set(newValue) {
objc_setAssociatedObject(self, &AssociatedKeys.styleName, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
@objc var isStyleApplied: Bool {
get {
guard let value = objc_getAssociatedObject(self, &AssociatedKeys.isStyleApplied) as? Bool else {
return false
}
return value
}
set(newValue) {
objc_setAssociatedObject(self, &AssociatedKeys.isStyleApplied, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
}

View file

@ -0,0 +1,46 @@
fileprivate struct AssociatedKeys {
static var styleName: UInt8 = 0
static var isStyleApplied: UInt8 = 1
}
@objc extension UIView: StyleApplicable {
@objc func sw_didMoveToWindow() {
guard MapsAppDelegate.theApp().window === window else {
sw_didMoveToWindow();
return
}
applyTheme()
isStyleApplied = true
sw_didMoveToWindow();
}
@objc var styleName: String {
get {
isStyleApplied = false
guard let value = objc_getAssociatedObject(self, &AssociatedKeys.styleName) as? String else {
return ""
}
return value
}
set(newValue) {
objc_setAssociatedObject(self, &AssociatedKeys.styleName, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
@objc var isStyleApplied: Bool {
get {
guard let value = objc_getAssociatedObject(self, &AssociatedKeys.isStyleApplied) as? Bool else {
return false
}
return value
}
set(newValue) {
objc_setAssociatedObject(self, &AssociatedKeys.isStyleApplied, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
}
@objc func setStyleNameAndApply(_ styleName: String) {
self.styleName = styleName
applyTheme()
}
}

View file

@ -0,0 +1,136 @@
enum FontStyleSheet: String, CaseIterable {
case regular9
case regular10
case regular11
case regular12
case regular13
case regular14
case regular15
case regular16
case regular17
case regular18
case regular20
case regular24
case regular32
case regular52
case medium9
case medium10
case medium12
case medium13
case medium14
case medium16
case medium17
case medium18
case medium20
case medium24
case medium28
case medium36
case medium40
case medium44
case light10
case light12
case light16
case light17
case bold12
case bold14
case bold16
case bold17
case bold18
case bold20
case bold22
case bold24
case bold28
case bold34
case bold36
case bold48
case heavy17
case heavy20
case heavy32
case heavy38
case italic12
case italic16
case semibold12
case semibold14
case semibold15
case semibold16
case semibold18
case semibold20
}
extension FontStyleSheet: IStyleSheet {
func styleResolverFor(colors: IColors, fonts: IFonts) -> Theme.StyleResolver {
let font: UIFont = {
switch self {
case .regular9: return fonts.regular9
case .regular10: return fonts.regular10
case .regular11: return fonts.regular11
case .regular12: return fonts.regular12
case .regular13: return fonts.regular13
case .regular14: return fonts.regular14
case .regular15: return fonts.regular15
case .regular16: return fonts.regular16
case .regular17: return fonts.regular17
case .regular18: return fonts.regular18
case .regular20: return fonts.regular20
case .regular24: return fonts.regular24
case .regular32: return fonts.regular32
case .regular52: return fonts.regular52
case .medium9: return fonts.medium9
case .medium10: return fonts.medium10
case .medium12: return fonts.medium12
case .medium13: return fonts.medium13
case .medium14: return fonts.medium14
case .medium16: return fonts.medium16
case .medium17: return fonts.medium17
case .medium18: return fonts.medium18
case .medium20: return fonts.medium20
case .medium24: return fonts.medium24
case .medium28: return fonts.medium28
case .medium36: return fonts.medium36
case .medium40: return fonts.medium40
case .medium44: return fonts.medium44
case .light10: return fonts.light10
case .light12: return fonts.light12
case .light16: return fonts.light16
case .light17: return fonts.light17
case .bold12: return fonts.bold12
case .bold14: return fonts.bold14
case .bold16: return fonts.bold16
case .bold17: return fonts.bold17
case .bold18: return fonts.bold18
case .bold20: return fonts.bold20
case .bold22: return fonts.bold22
case .bold24: return fonts.bold24
case .bold28: return fonts.bold28
case .bold34: return fonts.bold34
case .bold36: return fonts.bold36
case .bold48: return fonts.bold48
case .heavy17: return fonts.heavy17
case .heavy20: return fonts.heavy20
case .heavy32: return fonts.heavy32
case .heavy38: return fonts.heavy38
case .italic12: return fonts.italic12
case .italic16: return fonts.italic16
case .semibold12: return fonts.semibold12
case .semibold14: return fonts.semibold14
case .semibold15: return fonts.semibold15
case .semibold16: return fonts.semibold16
case .semibold18: return fonts.semibold18
case .semibold20: return fonts.semibold20
}
}()
return .add { s in s.font = font }
}
}

View file

@ -0,0 +1,59 @@
class Fonts: IFonts {
var regular9 = UIFont.systemFont(ofSize: 9)
var regular10 = UIFont.systemFont(ofSize: 10)
var regular11 = UIFont.systemFont(ofSize: 11)
var regular12 = UIFont.systemFont(ofSize: 12)
var regular13 = UIFont.systemFont(ofSize: 13)
var regular14 = UIFont.systemFont(ofSize: 14)
var regular15 = UIFont.systemFont(ofSize: 15)
var regular16 = UIFont.systemFont(ofSize: 16)
var regular17 = UIFont.systemFont(ofSize: 17)
var regular18 = UIFont.systemFont(ofSize: 18)
var regular20 = UIFont.systemFont(ofSize: 20)
var regular24 = UIFont.systemFont(ofSize: 24)
var regular32 = UIFont.systemFont(ofSize: 32)
var regular52 = UIFont.systemFont(ofSize: 52)
var medium9 = UIFont.systemFont(ofSize: 9, weight:UIFont.Weight.medium)
var medium10 = UIFont.systemFont(ofSize: 10, weight:UIFont.Weight.medium)
var medium12 = UIFont.systemFont(ofSize: 12, weight:UIFont.Weight.medium)
var medium13 = UIFont.systemFont(ofSize: 13, weight:UIFont.Weight.medium)
var medium14 = UIFont.systemFont(ofSize: 14, weight:UIFont.Weight.medium)
var medium16 = UIFont.systemFont(ofSize: 16, weight:UIFont.Weight.medium)
var medium17 = UIFont.systemFont(ofSize: 17, weight:UIFont.Weight.medium)
var medium18 = UIFont.systemFont(ofSize: 18, weight:UIFont.Weight.medium)
var medium20 = UIFont.systemFont(ofSize: 20, weight:UIFont.Weight.medium)
var medium24 = UIFont.systemFont(ofSize: 24, weight:UIFont.Weight.medium)
var medium28 = UIFont.systemFont(ofSize: 28, weight:UIFont.Weight.medium)
var medium36 = UIFont.systemFont(ofSize: 36, weight:UIFont.Weight.medium)
var medium40 = UIFont.systemFont(ofSize: 40, weight:UIFont.Weight.medium)
var medium44 = UIFont.systemFont(ofSize: 44, weight:UIFont.Weight.medium)
var light10 = UIFont.systemFont(ofSize: 10, weight:UIFont.Weight.light)
var light12 = UIFont.systemFont(ofSize: 12, weight:UIFont.Weight.light)
var light16 = UIFont.systemFont(ofSize: 16, weight:UIFont.Weight.light)
var light17 = UIFont.systemFont(ofSize: 17, weight:UIFont.Weight.light)
var bold12 = UIFont.systemFont(ofSize: 12, weight:UIFont.Weight.bold)
var bold14 = UIFont.systemFont(ofSize: 14, weight:UIFont.Weight.bold)
var bold16 = UIFont.systemFont(ofSize: 16, weight:UIFont.Weight.bold)
var bold17 = UIFont.systemFont(ofSize: 17, weight:UIFont.Weight.bold)
var bold18 = UIFont.systemFont(ofSize: 18, weight:UIFont.Weight.bold)
var bold20 = UIFont.systemFont(ofSize: 20, weight:UIFont.Weight.bold)
var bold22 = UIFont.systemFont(ofSize: 22, weight:UIFont.Weight.bold)
var bold24 = UIFont.systemFont(ofSize: 24, weight:UIFont.Weight.bold)
var bold28 = UIFont.systemFont(ofSize: 28, weight:UIFont.Weight.bold)
var bold34 = UIFont.systemFont(ofSize: 34, weight:UIFont.Weight.bold)
var bold36 = UIFont.systemFont(ofSize: 36, weight:UIFont.Weight.bold)
var bold48 = UIFont.systemFont(ofSize: 48, weight:UIFont.Weight.bold)
var header = UIFont.preferredFont(forTextStyle: .headline)
var heavy17 = UIFont.systemFont(ofSize: 17, weight:UIFont.Weight.heavy)
var heavy20 = UIFont.systemFont(ofSize: 20, weight:UIFont.Weight.heavy)
var heavy32 = UIFont.systemFont(ofSize: 32, weight:UIFont.Weight.heavy)
var heavy38 = UIFont.systemFont(ofSize: 38, weight:UIFont.Weight.heavy)
var italic12 = UIFont.italicSystemFont(ofSize: 12)
var italic16 = UIFont.italicSystemFont(ofSize: 16)
var semibold12 = UIFont.systemFont(ofSize: 12, weight:UIFont.Weight.semibold)
var semibold14 = UIFont.systemFont(ofSize: 14, weight:UIFont.Weight.semibold)
var semibold15 = UIFont.systemFont(ofSize: 15, weight:UIFont.Weight.semibold)
var semibold16 = UIFont.systemFont(ofSize: 16, weight:UIFont.Weight.semibold)
var semibold18 = UIFont.systemFont(ofSize: 18, weight:UIFont.Weight.semibold)
var semibold20 = UIFont.systemFont(ofSize: 20, weight:UIFont.Weight.semibold)
}

View file

@ -0,0 +1,476 @@
enum GlobalStyleSheet: String, CaseIterable {
case tableView = "TableView"
case tableCell = "TableCell"
case tableViewCell = "MWMTableViewCell"
case defaultTableViewCell
case tableViewHeaderFooterView = "TableViewHeaderFooterView"
case defaultSearchBar
case searchBar = "SearchBar"
case navigationBar = "NavigationBar"
case navigationBarItem = "NavigationBarItem"
case checkmark = "Checkmark"
case `switch` = "Switch"
case pageControl = "PageControl"
case starRatingView = "StarRatingView"
case difficultyView = "DifficultyView"
case divider = "Divider"
case solidDivider = "SolidDivider"
case background = "Background"
case pressBackground = "PressBackground"
case primaryBackground = "PrimaryBackground"
case secondaryBackground = "SecondaryBackground"
case menuBackground = "MenuBackground"
case bottomTabBarButton = "BottomTabBarButton"
case trackRecordingWidgetButton = "TrackRecordingWidgetButton"
case blackOpaqueBackground = "BlackOpaqueBackground"
case blueBackground = "BlueBackground"
case fadeBackground = "FadeBackground"
case errorBackground = "ErrorBackground"
case blackStatusBarBackground = "BlackStatusBarBackground"
case presentationBackground = "PresentationBackground"
case clearBackground = "ClearBackground"
case border = "Border"
case tabView = "TabView"
case dialogView = "DialogView"
case alertView = "AlertView"
case alertViewTextFieldContainer = "AlertViewTextFieldContainer"
case alertViewTextField = "AlertViewTextField"
case searchStatusBarView = "SearchStatusBarView"
case flatNormalButton = "FlatNormalButton"
case flatNormalButtonBig = "FlatNormalButtonBig"
case flatNormalTransButton = "FlatNormalTransButton"
case flatNormalTransButtonBig = "FlatNormalTransButtonBig"
case flatGrayTransButton = "FlatGrayTransButton"
case flatPrimaryTransButton = "FlatPrimaryTransButton"
case flatRedTransButton = "FlatRedTransButton"
case flatRedTransButtonBig = "FlatRedTransButtonBig"
case flatRedButton = "FlatRedButton"
case moreButton = "MoreButton"
case editButton = "EditButton"
case rateAppButton = "RateAppButton"
case termsOfUseLinkText = "TermsOfUseLinkText"
case termsOfUseGrayButton = "TermsOfUseGrayButton"
case badge = "Badge"
case blue = "MWMBlue"
case black = "MWMBlack"
case other = "MWMOther"
case gray = "MWMGray"
case separator = "MWMSeparator"
case white = "MWMWhite"
case datePickerView = "DatePickerView"
case valueStepperView = "ValueStepperView"
case grabber
case modalSheetBackground
case modalSheetContent
case toastBackground
case toastLabel
}
extension GlobalStyleSheet: IStyleSheet {
func styleResolverFor(colors: IColors, fonts: IFonts) -> Theme.StyleResolver {
switch self {
case .tableView:
return .add { s in
s.backgroundColor = colors.white
s.separatorColor = colors.blackDividers
s.exclusions = [String(describing: UIDatePicker.self)]
}
case .tableCell:
return .add { s in
s.backgroundColor = colors.white
s.fontColor = colors.blackPrimaryText
s.tintColor = colors.linkBlue
s.fontColorDetailed = colors.blackSecondaryText
s.backgroundColorSelected = colors.pressBackground
s.exclusions = [String(describing: UIDatePicker.self), "_UIActivityUserDefaultsActivityCell"]
}
case .tableViewCell:
return .addFrom(Self.tableCell) { s in
}
case .defaultTableViewCell:
return .add { s in
s.backgroundColor = colors.white
}
case .tableViewHeaderFooterView:
return .add { s in
s.font = fonts.medium14
s.fontColor = colors.blackSecondaryText
}
case .defaultSearchBar:
return .add { s in
s.backgroundColor = colors.pressBackground
s.barTintColor = colors.clear
s.fontColor = colors.blackPrimaryText
s.fontColorDetailed = UIColor.white
s.tintColor = colors.blackSecondaryText
}
case .searchBar:
return .add { s in
s.backgroundColor = colors.white
s.barTintColor = colors.primary
s.fontColor = colors.blackPrimaryText
s.fontColorDetailed = UIColor.white
s.tintColor = colors.blackSecondaryText
}
case .navigationBar:
return .add { s in
s.barTintColor = colors.primary
s.tintColor = colors.whitePrimaryText
s.backgroundImage = UIImage()
s.shadowImage = UIImage()
s.font = fonts.header
s.fontColor = colors.whitePrimaryText
}
case .navigationBarItem:
return .add { s in
s.font = fonts.regular18
s.fontColor = colors.whitePrimaryText
s.fontColorDisabled = UIColor.lightGray
s.fontColorHighlighted = colors.whitePrimaryTextHighlighted
s.tintColor = colors.whitePrimaryText
}
case .checkmark:
return .add { s in
s.onTintColor = colors.linkBlue
s.offTintColor = colors.blackHintText
}
case .switch:
return .add { s in
s.onTintColor = UIColor.accent
}
case .pageControl:
return .add { s in
s.pageIndicatorTintColor = colors.blackHintText
s.currentPageIndicatorTintColor = colors.blackSecondaryText
s.backgroundColor = colors.white
}
case .starRatingView:
return .add { s in
s.onTintColor = colors.ratingYellow
s.offTintColor = colors.blackDividers
}
case .difficultyView:
return .add { s in
s.colors = [colors.blackSecondaryText, colors.ratingGreen, colors.ratingYellow, colors.ratingRed]
s.offTintColor = colors.blackSecondaryText
s.backgroundColor = colors.clear
}
case .divider:
return .add { s in
s.backgroundColor = colors.blackDividers
}
case .solidDivider:
return .add { s in
s.backgroundColor = colors.solidDividers
}
case .background:
return .add { s in
s.backgroundColor = colors.white
s.backgroundColorSelected = colors.pressBackground
}
case .pressBackground:
return .add { s in
s.backgroundColor = colors.pressBackground
}
case .primaryBackground:
return .add { s in
s.backgroundColor = colors.primary
}
case .secondaryBackground:
return .add { s in
s.backgroundColor = colors.secondary
}
case .menuBackground:
return .add { s in
s.backgroundColor = colors.menuBackground
}
case .bottomTabBarButton:
return .add { s in
s.backgroundColor = colors.tabBarButtonBackground
s.tintColor = colors.blackSecondaryText
s.coloring = MWMButtonColoring.black
s.cornerRadius = .buttonDefault
s.shadowColor = UIColor(0,0,0,alpha20)
s.shadowOpacity = 1
s.shadowOffset = CGSize(width: 0, height: 1)
s.onTintColor = .red
}
case .trackRecordingWidgetButton:
return .addFrom(Self.bottomTabBarButton) { s in
s.cornerRadius = .custom(23)
s.coloring = .red
}
case .blackOpaqueBackground:
return .add { s in
s.backgroundColor = colors.blackOpaque
}
case .blueBackground:
return .add { s in
s.backgroundColor = colors.linkBlue
}
case .fadeBackground:
return .add { s in
s.backgroundColor = colors.fadeBackground
}
case .errorBackground:
return .add { s in
s.backgroundColor = colors.errorPink
}
case .blackStatusBarBackground:
return .add { s in
s.backgroundColor = colors.blackStatusBarBackground
}
case .presentationBackground:
return .add { s in
s.backgroundColor = UIColor.black.withAlphaComponent(alpha40)
}
case .clearBackground:
return .add { s in
s.backgroundColor = colors.clear
}
case .border:
return .add { s in
s.backgroundColor = colors.border
}
case .tabView:
return .add { s in
s.backgroundColor = colors.white
s.barTintColor = colors.white
s.tintColor = colors.linkBlue
s.fontColor = colors.blackSecondaryText
s.fontColorHighlighted = colors.linkBlue
s.font = fonts.medium14
}
case .dialogView:
return .add { s in
s.cornerRadius = .buttonDefault
s.shadowRadius = 2
s.shadowColor = UIColor(0,0,0,alpha26)
s.shadowOpacity = 1
s.shadowOffset = CGSize(width: 0, height: 1)
s.backgroundColor = colors.white
s.clip = true
}
case .alertView:
return .add { s in
s.cornerRadius = .modalSheet
s.shadowRadius = 6
s.shadowColor = UIColor(0,0,0,alpha20)
s.shadowOpacity = 1
s.shadowOffset = CGSize(width: 0, height: 3)
s.backgroundColor = colors.alertBackground
s.clip = true
}
case .alertViewTextFieldContainer:
return .add { s in
s.borderColor = colors.blackDividers
s.borderWidth = 0.5
s.backgroundColor = colors.white
}
case .alertViewTextField:
return .add { s in
s.font = fonts.regular14
s.fontColor = colors.blackPrimaryText
s.tintColor = colors.blackSecondaryText
}
case .searchStatusBarView:
return .add { s in
s.backgroundColor = colors.primary
s.shadowRadius = 2
s.shadowColor = colors.blackDividers
s.shadowOpacity = 1
s.shadowOffset = CGSize(width: 0, height: 0)
}
case .flatNormalButton:
return .add { s in
s.font = fonts.medium14
s.cornerRadius = .buttonDefault
s.clip = true
s.fontColor = colors.whitePrimaryText
s.backgroundColor = colors.linkBlue
s.fontColorHighlighted = colors.whitePrimaryTextHighlighted
s.fontColorDisabled = colors.whitePrimaryTextHighlighted
s.backgroundColorHighlighted = colors.linkBlueHighlighted
}
case .flatNormalButtonBig:
return .addFrom(Self.flatNormalButton) { s in
s.font = fonts.regular17
}
case .flatNormalTransButton:
return .add { s in
s.font = fonts.medium14
s.cornerRadius = .buttonDefault
s.clip = true
s.fontColor = colors.linkBlue
s.backgroundColor = colors.clear
s.fontColorHighlighted = colors.linkBlueHighlighted
s.fontColorDisabled = colors.blackHintText
s.backgroundColorHighlighted = colors.clear
}
case .flatNormalTransButtonBig:
return .addFrom(Self.flatNormalTransButton) { s in
s.font = fonts.regular17
}
case .flatGrayTransButton:
return .add { s in
s.font = fonts.medium14
s.fontColor = colors.blackSecondaryText
s.backgroundColor = colors.clear
s.fontColorHighlighted = colors.linkBlueHighlighted
}
case .flatPrimaryTransButton:
return .add { s in
s.fontColor = colors.blackPrimaryText
s.backgroundColor = colors.clear
s.fontColorHighlighted = colors.linkBlueHighlighted
}
case .flatRedTransButton:
return .add { s in
s.font = fonts.medium14
s.fontColor = colors.red
s.backgroundColor = colors.clear
s.fontColorHighlighted = colors.red
}
case .flatRedTransButtonBig:
return .add { s in
s.font = fonts.regular17
s.fontColor = colors.red
s.backgroundColor = colors.clear
s.fontColorHighlighted = colors.red
}
case .flatRedButton:
return .add { s in
s.font = fonts.medium14
s.cornerRadius = .buttonDefault
s.fontColor = colors.whitePrimaryText
s.backgroundColor = colors.buttonRed
s.fontColorHighlighted = colors.buttonRedHighlighted
}
case .moreButton:
return .add { s in
s.fontColor = colors.linkBlue
s.fontColorHighlighted = colors.linkBlueHighlighted
s.backgroundColor = colors.clear
s.font = fonts.regular16
}
case .editButton:
return .add { s in
s.font = fonts.regular14
s.fontColor = colors.linkBlue
s.cornerRadius = .buttonDefault
s.borderColor = colors.linkBlue
s.borderWidth = 1
s.fontColorHighlighted = colors.linkBlueHighlighted
s.backgroundColor = colors.clear
}
case .rateAppButton:
return .add { s in
s.font = fonts.medium17
s.fontColor = colors.linkBlue
s.fontColorHighlighted = colors.white
s.borderColor = colors.linkBlue
s.cornerRadius = .buttonDefault
s.borderWidth = 1
s.backgroundColor = colors.clear
s.backgroundColorHighlighted = colors.linkBlue
}
case .termsOfUseLinkText:
return .add { s in
s.font = fonts.regular16
s.fontColor = colors.blackPrimaryText
s.linkAttributes = [NSAttributedString.Key.font: fonts.regular16,
NSAttributedString.Key.foregroundColor: colors.linkBlue,
NSAttributedString.Key.underlineColor: UIColor.clear]
s.textContainerInset = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0)
}
case .termsOfUseGrayButton:
return .add { s in
s.font = fonts.medium10
s.fontColor = colors.blackSecondaryText
s.fontColorHighlighted = colors.blackHintText
}
case .badge:
return .add { s in
s.round = true
s.backgroundColor = colors.downloadBadgeBackground
}
case .blue:
return .add { s in
s.tintColor = colors.linkBlue
s.coloring = MWMButtonColoring.blue
}
case .black:
return .add { s in
s.tintColor = colors.blackSecondaryText
s.coloring = MWMButtonColoring.black
}
case .other:
return .add { s in
s.tintColor = colors.white
s.coloring = MWMButtonColoring.other
}
case .gray:
return .add { s in
s.tintColor = colors.blackHintText
s.coloring = MWMButtonColoring.gray
}
case .separator:
return .add { s in
s.tintColor = colors.blackDividers
s.coloring = MWMButtonColoring.black
}
case .white:
return .add { s in
s.tintColor = colors.white
s.coloring = MWMButtonColoring.white
}
case .datePickerView:
return .add { s in
s.backgroundColor = colors.white
s.fontColor = colors.blackPrimaryText
s.fontColorSelected = colors.whitePrimaryText
s.backgroundColorSelected = colors.linkBlue
s.backgroundColorHighlighted = colors.linkBlueHighlighted
s.fontColorDisabled = colors.blackSecondaryText
}
case .valueStepperView:
return .add { s in
s.font = fonts.regular16
s.fontColor = colors.blackPrimaryText
s.coloring = MWMButtonColoring.blue
}
case .grabber:
return .addFrom(Self.background) { s in
s.cornerRadius = .grabber
}
case .modalSheetBackground:
return .add { s in
s.backgroundColor = colors.white
s.shadowColor = UIColor.black
s.shadowOffset = CGSize(width: 0, height: 1)
s.shadowOpacity = 0.3
s.shadowRadius = 6
s.cornerRadius = .modalSheet
s.clip = false
s.maskedCorners = isiPad ? [] : [.layerMinXMinYCorner, .layerMaxXMinYCorner]
}
case .modalSheetContent:
return .addFrom(Self.modalSheetBackground) { s in
s.backgroundColor = colors.clear
s.clip = true
}
case .toastBackground:
return .add { s in
s.cornerRadius = .modalSheet
s.clip = true
}
case .toastLabel:
return .add { s in
s.font = fonts.regular16
s.fontColor = colors.whitePrimaryText
s.textAlignment = .center
}
}
}
}

View file

@ -0,0 +1,12 @@
class MainTheme: Theme {
override func register() {
registerStyleSheet(GlobalStyleSheet.self)
registerStyleSheet(PlacePageStyleSheet.self)
registerStyleSheet(MapStyleSheet.self)
registerStyleSheet(BookmarksStyleSheet.self)
registerStyleSheet(SearchStyleSheet.self)
registerStyleSheet(FontStyleSheet.self)
registerStyleSheet(TextColorStyleSheet.self)
}
}

View file

@ -0,0 +1,123 @@
enum MapStyleSheet: String, CaseIterable {
case mapMenuButtonDisabled = "MenuButtonDisabled"
case mapMenuButtonEnabled = "MenuButtonEnabled"
case mapStreetNameBackgroundView = "StreetNameBackgroundView"
case mapButtonZoomIn = "ButtonZoomIn"
case mapButtonZoomOut = "ButtonZoomOut"
case mapButtonPending = "ButtonPending"
case mapButtonGetPosition = "ButtonGetPosition"
case mapButtonFollow = "ButtonFollow"
case mapButtonFollowAndRotate = "ButtonFollowAndRotate"
case mapButtonMapBookmarks = "ButtonMapBookmarks"
case mapPromoDiscoveryButton = "PromoDiscroveryButton"
case mapButtonBookmarksBack = "ButtonBookmarksBack"
case mapButtonBookmarksBackOpaque = "ButtonBookmarksBackOpaque"
case mapFirstTurnView = "FirstTurnView"
case mapSecondTurnView = "SecondTurnView"
case mapAutoupdateView = "MapAutoupdateView"
case mapGuidesNavigationBar = "GuidesNavigationBar"
}
extension MapStyleSheet: IStyleSheet {
func styleResolverFor(colors: IColors, fonts: IFonts) -> Theme.StyleResolver {
switch self {
case .mapMenuButtonDisabled:
return .add { s in
s.fontColor = colors.blackSecondaryText
s.font = fonts.regular10
s.backgroundColor = colors.clear
s.borderColor = colors.clear
s.borderWidth = 0
s.cornerRadius = .buttonDefaultSmall
}
case .mapMenuButtonEnabled:
return .add { s in
s.fontColor = colors.linkBlue
s.font = fonts.regular10
s.backgroundColor = colors.linkBlue
s.borderColor = colors.linkBlue
s.borderWidth = 2
s.cornerRadius = .buttonDefaultSmall
}
case .mapStreetNameBackgroundView:
return .add { s in
s.backgroundColor = colors.white
s.shadowRadius = 2
s.shadowColor = UIColor(0, 0, 0, alpha26)
s.shadowOpacity = 1
s.shadowOffset = CGSize(width: 0, height: 1)
}
case .mapButtonZoomIn:
return .add { s in
s.mwmImage = "btn_zoom_in"
}
case .mapButtonZoomOut:
return .add { s in
s.mwmImage = "btn_zoom_out"
}
case .mapButtonPending:
return .add { s in
s.mwmImage = "btn_pending"
}
case .mapButtonGetPosition:
return .add { s in
s.mwmImage = "btn_get_position"
}
case .mapButtonFollow:
return .add { s in
s.mwmImage = "btn_follow"
}
case .mapButtonFollowAndRotate:
return .add { s in
s.mwmImage = "btn_follow_and_rotate"
}
case .mapButtonMapBookmarks:
return .add { s in
s.mwmImage = "ic_routing_bookmark"
}
case .mapPromoDiscoveryButton:
return .add { s in
s.mwmImage = "promo_discovery_button"
}
case .mapButtonBookmarksBack:
return .add { s in
s.mwmImage = "btn_back"
}
case .mapButtonBookmarksBackOpaque:
return .add { s in
s.mwmImage = "btn_back_opaque"
}
case .mapFirstTurnView:
return .add { s in
s.backgroundColor = colors.linkBlue
s.cornerRadius = .buttonSmall
s.shadowRadius = 2
s.shadowColor = colors.shadow
s.shadowOpacity = 0.2
s.shadowOffset = CGSize(width: 0, height: 2)
}
case .mapSecondTurnView:
return .addFrom(Self.mapFirstTurnView) { s in
s.backgroundColor = colors.white
s.shadowColor = colors.blackPrimaryText
}
case .mapAutoupdateView:
return .add { s in
s.shadowOffset = CGSize(width: 0, height: 3)
s.shadowRadius = 6
s.cornerRadius = .buttonSmall
s.shadowOpacity = 1
s.backgroundColor = colors.white
}
case .mapGuidesNavigationBar:
return .add { s in
s.barTintColor = colors.white
s.tintColor = colors.linkBlue
s.backgroundImage = UIImage()
s.shadowImage = UIImage()
s.font = fonts.regular18
s.fontColor = colors.blackPrimaryText
}
}
}
}

View file

@ -0,0 +1,191 @@
enum PlacePageStyleSheet: String, CaseIterable {
case ppTitlePopularView = "PPTitlePopularView"
case ppActionBarTitle = "PPActionBarTitle"
case ppActionBarTitlePartner = "PPActionBarTitlePartner"
case ppElevationProfileDescriptionCell = "ElevationProfileDescriptionCell"
case ppElevationProfileExtendedDifficulty = "ElevationProfileExtendedDifficulty"
case ppRouteBasePreview = "RouteBasePreview"
case ppRoutePreview = "RoutePreview"
case ppRatingSummaryView24 = "RatingSummaryView24"
case ppRatingSummaryView12 = "RatingSummaryView12"
case ppRatingSummaryView12User = "RatingSummaryView12User"
case ppHeaderView = "PPHeaderView"
case ppNavigationShadowView = "PPNavigationShadowView"
case ppBackgroundView = "PPBackgroundView"
case ppView = "PPView"
case ppHeaderCircleIcon = "PPHeaderCircleIcon"
case ppChartView = "ChartView"
case ppRatingView = "PPRatingView"
case ppRatingHorrible = "PPRatingHorrible"
case ppRatingBad = "PPRatingBad"
case ppRatingNormal = "PPRatingNormal"
case ppRatingGood = "PPRatingGood"
case ppRatingExcellent = "PPRatingExellent"
case ppButton = "PPButton"
}
extension PlacePageStyleSheet: IStyleSheet {
func styleResolverFor(colors: IColors, fonts: IFonts) -> Theme.StyleResolver {
switch self {
case .ppTitlePopularView:
return .add { s in
s.backgroundColor = colors.linkBlueHighlighted
s.cornerRadius = .custom(10)
}
case .ppActionBarTitle:
return .add { s in
s.font = fonts.regular10
s.fontColor = colors.blackSecondaryText
}
case .ppActionBarTitlePartner:
return .add { s in
s.font = fonts.regular10
s.fontColor = UIColor.white
}
case .ppElevationProfileDescriptionCell:
return .add { s in
s.backgroundColor = colors.blackOpaque
s.cornerRadius = .buttonDefault
}
case .ppElevationProfileExtendedDifficulty:
return .add { s in
s.backgroundColor = colors.blackSecondaryText
s.fontColor = colors.white
s.font = fonts.medium14
s.textContainerInset = UIEdgeInsets(top: 4, left: 6, bottom: 4, right: 6)
}
case .ppRouteBasePreview:
return .add { s in
s.borderColor = colors.blackDividers
s.borderWidth = 1
s.backgroundColor = colors.white
}
case .ppRoutePreview:
return .add { s in
s.shadowRadius = 2
s.shadowColor = colors.blackDividers
s.shadowOpacity = 1
s.shadowOffset = CGSize(width: 3, height: 0)
s.backgroundColor = colors.pressBackground
}
case .ppRatingSummaryView24:
return .add { s in
s.font = fonts.bold16
s.fontColorHighlighted = colors.ratingYellow
s.fontColorDisabled = colors.blackDividers
s.colors = [
colors.blackSecondaryText,
colors.ratingRed,
colors.ratingOrange,
colors.ratingYellow,
colors.ratingLightGreen,
colors.ratingGreen
]
s.images = [
"ic_24px_rating_normal",
"ic_24px_rating_horrible",
"ic_24px_rating_bad",
"ic_24px_rating_normal",
"ic_24px_rating_good",
"ic_24px_rating_excellent"
]
}
case .ppRatingSummaryView12:
return .addFrom(Self.ppRatingSummaryView24) { s in
s.font = fonts.bold12
s.images = [
"ic_12px_rating_normal",
"ic_12px_rating_horrible",
"ic_12px_rating_bad",
"ic_12px_rating_normal",
"ic_12px_rating_good",
"ic_12px_rating_excellent"
]
}
case .ppRatingSummaryView12User:
return .addFrom(Self.ppRatingSummaryView12) { s in
s.colors?[0] = colors.linkBlue
s.images?[0] = "ic_12px_radio_on"
}
case .ppHeaderView:
return .add { s in
s.backgroundColor = colors.white
s.cornerRadius = .modalSheet
s.clip = true
}
case .ppNavigationShadowView:
return .add { s in
s.backgroundColor = colors.white
s.shadowColor = UIColor.black
s.shadowOffset = CGSize(width: 0, height: 1)
s.shadowOpacity = 0.4
s.shadowRadius = 1
s.clip = false
}
case .ppBackgroundView:
return .addFrom(GlobalStyleSheet.modalSheetBackground) { s in
s.backgroundColor = colors.pressBackground
s.maskedCorners = isiPad ? CACornerMask.all : [.layerMinXMinYCorner, .layerMaxXMinYCorner]
s.clip = false
}
case .ppView:
return .add { s in
s.backgroundColor = colors.clear
s.cornerRadius = .modalSheet
s.clip = true
}
case .ppHeaderCircleIcon:
return .add { s in
s.tintColor = colors.iconOpaqueGrayTint
s.backgroundColor = colors.iconOpaqueGrayBackground
}
case .ppChartView:
return .add { s in
s.backgroundColor = colors.white
s.fontColor = colors.blackSecondaryText
s.font = fonts.regular12
s.gridColor = colors.blackDividers
s.previewSelectorColor = colors.elevationPreviewSelector
s.previewTintColor = colors.elevationPreviewTint
s.shadowOpacity = 0.25
s.shadowColor = colors.shadow
s.infoBackground = colors.pressBackground
}
case .ppRatingView:
return .add { s in
s.backgroundColor = colors.blackOpaque
s.round = true
}
case .ppRatingHorrible:
return .add { s in
s.image = "ic_24px_rating_horrible"
s.tintColor = colors.ratingRed
}
case .ppRatingBad:
return .add { s in
s.image = "ic_24px_rating_bad"
s.tintColor = colors.ratingOrange
}
case .ppRatingNormal:
return .add { s in
s.image = "ic_24px_rating_normal"
s.tintColor = colors.ratingYellow
}
case .ppRatingGood:
return .add { s in
s.image = "ic_24px_rating_good"
s.tintColor = colors.ratingLightGreen
}
case .ppRatingExcellent:
return .add { s in
s.image = "ic_24px_rating_excellent"
s.tintColor = colors.ratingGreen
}
case .ppButton:
return .addFrom(GlobalStyleSheet.flatNormalTransButtonBig) { s in
s.borderColor = colors.linkBlue
s.borderWidth = 1
}
}
}
}

View file

@ -0,0 +1,22 @@
extension BottomMenuLayerButton {
@objc override func applyTheme() {
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
BottomMenuLayerButtonRenderer.render(self, style: style)
}
}
}
class BottomMenuLayerButtonRenderer {
class func render(_ control: BottomMenuLayerButton, style: Style) {
if let font = style.font {
control.titleLabel.font = font
}
if let fontColor = style.fontColor {
control.titleLabel.textColor = fontColor
}
UIImageViewRenderer.render(control.imageView, style: style)
}
}

View file

@ -0,0 +1,26 @@
import Chart
extension ChartView {
override func applyTheme() {
if styleName.isEmpty {
setStyle(.ppChartView)
}
for style in StyleManager.shared.getStyle(styleName) where !style.isEmpty && !style.hasExclusion(view: self) {
ChartViewRenderer.render(self, style: style)
}
}
}
fileprivate final class ChartViewRenderer {
class func render(_ control: ChartView, style: Style) {
control.backgroundColor = style.backgroundColor
control.textColor = style.fontColor!
control.font = style.font!
control.gridColor = style.gridColor!
control.previewSelectorColor = style.previewSelectorColor!
control.previewTintColor = style.previewTintColor!
control.infoBackgroundColor = style.infoBackground!
control.infoShadowColor = style.shadowColor!
control.infoShadowOpacity = style.shadowOpacity!
}
}

View file

@ -0,0 +1,25 @@
import Foundation
extension Checkmark {
@objc override func applyTheme() {
if styleName.isEmpty {
setStyle(.checkmark)
}
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
CheckmarkRenderer.render(self, style: style)
}
}
}
class CheckmarkRenderer {
class func render(_ control: Checkmark, style: Style) {
if let onTintColor = style.onTintColor {
control.onTintColor = onTintColor
}
if let offTintColor = style.offTintColor {
control.offTintColor = offTintColor
}
}
}

View file

@ -0,0 +1,29 @@
import DatePicker
extension DatePickerView {
override func applyTheme() {
if styleName.isEmpty {
setStyle(.datePickerView)
}
for style in StyleManager.shared.getStyle(styleName) where !style.isEmpty && !style.hasExclusion(view: self) {
DatePickerViewRenderer.render(self, style: style)
}
}
}
fileprivate final class DatePickerViewRenderer {
class func render(_ control: DatePickerView, style: Style) {
control.backgroundColor = style.backgroundColor
var theme = DatePickerViewTheme()
theme.monthHeaderBackgroundColor = style.backgroundColor!
theme.monthHeaderColor = style.fontColorDisabled!
theme.weekdaySymbolsColor = style.fontColorDisabled!
theme.dayColor = style.fontColor!
theme.selectedDayColor = style.fontColorSelected!
theme.selectedDayBackgroundColor = style.backgroundColorSelected!
theme.selectedRangeBackgroundColor = style.backgroundColorHighlighted!
theme.inactiveDayColor = style.fontColorDisabled!
control.theme = theme
}
}

View file

@ -0,0 +1,25 @@
import Foundation
extension DifficultyView {
@objc override func applyTheme() {
if styleName.isEmpty {
setStyle(.difficultyView)
}
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
DifficultyViewRenderer.render(self, style: style)
}
}
}
class DifficultyViewRenderer: UIViewRenderer {
class func render(_ control: DifficultyView, style: Style) {
super.render(control, style: style)
if let colors = style.colors {
control.colors = colors
}
if let emptyColor = style.offTintColor {
control.emptyColor = emptyColor
}
}
}

View file

@ -0,0 +1,17 @@
extension InsetsLabel {
@objc override func applyTheme() {
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
InsetsLabelRenderer.render(self, style: style)
}
}
}
class InsetsLabelRenderer: UILabelRenderer {
class func render(_ control: InsetsLabel, style: Style) {
super.render(control, style: style)
if let insets = style.textContainerInset {
control.insets = insets
}
}
}

View file

@ -0,0 +1,21 @@
extension MWMButton {
@objc override func applyTheme() {
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
MWMButtonRenderer.render(self, style: style)
}
}
}
class MWMButtonRenderer {
class func render(_ control: MWMButton, style: Style) {
UIButtonRenderer.render(control, style: style)
if let coloring = style.coloring {
control.coloring = coloring
}
if let imageName = style.mwmImage {
control.imageName = imageName
}
}
}

View file

@ -0,0 +1,18 @@
import Foundation
extension MWMTableViewCell {
@objc override func applyTheme() {
if styleName.isEmpty {
setStyle(.tableViewCell)
}
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
MWMTableViewCellRenderer.render(self, style: style)
}
}
}
class MWMTableViewCellRenderer: UITableViewCellRenderer {
class func render(_ control: MWMTableViewCell, style: Style) {
super.render(control, style: style)
}
}

View file

@ -0,0 +1,33 @@
extension TabView {
@objc override func applyTheme() {
if styleName.isEmpty {
setStyle(.tabView)
}
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
TabViewRenderer.render(self, style: style)
}
}
}
class TabViewRenderer {
class func render(_ control: TabView, style: Style) {
if let backgroundColor = style.backgroundColor {
control.backgroundColor = backgroundColor
}
if let barTintColor = style.barTintColor {
control.barTintColor = barTintColor
}
if let tintColor = style.tintColor {
control.tintColor = tintColor
}
if let font = style.font, let fontColor = style.fontColorHighlighted {
control.selectedHeaderTextAttributes = [.foregroundColor: fontColor,
.font: font]
}
if let font = style.font, let fontColor = style.fontColor {
control.deselectedHeaderTextAttributes = [.foregroundColor: fontColor,
.font: font]
}
}
}

View file

@ -0,0 +1,16 @@
extension UIActivityIndicatorView {
@objc override func applyTheme() {
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
UIActivityIndicatorRenderer.render(self, style: style)
}
}
}
class UIActivityIndicatorRenderer {
class func render(_ control: UIActivityIndicatorView, style: Style) {
if let color = style.color {
control.color = color
}
}
}

View file

@ -0,0 +1,34 @@
import UIKit
class UIBarButtonItemRenderer {
class func render(_ control: UIBarButtonItem, style: Style) {
var normalAttributes = [NSAttributedString.Key: Any]()
var disableAttributes = [NSAttributedString.Key: Any]()
var highlightedAttributes = [NSAttributedString.Key: Any]()
if let backgroundImage = style.backgroundImage {
control.setBackgroundImage(backgroundImage, for: .normal, barMetrics: .default)
}
if let tintColor = style.tintColor {
control.tintColor = tintColor
}
if let font = style.font {
normalAttributes[NSAttributedString.Key.font] = font
disableAttributes[NSAttributedString.Key.font] = font
highlightedAttributes[NSAttributedString.Key.font] = font
}
if let fontColor = style.fontColor {
normalAttributes[NSAttributedString.Key.foregroundColor] = fontColor
}
if let fontColorDisabled = style.fontColorDisabled {
disableAttributes[NSAttributedString.Key.foregroundColor] = fontColorDisabled
}
if let fontColorHighlighted = style.fontColorHighlighted {
highlightedAttributes[NSAttributedString.Key.foregroundColor] = fontColorHighlighted
}
control.setTitleTextAttributes(normalAttributes, for: .normal)
control.setTitleTextAttributes(disableAttributes, for: .disabled)
control.setTitleTextAttributes(highlightedAttributes, for: .highlighted)
}
}

View file

@ -0,0 +1,55 @@
extension UIButton {
@objc override func applyTheme() {
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
UIButtonRenderer.render(self, style: style)
}
}
}
class UIButtonRenderer {
class func render(_ control: UIButton, style: Style) {
if let titleLabel = control.titleLabel {
if let font = style.font {
titleLabel.font = font
}
}
if let fontColor = style.fontColor {
control.setTitleColor(fontColor, for: .normal)
}
if let backgroundColor = style.backgroundColor {
control.setBackgroundImage(backgroundColor.getImage(), for: .normal)
control.backgroundColor = UIColor.clear
}
if let backgroundColorSelected = style.backgroundColorSelected {
control.setBackgroundImage(backgroundColorSelected.getImage(), for: .selected)
}
if let backgroundColorHighlighted = style.backgroundColorHighlighted {
control.setBackgroundImage(backgroundColorHighlighted.getImage(), for: .highlighted)
}
if let backgroundColorDisabled = style.backgroundColorDisabled {
control.setBackgroundImage(backgroundColorDisabled.getImage(), for: .disabled)
}
if let fontColorSelected = style.fontColorSelected {
control.setTitleColor(fontColorSelected, for: .selected)
}
if let fontColorHighlighted = style.fontColorHighlighted {
control.setTitleColor(fontColorHighlighted, for: .highlighted)
}
if let fontColorDisabled = style.fontColorDisabled {
control.setTitleColor(fontColorDisabled, for: .disabled)
}
if let image = style.image {
control.setImage(UIImage(named: image), for: .normal)
}
if let tintColor = style.tintColor {
control.tintColor = tintColor
}
UIViewRenderer.renderBorder(control, style: style)
UIViewRenderer.renderShadow(control, style: style)
}
}

View file

@ -0,0 +1,23 @@
extension UIImageView {
@objc override func applyTheme() {
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
UIImageViewRenderer.render(self, style: style)
}
}
}
class UIImageViewRenderer: UIViewRenderer {
class func render(_ control: UIImageView, style: Style) {
super.render(control, style: style)
if let image = style.image {
control.image = UIImage(named: image)
}
if let tintColor = style.tintColor {
control.tintColor = tintColor
}
if let imageName = style.mwmImage {
control.mwm_name = imageName
}
}
}

View file

@ -0,0 +1,62 @@
extension UILabel {
var isAttributed: Bool {
guard let attributedText = attributedText else {
return false
}
guard !attributedText.string.isEmpty else {
return false
}
var range = NSRange()
attributedText.attributes(at: 0, effectiveRange: &range)
return attributedText.string.count != range.length
}
@objc override func applyTheme() {
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
UILabelRenderer.render(self, style: style)
}
}
@objc func sw_setAttributedText(text: NSAttributedString) -> CGRect {
var attributedString = text
if styleName.isEmpty == false {
let styles = StyleManager.shared.getStyle(styleName)
for style in styles where style.attributes != nil {
attributedString = UILabelRenderer.transformText(style: style,
text: attributedString)
}
}
return self.sw_setAttributedText(text: attributedString)
}
}
class UILabelRenderer: UIViewRenderer {
class func render(_ control: UILabel, style: Style) {
super.render(control, style: style)
if let font = style.font {
control.font = font
}
if let fontColor = style.fontColor {
control.textColor = fontColor
}
if let textAlignment = style.textAlignment {
control.textAlignment = textAlignment
}
if style.attributes != nil,
control.isAttributed,
let attributedText = control.attributedText {
control.attributedText = attributedText
}
}
class func transformText(style: Style, text: NSAttributedString) -> NSAttributedString {
if let attributes = style.attributes,
attributes.isEmpty == false,
let attributedtext = text.mutableCopy() as? NSMutableAttributedString{
attributedtext.setAttributes(attributes, range: NSRange(location: 0, length: attributedtext.length));
return attributedtext
}
return text
}
}

View file

@ -0,0 +1,39 @@
extension UINavigationBar {
@objc override func applyTheme() {
if styleName.isEmpty {
setStyle(.navigationBar)
}
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
UINavigationBarRenderer.render(self, style: style)
}
}
}
class UINavigationBarRenderer: UIViewRenderer {
class func render(_ control: UINavigationBar, style: Style) {
super.render(control, style: style)
if let barTintColor = style.barTintColor {
let appearance = UINavigationBarAppearance()
appearance.configureWithOpaqueBackground()
appearance.backgroundColor = barTintColor
control.standardAppearance = appearance
control.scrollEdgeAppearance = appearance
}
if let shadowImage = style.shadowImage {
control.standardAppearance.shadowImage = shadowImage
control.scrollEdgeAppearance!.shadowImage = shadowImage
}
var attributes = [NSAttributedString.Key: Any]()
if let font = style.font {
attributes[NSAttributedString.Key.font] = font
}
if let fontColor = style.fontColor {
attributes[NSAttributedString.Key.foregroundColor] = fontColor
}
control.standardAppearance.titleTextAttributes = attributes
control.scrollEdgeAppearance!.titleTextAttributes = attributes
}
}

View file

@ -0,0 +1,24 @@
extension UINavigationItem {
@objc func applyTheme() {
if styleName.isEmpty {
setStyle(.navigationBarItem)
}
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty {
UINavigationItemRenderer.render(self, style: style)
}
}
}
class UINavigationItemRenderer {
class func render(_ control: UINavigationItem, style: Style) {
if let item = control.backBarButtonItem {
UIBarButtonItemRenderer.render(item, style: style)
}
if let item = control.leftBarButtonItem {
UIBarButtonItemRenderer.render(item, style: style)
}
if let item = control.rightBarButtonItem {
UIBarButtonItemRenderer.render(item, style: style)
}
}
}

View file

@ -0,0 +1,25 @@
extension UIPageControl {
@objc override func applyTheme() {
if styleName.isEmpty {
setStyle(.pageControl)
}
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
UIPageControlenderer.render(self, style: style)
}
}
}
class UIPageControlenderer {
class func render(_ control: UIPageControl, style: Style) {
if let backgroundColor = style.backgroundColor {
control.backgroundColor = backgroundColor
}
if let pageIndicatorTintColor = style.pageIndicatorTintColor {
control.pageIndicatorTintColor = pageIndicatorTintColor
}
if let currentPageIndicatorTintColor = style.currentPageIndicatorTintColor {
control.currentPageIndicatorTintColor = currentPageIndicatorTintColor
}
}
}

View file

@ -0,0 +1,84 @@
import Foundation
extension UISearchBar {
@objc override func applyTheme() {
if #available(iOS 26, *) {
return;
}
if styleName.isEmpty {
setStyle(.searchBar)
}
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
UISearchBarRenderer.render(self, style: style)
}
}
@objc override func sw_didMoveToWindow() {
guard MapsAppDelegate.theApp().window === window else {
sw_didMoveToWindow();
return
}
applyTheme()
isStyleApplied = true
sw_didMoveToWindow();
}
}
class UISearchBarRenderer: UIViewRenderer {
class func render(_ control: UISearchBar, style: Style) {
super.render(control, style: style)
if #available(iOS 26, *) {
return;
}
let searchTextField = control.searchTextField
// Default search bar implementation adds the grey transparent image for background. This code removes it and updates the corner radius. This is not working on iPad designed for mac.
if !ProcessInfo.processInfo.isiOSAppOnMac {
control.setSearchFieldBackgroundImage(UIImage(), for: .normal)
}
searchTextField.layer.setCornerRadius(.buttonDefault)
searchTextField.layer.masksToBounds = true
// Placeholder color
if let placeholder = searchTextField.placeholder {
searchTextField.attributedPlaceholder = NSAttributedString(string: placeholder, attributes: [.foregroundColor: UIColor.gray])
}
if let backgroundColor = style.backgroundColor {
searchTextField.backgroundColor = backgroundColor
}
if let font = style.font {
searchTextField.font = font
}
if let fontColor = style.fontColor {
searchTextField.textColor = fontColor
}
if let tintColor = style.tintColor {
searchTextField.leftView?.tintColor = tintColor
// Placeholder indicator color
searchTextField.tintColor = tintColor
// Clear button image
let clearButtonImage = UIImage(named: "ic_clear")?.withRenderingMode(.alwaysTemplate).withTintColor(tintColor)
control.setImage(clearButtonImage, for: .clear, state: .normal)
}
if let barTintColor = style.barTintColor {
let position = control.delegate?.position?(for: control) ?? control.barPosition
control.setBackgroundImage(barTintColor.getImage(), for: position, barMetrics: .defaultPrompt)
control.setBackgroundImage(barTintColor.getImage(), for: position, barMetrics: .default)
control.backgroundColor = barTintColor
}
if let fontColorDetailed = style.fontColorDetailed {
// Cancel button color
control.tintColor = fontColorDetailed
}
}
@available(iOS, deprecated: 13.0)
private static let kiOS12DefaultSystemTextFieldHeight = 36
@available(iOS, deprecated: 13.0)
private static var searchBarBackgroundColor: UIColor?
@available(iOS, deprecated: 13.0)
private static var searchBarBackgroundImage: UIImage?
}

View file

@ -0,0 +1,20 @@
extension UISwitch {
@objc override func applyTheme() {
if styleName.isEmpty {
setStyle(.switch)
}
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
UISwitchRenderer.render(self, style: style)
}
}
}
class UISwitchRenderer: UIViewRenderer {
class func render(_ control: UISwitch, style: Style) {
super.render(control, style: style)
if let onTintColor = style.onTintColor {
control.onTintColor = onTintColor
}
}
}

View file

@ -0,0 +1,46 @@
extension UITableViewCell {
@objc override func applyTheme() {
if styleName.isEmpty {
setStyle(.tableCell)
}
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
UITableViewCellRenderer.render(self, style: style)
}
}
}
class UITableViewCellRenderer {
class func render(_ control: UITableViewCell, style: Style) {
if let label = control.textLabel {
if let font = style.font {
label.font = font
}
if let fontColor = style.fontColor {
label.textColor = fontColor
}
}
if let detailedLabel = control.detailTextLabel {
if let fontDetailed = style.fontDetailed {
detailedLabel.font = fontDetailed
}
if let fontColorDetailed = style.fontColorDetailed {
detailedLabel.textColor = fontColorDetailed
}
}
if let fontColorDetailed = style.fontColorDetailed {
control.imageView?.tintColor = fontColorDetailed
}
if let tintColor = style.tintColor {
control.tintColor = tintColor
control.accessoryView?.tintColor = tintColor
}
if let backgroundColor = style.backgroundColor {
control.backgroundColor = backgroundColor
control.backgroundView = UIImageView(image: backgroundColor.getImage())
}
if let backgroundColorSelected = style.backgroundColorSelected {
control.selectedBackgroundView = UIImageView(image: backgroundColorSelected.getImage())
}
}
}

View file

@ -0,0 +1,22 @@
extension UITableViewHeaderFooterView {
@objc override func applyTheme() {
if styleName.isEmpty {
setStyle(.tableViewHeaderFooterView)
}
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
UITableViewHeaderFooterViewRenderer.render(self, style: style)
}
}
}
class UITableViewHeaderFooterViewRenderer {
class func render(_ control: UITableViewHeaderFooterView, style: Style) {
if let backgroundColor = style.backgroundColor {
control.backgroundView = UIImageView(image: backgroundColor.getImage())
}
if let fontColor = style.fontColor {
control.textLabel?.textColor = fontColor
}
}
}

View file

@ -0,0 +1,25 @@
extension UITableView {
@objc override func applyTheme() {
if styleName.isEmpty, style != .insetGrouped, style != .grouped {
setStyle(.tableView)
}
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
UITableViewRenderer.render(self, style: style)
}
}
}
class UITableViewRenderer: UIViewRenderer {
class func render(_ control: UITableView, style: Style) {
super.render(control, style: style)
if let backgroundColor = style.backgroundColor {
control.backgroundView = UIImageView(image: backgroundColor.getImage())
}
if let separatorColor = style.separatorColor {
control.separatorColor = separatorColor
}
UIViewRenderer.renderBorder(control, style: style)
UIViewRenderer.renderShadow(control, style: style)
}
}

View file

@ -0,0 +1,47 @@
extension UITextField {
@objc override func applyTheme() {
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
UITextFieldRenderer.render(self, style: style)
}
}
@objc override func sw_didMoveToWindow() {
guard MapsAppDelegate.theApp().window === window else {
sw_didMoveToWindow();
return
}
applyTheme()
isStyleApplied = true
sw_didMoveToWindow();
}
}
class UITextFieldRenderer {
class func render(_ control: UITextField, style: Style) {
if let cornerRadius = style.cornerRadius {
control.layer.setCornerRadius(cornerRadius)
control.clipsToBounds = true
}
control.borderStyle = .none
var placeholderAttributes = [NSAttributedString.Key : Any]()
if let backgroundColor = style.backgroundColor {
control.backgroundColor = backgroundColor
}
if let font = style.font {
control.font = font
placeholderAttributes[NSAttributedString.Key.font] = font
}
if let fontColor = style.fontColor {
control.textColor = fontColor
}
if let tintColor = style.tintColor {
control.tintColor = tintColor
placeholderAttributes[NSAttributedString.Key.foregroundColor] = tintColor
}
if let attributedPlaceholder = control.attributedPlaceholder, !attributedPlaceholder.string.isEmpty {
control.attributedPlaceholder = NSAttributedString(string: attributedPlaceholder.string,
attributes: placeholderAttributes)
}
}
}

View file

@ -0,0 +1,28 @@
extension UITextView {
@objc override func applyTheme() {
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
UITextViewRenderer.render(self, style: style)
}
}
}
class UITextViewRenderer {
class func render(_ control: UITextView, style: Style) {
if let backgroundColor = style.backgroundColor {
control.backgroundColor = backgroundColor
}
if let font = style.font {
control.font = font
}
if let fontColor = style.fontColor {
control.textColor = fontColor
}
if let textContainerInset = style.textContainerInset {
control.textContainerInset = textContainerInset
}
if let linkAttributes = style.linkAttributes {
control.linkTextAttributes = linkAttributes
}
}
}

View file

@ -0,0 +1,19 @@
extension UIToolbar {
@objc override func applyTheme() {
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
UIToolbarRenderer.render(self, style: style)
}
}
}
class UIToolbarRenderer {
class func render(_ control: UIToolbar, style: Style) {
if let backgroundColor = style.backgroundColor {
control.setBackgroundImage(backgroundColor.getImage(), forToolbarPosition: .any, barMetrics: .default)
}
if let tintColor = style.tintColor {
control.tintColor = tintColor
}
}
}

View file

@ -0,0 +1,4 @@
extension UIViewController {
@objc func applyTheme() {
}
}

View file

@ -0,0 +1,62 @@
extension UIView {
@objc func applyTheme() {
if type(of: self.superview) == UINavigationBar.self {
return;
}
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
UIViewRenderer.render(self, style: style)
}
}
}
class UIViewRenderer {
class func render(_ control: UIView, style: Style) {
if let backgroundColor = style.backgroundColor {
control.backgroundColor = backgroundColor
}
if let tintColor = style.tintColor {
control.tintColor = tintColor
}
UIViewRenderer.renderShadow(control, style: style)
UIViewRenderer.renderBorder(control, style: style)
}
class func renderShadow(_ control: UIView, style: Style) {
if let shadowColor = style.shadowColor {
control.layer.shadowColor = shadowColor.cgColor
}
if let shadowOffset = style.shadowOffset {
control.layer.shadowOffset = shadowOffset
}
if let shadowOpacity = style.shadowOpacity {
control.layer.shadowOpacity = shadowOpacity
}
if let shadowRadius = style.shadowRadius {
control.layer.shadowRadius = shadowRadius
}
}
class func renderBorder(_ control: UIView, style: Style) {
if let borderColor = style.borderColor {
control.layer.borderColor = borderColor.cgColor
}
if let borderWidth = style.borderWidth {
control.layer.borderWidth = borderWidth
}
if let cornerRadius = style.cornerRadius {
control.layer.cornerRadius = cornerRadius.value
}
if let maskedCorners = style.maskedCorners {
control.layer.maskedCorners = maskedCorners
}
if let clip = style.clip {
control.clipsToBounds = clip
}
if let round = style.round, round == true {
control.layer.cornerRadius = control.size.height / 2
}
control.layer.cornerCurve = .continuous
}
}

View file

@ -0,0 +1,21 @@
extension UIWindow {
@objc override func applyTheme() {
for style in StyleManager.shared.getStyle(styleName)
where !style.isEmpty && !style.hasExclusion(view: self) {
UIWindowRenderer.render(self, style: style)
}
}
@objc func sw_becomeKeyWindow() {
if !isStyleApplied {
self.applyTheme()
}
self.isStyleApplied = true
self.sw_becomeKeyWindow();
}
}
class UIWindowRenderer {
class func render(_ control: UIView, style: Style) {
}
}

View file

@ -0,0 +1,19 @@
extension ValueStepperView {
override func applyTheme() {
if styleName.isEmpty {
setStyle(.valueStepperView)
}
for style in StyleManager.shared.getStyle(styleName) where !style.isEmpty && !style.hasExclusion(view: self) {
ValueStepperViewRenderer.render(self, style: style)
}
}
}
fileprivate final class ValueStepperViewRenderer {
class func render(_ control: ValueStepperView, style: Style) {
control.plusButton.coloring = style.coloring!
control.minusButton.coloring = style.coloring!
control.valueLabel.font = style.font
control.valueLabel.textColor = style.fontColor
}
}

View file

@ -0,0 +1,28 @@
enum SearchStyleSheet: String, CaseIterable {
case searchCancelButton
case searchPopularView = "SearchPopularView"
case searchSideAvailableMarker = "SearchSideAvaliableMarker"
}
extension SearchStyleSheet: IStyleSheet {
func styleResolverFor(colors: IColors, fonts: IFonts) -> Theme.StyleResolver {
switch self {
case .searchPopularView:
return .add { s in
s.cornerRadius = .custom(10)
s.backgroundColor = colors.linkBlueHighlighted
}
case .searchSideAvailableMarker:
return .add { s in
s.backgroundColor = colors.ratingGreen
}
case .searchCancelButton:
return .add { s in
s.fontColor = colors.linkBlue
s.fontColorHighlighted = colors.linkBlueHighlighted
s.font = fonts.regular17
s.backgroundColor = .clear
}
}
}
}

View file

@ -0,0 +1,54 @@
protocol StyleApplicable: AnyObject {
var styleName: String { get set }
var isStyleApplied: Bool { get set }
func setStyleName(_ styleName: String)
func setStyleNameAndApply(_ styleName: String)
func setStyle(_ style: StyleStringRepresentable)
func setStyleAndApply(_ style: StyleStringRepresentable)
func applyTheme()
}
extension StyleApplicable {
func setStyleName(_ styleName: String) {
self.styleName = styleName
}
func setStyleNameAndApply(_ styleName: String) {
self.styleName = styleName
applyTheme()
}
func setStyle(_ style: StyleStringRepresentable) {
styleName = style.rawValue
}
func setStyleAndApply(_ style: StyleStringRepresentable) {
styleName = style.rawValue
applyTheme()
}
}
// Overload for the direct usage of the nested StyleSheet enums
extension StyleApplicable {
func setStyle(_ style: GlobalStyleSheet) { setStyle(style) }
func setStyle(_ style: PlacePageStyleSheet) { setStyle(style) }
func setStyle(_ style: MapStyleSheet) { setStyle(style) }
func setStyle(_ style: BookmarksStyleSheet) { setStyle(style) }
func setStyle(_ style: SearchStyleSheet) { setStyle(style) }
func setStyleAndApply(_ style: GlobalStyleSheet) { setStyleAndApply(style) }
func setStyleAndApply(_ style: PlacePageStyleSheet) { setStyleAndApply(style) }
func setStyleAndApply(_ style: MapStyleSheet) { setStyleAndApply(style) }
func setStyleAndApply(_ style: BookmarksStyleSheet) { setStyleAndApply(style) }
func setStyleAndApply(_ style: SearchStyleSheet) { setStyleAndApply(style) }
func setStyles(_ styles: [GlobalStyleSheet]) { styleName = styles.joinedStyle }
}
private extension Collection where Element: RawRepresentable, Element.RawValue == String {
var joinedStyle: String {
map(\.rawValue).joined(separator: ":")
}
}

View file

@ -0,0 +1,27 @@
protocol StyleStringRepresentable {
var rawValue: String { get }
func styleResolverFor(colors: IColors, fonts: IFonts) -> Theme.StyleResolver
}
extension Theme {
enum StyleResolver {
case add(_ resolver: Theme.Resolver)
case addFrom(_ from: StyleStringRepresentable, _ resolver: Theme.Resolver)
case addFromType(_ forType: ThemeType, _ resolver: Theme.Resolver)
case addFromForType(_ from: StyleStringRepresentable, _ forType: ThemeType, _ resolver: Theme.Resolver)
}
func add(_ style: StyleStringRepresentable, _ resolvingType: StyleResolver) {
switch resolvingType {
case .add(let resolver):
add(styleName: style.rawValue, resolver)
case .addFrom(let from, let resolver):
add(styleName: style.rawValue, from: from.rawValue, resolver)
case .addFromType(let forType, let resolver):
add(styleName: style.rawValue, forType: forType, resolver)
case .addFromForType(let from, let forType, let resolver):
add(styleName: style.rawValue, from: from.rawValue, forType: forType, resolver)
}
}
}

View file

@ -0,0 +1,11 @@
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface SwizzleStyle : NSObject
+ (void)swizzle;
@end
NS_ASSUME_NONNULL_END

View file

@ -0,0 +1,33 @@
#import "SwizzleStyle.h"
#import <UIKit/UIKit.h>
#import "objc/runtime.h"
#import "objc/message.h"
@implementation SwizzleStyle
+ (void)swizzle
{
[SwizzleStyle swizzle:[UISearchBar class] methodName:@"didMoveToWindow"];
[SwizzleStyle swizzle:[UITextField class] methodName:@"didMoveToWindow"];
[SwizzleStyle swizzle:[UIView class] methodName:@"didMoveToWindow"];
}
+ (void)swizzle:(Class)forClass methodName:(NSString*)methodName
{
SEL originalMethod = NSSelectorFromString(methodName);
SEL newMethod = NSSelectorFromString([NSString stringWithFormat:@"%@%@", @"sw_", methodName]);
[SwizzleStyle swizzle:forClass from:originalMethod to:newMethod];
}
+ (void)swizzle:(Class)forClass from:(SEL)original to:(SEL)new
{
Method originalMethod = class_getInstanceMethod(forClass, original);
Method newMethod = class_getInstanceMethod(forClass, new);
if (class_addMethod(forClass, original, method_getImplementation(newMethod), method_getTypeEncoding(newMethod))) {
class_replaceMethod(forClass, new, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, newMethod);
}
}
@end

View file

@ -0,0 +1,32 @@
enum TextColorStyleSheet: String, CaseIterable {
case whitePrimary = "whitePrimaryText"
case blackSecondary = "blackSecondaryText"
case blackPrimary = "blackPrimaryText"
case linkBlue = "linkBlueText"
case linkBlueHighlighted = "linkBlueHighlightedText"
case white = "whiteText"
case blackHint = "blackHintText"
case green = "greenText"
case red = "redText"
case buttonRed = "buttonRedText"
}
extension TextColorStyleSheet: IStyleSheet {
func styleResolverFor(colors: IColors, fonts: IFonts) -> Theme.StyleResolver {
let color: UIColor = {
switch self {
case .whitePrimary: return colors.whitePrimaryText
case .blackSecondary: return colors.blackSecondaryText
case .blackPrimary: return colors.blackPrimaryText
case .linkBlue: return colors.linkBlue
case .linkBlueHighlighted: return colors.linkBlueHighlighted
case .white: return colors.white
case .blackHint: return colors.blackHintText
case .green: return colors.ratingGreen
case .red: return colors.red
case .buttonRed: return colors.buttonRed
}
}()
return .add { $0.fontColor = color }
}
}