diff --git a/Odyssey.xcodeproj/project.pbxproj b/Odyssey.xcodeproj/project.pbxproj index 59c1ea5..8707116 100644 --- a/Odyssey.xcodeproj/project.pbxproj +++ b/Odyssey.xcodeproj/project.pbxproj @@ -47,8 +47,6 @@ 53E564222506A8F400C4591F /* ColorPickerSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53E564092506A8F400C4591F /* ColorPickerSlider.swift */; }; 53E564232506A8F400C4591F /* LayoutGuide.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53E5640A2506A8F400C4591F /* LayoutGuide.swift */; }; 53E564242506A8F400C4591F /* LayoutGuide.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53E5640A2506A8F400C4591F /* LayoutGuide.swift */; }; - 53E564252506A8F400C4591F /* UIColor+HBAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 53E5640B2506A8F400C4591F /* UIColor+HBAdditions.m */; }; - 53E564262506A8F400C4591F /* UIColor+HBAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = 53E5640B2506A8F400C4591F /* UIColor+HBAdditions.m */; }; 53E564272506A8F400C4591F /* ColorPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53E5640C2506A8F400C4591F /* ColorPickerViewController.swift */; }; 53E564282506A8F400C4591F /* ColorPickerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53E5640C2506A8F400C4591F /* ColorPickerViewController.swift */; }; 53E564292506A8F400C4591F /* ColorPickerMapSlider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53E5640D2506A8F400C4591F /* ColorPickerMapSlider.swift */; }; @@ -69,6 +67,7 @@ 53E5643B2506F18500C4591F /* ColourViewer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 53E564392506F18500C4591F /* ColourViewer.swift */; }; 933AA7C324E9D34F006182FC /* AppVersionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 933AA7C224E9D34F006182FC /* AppVersionManager.swift */; }; 933AA7C424E9D34F006182FC /* AppVersionManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 933AA7C224E9D34F006182FC /* AppVersionManager.swift */; }; + 9439AFAC259FD77100FA79EF /* UIColorAdditions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9439AFAB259FD77100FA79EF /* UIColorAdditions.swift */; }; F10593C124B1D98C00343F46 /* TableButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F10593C024B1D98C00343F46 /* TableButton.swift */; }; F10593C324B29DAC00343F46 /* AvatarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F10593C224B29DAC00343F46 /* AvatarView.swift */; }; F10593C524B2A49500343F46 /* CreditsButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = F10593C424B2A49500343F46 /* CreditsButton.swift */; }; @@ -264,11 +263,9 @@ 53E564032506A8F400C4591F /* ColorPickerWheelView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorPickerWheelView.swift; sourceTree = ""; }; 53E564042506A8F400C4591F /* ColorPickerSlidersViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorPickerSlidersViewController.swift; sourceTree = ""; }; 53E564052506A8F400C4591F /* ColorPickerSeparatorView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorPickerSeparatorView.swift; sourceTree = ""; }; - 53E564062506A8F400C4591F /* UIColor+HBAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIColor+HBAdditions.h"; sourceTree = ""; }; 53E564072506A8F400C4591F /* ColorPickerSwatchViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorPickerSwatchViewController.swift; sourceTree = ""; }; 53E564092506A8F400C4591F /* ColorPickerSlider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorPickerSlider.swift; sourceTree = ""; }; 53E5640A2506A8F400C4591F /* LayoutGuide.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LayoutGuide.swift; sourceTree = ""; }; - 53E5640B2506A8F400C4591F /* UIColor+HBAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIColor+HBAdditions.m"; sourceTree = ""; }; 53E5640C2506A8F400C4591F /* ColorPickerViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorPickerViewController.swift; sourceTree = ""; }; 53E5640D2506A8F400C4591F /* ColorPickerMapSlider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorPickerMapSlider.swift; sourceTree = ""; }; 53E5640E2506A8F400C4591F /* ColorPickerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ColorPickerDelegate.swift; sourceTree = ""; }; @@ -279,6 +276,7 @@ 53E564132506A8F400C4591F /* Color.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Color.swift; sourceTree = ""; }; 53E564392506F18500C4591F /* ColourViewer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ColourViewer.swift; sourceTree = ""; }; 933AA7C224E9D34F006182FC /* AppVersionManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppVersionManager.swift; sourceTree = ""; }; + 9439AFAB259FD77100FA79EF /* UIColorAdditions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIColorAdditions.swift; sourceTree = ""; }; F10593C024B1D98C00343F46 /* TableButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TableButton.swift; sourceTree = ""; }; F10593C224B29DAC00343F46 /* AvatarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AvatarView.swift; sourceTree = ""; }; F10593C424B2A49500343F46 /* CreditsButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreditsButton.swift; sourceTree = ""; }; @@ -411,11 +409,10 @@ 53E564032506A8F400C4591F /* ColorPickerWheelView.swift */, 53E564042506A8F400C4591F /* ColorPickerSlidersViewController.swift */, 53E564052506A8F400C4591F /* ColorPickerSeparatorView.swift */, - 53E564062506A8F400C4591F /* UIColor+HBAdditions.h */, 53E564072506A8F400C4591F /* ColorPickerSwatchViewController.swift */, 53E564092506A8F400C4591F /* ColorPickerSlider.swift */, 53E5640A2506A8F400C4591F /* LayoutGuide.swift */, - 53E5640B2506A8F400C4591F /* UIColor+HBAdditions.m */, + 9439AFAB259FD77100FA79EF /* UIColorAdditions.swift */, 53E5640C2506A8F400C4591F /* ColorPickerViewController.swift */, 53E5640D2506A8F400C4591F /* ColorPickerMapSlider.swift */, 53E5640E2506A8F400C4591F /* ColorPickerDelegate.swift */, @@ -852,7 +849,6 @@ F1C8FE9124F9DE04008A551E /* exploit_utilities.c in Sources */, 360512E024B10E5700DFD3AF /* UICircularRing.swift in Sources */, F1A2B43624B430760087D978 /* PanelView.swift in Sources */, - 53E564252506A8F400C4591F /* UIColor+HBAdditions.m in Sources */, F191A9BD2432A948005E0F8F /* amfidtakeover.swift in Sources */, 5310399125041BB400CADF5C /* ThemeImagePicker.swift in Sources */, 360512E224B10E5700DFD3AF /* UICircularRingStyle.swift in Sources */, @@ -875,6 +871,7 @@ F10593C324B29DAC00343F46 /* AvatarView.swift in Sources */, 36C0994824A456390043250A /* SeparatorView.swift in Sources */, 360512E624B10E5700DFD3AF /* UICircularProgressRing.swift in Sources */, + 9439AFAC259FD77100FA79EF /* UIColorAdditions.swift in Sources */, F14A7A9024A6FB3500215A6F /* kmem.c in Sources */, 531039962504F59800CADF5C /* AlderisButton.swift in Sources */, F125E0532469E59F0023161C /* patchfinder64.c in Sources */, @@ -935,7 +932,6 @@ F170602724CD53CD001596A0 /* PanelStackView.swift in Sources */, F170602824CD53CD001596A0 /* PanelButton.swift in Sources */, F170605724CD54D5001596A0 /* electra-dummy.swift in Sources */, - 53E564262506A8F400C4591F /* UIColor+HBAdditions.m in Sources */, F170602924CD53CD001596A0 /* TableButton.swift in Sources */, F170602A24CD53CD001596A0 /* CreditsButton.swift in Sources */, 53E564182506A8F400C4591F /* ColorPickerWheelView.swift in Sources */, diff --git a/Odyssey/Alderis/Alderis.h b/Odyssey/Alderis/Alderis.h index e0afaec..a82f217 100644 --- a/Odyssey/Alderis/Alderis.h +++ b/Odyssey/Alderis/Alderis.h @@ -8,8 +8,6 @@ @import UIKit; -#import "UIColor+HBAdditions.h" - @interface UIView () @property (setter=_setContinuousCornerRadius:, nonatomic) double _continuousCornerRadius; diff --git a/Odyssey/Alderis/ColorPickerSlidersViewController.swift b/Odyssey/Alderis/ColorPickerSlidersViewController.swift index 81101ad..0add98a 100644 --- a/Odyssey/Alderis/ColorPickerSlidersViewController.swift +++ b/Odyssey/Alderis/ColorPickerSlidersViewController.swift @@ -219,7 +219,7 @@ extension ColorPickerSlidersViewController: UITextFieldDelegate { return true } - guard let uiColor = UIColor(hbcp_propertyListValue: "#\(canonicalizedString)") else { + guard let uiColor = UIColor(propertyListValue: "#\(canonicalizedString)") else { return true } diff --git a/Odyssey/Alderis/UIColor+HBAdditions.h b/Odyssey/Alderis/UIColor+HBAdditions.h deleted file mode 100644 index 8fa4424..0000000 --- a/Odyssey/Alderis/UIColor+HBAdditions.h +++ /dev/null @@ -1,28 +0,0 @@ -#import -#import - -NS_ASSUME_NONNULL_BEGIN - -/// UIColor (HBAdditions) is a class category in `Cephei` that provides some convenience methods. -@interface UIColor (HBColorPickerAdditions) - -/// Initializes and returns a color object using data from the specified object. -/// -/// The value is expected to be one of: -/// -/// * An array of 3 or 4 integer RGB or RGBA color components, with values between 0 and 255 (e.g. -/// `@[ 218, 192, 222 ]`) -/// * A CSS-style hex string, with an optional alpha component (e.g. `#DAC0DE` or `#DACODE55`) -/// * A short CSS-style hex string, with an optional alpha component (e.g. `#DC0` or `#DC05`) -/// -/// @param value The object to retrieve data from. See the discussion for the supported object -/// types. -/// @returns An initialized color object. The color information represented by this object is in the -/// device RGB colorspace. -- (nullable instancetype)initWithHbcp_propertyListValue:(id)value; - -- (NSString *)hbcp_propertyListValue; - -@end - -NS_ASSUME_NONNULL_END diff --git a/Odyssey/Alderis/UIColor+HBAdditions.m b/Odyssey/Alderis/UIColor+HBAdditions.m deleted file mode 100644 index 50efa94..0000000 --- a/Odyssey/Alderis/UIColor+HBAdditions.m +++ /dev/null @@ -1,70 +0,0 @@ -#import "UIColor+HBAdditions.h" - -@implementation UIColor (HBColorPickerAdditions) - -- (instancetype)initWithHbcp_propertyListValue:(id)value { - if (!value) { - return nil; - } else if ([value isKindOfClass:NSArray.class] && (((NSArray *)value).count == 3 || ((NSArray *)value).count == 4)) { - NSArray *array = value; - return [self initWithRed:((NSNumber *)array[0]).integerValue / 255.f - green:((NSNumber *)array[1]).integerValue / 255.f - blue:((NSNumber *)array[2]).integerValue / 255.f - alpha:array.count == 4 ? ((NSNumber *)array[3]).doubleValue : 1]; - } else if ([value isKindOfClass:NSString.class]) { - NSString *string = value; - NSUInteger colonLocation = [string rangeOfString:@":"].location; - NSString *alphaString = nil; - if (colonLocation != NSNotFound) { - alphaString = [string substringFromIndex:colonLocation + 1]; - string = [string substringToIndex:colonLocation]; - } - - if (string.length == 4 || string.length == 5) { - NSString *r = [string substringWithRange:NSMakeRange(1, 1)]; - NSString *g = [string substringWithRange:NSMakeRange(2, 1)]; - NSString *b = [string substringWithRange:NSMakeRange(3, 1)]; - NSString *a = string.length == 5 ? [string substringWithRange:NSMakeRange(4, 1)] : @"F"; - string = [NSString stringWithFormat:@"#%1$@%1$@%2$@%2$@%3$@%3$@%4$@%4$@", r, g, b, a]; - } - - unsigned int hex = 0; - NSScanner *scanner = [NSScanner scannerWithString:string]; - scanner.charactersToBeSkipped = [NSCharacterSet characterSetWithCharactersInString:@"#"]; - [scanner scanHexInt:&hex]; - - if (string.length == 9) { - return [self initWithRed:((hex & 0xFF000000) >> 24) / 255.f - green:((hex & 0x00FF0000) >> 16) / 255.f - blue:((hex & 0x0000FF00) >> 8) / 255.f - alpha:((hex & 0x000000FF) >> 0) / 255.f]; - } else { - CGFloat alpha = 1; - if (alphaString.length > 0) { - NSScanner *alphaScanner = [NSScanner scannerWithString:alphaString]; - if (![alphaScanner scanDouble:&alpha]) { - alpha = 1; - } - } - return [self initWithRed:((hex & 0xFF0000) >> 16) / 255.f - green:((hex & 0x00FF00) >> 8) / 255.f - blue:((hex & 0x0000FF) >> 0) / 255.f - alpha:alpha]; - } - } - - return nil; -} - -- (NSString *)hbcp_propertyListValue { - CGFloat r, g, b, a; - [self getRed:&r green:&g blue:&b alpha:&a]; - unsigned int hex = - (((unsigned int)(r * 255.0) & 0xFF) << 16) + - (((unsigned int)(g * 255.0) & 0xFF) << 8) + - ((unsigned int)(b * 255.0) & 0xFF); - NSString *alphaString = a == 1 ? @"" : [NSString stringWithFormat:@":%.5G", a]; - return [NSString stringWithFormat:@"#%06X%@", hex, alphaString]; -} - -@end diff --git a/Odyssey/Alderis/UIColorAdditions.swift b/Odyssey/Alderis/UIColorAdditions.swift new file mode 100644 index 0000000..edf1201 --- /dev/null +++ b/Odyssey/Alderis/UIColorAdditions.swift @@ -0,0 +1,135 @@ +// +// UIColorAdditions.swift +// Alderis +// +// Created by Ryan Nair on 10/5/20. +// Copyright © 2020 HASHBANG Productions. All rights reserved. +// + +import UIKit + +/// ColorPropertyListValue is a protocol representing types that can be passed to the\ +/// `UIColor.init(propertyListValue:)` initialiser. `String` and `Array` both conform to this type. +/// +/// - see: `UIColor.init(propertyListValue:)` +public protocol ColorPropertyListValue {} + +/// A string can represent a `ColorPropertyListValue`. +/// +/// - see: `UIColor.init(propertyListValue:)` +extension String: ColorPropertyListValue {} + +/// An array of integers can represent a `ColorPropertyListValue`. +/// +/// - see: `UIColor.init(propertyListValue:)` +extension Array: ColorPropertyListValue where Element: FixedWidthInteger {} + +/// Alderis provides extensions to `UIColor` for the purpose of serializing and deserializing colors +/// into representations that can be stored in property lists, JSON, and similar formats. +public extension UIColor { + + /// Initializes and returns a color object using data from the specified object. + /// + /// The value is expected to be one of: + /// + /// * An array of 3 or 4 integer RGB or RGBA color components, with values between 0 and 255 (e.g. + /// `[ 218, 192, 222 ]`) + /// * A CSS-style hex string, with an optional alpha component (e.g. `#DAC0DE` or `#DACODE55`) + /// * A short CSS-style hex string, with an optional alpha component (e.g. `#DC0` or `#DC05`) + /// + /// Use `-[UIColor initWithHbcp_propertyListValue:]` to access this method from Objective-C. + /// + /// - parameter value: The object to retrieve data from. See the discussion for the supported object + /// types. + /// - returns: An initialized color object, or nil if the value does not conform to the expected + /// type. The color information represented by this object is in the device RGB colorspace. + /// - see: `propertyListValue` + @nonobjc convenience init?(propertyListValue: ColorPropertyListValue?) { + if let array = propertyListValue as? [Int], array.count == 3 || array.count == 4 { + let floats = array.map { CGFloat($0) } + self.init(red: floats[0] / 255, + green: floats[1] / 255, + blue: floats[2] / 255, + alpha: array.count == 4 ? floats[3] : 1) + return + } else if var string = propertyListValue as? String { + if let range = string.range(of: ":") { + let location = string.distance(from: string.startIndex, to: range.lowerBound) + string = String(string[..> 24) / 255, + green: CGFloat((hex & 0x00FF0000) >> 16) / 255, + blue: CGFloat((hex & 0x0000FF00) >> 8) / 255, + alpha: CGFloat((hex & 0x000000FF) >> 0) / 255) + return + } else { + self.init(red: CGFloat((hex & 0xFF0000) >> 16) / 255, + green: CGFloat((hex & 0x00FF00) >> 8) / 255, + blue: CGFloat((hex & 0x0000FF) >> 0) / 255, + alpha: 1) + return + } + } + + return nil + } + + /// Maps `init(propertyListValue:)` to Objective-C due to Swift limitations. This is an + /// implementation detail. Ignore this and use `UIColor(propertyListValue:)` or + /// `-[UIColor initWithHbcp_propertyListValue:]` as per usual. + /// + /// - parameter value: The object to retrieve data from. See the discussion for the supported + /// object types. + /// - returns: An initialized color object, or nil if the value does not conform to the expected + /// type. The color information represented by this object is in the device RGB colorspace. + /// device RGB colorspace. + /// - see: `init(propertyListValue:)` + @objc(initWithHbcp_propertyListValue:) + convenience init?(_propertyListValueObjC propertyListValue: Any?) { + if let value = propertyListValue as? String { + self.init(propertyListValue: value) + } else if let value = propertyListValue as? [Int] { + self.init(propertyListValue: value) + } else { + return nil + } + } + + /// Returns a string that represents the color. + /// + /// The output is a string in the format `#AABBCC:0.5`, where the initial `#AABBCC` portion is a + /// 6-character CSS-style hex string, and the final `:0.5` portion represents the alpha value. If + /// the color’s alpha value is `1`, the alpha portion is excluded. + /// + /// If the color is dynamic, for instance if it is a UIKit system color, or initialised via + /// `UIColor(dynamicProvider:)`, the color that matches the current trait collection is used. + /// + /// - returns: A string representing the color, in the format discussed above. + /// - see: `init(propertyListValue:)` + @objc(hbcp_propertyListValue) + var propertyListValue: String { + var alpha: CGFloat = 0 + getRed(nil, green: nil, blue: nil, alpha: &alpha) + + let color = Color(uiColor: self.withAlphaComponent(1)) + let hexString = color.hexString() + let alphaString = alpha == 1 ? "" : String(format: ":%.5G", alpha) + return "\(hexString)\(alphaString)" + } + +}