1
0
mirror of https://github.com/Toxblh/MTMR.git synced 2026-01-10 00:58:37 +00:00

longActions

This commit is contained in:
Toxblh 2018-06-29 15:08:09 +01:00
parent e95c707009
commit 1f764d539a
3 changed files with 142 additions and 62 deletions

View File

@ -3,7 +3,7 @@ import AppKit
extension Data { extension Data {
func barItemDefinitions() -> [BarItemDefinition]? { func barItemDefinitions() -> [BarItemDefinition]? {
return try? JSONDecoder().decode([BarItemDefinition].self, from: self.utf8string!.stripComments().data(using: .utf8)!) return try? JSONDecoder().decode([BarItemDefinition].self, from: self.utf8string!.stripComments().data(using: .utf8)!)
} }
} }
@ -12,23 +12,24 @@ struct BarItemDefinition: Decodable {
let action: ActionType let action: ActionType
let longAction: LongActionType let longAction: LongActionType
let additionalParameters: [GeneralParameters.CodingKeys: GeneralParameter] let additionalParameters: [GeneralParameters.CodingKeys: GeneralParameter]
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case type case type
} }
init(type: ItemType, action: ActionType, longAction: LongActionType, additionalParameters: [GeneralParameters.CodingKeys:GeneralParameter]) { init(type: ItemType, action: ActionType, longAction: LongActionType, additionalParameters: [GeneralParameters.CodingKeys:GeneralParameter]) {
self.type = type self.type = type
self.action = action self.action = action
self.longAction = longAction self.longAction = longAction
self.additionalParameters = additionalParameters self.additionalParameters = additionalParameters
} }
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)
let type = try container.decode(String.self, forKey: .type) let type = try container.decode(String.self, forKey: .type)
let parametersDecoder = SupportedTypesHolder.sharedInstance.lookup(by: type) let parametersDecoder = SupportedTypesHolder.sharedInstance.lookup(by: type)
var additionalParameters = try GeneralParameters(from: decoder).parameters var additionalParameters = try GeneralParameters(from: decoder).parameters
if let result = try? parametersDecoder(decoder), if let result = try? parametersDecoder(decoder),
case let (itemType, action, longAction, parameters) = result { case let (itemType, action, longAction, parameters) = result {
parameters.forEach { additionalParameters[$0] = $1 } parameters.forEach { additionalParameters[$0] = $1 }
@ -37,46 +38,56 @@ struct BarItemDefinition: Decodable {
self.init(type: .staticButton(title: "unknown"), action: .none, longAction: .none, additionalParameters: additionalParameters) self.init(type: .staticButton(title: "unknown"), action: .none, longAction: .none, additionalParameters: additionalParameters)
} }
} }
} }
class SupportedTypesHolder { class SupportedTypesHolder {
typealias ParametersDecoder = (Decoder) throws ->(item: ItemType, action: ActionType, longAction: LongActionType, parameters: [GeneralParameters.CodingKeys: GeneralParameter]) typealias ParametersDecoder = (Decoder) throws ->(item: ItemType, action: ActionType, longAction: LongActionType, parameters: [GeneralParameters.CodingKeys: GeneralParameter])
private var supportedTypes: [String: ParametersDecoder] = [ private var supportedTypes: [String: ParametersDecoder] = [
"escape": { _ in return (item: .staticButton(title: "esc"), action: .keyPress(keycode: 53), longAction: .none, parameters: [.align: .align(.left)]) }, "escape": { _ in return (item: .staticButton(title: "esc"), action: .keyPress(keycode: 53), longAction: .none, parameters: [.align: .align(.left)]) },
"delete": { _ in return (item: .staticButton(title: "del"), action: .keyPress(keycode: 117), longAction: .none, parameters: [:])}, "delete": { _ in return (item: .staticButton(title: "del"), action: .keyPress(keycode: 117), longAction: .none, parameters: [:])},
"brightnessUp": { _ in "brightnessUp": { _ in
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "brightnessUp")) let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "brightnessUp"))
return (item: .staticButton(title: ""), action: .keyPress(keycode: 144), longAction: .none, parameters: [.image: imageParameter]) return (item: .staticButton(title: ""), action: .keyPress(keycode: 144), longAction: .none, parameters: [.image: imageParameter])
}, },
"brightnessDown": { _ in "brightnessDown": { _ in
let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "brightnessDown")) let imageParameter = GeneralParameter.image(source: #imageLiteral(resourceName: "brightnessDown"))
return (item: .staticButton(title: ""), action: .keyPress(keycode: 145), longAction: .none, parameters: [.image: imageParameter]) return (item: .staticButton(title: ""), action: .keyPress(keycode: 145), longAction: .none, parameters: [.image: imageParameter])
}, },
"volumeDown": { _ in "volumeDown": { _ in
let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarVolumeDownTemplate)!) let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarVolumeDownTemplate)!)
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_SOUND_DOWN), longAction: .none, parameters: [.image: imageParameter]) return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_SOUND_DOWN), longAction: .none, parameters: [.image: imageParameter])
}, },
"volumeUp": { _ in "volumeUp": { _ in
let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarVolumeUpTemplate)!) let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarVolumeUpTemplate)!)
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_SOUND_UP), longAction: .none, parameters: [.image: imageParameter]) return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_SOUND_UP), longAction: .none, parameters: [.image: imageParameter])
}, },
"mute": { _ in "mute": { _ in
let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarAudioOutputMuteTemplate)!) let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarAudioOutputMuteTemplate)!)
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_MUTE), longAction: .none, parameters: [.image: imageParameter]) return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_MUTE), longAction: .none, parameters: [.image: imageParameter])
}, },
"previous": { _ in "previous": { _ in
let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarRewindTemplate)!) let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarRewindTemplate)!)
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_PREVIOUS), longAction: .none, parameters: [.image: imageParameter]) return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_PREVIOUS), longAction: .none, parameters: [.image: imageParameter])
}, },
"play": { _ in "play": { _ in
let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarPlayPauseTemplate)!) let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarPlayPauseTemplate)!)
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_PLAY), longAction: .none, parameters: [.image: imageParameter]) return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_PLAY), longAction: .none, parameters: [.image: imageParameter])
}, },
"next": { _ in "next": { _ in
let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarFastForwardTemplate)!) let imageParameter = GeneralParameter.image(source: NSImage(named: .touchBarFastForwardTemplate)!)
return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_NEXT), longAction: .none, parameters: [.image: imageParameter]) return (item: .staticButton(title: ""), action: .hidKey(keycode: NX_KEYTYPE_NEXT), longAction: .none, parameters: [.image: imageParameter])
}, },
"weather": { decoder in "weather": { decoder in
enum CodingKeys: String, CodingKey { case refreshInterval; case units; case api_key ; case icon_type } enum CodingKeys: String, CodingKey { case refreshInterval; case units; case api_key ; case icon_type }
let container = try decoder.container(keyedBy: CodingKeys.self) let container = try decoder.container(keyedBy: CodingKeys.self)
@ -88,6 +99,7 @@ class SupportedTypesHolder {
let longAction = try LongActionType(from: decoder) let longAction = try LongActionType(from: decoder)
return (item: .weather(interval: interval ?? 1800.00, units: units ?? "metric", api_key: api_key ?? "32c4256d09a4c52b38aecddba7a078f6", icon_type: icon_type ?? "text"), action: action, longAction: longAction, parameters: [:]) return (item: .weather(interval: interval ?? 1800.00, units: units ?? "metric", api_key: api_key ?? "32c4256d09a4c52b38aecddba7a078f6", icon_type: icon_type ?? "text"), action: action, longAction: longAction, parameters: [:])
}, },
"currency": { decoder in "currency": { decoder in
enum CodingKeys: String, CodingKey { case refreshInterval; case from; case to } enum CodingKeys: String, CodingKey { case refreshInterval; case from; case to }
let container = try decoder.container(keyedBy: CodingKeys.self) let container = try decoder.container(keyedBy: CodingKeys.self)
@ -98,12 +110,15 @@ class SupportedTypesHolder {
let longAction = try LongActionType(from: decoder) let longAction = try LongActionType(from: decoder)
return (item: .currency(interval: interval ?? 600.00, from: from ?? "RUB", to: to ?? "USD"), action: action, longAction: longAction, parameters: [:]) return (item: .currency(interval: interval ?? 600.00, from: from ?? "RUB", to: to ?? "USD"), action: action, longAction: longAction, parameters: [:])
}, },
"dock": { decoder in "dock": { decoder in
return (item: .dock(), action: .none, longAction: .none, parameters: [:]) return (item: .dock(), action: .none, longAction: .none, parameters: [:])
}, },
"inputsource": { decoder in "inputsource": { decoder in
return (item: .inputsource(), action: .none, longAction: .none, parameters: [:]) return (item: .inputsource(), action: .none, longAction: .none, parameters: [:])
}, },
"volume": { decoder in "volume": { decoder in
enum CodingKeys: String, CodingKey { case image } enum CodingKeys: String, CodingKey { case image }
let container = try decoder.container(keyedBy: CodingKeys.self) let container = try decoder.container(keyedBy: CodingKeys.self)
@ -113,6 +128,7 @@ class SupportedTypesHolder {
return (item: .volume(), action: .none, longAction: .none, parameters: [:]) return (item: .volume(), action: .none, longAction: .none, parameters: [:])
} }
}, },
"brightness": { decoder in "brightness": { decoder in
enum CodingKeys: String, CodingKey { case refreshInterval; case image } enum CodingKeys: String, CodingKey { case refreshInterval; case image }
let container = try decoder.container(keyedBy: CodingKeys.self) let container = try decoder.container(keyedBy: CodingKeys.self)
@ -123,8 +139,11 @@ class SupportedTypesHolder {
return (item: .brightness(refreshInterval: interval ?? 0.5), action: .none, longAction: .none, parameters: [:]) return (item: .brightness(refreshInterval: interval ?? 0.5), action: .none, longAction: .none, parameters: [:])
} }
}, },
"sleep": { _ in return (item: .staticButton(title: "☕️"), action: .shellScript(executable: "/usr/bin/pmset", parameters: ["sleepnow"]), longAction: .none, parameters: [:]) }, "sleep": { _ in return (item: .staticButton(title: "☕️"), action: .shellScript(executable: "/usr/bin/pmset", parameters: ["sleepnow"]), longAction: .none, parameters: [:]) },
"displaySleep": { _ in return (item: .staticButton(title: "☕️"), action: .shellScript(executable: "/usr/bin/pmset", parameters: ["displaysleepnow"]), longAction: .none, parameters: [:])}, "displaySleep": { _ in return (item: .staticButton(title: "☕️"), action: .shellScript(executable: "/usr/bin/pmset", parameters: ["displaysleepnow"]), longAction: .none, parameters: [:])},
"music": { decoder in "music": { 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)
@ -136,6 +155,7 @@ class SupportedTypesHolder {
parameters: [:] parameters: [:]
) )
}, },
"group": { decoder in "group": { decoder in
enum CodingKeys: CodingKey { case items } enum CodingKeys: CodingKey { case items }
let container = try decoder.container(keyedBy: CodingKeys.self) let container = try decoder.container(keyedBy: CodingKeys.self)
@ -147,20 +167,20 @@ class SupportedTypesHolder {
parameters: [:] 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), longAction: try LongActionType(from: decoder), parameters: [:]) return (item: try ItemType(from: decoder), action: try ActionType(from: decoder), longAction: try LongActionType(from: decoder), parameters: [:])
} }
} }
func register(typename: String, decoder: @escaping ParametersDecoder) { func register(typename: String, decoder: @escaping ParametersDecoder) {
supportedTypes[typename] = decoder supportedTypes[typename] = decoder
} }
func register(typename: String, item: ItemType, action: ActionType, longAction: LongActionType) { func register(typename: String, item: ItemType, action: ActionType, longAction: LongActionType) {
register(typename: typename) { _ in register(typename: typename) { _ in
return (item: item, action: action, longAction: longAction, parameters: [:]) return (item: item, action: action, longAction: longAction, parameters: [:])
@ -181,7 +201,7 @@ enum ItemType: Decodable {
case inputsource() case inputsource()
case music(interval: Double) case music(interval: Double)
case groupBar(items: [BarItemDefinition]) case groupBar(items: [BarItemDefinition])
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case type case type
case title case title
@ -198,7 +218,7 @@ enum ItemType: Decodable {
case longUrl case longUrl
case items case items
} }
enum ItemTypeRaw: String, Decodable { enum ItemTypeRaw: String, Decodable {
case staticButton case staticButton
case appleScriptTitledButton case appleScriptTitledButton
@ -213,46 +233,58 @@ enum ItemType: Decodable {
case music case music
case groupBar case groupBar
} }
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)
let type = try container.decode(ItemTypeRaw.self, forKey: .type) let type = try container.decode(ItemTypeRaw.self, forKey: .type)
switch type { switch type {
case .appleScriptTitledButton: case .appleScriptTitledButton:
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 .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)
case .timeButton: case .timeButton:
let template = try container.decodeIfPresent(String.self, forKey: .formatTemplate) ?? "HH:mm" let template = try container.decodeIfPresent(String.self, forKey: .formatTemplate) ?? "HH:mm"
self = .timeButton(formatTemplate: template) self = .timeButton(formatTemplate: template)
case .battery: case .battery:
self = .battery() self = .battery()
case .dock: case .dock:
self = .dock() self = .dock()
case .volume: case .volume:
self = .volume() self = .volume()
case .brightness: case .brightness:
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 0.5 let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 0.5
self = .brightness(refreshInterval: interval) self = .brightness(refreshInterval: interval)
case .weather: case .weather:
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0 let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0
let units = try container.decodeIfPresent(String.self, forKey: .units) ?? "metric" let units = try container.decodeIfPresent(String.self, forKey: .units) ?? "metric"
let api_key = try container.decodeIfPresent(String.self, forKey: .api_key) ?? "32c4256d09a4c52b38aecddba7a078f6" let api_key = try container.decodeIfPresent(String.self, forKey: .api_key) ?? "32c4256d09a4c52b38aecddba7a078f6"
let icon_type = try container.decodeIfPresent(String.self, forKey: .icon_type) ?? "text" let icon_type = try container.decodeIfPresent(String.self, forKey: .icon_type) ?? "text"
self = .weather(interval: interval, units: units, api_key: api_key, icon_type: icon_type) self = .weather(interval: interval, units: units, api_key: api_key, icon_type: icon_type)
case .currency: case .currency:
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 600.0 let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 600.0
let from = try container.decodeIfPresent(String.self, forKey: .from) ?? "RUB" let from = try container.decodeIfPresent(String.self, forKey: .from) ?? "RUB"
let to = try container.decodeIfPresent(String.self, forKey: .to) ?? "USD" let to = try container.decodeIfPresent(String.self, forKey: .to) ?? "USD"
self = .currency(interval: interval, from: from, to: to) self = .currency(interval: interval, from: from, to: to)
case .inputsource: case .inputsource:
self = .inputsource() self = .inputsource()
case .music: case .music:
let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0 let interval = try container.decodeIfPresent(Double.self, forKey: .refreshInterval) ?? 1800.0
self = .music(interval: interval) self = .music(interval: interval)
case .groupBar: case .groupBar:
let items = try container.decode([BarItemDefinition].self, forKey: .items) let items = try container.decode([BarItemDefinition].self, forKey: .items)
self = .groupBar(items: items) self = .groupBar(items: items)
@ -264,11 +296,11 @@ enum ActionType: Decodable {
case none case none
case hidKey(keycode: Int32) case hidKey(keycode: Int32)
case keyPress(keycode: Int) case keyPress(keycode: Int)
case appleSctipt(source: SourceProtocol) case appleScript(source: SourceProtocol)
case shellScript(executable: String, parameters: [String]) case shellScript(executable: String, parameters: [String])
case custom(closure: ()->()) case custom(closure: ()->())
case openUrl(url: String) case openUrl(url: String)
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case action case action
case keycode case keycode
@ -277,7 +309,7 @@ enum ActionType: Decodable {
case shellArguments case shellArguments
case url case url
} }
private enum ActionTypeRaw: String, Decodable { private enum ActionTypeRaw: String, Decodable {
case hidKey case hidKey
case keyPress case keyPress
@ -285,29 +317,35 @@ enum ActionType: Decodable {
case shellScript case shellScript
case openUrl case openUrl
} }
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)
let type = try container.decodeIfPresent(ActionTypeRaw.self, forKey: .action) let type = try container.decodeIfPresent(ActionTypeRaw.self, forKey: .action)
switch type { switch type {
case .some(.hidKey): case .some(.hidKey):
let keycode = try container.decode(Int32.self, forKey: .keycode) let keycode = try container.decode(Int32.self, forKey: .keycode)
self = .hidKey(keycode: keycode) self = .hidKey(keycode: keycode)
case .some(.keyPress):
let keycode = try container.decode(Int.self, forKey: .keycode) case .some(.keyPress):
self = .keyPress(keycode: keycode) let keycode = try container.decode(Int.self, forKey: .keycode)
case .some(.appleScript): self = .keyPress(keycode: keycode)
let source = try container.decode(Source.self, forKey: .actionAppleScript)
self = .appleSctipt(source: source) case .some(.appleScript):
case .some(.shellScript): let source = try container.decode(Source.self, forKey: .actionAppleScript)
let executable = try container.decode(String.self, forKey: .executablePath) self = .appleScript(source: source)
let parameters = try container.decodeIfPresent([String].self, forKey: .shellArguments) ?? []
self = .shellScript(executable: executable, parameters: parameters) case .some(.shellScript):
case .some(.openUrl): let executable = try container.decode(String.self, forKey: .executablePath)
let url = try container.decode(String.self, forKey: .url) let parameters = try container.decodeIfPresent([String].self, forKey: .shellArguments) ?? []
self = .openUrl(url: url) self = .shellScript(executable: executable, parameters: parameters)
case .none:
self = .none case .some(.openUrl):
let url = try container.decode(String.self, forKey: .url)
self = .openUrl(url: url)
case .none:
self = .none
} }
} }
} }
@ -317,17 +355,17 @@ enum LongActionType: Decodable {
case none case none
case hidKey(keycode: Int32) case hidKey(keycode: Int32)
case keyPress(keycode: Int) case keyPress(keycode: Int)
case appleSctipt(source: SourceProtocol) case appleScript(source: SourceProtocol)
case shellScript(executable: String, parameters: [String]) case shellScript(executable: String, parameters: [String])
case custom(closure: ()->()) case custom(closure: ()->())
case openUrl(url: String) case openUrl(url: String)
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case longAction case longAction
case keycode case longKeycode
case actionAppleScript case longActionAppleScript
case executablePath case longExecutablePath
case shellArguments case longShellArguments
case longUrl case longUrl
} }
@ -342,25 +380,31 @@ enum LongActionType: Decodable {
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)
let longType = try container.decodeIfPresent(LongActionTypeRaw.self, forKey: .longAction) let longType = try container.decodeIfPresent(LongActionTypeRaw.self, forKey: .longAction)
switch longType { switch longType {
case .some(.hidKey): case .some(.hidKey):
let keycode = try container.decode(Int32.self, forKey: .keycode) let keycode = try container.decode(Int32.self, forKey: .longKeycode)
self = .hidKey(keycode: keycode) self = .hidKey(keycode: keycode)
case .some(.keyPress):
let keycode = try container.decode(Int.self, forKey: .keycode) case .some(.keyPress):
self = .keyPress(keycode: keycode) let keycode = try container.decode(Int.self, forKey: .longKeycode)
case .some(.appleScript): self = .keyPress(keycode: keycode)
let source = try container.decode(Source.self, forKey: .actionAppleScript)
self = .appleSctipt(source: source) case .some(.appleScript):
case .some(.shellScript): let source = try container.decode(Source.self, forKey: .longActionAppleScript)
let executable = try container.decode(String.self, forKey: .executablePath) self = .appleScript(source: source)
let parameters = try container.decodeIfPresent([String].self, forKey: .shellArguments) ?? []
self = .shellScript(executable: executable, parameters: parameters) case .some(.shellScript):
case .some(.openUrl): let executable = try container.decode(String.self, forKey: .longExecutablePath)
let longUrl = try container.decode(String.self, forKey: .longUrl) let parameters = try container.decodeIfPresent([String].self, forKey: .longShellArguments) ?? []
self = .openUrl(url: longUrl) self = .shellScript(executable: executable, parameters: parameters)
case .none:
self = .none case .some(.openUrl):
let longUrl = try container.decode(String.self, forKey: .longUrl)
self = .openUrl(url: longUrl)
case .none:
self = .none
} }
} }
} }
@ -377,7 +421,7 @@ enum GeneralParameter {
struct GeneralParameters: Decodable { struct GeneralParameters: Decodable {
let parameters: [GeneralParameters.CodingKeys: GeneralParameter] let parameters: [GeneralParameters.CodingKeys: GeneralParameter]
enum CodingKeys: String, CodingKey { enum CodingKeys: String, CodingKey {
case width case width
case image case image
@ -386,35 +430,45 @@ struct GeneralParameters: Decodable {
case background case background
case title case title
} }
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)
var result: [GeneralParameters.CodingKeys: GeneralParameter] = [:] var result: [GeneralParameters.CodingKeys: GeneralParameter] = [:]
if let value = try container.decodeIfPresent(CGFloat.self, forKey: .width) { if let value = try container.decodeIfPresent(CGFloat.self, forKey: .width) {
result[.width] = .width(value) result[.width] = .width(value)
} }
if let imageSource = try container.decodeIfPresent(Source.self, forKey: .image) { if let imageSource = try container.decodeIfPresent(Source.self, forKey: .image) {
result[.image] = .image(source: imageSource) result[.image] = .image(source: imageSource)
} }
let align = try container.decodeIfPresent(Align.self, forKey: .align) ?? .center let align = try container.decodeIfPresent(Align.self, forKey: .align) ?? .center
result[.align] = .align(align) result[.align] = .align(align)
if let borderedFlag = try container.decodeIfPresent(Bool.self, forKey: .bordered) { if let borderedFlag = try container.decodeIfPresent(Bool.self, forKey: .bordered) {
result[.bordered] = .bordered(borderedFlag) result[.bordered] = .bordered(borderedFlag)
} }
if let backgroundColor = try container.decodeIfPresent(String.self, forKey: .background)?.hexColor { if let backgroundColor = try container.decodeIfPresent(String.self, forKey: .background)?.hexColor {
result[.background] = .background(backgroundColor) result[.background] = .background(backgroundColor)
} }
if let title = try container.decodeIfPresent(String.self, forKey: .title) { if let title = try container.decodeIfPresent(String.self, forKey: .title) {
result[.title] = .title(title) result[.title] = .title(title)
} }
parameters = result parameters = result
} }
} }
protocol SourceProtocol { protocol SourceProtocol {
var data: Data? { get } var data: Data? { get }
var string: String? { get } var string: String? { get }
var image: NSImage? { get } var image: NSImage? { get }
var appleScript: NSAppleScript? { get } var appleScript: NSAppleScript? { get }
} }
struct Source: Decodable, SourceProtocol { struct Source: Decodable, SourceProtocol {
let filePath: String? let filePath: String?
let base64: String? let base64: String?
@ -429,35 +483,43 @@ struct Source: Decodable, SourceProtocol {
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 ?? filePath?.fileString return inline ?? filePath?.fileString
} }
var image: NSImage? { var image: NSImage? {
return data?.image return data?.image
} }
var appleScript: NSAppleScript? { var appleScript: NSAppleScript? {
return filePath?.fileURL.appleScript ?? self.string?.appleScript return filePath?.fileURL.appleScript ?? self.string?.appleScript
} }
private init(filePath: String?, base64: String?, inline: String?) { private init(filePath: String?, base64: String?, inline: String?) {
self.filePath = filePath self.filePath = filePath
self.base64 = base64 self.base64 = base64
self.inline = inline self.inline = inline
} }
init(filePath: String) { init(filePath: String) {
self.init(filePath: filePath, base64: nil, inline: nil) self.init(filePath: filePath, base64: nil, inline: nil)
} }
} }
extension NSImage: SourceProtocol { extension NSImage: SourceProtocol {
var data: Data? { var data: Data? {
return nil return nil
} }
var string: String? { var string: String? {
return nil return nil
} }
var image: NSImage? { var image: NSImage? {
return self return self
} }
var appleScript: NSAppleScript? { var appleScript: NSAppleScript? {
return nil return nil
} }
@ -467,6 +529,7 @@ extension String {
var base64Data: Data? { var base64Data: Data? {
return Data(base64Encoded: self) return Data(base64Encoded: self)
} }
var fileData: Data? { var fileData: Data? {
return try? Data(contentsOf: URL(fileURLWithPath: self)) return try? Data(contentsOf: URL(fileURLWithPath: self))
} }
@ -477,10 +540,12 @@ extension String {
} }
} }
extension Data { extension Data {
var utf8string: String? { var utf8string: String? {
return String(data: self, encoding: .utf8) return String(data: self, encoding: .utf8)
} }
var image: NSImage? { var image: NSImage? {
return NSImage(data: self)?.resize(maxSize: NSSize(width: 24, height: 24)) return NSImage(data: self)?.resize(maxSize: NSSize(width: 24, height: 24))
} }
@ -496,6 +561,7 @@ extension String {
var fileURL: URL { var fileURL: URL {
return URL(fileURLWithPath: self) return URL(fileURLWithPath: self)
} }
var appleScript: NSAppleScript? { var appleScript: NSAppleScript? {
return NSAppleScript(source: self) return NSAppleScript(source: self)
} }

View File

@ -315,7 +315,7 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
return { HIDPostAuxKey(keycode) } return { HIDPostAuxKey(keycode) }
case .keyPress(keycode: let keycode): case .keyPress(keycode: let keycode):
return { GenericKeyPress(keyCode: CGKeyCode(keycode)).send() } return { GenericKeyPress(keyCode: CGKeyCode(keycode)).send() }
case .appleSctipt(source: let source): case .appleScript(source: let source):
guard let appleScript = source.appleScript else { guard let appleScript = source.appleScript else {
print("cannot create apple script for item \(item)") print("cannot create apple script for item \(item)")
return {} return {}
@ -360,7 +360,7 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
return { HIDPostAuxKey(keycode) } return { HIDPostAuxKey(keycode) }
case .keyPress(keycode: let keycode): case .keyPress(keycode: let keycode):
return { GenericKeyPress(keyCode: CGKeyCode(keycode)).send() } return { GenericKeyPress(keyCode: CGKeyCode(keycode)).send() }
case .appleSctipt(source: let source): case .appleScript(source: let source):
guard let appleScript = source.appleScript else { guard let appleScript = source.appleScript else {
print("cannot create apple script for item \(item)") print("cannot create apple script for item \(item)")
return {} return {}

View File

@ -202,6 +202,20 @@ File for customize your preset for MTMR: `open ~/Library/Application\ Support/MT
"url": "https://google.com", "url": "https://google.com",
``` ```
## LongActions
This then you want to use longPress for some operations is will the same values like for Actions but different additional parameters, example:
```js
"longAction": "hidKey",
"longKeycode": 53,
```
- longAction
- longKeycode
- longActionAppleScript
- longExecutablePath
- longShellArguments
- longUrl
## Additional parameters: ## Additional parameters:
- `width` allow to restrict how much room a particular button will take - `width` allow to restrict how much room a particular button will take