mirror of
https://github.com/element-hq/element-x-ios.git
synced 2025-03-10 21:39:12 +00:00
Correct dark theme support with html rendering.
This commit is contained in:
parent
ab25689e38
commit
af5b75cde0
@ -26,6 +26,7 @@
|
|||||||
18920C1327F2347600A717B5 /* EmoteRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18920C1127F2347600A717B5 /* EmoteRoomTimelineItem.swift */; };
|
18920C1327F2347600A717B5 /* EmoteRoomTimelineItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18920C1127F2347600A717B5 /* EmoteRoomTimelineItem.swift */; };
|
||||||
18920C1627F2E3F400A717B5 /* NoticeRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18920C1427F2E3F400A717B5 /* NoticeRoomTimelineView.swift */; };
|
18920C1627F2E3F400A717B5 /* NoticeRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18920C1427F2E3F400A717B5 /* NoticeRoomTimelineView.swift */; };
|
||||||
18920C1727F2E3F400A717B5 /* EmoteRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18920C1527F2E3F400A717B5 /* EmoteRoomTimelineView.swift */; };
|
18920C1727F2E3F400A717B5 /* EmoteRoomTimelineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18920C1527F2E3F400A717B5 /* EmoteRoomTimelineView.swift */; };
|
||||||
|
18920C1927F3222E00A717B5 /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18920C1827F3222E00A717B5 /* Colors.swift */; };
|
||||||
18ADC7D527E4B20300A8C953 /* PlaceholderAvatarImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18ADC7D427E4B20300A8C953 /* PlaceholderAvatarImage.swift */; };
|
18ADC7D527E4B20300A8C953 /* PlaceholderAvatarImage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18ADC7D427E4B20300A8C953 /* PlaceholderAvatarImage.swift */; };
|
||||||
18ADC7D827E4B63C00A8C953 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 18ADC7D727E4B63C00A8C953 /* MatrixRustSDK */; };
|
18ADC7D827E4B63C00A8C953 /* MatrixRustSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 18ADC7D727E4B63C00A8C953 /* MatrixRustSDK */; };
|
||||||
18ADC7FA27EB02D900A8C953 /* AttributedStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18ADC7F927EB02D900A8C953 /* AttributedStringBuilder.swift */; };
|
18ADC7FA27EB02D900A8C953 /* AttributedStringBuilder.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18ADC7F927EB02D900A8C953 /* AttributedStringBuilder.swift */; };
|
||||||
@ -158,6 +159,7 @@
|
|||||||
18920C1127F2347600A717B5 /* EmoteRoomTimelineItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItem.swift; sourceTree = "<group>"; };
|
18920C1127F2347600A717B5 /* EmoteRoomTimelineItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineItem.swift; sourceTree = "<group>"; };
|
||||||
18920C1427F2E3F400A717B5 /* NoticeRoomTimelineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineView.swift; sourceTree = "<group>"; };
|
18920C1427F2E3F400A717B5 /* NoticeRoomTimelineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NoticeRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||||
18920C1527F2E3F400A717B5 /* EmoteRoomTimelineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineView.swift; sourceTree = "<group>"; };
|
18920C1527F2E3F400A717B5 /* EmoteRoomTimelineView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EmoteRoomTimelineView.swift; sourceTree = "<group>"; };
|
||||||
|
18920C1827F3222E00A717B5 /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
|
||||||
18ADC7D427E4B20300A8C953 /* PlaceholderAvatarImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlaceholderAvatarImage.swift; sourceTree = "<group>"; };
|
18ADC7D427E4B20300A8C953 /* PlaceholderAvatarImage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PlaceholderAvatarImage.swift; sourceTree = "<group>"; };
|
||||||
18ADC7F927EB02D900A8C953 /* AttributedStringBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilder.swift; sourceTree = "<group>"; };
|
18ADC7F927EB02D900A8C953 /* AttributedStringBuilder.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AttributedStringBuilder.swift; sourceTree = "<group>"; };
|
||||||
18ADC80427EB1ED100A8C953 /* UIFont+AttributedStringBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIFont+AttributedStringBuilder.m"; sourceTree = "<group>"; };
|
18ADC80427EB1ED100A8C953 /* UIFont+AttributedStringBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIFont+AttributedStringBuilder.m"; sourceTree = "<group>"; };
|
||||||
@ -509,6 +511,7 @@
|
|||||||
18F2BA7E27D25B4000DD1988 /* Routers */,
|
18F2BA7E27D25B4000DD1988 /* Routers */,
|
||||||
18F2BA9B27D25B4000DD1988 /* SwiftUI */,
|
18F2BA9B27D25B4000DD1988 /* SwiftUI */,
|
||||||
18F2BA9527D25B4000DD1988 /* WeakDictionary */,
|
18F2BA9527D25B4000DD1988 /* WeakDictionary */,
|
||||||
|
18920C1827F3222E00A717B5 /* Colors.swift */,
|
||||||
);
|
);
|
||||||
path = Other;
|
path = Other;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
@ -984,6 +987,7 @@
|
|||||||
18DF7C3127E3608100291672 /* MediaProviderProtocol.swift in Sources */,
|
18DF7C3127E3608100291672 /* MediaProviderProtocol.swift in Sources */,
|
||||||
18F2BB0127D25B4000DD1988 /* HomeScreenViewModel.swift in Sources */,
|
18F2BB0127D25B4000DD1988 /* HomeScreenViewModel.swift in Sources */,
|
||||||
18F2BAF027D25B4000DD1988 /* ActivityDismissal.swift in Sources */,
|
18F2BAF027D25B4000DD1988 /* ActivityDismissal.swift in Sources */,
|
||||||
|
18920C1927F3222E00A717B5 /* Colors.swift in Sources */,
|
||||||
18F2BADD27D25B4000DD1988 /* KeychainController.swift in Sources */,
|
18F2BADD27D25B4000DD1988 /* KeychainController.swift in Sources */,
|
||||||
18920C1227F2347600A717B5 /* NoticeRoomTimelineItem.swift in Sources */,
|
18920C1227F2347600A717B5 /* NoticeRoomTimelineItem.swift in Sources */,
|
||||||
18920C1727F2E3F400A717B5 /* EmoteRoomTimelineView.swift in Sources */,
|
18920C1727F2E3F400A717B5 /* EmoteRoomTimelineView.swift in Sources */,
|
||||||
|
37
ElementX/Sources/Other/Colors.swift
Normal file
37
ElementX/Sources/Other/Colors.swift
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
//
|
||||||
|
// Colors.swift
|
||||||
|
// ElementX
|
||||||
|
//
|
||||||
|
// Created by Stefan Ceriu on 29/03/2022.
|
||||||
|
// Copyright © 2022 Element. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Foundation
|
||||||
|
import UIKit
|
||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
//TODO: Switch this to SwiftGen
|
||||||
|
|
||||||
|
extension Color {
|
||||||
|
static let elementGreen = Color(ColorNames.elementGreen.rawValue)
|
||||||
|
static let codeBlockBackgroundColor = Color(ColorNames.codeBlockBackgroundColor.rawValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
extension UIColor {
|
||||||
|
static let elementGreen = UIColor(named: ColorNames.elementGreen.rawValue)
|
||||||
|
static let codeBlockBackgroundColor = UIColor(named: ColorNames.codeBlockBackgroundColor.rawValue)
|
||||||
|
}
|
||||||
|
|
||||||
|
private enum ColorNames: String {
|
||||||
|
case elementGreen
|
||||||
|
case codeBlockBackgroundColor
|
||||||
|
|
||||||
|
var rawValue: String {
|
||||||
|
switch self {
|
||||||
|
case .elementGreen:
|
||||||
|
return "ElementGreen"
|
||||||
|
case .codeBlockBackgroundColor:
|
||||||
|
return "CodeBlockBackgroundColor"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -12,6 +12,7 @@ import DTCoreText
|
|||||||
struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
||||||
|
|
||||||
private let temporaryBlockquoteMarkingColor = UIColor.magenta
|
private let temporaryBlockquoteMarkingColor = UIColor.magenta
|
||||||
|
private let temporaryCodeBlockMarkingColor = UIColor.cyan
|
||||||
private let linkColor = UIColor.blue
|
private let linkColor = UIColor.blue
|
||||||
|
|
||||||
private let userIdDetector: NSRegularExpression
|
private let userIdDetector: NSRegularExpression
|
||||||
@ -40,22 +41,8 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mutableAttributedString = NSMutableAttributedString(string: string)
|
let mutableAttributedString = NSMutableAttributedString(string: string)
|
||||||
|
addLinks(mutableAttributedString)
|
||||||
addLinkAttributesToAttributedString(mutableAttributedString)
|
removeLinkColors(mutableAttributedString)
|
||||||
|
|
||||||
return try? AttributedString(mutableAttributedString, including: \.elementX)
|
|
||||||
}
|
|
||||||
|
|
||||||
func fromMarkdown(_ string: String?) -> AttributedString? {
|
|
||||||
guard let string = string else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let mutableAttributedString = try? NSMutableAttributedString(markdown: string) else {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
addLinkAttributesToAttributedString(mutableAttributedString)
|
|
||||||
|
|
||||||
return try? AttributedString(mutableAttributedString, including: \.elementX)
|
return try? AttributedString(mutableAttributedString, including: \.elementX)
|
||||||
}
|
}
|
||||||
@ -74,15 +61,13 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let defaultFont = UIFont.preferredFont(forTextStyle: .body)
|
let defaultFont = UIFont.preferredFont(forTextStyle: .body)
|
||||||
let defaultColor = UIColor.black
|
|
||||||
|
|
||||||
let parsingOptions: [String: Any] = [
|
let parsingOptions: [String: Any] = [
|
||||||
DTUseiOS6Attributes: true,
|
DTUseiOS6Attributes: true,
|
||||||
DTDefaultFontFamily: defaultFont.familyName,
|
DTDefaultFontFamily: defaultFont.familyName,
|
||||||
DTDefaultFontName: defaultFont.fontName,
|
DTDefaultFontName: defaultFont.fontName,
|
||||||
DTDefaultFontSize: defaultFont.pointSize,
|
DTDefaultFontSize: defaultFont.pointSize,
|
||||||
DTDefaultTextColor: defaultColor,
|
DTDefaultLinkDecoration: false,
|
||||||
DTDefaultLinkColor: linkColor,
|
|
||||||
DTDefaultStyleSheet: DTCSSStylesheet(styleBlock: self.defaultCSS) as Any
|
DTDefaultStyleSheet: DTCSSStylesheet(styleBlock: self.defaultCSS) as Any
|
||||||
]
|
]
|
||||||
|
|
||||||
@ -99,12 +84,11 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let mutableAttributedString = NSMutableAttributedString(attributedString: attributedString)
|
let mutableAttributedString = NSMutableAttributedString(attributedString: attributedString)
|
||||||
|
addLinks(mutableAttributedString)
|
||||||
removeDTCoreTextArtifactsFromAttributedString(mutableAttributedString)
|
removeLinkColors(mutableAttributedString)
|
||||||
|
removeDTCoreTextArtifacts(mutableAttributedString)
|
||||||
replaceMarkedBlockquotes(mutableAttributedString)
|
replaceMarkedBlockquotes(mutableAttributedString)
|
||||||
|
replaceMarkedCodeBlocks(mutableAttributedString)
|
||||||
addLinkAttributesToAttributedString(mutableAttributedString)
|
|
||||||
|
|
||||||
return try? AttributedString(mutableAttributedString, including: \.elementX)
|
return try? AttributedString(mutableAttributedString, including: \.elementX)
|
||||||
}
|
}
|
||||||
@ -123,13 +107,9 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
|||||||
// MARK: - Private
|
// MARK: - Private
|
||||||
|
|
||||||
private func replaceMarkedBlockquotes(_ attributedString: NSMutableAttributedString) {
|
private func replaceMarkedBlockquotes(_ attributedString: NSMutableAttributedString) {
|
||||||
// Enumerate all sections marked thanks to `cssToMarkBlockquotes`
|
|
||||||
// and apply our own attribute instead.
|
|
||||||
|
|
||||||
// According to blockquotes in the string, DTCoreText can apply 2 policies:
|
// According to blockquotes in the string, DTCoreText can apply 2 policies:
|
||||||
// - define a `DTTextBlocksAttribute` attribute on a <blockquote> block
|
// - define a `DTTextBlocksAttribute` attribute on a <blockquote> block
|
||||||
// - or, just define a `NSBackgroundColorAttributeName` attribute
|
// - or, just define a `NSBackgroundColorAttributeName` attribute
|
||||||
|
|
||||||
attributedString.enumerateAttribute(.DTTextBlocks, in: .init(location: 0, length: attributedString.length), options: []) { value, range, _ in
|
attributedString.enumerateAttribute(.DTTextBlocks, in: .init(location: 0, length: attributedString.length), options: []) { value, range, _ in
|
||||||
guard let value = value as? NSArray,
|
guard let value = value as? NSArray,
|
||||||
let dtTextBlock = value.firstObject as? DTTextBlock,
|
let dtTextBlock = value.firstObject as? DTTextBlock,
|
||||||
@ -151,7 +131,16 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func removeDTCoreTextArtifactsFromAttributedString(_ attributedString: NSMutableAttributedString) {
|
func replaceMarkedCodeBlocks(_ attributedString: NSMutableAttributedString) {
|
||||||
|
attributedString.enumerateAttribute(.backgroundColor, in: .init(location: 0, length: attributedString.length), options: []) { value, range, _ in
|
||||||
|
if let value = value as? UIColor,
|
||||||
|
value == temporaryCodeBlockMarkingColor {
|
||||||
|
attributedString.addAttribute(.backgroundColor, value: UIColor.codeBlockBackgroundColor as Any, range: range)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func removeDTCoreTextArtifacts(_ attributedString: NSMutableAttributedString) {
|
||||||
guard attributedString.length > 0 else {
|
guard attributedString.length > 0 else {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -164,7 +153,7 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func addLinkAttributesToAttributedString(_ attributedString: NSMutableAttributedString) {
|
private func addLinks(_ attributedString: NSMutableAttributedString) {
|
||||||
|
|
||||||
let string = attributedString.string
|
let string = attributedString.string
|
||||||
let range = NSRange(location: 0, length: attributedString.string.count)
|
let range = NSRange(location: 0, length: attributedString.string.count)
|
||||||
@ -186,21 +175,24 @@ struct AttributedStringBuilder: AttributedStringBuilderProtocol {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let link = string[matchRange].addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
|
let link = string[matchRange].addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
|
||||||
attributedString.addAttributes([NSAttributedString.Key.link: link as Any,
|
attributedString.addAttribute(.link, value: link as Any, range: match.range)
|
||||||
NSAttributedString.Key.foregroundColor: linkColor],
|
|
||||||
range: match.range)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var cssToMarkBlockquotes: String {
|
private func removeLinkColors(_ attributedString: NSMutableAttributedString) {
|
||||||
return "blockquote {background: \(temporaryBlockquoteMarkingColor.toHexString()); display: block;}"
|
attributedString.enumerateAttribute(.link, in: .init(location: 0, length: attributedString.length), options: []) { _, range, _ in
|
||||||
|
attributedString.removeAttribute(.foregroundColor, range: range)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private var defaultCSS: String {
|
private var defaultCSS: String {
|
||||||
cssToMarkBlockquotes +
|
|
||||||
"""
|
"""
|
||||||
|
blockquote {
|
||||||
|
background: \(temporaryBlockquoteMarkingColor.toHexString());
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
pre,code {
|
pre,code {
|
||||||
background-color: #F5F7FA;
|
background-color: \(temporaryCodeBlockMarkingColor.toHexString());
|
||||||
display: inline;
|
display: inline;
|
||||||
font-family: monospace;
|
font-family: monospace;
|
||||||
white-space: pre;
|
white-space: pre;
|
||||||
|
@ -16,7 +16,6 @@ struct AttributedStringBuilderComponent: Hashable {
|
|||||||
protocol AttributedStringBuilderProtocol {
|
protocol AttributedStringBuilderProtocol {
|
||||||
func fromPlain(_ string: String?) -> AttributedString?
|
func fromPlain(_ string: String?) -> AttributedString?
|
||||||
func fromHTML(_ htmlString: String?) -> AttributedString?
|
func fromHTML(_ htmlString: String?) -> AttributedString?
|
||||||
func fromMarkdown(_ string: String?) -> AttributedString?
|
|
||||||
|
|
||||||
func blockquoteCoalescedComponentsFrom(_ attributedString: AttributedString?) -> [AttributedStringBuilderComponent]?
|
func blockquoteCoalescedComponentsFrom(_ attributedString: AttributedString?) -> [AttributedStringBuilderComponent]?
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ struct EventBasedTimelineView: View {
|
|||||||
Image(uiImage: avatar)
|
Image(uiImage: avatar)
|
||||||
.resizable()
|
.resizable()
|
||||||
.scaledToFill()
|
.scaledToFill()
|
||||||
.overlay(Circle().stroke(Color(.sRGB, red: 0.05, green: 0.74, blue: 0.55, opacity: 1.0)))
|
.overlay(Circle().stroke(Color.elementGreen))
|
||||||
} else {
|
} else {
|
||||||
PlaceholderAvatarImage(firstCharacter: String(firstLetter))
|
PlaceholderAvatarImage(firstCharacter: String(firstLetter))
|
||||||
}
|
}
|
||||||
|
@ -29,5 +29,6 @@ struct FormattedBodyText: View {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.tint(.elementGreen)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "240",
|
||||||
|
"green" : "240",
|
||||||
|
"red" : "240"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "100",
|
||||||
|
"green" : "100",
|
||||||
|
"red" : "100"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,6 @@
|
|||||||
|
{
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"colors" : [
|
||||||
|
{
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "139",
|
||||||
|
"green" : "189",
|
||||||
|
"red" : "13"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"appearances" : [
|
||||||
|
{
|
||||||
|
"appearance" : "luminosity",
|
||||||
|
"value" : "dark"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"color" : {
|
||||||
|
"color-space" : "srgb",
|
||||||
|
"components" : {
|
||||||
|
"alpha" : "1.000",
|
||||||
|
"blue" : "139",
|
||||||
|
"green" : "198",
|
||||||
|
"red" : "13"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"idiom" : "universal"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user