1
0
mirror of https://github.com/Toxblh/MTMR.git synced 2026-01-11 17:38:38 +00:00

image as generic parameter

This commit is contained in:
Serg 2018-04-12 22:53:58 +07:00
parent 2ad89bd8c8
commit 79eba1a281
4 changed files with 85 additions and 50 deletions

View File

@ -5,7 +5,7 @@ class AppleScriptTouchBarItem: CustomButtonTouchBarItem {
private let interval: TimeInterval private let interval: TimeInterval
private var forceHideConstraint: NSLayoutConstraint! private var forceHideConstraint: NSLayoutConstraint!
init?(identifier: NSTouchBarItem.Identifier, source: Source, interval: TimeInterval, onTap: @escaping ()->()) { init?(identifier: NSTouchBarItem.Identifier, source: SourceProtocol, interval: TimeInterval, onTap: @escaping ()->()) {
self.interval = interval self.interval = interval
super.init(identifier: identifier, title: "compile", onTap: onTap) super.init(identifier: identifier, title: "compile", onTap: onTap)
self.forceHideConstraint = self.view.widthAnchor.constraint(equalToConstant: 0) self.forceHideConstraint = self.view.widthAnchor.constraint(equalToConstant: 0)
@ -56,7 +56,7 @@ class AppleScriptTouchBarItem: CustomButtonTouchBarItem {
} }
extension Source { extension SourceProtocol {
var appleScript: NSAppleScript? { var appleScript: NSAppleScript? {
guard let source = self.string else { return nil } guard let source = self.string else { return nil }
return NSAppleScript(source: source) return NSAppleScript(source: source)

View File

@ -12,15 +12,10 @@ class CustomButtonTouchBarItem: NSCustomTouchBarItem {
let tapClosure: () -> () let tapClosure: () -> ()
private(set) var button: NSButton! private(set) var button: NSButton!
init(identifier: NSTouchBarItem.Identifier, title: String, onTap callback: @escaping () -> (), image: NSImage? = nil) { init(identifier: NSTouchBarItem.Identifier, title: String, onTap callback: @escaping () -> ()) {
self.tapClosure = callback self.tapClosure = callback
super.init(identifier: identifier) super.init(identifier: identifier)
if let image = image {
button = NSButton(title: title, image: image, target: self, action: #selector(didTapped))
button.bezelColor = .clear
} else {
button = NSButton(title: title, target: self, action: #selector(didTapped)) button = NSButton(title: title, target: self, action: #selector(didTapped))
}
self.view = button self.view = button
} }

View File

@ -29,8 +29,8 @@ struct BarItemDefinition: Decodable {
let parametersDecoder = SupportedTypesHolder.sharedInstance.lookup(by: type) let parametersDecoder = SupportedTypesHolder.sharedInstance.lookup(by: type)
let additionalParameters = try GeneralParameters(from: decoder).parameters let additionalParameters = try GeneralParameters(from: decoder).parameters
if let result = try? parametersDecoder(decoder), if let result = try? parametersDecoder(decoder),
case let (itemType, action) = result { case let (itemType, action, parameters) = result {
self.init(type: itemType, action: action, additionalParameters: additionalParameters) self.init(type: itemType, action: action, additionalParameters: additionalParameters + parameters)
} else { } else {
self.init(type: .staticButton(title: "unknown"), action: .none, additionalParameters: additionalParameters) self.init(type: .staticButton(title: "unknown"), action: .none, additionalParameters: additionalParameters)
} }
@ -39,23 +39,38 @@ struct BarItemDefinition: Decodable {
} }
class SupportedTypesHolder { class SupportedTypesHolder {
typealias ParametersDecoder = (Decoder) throws ->(item: ItemType, action: ActionType) typealias ParametersDecoder = (Decoder) throws ->(item: ItemType, action: ActionType, parameters: [GeneralParameter])
private var supportedTypes: [String: ParametersDecoder] = [ private var supportedTypes: [String: ParametersDecoder] = [
"escape": { _ in return (item: .staticButton(title: "esc"), action: .keyPress(keycode: 53)) }, "escape": { _ in return (item: .staticButton(title: "esc"), action: .keyPress(keycode: 53), parameters: []) },
"brightnessUp": { _ in return (item: .staticButton(title: "🔆"), action: .keyPress(keycode: 113)) }, "brightnessUp": { _ in return (item: .staticButton(title: "🔆"), action: .keyPress(keycode: 113), parameters: []) },
"brightnessDown": { _ in return (item: .staticButton(title: "🔅"), action: .keyPress(keycode: 107)) }, "brightnessDown": { _ in return (item: .staticButton(title: "🔅"), action: .keyPress(keycode: 107), parameters: []) },
"volumeDown": { _ in return (item: .staticImageButton(title: "", image: NSImage(named: .touchBarVolumeDownTemplate)!), action: .hidKey(keycode: NX_KEYTYPE_SOUND_DOWN)) }, "volumeDown": { _ in
"volumeUp": { _ in return (item: .staticImageButton(title: "", image: NSImage(named: .touchBarVolumeUpTemplate)!), action: .hidKey(keycode: NX_KEYTYPE_SOUND_UP)) }, let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarVolumeDownTemplate)!)
"previous": { _ in return (item: .staticImageButton(title: "", image: NSImage(named: .touchBarRewindTemplate)!), action: .hidKey(keycode: NX_KEYTYPE_PREVIOUS)) }, return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_SOUND_DOWN), parameters: [imageParameter])
"play": { _ in return (item: .staticImageButton(title: "", image: NSImage(named: .touchBarPlayPauseTemplate)!), action: .hidKey(keycode: NX_KEYTYPE_PLAY)) }, },
"next": { _ in return (item: .staticImageButton(title: "", image: NSImage(named: .touchBarFastForwardTemplate)!), action: .hidKey(keycode: NX_KEYTYPE_NEXT)) }, "volumeUp": { _ in
let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarVolumeUpTemplate)!)
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_SOUND_UP), parameters: [imageParameter])
},
"previous": { _ in
let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarRewindTemplate)!)
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_PREVIOUS), parameters: [imageParameter])
},
"play": { _ in
let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarPlayPauseTemplate)!)
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_PLAY), parameters: [imageParameter])
},
"next": { _ in
let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarFastForwardTemplate)!)
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_NEXT), parameters: [imageParameter])
},
"weather": { decoder in "weather": { decoder in
enum CodingKeys: String, CodingKey { case refreshInterval } enum CodingKeys: String, CodingKey { case refreshInterval }
let container = try decoder.container(keyedBy: CodingKeys.self) let container = try decoder.container(keyedBy: CodingKeys.self)
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval)
let scriptPath = Bundle.main.path(forResource: "Weather", ofType: "scpt")! let scriptPath = Bundle.main.path(forResource: "Weather", ofType: "scpt")!
let item = ItemType.appleScriptTitledButton(source: Source(filePath: scriptPath), refreshInterval: interval ?? 1800.0) let item = ItemType.appleScriptTitledButton(source: Source(filePath: scriptPath), refreshInterval: interval ?? 1800.0)
return (item: item, action: .none) return (item: item, action: .none, parameters: [])
}, },
"battery": { decoder in "battery": { decoder in
enum CodingKeys: String, CodingKey { case refreshInterval } enum CodingKeys: String, CodingKey { case refreshInterval }
@ -63,17 +78,17 @@ class SupportedTypesHolder {
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval)
let scriptPath = Bundle.main.path(forResource: "Battery", ofType: "scpt")! let scriptPath = Bundle.main.path(forResource: "Battery", ofType: "scpt")!
let item = ItemType.appleScriptTitledButton(source: Source(filePath: scriptPath), refreshInterval: interval ?? 1800.0) let item = ItemType.appleScriptTitledButton(source: Source(filePath: scriptPath), refreshInterval: interval ?? 1800.0)
return (item: item, action: .none) return (item: item, action: .none, parameters: [])
}, },
"sleep": { _ in return (item: .staticButton(title: "☕️"), action: .shellScript(executable: "/usr/bin/pmset", parameters: ["sleepnow"]) ) }, "sleep": { _ in return (item: .staticButton(title: "☕️"), action: .shellScript(executable: "/usr/bin/pmset", parameters: ["sleepnow"]), parameters: []) },
"displaySleep": { _ in return (item: .staticButton(title: "☕️"), action: .shellScript(executable: "/usr/bin/pmset", parameters: ["displaysleepnow"]) ) }, "displaySleep": { _ in return (item: .staticButton(title: "☕️"), action: .shellScript(executable: "/usr/bin/pmset", parameters: ["displaysleepnow"]), parameters: []) },
] ]
static let sharedInstance = SupportedTypesHolder() static let sharedInstance = SupportedTypesHolder()
func lookup(by type: String) -> ParametersDecoder { func lookup(by type: String) -> ParametersDecoder {
return supportedTypes[type] ?? { decoder in return supportedTypes[type] ?? { decoder in
return (item: try ItemType(from: decoder), action: try ActionType(from: decoder)) return (item: try ItemType(from: decoder), action: try ActionType(from: decoder), parameters: [])
} }
} }
@ -83,15 +98,14 @@ class SupportedTypesHolder {
func register(typename: String, item: ItemType, action: ActionType) { func register(typename: String, item: ItemType, action: ActionType) {
register(typename: typename) { _ in register(typename: typename) { _ in
return (item: item, action: action) return (item: item, action: action, parameters: [])
} }
} }
} }
enum ItemType: Decodable { enum ItemType: Decodable {
case staticButton(title: String) case staticButton(title: String)
case staticImageButton(title: String, image: NSImage) case appleScriptTitledButton(source: SourceProtocol, refreshInterval: Double)
case appleScriptTitledButton(source: Source, refreshInterval: Double)
case timeButton(formatTemplate: String) case timeButton(formatTemplate: String)
case flexSpace() case flexSpace()
@ -106,7 +120,6 @@ enum ItemType: Decodable {
enum ItemTypeRaw: String, Decodable { enum ItemTypeRaw: String, Decodable {
case staticButton case staticButton
case staticImageButton
case appleScriptTitledButton case appleScriptTitledButton
case timeButton case timeButton
case flexSpace case flexSpace
@ -120,15 +133,6 @@ enum ItemType: Decodable {
let source = try container.decode(Source.self, forKey: .source) let source = try container.decode(Source.self, forKey: .source)
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0 let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0
self = .appleScriptTitledButton(source: source, refreshInterval: interval) self = .appleScriptTitledButton(source: source, refreshInterval: interval)
case .staticImageButton:
let title = try container.decode(String.self, forKey: .title)
let imageRaw = try container.decode(String.self, forKey: .image)
if let decodedImageData = Data(base64Encoded: imageRaw, options: .ignoreUnknownCharacters) {
let decImage = NSImage(data: decodedImageData)!
self = .staticImageButton(title: title, image: decImage)
} else {
self = .staticButton(title: title)
}
case .staticButton: case .staticButton:
let title = try container.decode(String.self, forKey: .title) let title = try container.decode(String.self, forKey: .title)
self = .staticButton(title: title) self = .staticButton(title: title)
@ -145,7 +149,7 @@ enum ActionType: Decodable {
case none case none
case hidKey(keycode: Int) case hidKey(keycode: Int)
case keyPress(keycode: Int) case keyPress(keycode: Int)
case appleSctipt(source: Source) case appleSctipt(source: SourceProtocol)
case shellScript(executable: String, parameters: [String]) case shellScript(executable: String, parameters: [String])
case custom(closure: ()->()) case custom(closure: ()->())
@ -221,6 +225,7 @@ func ==(lhs: ActionType, rhs: ActionType) -> Bool {
enum GeneralParameter { enum GeneralParameter {
case width(_: CGFloat) case width(_: CGFloat)
case image(source: SourceProtocol)
} }
struct GeneralParameters: Decodable { struct GeneralParameters: Decodable {
@ -228,6 +233,7 @@ struct GeneralParameters: Decodable {
fileprivate enum CodingKeys: String, CodingKey { fileprivate enum CodingKeys: String, CodingKey {
case width case width
case image
} }
init(from decoder: Decoder) throws { init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self) let container = try decoder.container(keyedBy: CodingKeys.self)
@ -235,20 +241,36 @@ struct GeneralParameters: Decodable {
if let value = try container.decodeIfPresent(CGFloat.self, forKey: .width) { if let value = try container.decodeIfPresent(CGFloat.self, forKey: .width) {
result.append(.width(value)) result.append(.width(value))
} }
if let imageSource = try container.decodeIfPresent(Source.self, forKey: .image) {
result.append(.image(source: imageSource))
}
parameters = result parameters = result
} }
} }
protocol SourceProtocol {
struct Source: Decodable { var data: Data? { get }
var string: String? { get }
var image: NSImage? { get }
}
struct Source: Decodable, SourceProtocol {
let filePath: String? let filePath: String?
let base64: String? let base64: String?
let inline: String? let inline: String?
private enum CodingKeys: String, CodingKey {
case filePath
case base64
case inline
}
var data: Data? { var data: Data? {
return base64?.base64Data ?? inline?.data(using: .utf8) ?? filePath?.fileData return base64?.base64Data ?? inline?.data(using: .utf8) ?? filePath?.fileData
} }
var string: String? { var string: String? {
return inline ?? self.data?.base64Content return inline ?? self.data?.utf8string
}
var image: NSImage? {
return data?.image
} }
private init(filePath: String?, base64: String?, inline: String?) { private init(filePath: String?, base64: String?, inline: String?) {
@ -260,8 +282,19 @@ struct Source: Decodable {
self.init(filePath: filePath, base64: nil, inline: nil) self.init(filePath: filePath, base64: nil, inline: nil)
} }
} }
extension Source: Equatable {} extension NSImage: SourceProtocol {
func ==(left: Source, right: Source) -> Bool { var data: Data? {
return nil
}
var string: String? {
return nil
}
var image: NSImage? {
return self
}
}
extension SourceProtocol where Self: Equatable {}
func ==(left: SourceProtocol, right: SourceProtocol) -> Bool {
return left.data == right.data return left.data == right.data
} }
@ -274,7 +307,10 @@ extension String {
} }
} }
extension Data { extension Data {
var base64Content: String? { var utf8string: String? {
return String(data: self, encoding: .utf8) return String(data: self, encoding: .utf8)
} }
var image: NSImage? {
return NSImage(data: self)
}
} }

View File

@ -19,8 +19,6 @@ extension ItemType {
switch self { switch self {
case .staticButton(title: _): case .staticButton(title: _):
return "com.toxblh.mtmr.staticButton." return "com.toxblh.mtmr.staticButton."
case .staticImageButton(title: _):
return "com.toxblh.mtmr.staticImageButton."
case .appleScriptTitledButton(source: _): case .appleScriptTitledButton(source: _):
return "com.toxblh.mtmr.appleScriptButton." return "com.toxblh.mtmr.appleScriptButton."
case .timeButton(formatTemplate: _): case .timeButton(formatTemplate: _):
@ -102,12 +100,11 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
return nil return nil
} }
let action = self.action(forItem: item) let action = self.action(forItem: item)
var barItem: NSTouchBarItem! var barItem: NSTouchBarItem!
switch item.type { switch item.type {
case .staticButton(title: let title): case .staticButton(title: let title):
barItem = CustomButtonTouchBarItem(identifier: identifier, title: title, onTap: action) barItem = CustomButtonTouchBarItem(identifier: identifier, title: title, onTap: action)
case .staticImageButton(title: let title, image: let image):
barItem = CustomButtonTouchBarItem(identifier: identifier, title: title, onTap: action, image: image)
case .appleScriptTitledButton(source: let source, refreshInterval: let interval): case .appleScriptTitledButton(source: let source, refreshInterval: let interval):
barItem = AppleScriptTouchBarItem(identifier: identifier, source: source, interval: interval, onTap: action) barItem = AppleScriptTouchBarItem(identifier: identifier, source: source, interval: interval, onTap: action)
case .timeButton(formatTemplate: let template): case .timeButton(formatTemplate: let template):
@ -119,6 +116,13 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
if case .width(let value) = parameter, let widthBarItem = barItem as? CanSetWidth { if case .width(let value) = parameter, let widthBarItem = barItem as? CanSetWidth {
widthBarItem.setWidth(value: value) widthBarItem.setWidth(value: value)
} }
if case .image(let source) = parameter, let item = barItem as? CustomButtonTouchBarItem {
let button = item.button!
button.image = source.image
button.imagePosition = .imageLeading
button.insets
button.bezelColor = .clear
}
} }
return barItem return barItem
} }