mirror of
https://github.com/Toxblh/MTMR.git
synced 2026-10-31 18:38:35 +00:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
744ea067db | ||
|
|
8064ab759c | ||
|
|
556c28df85 | ||
|
|
780a8ba81e | ||
|
|
71f5030fa6 | ||
|
|
f435c0b530 | ||
|
|
e278482807 | ||
|
|
51d246bf7f | ||
|
|
c1cd402241 | ||
|
|
c496156cf2 | ||
|
|
154ea09e98 | ||
|
|
3b493fd5be | ||
|
|
b718b1c9dd | ||
|
|
acc248a579 | ||
|
|
59581ffdc8 | ||
|
|
e988951ff9 |
@@ -46,6 +46,7 @@
|
||||
B082B253205C7D8000BC04DC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B082B252205C7D8000BC04DC /* AppDelegate.swift */; };
|
||||
B082B257205C7D8000BC04DC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = B082B256205C7D8000BC04DC /* Assets.xcassets */; };
|
||||
B082B25A205C7D8000BC04DC /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B082B258205C7D8000BC04DC /* Main.storyboard */; };
|
||||
B0846A752220C968000288A7 /* NetworkBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0846A742220C968000288A7 /* NetworkBarItem.swift */; };
|
||||
B09EB1E4207C082000D5C1E0 /* HapticFeedback.swift in Sources */ = {isa = PBXBuildFile; fileRef = B09EB1E3207C082000D5C1E0 /* HapticFeedback.swift */; };
|
||||
B09EB1E6207C0F8E00D5C1E0 /* MultitouchSupport.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B09EB1E5207C0F8E00D5C1E0 /* MultitouchSupport.framework */; };
|
||||
B0A7E9AA205D6AA400EEF070 /* KeyPress.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0A7E9A9205D6AA400EEF070 /* KeyPress.swift */; };
|
||||
@@ -126,6 +127,7 @@
|
||||
B082B25C205C7D8000BC04DC /* MTMR.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = MTMR.entitlements; sourceTree = "<group>"; };
|
||||
B082B261205C7D8000BC04DC /* MTMRTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MTMRTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||
B082B267205C7D8000BC04DC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
|
||||
B0846A742220C968000288A7 /* NetworkBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NetworkBarItem.swift; sourceTree = "<group>"; };
|
||||
B09EB1E3207C082000D5C1E0 /* HapticFeedback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HapticFeedback.swift; sourceTree = "<group>"; };
|
||||
B09EB1E5207C0F8E00D5C1E0 /* MultitouchSupport.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MultitouchSupport.framework; path = ../../../../../System/Library/PrivateFrameworks/MultitouchSupport.framework; sourceTree = "<group>"; };
|
||||
B0A7E9A9205D6AA400EEF070 /* KeyPress.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeyPress.swift; sourceTree = "<group>"; };
|
||||
@@ -276,19 +278,20 @@
|
||||
B0B88A07208CD12000A2C160 /* Widgets */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
36C2ECD6207B6DAE003CDA33 /* TimeTouchBarItem.swift */,
|
||||
6027D1B72080E52A004FFDC7 /* BrightnessViewController.swift */,
|
||||
6027D1B82080E52A004FFDC7 /* VolumeViewController.swift */,
|
||||
B04B7BB62087398C00C835D0 /* BatteryBarItem.swift */,
|
||||
607EEA4A2087835F009DA5F0 /* WeatherBarItem.swift */,
|
||||
607EEA4C2087A8DA009DA5F0 /* CurrencyBarItem.swift */,
|
||||
6042B6A62083E03A00C525C8 /* AppScrubberTouchBarItem.swift */,
|
||||
B04B7BB62087398C00C835D0 /* BatteryBarItem.swift */,
|
||||
6027D1B72080E52A004FFDC7 /* BrightnessViewController.swift */,
|
||||
607EEA4C2087A8DA009DA5F0 /* CurrencyBarItem.swift */,
|
||||
B081732B213739FE005D4908 /* DnDBarItem.swift */,
|
||||
60669B4220AD8FA80074E817 /* GroupBarItem.swift */,
|
||||
60F7D453208CC31400ABF5D2 /* InputSourceBarItem.swift */,
|
||||
60C44AFC20A373A100C0EC91 /* MusicBarItem.swift */,
|
||||
60669B4220AD8FA80074E817 /* GroupBarItem.swift */,
|
||||
B0846A742220C968000288A7 /* NetworkBarItem.swift */,
|
||||
B08173262135F02B005D4908 /* NightShiftBarItem.swift */,
|
||||
B081732B213739FE005D4908 /* DnDBarItem.swift */,
|
||||
B08126EE217BD0B900A98970 /* PomodoroBarItem.swift */,
|
||||
36C2ECD6207B6DAE003CDA33 /* TimeTouchBarItem.swift */,
|
||||
6027D1B82080E52A004FFDC7 /* VolumeViewController.swift */,
|
||||
607EEA4A2087835F009DA5F0 /* WeatherBarItem.swift */,
|
||||
B08126F0217BE19000A98970 /* WidgetProtocol.swift */,
|
||||
);
|
||||
path = Widgets;
|
||||
@@ -437,6 +440,7 @@
|
||||
B059D622205E03F5006E6B86 /* TouchBarController.swift in Sources */,
|
||||
B05600D32083E9BB00EB218D /* CustomSlider.swift in Sources */,
|
||||
36C2ECD9207B74B4003CDA33 /* AppleScriptTouchBarItem.swift in Sources */,
|
||||
B0846A752220C968000288A7 /* NetworkBarItem.swift in Sources */,
|
||||
B0F8771A207AC1EA00D6E430 /* TouchBarSupport.m in Sources */,
|
||||
B08126F1217BE19000A98970 /* WidgetProtocol.swift in Sources */,
|
||||
B0008E552080286C003AD4DD /* SupportHelpers.swift in Sources */,
|
||||
@@ -626,7 +630,7 @@
|
||||
isa = XCBuildConfiguration;
|
||||
buildSettings = {
|
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
|
||||
CODE_SIGN_IDENTITY = "Mac Developer";
|
||||
CODE_SIGN_IDENTITY = "Developer ID Application";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COMBINE_HIDPI_IMAGES = YES;
|
||||
DEVELOPMENT_TEAM = D6D8BR2QNB;
|
||||
|
||||
@@ -3,6 +3,6 @@
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BuildSystemType</key>
|
||||
<string>Latest</string>
|
||||
<string>Original</string>
|
||||
</dict>
|
||||
</plist>
|
||||
|
||||
@@ -50,7 +50,11 @@ class AppDelegate: NSObject, NSApplicationDelegate {
|
||||
return frontmostId
|
||||
}
|
||||
|
||||
isBlockedApp = blacklistAppIdentifiers.index(of: frontmostApplicationIdentifier!) != nil
|
||||
if frontmostApplicationIdentifier != nil {
|
||||
isBlockedApp = blacklistAppIdentifiers.index(of: frontmostApplicationIdentifier!) != nil
|
||||
} else {
|
||||
isBlockedApp = false
|
||||
}
|
||||
createMenu()
|
||||
}
|
||||
|
||||
|
||||
@@ -9,13 +9,19 @@ class AppleScriptTouchBarItem: CustomButtonTouchBarItem {
|
||||
self.interval = interval
|
||||
super.init(identifier: identifier, title: "⏳")
|
||||
forceHideConstraint = view.widthAnchor.constraint(equalToConstant: 0)
|
||||
guard let script = source.appleScript else {
|
||||
title = "no script"
|
||||
return
|
||||
}
|
||||
self.script = script
|
||||
isBordered = false
|
||||
title = "scheduled"
|
||||
DispatchQueue.appleScriptQueue.async {
|
||||
guard let script = source.appleScript else {
|
||||
DispatchQueue.main.async {
|
||||
self.title = "no script"
|
||||
}
|
||||
return
|
||||
}
|
||||
self.script = script
|
||||
DispatchQueue.main.async {
|
||||
self.isBordered = false
|
||||
}
|
||||
|
||||
var error: NSDictionary?
|
||||
guard script.compileAndReturnError(&error) else {
|
||||
#if DEBUG
|
||||
|
||||
+2
-2
@@ -17,9 +17,9 @@
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>0.19.3</string>
|
||||
<string>0.20.1</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>130</string>
|
||||
<string>185</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.utilities</string>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
|
||||
@@ -303,7 +303,7 @@ class SupportedTypesHolder {
|
||||
action: try ActionType(from: decoder),
|
||||
longAction: try LongActionType(from: decoder),
|
||||
parameters: [:]
|
||||
)}
|
||||
) }
|
||||
}
|
||||
|
||||
func register(typename: String, decoder: @escaping ParametersDecoder) {
|
||||
@@ -338,6 +338,7 @@ enum ItemType: Decodable {
|
||||
case nightShift()
|
||||
case dnd()
|
||||
case pomodoro(workTime: Double, restTime: Double)
|
||||
case network(flip: Bool)
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case type
|
||||
@@ -358,6 +359,7 @@ enum ItemType: Decodable {
|
||||
case items
|
||||
case workTime
|
||||
case restTime
|
||||
case flip
|
||||
}
|
||||
|
||||
enum ItemTypeRaw: String, Decodable {
|
||||
@@ -376,6 +378,7 @@ enum ItemType: Decodable {
|
||||
case nightShift
|
||||
case dnd
|
||||
case pomodoro
|
||||
case network
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
@@ -444,6 +447,10 @@ enum ItemType: Decodable {
|
||||
let workTime = try container.decodeIfPresent(Double.self, forKey: .workTime) ?? 1500.0
|
||||
let restTime = try container.decodeIfPresent(Double.self, forKey: .restTime) ?? 600.0
|
||||
self = .pomodoro(workTime: workTime, restTime: restTime)
|
||||
|
||||
case .network:
|
||||
let flip = try container.decodeIfPresent(Bool.self, forKey: .flip) ?? false
|
||||
self = .network(flip: flip)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+22
-25
@@ -6,17 +6,17 @@
|
||||
// Copyright © 2018 Anton Palgunov. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import AppKit
|
||||
import Foundation
|
||||
|
||||
extension String {
|
||||
func trim() -> String {
|
||||
return self.trimmingCharacters(in: NSCharacterSet.whitespaces)
|
||||
return trimmingCharacters(in: NSCharacterSet.whitespaces)
|
||||
}
|
||||
|
||||
func stripComments() -> String {
|
||||
// ((\s|,)\/\*[\s\S]*?\*\/)|(( |, ")\/\/.*)
|
||||
return self.replacingOccurrences(of: "((\\s|,)\\/\\*[\\s\\S]*?\\*\\/)|(( |, \\\")\\/\\/.*)", with: "", options: .regularExpression)
|
||||
return replacingOccurrences(of: "((\\s|,)\\/\\*[\\s\\S]*?\\*\\/)|(( |, \\\")\\/\\/.*)", with: "", options: .regularExpression)
|
||||
}
|
||||
|
||||
var hexColor: NSColor? {
|
||||
@@ -39,21 +39,20 @@ extension String {
|
||||
}
|
||||
|
||||
extension NSImage {
|
||||
func resize(maxSize:NSSize) -> NSImage {
|
||||
var ratio:Float = 0.0
|
||||
let imageWidth = Float(self.size.width)
|
||||
let imageHeight = Float(self.size.height)
|
||||
func resize(maxSize: NSSize) -> NSImage {
|
||||
var ratio: Float = 0.0
|
||||
let imageWidth = Float(size.width)
|
||||
let imageHeight = Float(size.height)
|
||||
let maxWidth = Float(maxSize.width)
|
||||
let maxHeight = Float(maxSize.height)
|
||||
|
||||
// Get ratio (landscape or portrait)
|
||||
if (imageWidth > imageHeight) {
|
||||
if imageWidth > imageHeight {
|
||||
// Landscape
|
||||
ratio = maxWidth / imageWidth;
|
||||
}
|
||||
else {
|
||||
ratio = maxWidth / imageWidth
|
||||
} else {
|
||||
// Portrait
|
||||
ratio = maxHeight / imageHeight;
|
||||
ratio = maxHeight / imageHeight
|
||||
}
|
||||
|
||||
// Calculate new size based on the ratio
|
||||
@@ -61,11 +60,11 @@ extension NSImage {
|
||||
let newHeight = imageHeight * ratio
|
||||
|
||||
// Create a new NSSize object with the newly calculated size
|
||||
let newSize:NSSize = NSSize(width: Int(newWidth), height: Int(newHeight))
|
||||
let newSize: NSSize = NSSize(width: Int(newWidth), height: Int(newHeight))
|
||||
|
||||
// Cast the NSImage to a CGImage
|
||||
var imageRect:NSRect = NSMakeRect(0, 0, self.size.width, self.size.height)
|
||||
let imageRef = self.cgImage(forProposedRect: &imageRect, context: nil, hints: nil)
|
||||
var imageRect: NSRect = NSMakeRect(0, 0, size.width, size.height)
|
||||
let imageRef = cgImage(forProposedRect: &imageRect, context: nil, hints: nil)
|
||||
|
||||
// Create NSImage from the CGImage using the new size
|
||||
let imageWithNewSize = NSImage(cgImage: imageRef!, size: newSize)
|
||||
@@ -74,34 +73,32 @@ extension NSImage {
|
||||
return imageWithNewSize
|
||||
}
|
||||
|
||||
func rotateByDegreess(degrees:CGFloat) -> NSImage {
|
||||
|
||||
var imageBounds = NSZeroRect ; imageBounds.size = self.size
|
||||
func rotateByDegreess(degrees: CGFloat) -> NSImage {
|
||||
var imageBounds = NSZeroRect; imageBounds.size = size
|
||||
let pathBounds = NSBezierPath(rect: imageBounds)
|
||||
var transform = NSAffineTransform()
|
||||
transform.rotate(byDegrees: degrees)
|
||||
pathBounds.transform(using: transform as AffineTransform)
|
||||
let rotatedBounds:NSRect = NSMakeRect(NSZeroPoint.x, NSZeroPoint.y , self.size.width, self.size.height )
|
||||
let rotatedBounds: NSRect = NSMakeRect(NSZeroPoint.x, NSZeroPoint.y, size.width, size.height)
|
||||
let rotatedImage = NSImage(size: rotatedBounds.size)
|
||||
|
||||
//Center the image within the rotated bounds
|
||||
// Center the image within the rotated bounds
|
||||
imageBounds.origin.x = NSMidX(rotatedBounds) - (NSWidth(imageBounds) / 2)
|
||||
imageBounds.origin.y = NSMidY(rotatedBounds) - (NSHeight(imageBounds) / 2)
|
||||
imageBounds.origin.y = NSMidY(rotatedBounds) - (NSHeight(imageBounds) / 2)
|
||||
|
||||
// Start a new transform
|
||||
transform = NSAffineTransform()
|
||||
// Move coordinate system to the center (since we want to rotate around the center)
|
||||
transform.translateX(by: +(NSWidth(rotatedBounds) / 2 ), yBy: +(NSHeight(rotatedBounds) / 2))
|
||||
transform.translateX(by: +(NSWidth(rotatedBounds) / 2), yBy: +(NSHeight(rotatedBounds) / 2))
|
||||
transform.rotate(byDegrees: degrees)
|
||||
// Move the coordinate system bak to normal
|
||||
transform.translateX(by: -(NSWidth(rotatedBounds) / 2 ), yBy: -(NSHeight(rotatedBounds) / 2))
|
||||
transform.translateX(by: -(NSWidth(rotatedBounds) / 2), yBy: -(NSHeight(rotatedBounds) / 2))
|
||||
// Draw the original image, rotated, into the new image
|
||||
rotatedImage.lockFocus()
|
||||
transform.concat()
|
||||
self.draw(in: imageBounds, from: NSZeroRect, operation: NSCompositingOperation.copy, fraction: 1.0)
|
||||
draw(in: imageBounds, from: NSZeroRect, operation: NSCompositingOperation.copy, fraction: 1.0)
|
||||
rotatedImage.unlockFocus()
|
||||
|
||||
return rotatedImage
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ let appSupportDirectory = NSSearchPathForDirectoriesInDomains(.applicationSuppor
|
||||
let standardConfigPath = appSupportDirectory.appending("/items.json")
|
||||
|
||||
extension ItemType {
|
||||
|
||||
var identifierBase: String {
|
||||
switch self {
|
||||
case .staticButton(title: _):
|
||||
@@ -50,9 +49,10 @@ extension ItemType {
|
||||
return "com.toxblh.mtmr.dnd."
|
||||
case .pomodoro(interval: _):
|
||||
return PomodoroBarItem.identifier
|
||||
case .network(flip: _):
|
||||
return NetworkBarItem.identifier
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
extension NSTouchBarItem.Identifier {
|
||||
@@ -60,7 +60,6 @@ extension NSTouchBarItem.Identifier {
|
||||
}
|
||||
|
||||
class TouchBarController: NSObject, NSTouchBarDelegate {
|
||||
|
||||
static let shared = TouchBarController()
|
||||
|
||||
var touchBar: NSTouchBar!
|
||||
@@ -87,25 +86,23 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
||||
|
||||
var blacklistAppIdentifiers: [String] = []
|
||||
var frontmostApplicationIdentifier: String? {
|
||||
get {
|
||||
guard let frontmostId = NSWorkspace.shared.frontmostApplication?.bundleIdentifier else { return nil }
|
||||
return frontmostId
|
||||
}
|
||||
guard let frontmostId = NSWorkspace.shared.frontmostApplication?.bundleIdentifier else { return nil }
|
||||
return frontmostId
|
||||
}
|
||||
|
||||
private override init() {
|
||||
super.init()
|
||||
SupportedTypesHolder.sharedInstance.register(typename: "exitTouchbar", item: .staticButton(title: "exit"), action: .custom(closure: { [weak self] in self?.dismissTouchBar()}), longAction: .none)
|
||||
SupportedTypesHolder.sharedInstance.register(typename: "exitTouchbar", item: .staticButton(title: "exit"), action: .custom(closure: { [weak self] in self?.dismissTouchBar() }), longAction: .none)
|
||||
|
||||
SupportedTypesHolder.sharedInstance.register(typename: "close") { _ in
|
||||
return (item: .staticButton(title: ""), action: .custom(closure: { [weak self] in
|
||||
(item: .staticButton(title: ""), action: .custom(closure: { [weak self] in
|
||||
guard let `self` = self else { return }
|
||||
self.reloadPreset(path: self.lastPresetPath)
|
||||
}), longAction: .none, parameters: [.width: .width(30), .image: .image(source: (NSImage(named: NSImage.stopProgressFreestandingTemplateName))!)])
|
||||
}
|
||||
|
||||
if let blackListed = UserDefaults.standard.stringArray(forKey: "com.toxblh.mtmr.blackListedApps") {
|
||||
self.blacklistAppIdentifiers = blackListed
|
||||
blacklistAppIdentifiers = blackListed
|
||||
}
|
||||
|
||||
NSWorkspace.shared.notificationCenter.addObserver(self, selector: #selector(activeApplicationChanged), name: NSWorkspace.didLaunchApplicationNotification, object: nil)
|
||||
@@ -119,37 +116,37 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
||||
if let oldBar = self.touchBar {
|
||||
minimizeSystemModal(oldBar)
|
||||
}
|
||||
self.touchBar = NSTouchBar()
|
||||
self.jsonItems = newJsonItems
|
||||
self.itemDefinitions = [:]
|
||||
self.items = [:]
|
||||
self.leftIdentifiers = []
|
||||
self.centerItems = []
|
||||
self.rightIdentifiers = []
|
||||
touchBar = NSTouchBar()
|
||||
jsonItems = newJsonItems
|
||||
itemDefinitions = [:]
|
||||
items = [:]
|
||||
leftIdentifiers = []
|
||||
centerItems = []
|
||||
rightIdentifiers = []
|
||||
|
||||
loadItemDefinitions(jsonItems: self.jsonItems)
|
||||
loadItemDefinitions(jsonItems: jsonItems)
|
||||
createItems()
|
||||
|
||||
centerItems = centerIdentifiers.compactMap({ (identifier) -> NSTouchBarItem? in
|
||||
return items[identifier]
|
||||
items[identifier]
|
||||
})
|
||||
|
||||
self.centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea.".appending(UUID().uuidString))
|
||||
self.scrollArea = ScrollViewItem(identifier: centerScrollArea, items: centerItems)
|
||||
centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea.".appending(UUID().uuidString))
|
||||
scrollArea = ScrollViewItem(identifier: centerScrollArea, items: centerItems)
|
||||
|
||||
touchBar.delegate = self
|
||||
touchBar.defaultItemIdentifiers = []
|
||||
touchBar.defaultItemIdentifiers = self.leftIdentifiers + [centerScrollArea] + self.rightIdentifiers
|
||||
touchBar.defaultItemIdentifiers = leftIdentifiers + [centerScrollArea] + rightIdentifiers
|
||||
|
||||
self.updateActiveApp()
|
||||
updateActiveApp()
|
||||
}
|
||||
|
||||
@objc func activeApplicationChanged(_ n: Notification) {
|
||||
@objc func activeApplicationChanged(_: Notification) {
|
||||
updateActiveApp()
|
||||
}
|
||||
|
||||
func updateActiveApp() {
|
||||
if self.blacklistAppIdentifiers.index(of: self.frontmostApplicationIdentifier!) != nil {
|
||||
if frontmostApplicationIdentifier != nil && blacklistAppIdentifiers.index(of: frontmostApplicationIdentifier!) != nil {
|
||||
dismissTouchBar()
|
||||
} else {
|
||||
presentTouchBar()
|
||||
@@ -194,8 +191,8 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
||||
}
|
||||
|
||||
func createItems() {
|
||||
for (identifier, definition) in self.itemDefinitions {
|
||||
self.items[identifier] = self.createItem(forIdentifier: identifier, definition: definition)
|
||||
for (identifier, definition) in itemDefinitions {
|
||||
items[identifier] = createItem(forIdentifier: identifier, definition: definition)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -212,7 +209,7 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
||||
}
|
||||
|
||||
@objc private func presentTouchBar() {
|
||||
if self.showControlStripState {
|
||||
if showControlStripState {
|
||||
updateControlStripPresence()
|
||||
presentSystemModal(touchBar, systemTrayItemIdentifier: .controlStripItem)
|
||||
} else {
|
||||
@@ -230,9 +227,9 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
||||
presentTouchBar()
|
||||
}
|
||||
|
||||
func touchBar(_ touchBar: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? {
|
||||
func touchBar(_: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? {
|
||||
if identifier == centerScrollArea {
|
||||
return self.scrollArea
|
||||
return scrollArea
|
||||
}
|
||||
|
||||
guard let item = self.items[identifier],
|
||||
@@ -244,47 +241,48 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
||||
}
|
||||
|
||||
func createItem(forIdentifier identifier: NSTouchBarItem.Identifier, definition item: BarItemDefinition) -> NSTouchBarItem? {
|
||||
|
||||
var barItem: NSTouchBarItem!
|
||||
switch item.type {
|
||||
case .staticButton(title: let title):
|
||||
case let .staticButton(title: title):
|
||||
barItem = CustomButtonTouchBarItem(identifier: identifier, title: title)
|
||||
case .appleScriptTitledButton(source: let source, refreshInterval: let interval):
|
||||
case let .appleScriptTitledButton(source: source, refreshInterval: interval):
|
||||
barItem = AppleScriptTouchBarItem(identifier: identifier, source: source, interval: interval)
|
||||
case .timeButton(formatTemplate: let template, timeZone: let timeZone):
|
||||
case let .timeButton(formatTemplate: template, timeZone: timeZone):
|
||||
barItem = TimeTouchBarItem(identifier: identifier, formatTemplate: template, timeZone: timeZone)
|
||||
case .battery():
|
||||
barItem = BatteryBarItem(identifier: identifier)
|
||||
case .dock:
|
||||
barItem = AppScrubberTouchBarItem(identifier: identifier)
|
||||
case .volume:
|
||||
if case .image(let source)? = item.additionalParameters[.image] {
|
||||
if case let .image(source)? = item.additionalParameters[.image] {
|
||||
barItem = VolumeViewController(identifier: identifier, image: source.image)
|
||||
} else {
|
||||
barItem = VolumeViewController(identifier: identifier)
|
||||
}
|
||||
case .brightness(refreshInterval: let interval):
|
||||
if case .image(let source)? = item.additionalParameters[.image] {
|
||||
case let .brightness(refreshInterval: interval):
|
||||
if case let .image(source)? = item.additionalParameters[.image] {
|
||||
barItem = BrightnessViewController(identifier: identifier, refreshInterval: interval, image: source.image)
|
||||
} else {
|
||||
barItem = BrightnessViewController(identifier: identifier, refreshInterval: interval)
|
||||
}
|
||||
case .weather(interval: let interval, units: let units, api_key: let api_key, icon_type: let icon_type):
|
||||
case let .weather(interval: interval, units: units, api_key: api_key, icon_type: icon_type):
|
||||
barItem = WeatherBarItem(identifier: identifier, interval: interval, units: units, api_key: api_key, icon_type: icon_type)
|
||||
case .currency(interval: let interval, from: let from, to: let to, full: let full):
|
||||
case let .currency(interval: interval, from: from, to: to, full: full):
|
||||
barItem = CurrencyBarItem(identifier: identifier, interval: interval, from: from, to: to, full: full)
|
||||
case .inputsource():
|
||||
barItem = InputSourceBarItem(identifier: identifier)
|
||||
case .music(interval: let interval):
|
||||
case let .music(interval: interval):
|
||||
barItem = MusicBarItem(identifier: identifier, interval: interval)
|
||||
case .groupBar(items: let items):
|
||||
case let .groupBar(items: items):
|
||||
barItem = GroupBarItem(identifier: identifier, items: items)
|
||||
case .nightShift():
|
||||
barItem = NightShiftBarItem(identifier: identifier)
|
||||
case .dnd():
|
||||
barItem = DnDBarItem(identifier: identifier)
|
||||
case .pomodoro(workTime: let workTime, restTime: let restTime):
|
||||
case let .pomodoro(workTime: workTime, restTime: restTime):
|
||||
barItem = PomodoroBarItem(identifier: identifier, workTime: workTime, restTime: restTime)
|
||||
case let .network(flip: flip):
|
||||
barItem = NetworkBarItem(identifier: identifier, flip: flip)
|
||||
}
|
||||
|
||||
if let action = self.action(forItem: item), let item = barItem as? CustomButtonTouchBarItem {
|
||||
@@ -293,19 +291,19 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
||||
if let longAction = self.longAction(forItem: item), let item = barItem as? CustomButtonTouchBarItem {
|
||||
item.longTapClosure = longAction
|
||||
}
|
||||
if case .bordered(let bordered)? = item.additionalParameters[.bordered], let item = barItem as? CustomButtonTouchBarItem {
|
||||
if case let .bordered(bordered)? = item.additionalParameters[.bordered], let item = barItem as? CustomButtonTouchBarItem {
|
||||
item.isBordered = bordered
|
||||
}
|
||||
if case .background(let color)? = item.additionalParameters[.background], let item = barItem as? CustomButtonTouchBarItem {
|
||||
if case let .background(color)? = item.additionalParameters[.background], let item = barItem as? CustomButtonTouchBarItem {
|
||||
item.backgroundColor = color
|
||||
}
|
||||
if case .width(let value)? = item.additionalParameters[.width], let widthBarItem = barItem as? CanSetWidth {
|
||||
if case let .width(value)? = item.additionalParameters[.width], let widthBarItem = barItem as? CanSetWidth {
|
||||
widthBarItem.setWidth(value: value)
|
||||
}
|
||||
if case .image(let source)? = item.additionalParameters[.image], let item = barItem as? CustomButtonTouchBarItem {
|
||||
if case let .image(source)? = item.additionalParameters[.image], let item = barItem as? CustomButtonTouchBarItem {
|
||||
item.image = source.image
|
||||
}
|
||||
if case .title(let value)? = item.additionalParameters[.title] {
|
||||
if case let .title(value)? = item.additionalParameters[.title] {
|
||||
if let item = barItem as? GroupBarItem {
|
||||
item.collapsedRepresentationLabel = value
|
||||
} else if let item = barItem as? CustomButtonTouchBarItem {
|
||||
@@ -315,13 +313,13 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
||||
return barItem
|
||||
}
|
||||
|
||||
func action(forItem item: BarItemDefinition) -> (()->())? {
|
||||
func action(forItem item: BarItemDefinition) -> (() -> Void)? {
|
||||
switch item.action {
|
||||
case .hidKey(keycode: let keycode):
|
||||
case let .hidKey(keycode: keycode):
|
||||
return { HIDPostAuxKey(keycode) }
|
||||
case .keyPress(keycode: let keycode):
|
||||
case let .keyPress(keycode: keycode):
|
||||
return { GenericKeyPress(keyCode: CGKeyCode(keycode)).send() }
|
||||
case .appleScript(source: let source):
|
||||
case let .appleScript(source: source):
|
||||
guard let appleScript = source.appleScript else {
|
||||
print("cannot create apple script for item \(item)")
|
||||
return {}
|
||||
@@ -335,38 +333,37 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
||||
}
|
||||
}
|
||||
}
|
||||
case .shellScript(executable: let executable, parameters: let parameters):
|
||||
case let .shellScript(executable: executable, parameters: parameters):
|
||||
return {
|
||||
let task = Process()
|
||||
task.launchPath = executable
|
||||
task.arguments = parameters
|
||||
task.launch()
|
||||
}
|
||||
case .openUrl(url: let url):
|
||||
case let .openUrl(url: url):
|
||||
return {
|
||||
if let url = URL(string: url), NSWorkspace.shared.open(url) {
|
||||
#if DEBUG
|
||||
print("URL was successfully opened")
|
||||
print("URL was successfully opened")
|
||||
#endif
|
||||
} else {
|
||||
print("error", url)
|
||||
}
|
||||
}
|
||||
case .custom(closure: let closure):
|
||||
case let .custom(closure: closure):
|
||||
return closure
|
||||
case .none:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func longAction(forItem item: BarItemDefinition) -> (()->())? {
|
||||
func longAction(forItem item: BarItemDefinition) -> (() -> Void)? {
|
||||
switch item.longAction {
|
||||
case .hidKey(keycode: let keycode):
|
||||
case let .hidKey(keycode: keycode):
|
||||
return { HIDPostAuxKey(keycode) }
|
||||
case .keyPress(keycode: let keycode):
|
||||
case let .keyPress(keycode: keycode):
|
||||
return { GenericKeyPress(keyCode: CGKeyCode(keycode)).send() }
|
||||
case .appleScript(source: let source):
|
||||
case let .appleScript(source: source):
|
||||
guard let appleScript = source.appleScript else {
|
||||
print("cannot create apple script for item \(item)")
|
||||
return {}
|
||||
@@ -378,24 +375,24 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
||||
print("error \(error) when handling \(item) ")
|
||||
}
|
||||
}
|
||||
case .shellScript(executable: let executable, parameters: let parameters):
|
||||
case let .shellScript(executable: executable, parameters: parameters):
|
||||
return {
|
||||
let task = Process()
|
||||
task.launchPath = executable
|
||||
task.arguments = parameters
|
||||
task.launch()
|
||||
}
|
||||
case .openUrl(url: let url):
|
||||
case let .openUrl(url: url):
|
||||
return {
|
||||
if let url = URL(string: url), NSWorkspace.shared.open(url) {
|
||||
#if DEBUG
|
||||
print("URL was successfully opened")
|
||||
print("URL was successfully opened")
|
||||
#endif
|
||||
} else {
|
||||
print("error", url)
|
||||
}
|
||||
}
|
||||
case .custom(closure: let closure):
|
||||
case let .custom(closure: closure):
|
||||
return closure
|
||||
case .none:
|
||||
return nil
|
||||
@@ -409,13 +406,13 @@ protocol CanSetWidth {
|
||||
|
||||
extension NSCustomTouchBarItem: CanSetWidth {
|
||||
func setWidth(value: CGFloat) {
|
||||
self.view.widthAnchor.constraint(equalToConstant: value).isActive = true
|
||||
view.widthAnchor.constraint(equalToConstant: value).isActive = true
|
||||
}
|
||||
}
|
||||
|
||||
extension BarItemDefinition {
|
||||
var align: Align {
|
||||
if case .align(let result)? = self.additionalParameters[.align] {
|
||||
if case let .align(result)? = additionalParameters[.align] {
|
||||
return result
|
||||
}
|
||||
return .center
|
||||
|
||||
@@ -0,0 +1,147 @@
|
||||
//
|
||||
// NetworkBarItem.swift
|
||||
// MTMR
|
||||
//
|
||||
// Created by Anton Palgunov on 23/02/2019.
|
||||
// Copyright © 2019 Anton Palgunov. All rights reserved.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
|
||||
class NetworkBarItem: CustomButtonTouchBarItem, Widget {
|
||||
static var name: String = "network"
|
||||
static var identifier: String = "com.toxblh.mtmr.network"
|
||||
|
||||
private let flip: Bool
|
||||
|
||||
init(identifier: NSTouchBarItem.Identifier, flip: Bool = false) {
|
||||
self.flip = flip
|
||||
super.init(identifier: identifier, title: " ")
|
||||
startMonitoringProcess()
|
||||
}
|
||||
|
||||
required init?(coder _: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func startMonitoringProcess() {
|
||||
var pipe: Pipe
|
||||
var outputHandle: FileHandle
|
||||
var bandwidthProcess: Process?
|
||||
var dSpeed: UInt64?
|
||||
var uSpeed: UInt64?
|
||||
var curr: Array<Substring>?
|
||||
var dataAvailable: NSObjectProtocol!
|
||||
|
||||
pipe = Pipe()
|
||||
bandwidthProcess = Process()
|
||||
bandwidthProcess?.launchPath = "/usr/bin/env"
|
||||
bandwidthProcess?.arguments = ["netstat", "-w1", "-l", "en0"]
|
||||
bandwidthProcess?.standardOutput = pipe
|
||||
|
||||
outputHandle = pipe.fileHandleForReading
|
||||
outputHandle.waitForDataInBackgroundAndNotify(forModes: [RunLoop.Mode.common])
|
||||
|
||||
dataAvailable = NotificationCenter.default.addObserver(
|
||||
forName: NSNotification.Name.NSFileHandleDataAvailable,
|
||||
object: outputHandle,
|
||||
queue: nil
|
||||
) { _ -> Void in
|
||||
let data = pipe.fileHandleForReading.availableData
|
||||
if data.count > 0 {
|
||||
if let str = NSString(data: data, encoding: String.Encoding.utf8.rawValue) {
|
||||
curr = [""]
|
||||
curr = str
|
||||
.replacingOccurrences(of: " ", with: " ")
|
||||
.split(separator: " ")
|
||||
if curr == nil || (curr?.count)! < 6 {} else {
|
||||
if Int64(curr![2]) == nil {} else {
|
||||
dSpeed = UInt64(curr![2])
|
||||
uSpeed = UInt64(curr![5])
|
||||
|
||||
self.setTitle(up: self.getHumanizeSize(speed: uSpeed!), down: self.getHumanizeSize(speed: dSpeed!))
|
||||
}
|
||||
}
|
||||
}
|
||||
outputHandle.waitForDataInBackgroundAndNotify()
|
||||
} else {
|
||||
NotificationCenter.default.removeObserver(dataAvailable)
|
||||
}
|
||||
}
|
||||
|
||||
var dataReady: NSObjectProtocol!
|
||||
dataReady = NotificationCenter.default.addObserver(
|
||||
forName: Process.didTerminateNotification,
|
||||
object: outputHandle,
|
||||
queue: nil
|
||||
) { _ -> Void in
|
||||
print("Task terminated!")
|
||||
NotificationCenter.default.removeObserver(dataReady)
|
||||
}
|
||||
|
||||
bandwidthProcess?.launch()
|
||||
}
|
||||
|
||||
func getHumanizeSize(speed: UInt64) -> String {
|
||||
let humanText: String
|
||||
|
||||
if speed < 1024 {
|
||||
humanText = String(format: "%.0f", Double(speed)) + " B/s"
|
||||
} else if speed < (1024 * 1024) {
|
||||
humanText = String(format: "%.1f", Double(speed) / 1024) + " KB/s"
|
||||
} else if speed < (1024 * 1024 * 1024) {
|
||||
humanText = String(format: "%.1f", Double(speed) / (1024 * 1024)) + " MB/s"
|
||||
} else {
|
||||
humanText = String(format: "%.2f", Double(speed) / (1024 * 1024 * 1024)) + " GB/s"
|
||||
}
|
||||
|
||||
return humanText
|
||||
}
|
||||
|
||||
func appendUpSpeed(appendString: NSMutableAttributedString, up: String, titleFont: NSFont, newStr: Bool = false) {
|
||||
appendString.append(NSMutableAttributedString(
|
||||
string: newStr ? "\n↑" : "↑",
|
||||
attributes: [
|
||||
NSAttributedString.Key.foregroundColor: NSColor.blue,
|
||||
NSAttributedString.Key.font: titleFont,
|
||||
]))
|
||||
|
||||
appendString.append(NSMutableAttributedString(
|
||||
string: up,
|
||||
attributes: [
|
||||
NSAttributedString.Key.font: titleFont,
|
||||
]))
|
||||
}
|
||||
|
||||
func appendDownSpeed(appendString: NSMutableAttributedString, down: String, titleFont: NSFont, newStr: Bool = false) {
|
||||
appendString.append(NSMutableAttributedString(
|
||||
string: newStr ? "\n↓" : "↓",
|
||||
attributes: [
|
||||
NSAttributedString.Key.foregroundColor: NSColor.red,
|
||||
NSAttributedString.Key.font: titleFont,
|
||||
]))
|
||||
|
||||
appendString.append(NSMutableAttributedString(
|
||||
string: down,
|
||||
attributes: [
|
||||
NSAttributedString.Key.font: titleFont
|
||||
]))
|
||||
}
|
||||
|
||||
func setTitle(up: String, down: String) {
|
||||
let titleFont = NSFont.monospacedDigitSystemFont(ofSize: 12, weight: NSFont.Weight.light)
|
||||
|
||||
let newTitle: NSMutableAttributedString = NSMutableAttributedString(string: "")
|
||||
|
||||
if (self.flip) {
|
||||
appendUpSpeed(appendString: newTitle, up: up, titleFont: titleFont)
|
||||
appendDownSpeed(appendString: newTitle, down: down, titleFont: titleFont, newStr: true)
|
||||
} else {
|
||||
appendDownSpeed(appendString: newTitle, down: down, titleFont: titleFont)
|
||||
appendUpSpeed(appendString: newTitle, up: up, titleFont: titleFont, newStr: true)
|
||||
}
|
||||
|
||||
|
||||
self.attributedTitle = newTitle
|
||||
}
|
||||
}
|
||||
@@ -16,11 +16,11 @@ class PomodoroBarItem: CustomButtonTouchBarItem, Widget {
|
||||
case workTime
|
||||
case restTime
|
||||
}
|
||||
|
||||
|
||||
let container = try decoder.container(keyedBy: CodingKeys.self)
|
||||
let workTime = try container.decodeIfPresent(Double.self, forKey: .workTime)
|
||||
let restTime = try container.decodeIfPresent(Double.self, forKey: .restTime)
|
||||
|
||||
|
||||
return (
|
||||
item: .pomodoro(workTime: workTime ?? 1500.00, restTime: restTime ?? 300),
|
||||
action: .none,
|
||||
@@ -34,6 +34,7 @@ class PomodoroBarItem: CustomButtonTouchBarItem, Widget {
|
||||
case rest
|
||||
case none
|
||||
}
|
||||
|
||||
private let defaultTitle = "🍅"
|
||||
private let workTime: TimeInterval
|
||||
private let restTime: TimeInterval
|
||||
@@ -66,12 +67,12 @@ class PomodoroBarItem: CustomButtonTouchBarItem, Widget {
|
||||
typeTime = .work
|
||||
startStopTimer()
|
||||
}
|
||||
|
||||
|
||||
@objc func startStopRest() {
|
||||
typeTime = .rest
|
||||
startStopTimer()
|
||||
}
|
||||
|
||||
|
||||
func startStopTimer() {
|
||||
timer == nil ? start() : reset()
|
||||
}
|
||||
|
||||
@@ -9,5 +9,4 @@
|
||||
protocol Widget {
|
||||
static var name: String { get }
|
||||
static var identifier: String { get }
|
||||
static var decoder: ParametersDecoder { get }
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import XCTest
|
||||
|
||||
class AppleScriptDefinitionTests: XCTestCase {
|
||||
|
||||
func testInline() {
|
||||
let buttonNoActionFixture = """
|
||||
[ { "type": "appleScriptTitledButton", "source": { "inline": "tell everything fine" } } ]
|
||||
@@ -13,7 +12,7 @@ class AppleScriptDefinitionTests: XCTestCase {
|
||||
}
|
||||
XCTAssertEqual(source.string, "tell everything fine")
|
||||
}
|
||||
|
||||
|
||||
func testPath() {
|
||||
let buttonNoActionFixture = """
|
||||
[ { "type": "appleScriptTitledButton", "source": { "filePath": "/ololo/pew" } } ]
|
||||
@@ -26,7 +25,7 @@ class AppleScriptDefinitionTests: XCTestCase {
|
||||
let sourceStruct = source as? Source
|
||||
XCTAssertEqual(sourceStruct?.filePath, "/ololo/pew")
|
||||
}
|
||||
|
||||
|
||||
func testRefreshInterval() {
|
||||
let buttonNoActionFixture = """
|
||||
[ { "type": "appleScriptTitledButton", "source": { "inline": "tell everything fine" }, "refreshInterval": 305} ]
|
||||
@@ -37,5 +36,4 @@ class AppleScriptDefinitionTests: XCTestCase {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,29 +1,27 @@
|
||||
import XCTest
|
||||
|
||||
class BackgroundColorTests: XCTestCase {
|
||||
|
||||
func testOpaque() {
|
||||
let buttonNoActionFixture = """
|
||||
[ { "type": "staticButton", "title": "Pew", "background": "#FF0000" } ]
|
||||
""".data(using: .utf8)!
|
||||
let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonNoActionFixture)
|
||||
guard case .background(let color)? = result?.first?.additionalParameters[.background] else {
|
||||
guard case let .background(color)? = result?.first?.additionalParameters[.background] else {
|
||||
XCTFail()
|
||||
return
|
||||
}
|
||||
XCTAssertEqual(color, .red)
|
||||
}
|
||||
|
||||
|
||||
func testAlpha() {
|
||||
let buttonNoActionFixture = """
|
||||
[ { "type": "staticButton", "title": "Pew", "background": "#FF000080" } ]
|
||||
""".data(using: .utf8)!
|
||||
let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonNoActionFixture)
|
||||
guard case .background(let color)? = result?.first?.additionalParameters[.background] else {
|
||||
guard case let .background(color)? = result?.first?.additionalParameters[.background] else {
|
||||
XCTFail()
|
||||
return
|
||||
}
|
||||
XCTAssertEqual(color.alphaComponent, 0.5, accuracy: 0.01)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import XCTest
|
||||
|
||||
class ParseConfig: XCTestCase {
|
||||
|
||||
func testButtonNoAction() {
|
||||
let buttonNoActionFixture = """
|
||||
[ { "type": "staticButton", "title": "Pew" } ]
|
||||
@@ -31,7 +30,7 @@ class ParseConfig: XCTestCase {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testPredefinedItem() {
|
||||
let buttonKeycodeFixture = """
|
||||
[ { "type": "escape" } ]
|
||||
@@ -46,7 +45,7 @@ class ParseConfig: XCTestCase {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func testExtendedWidthForPredefinedItem() {
|
||||
let buttonKeycodeFixture = """
|
||||
[ { "type": "escape", "width": 110}, ]
|
||||
@@ -65,5 +64,4 @@ class ParseConfig: XCTestCase {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -31,6 +31,17 @@ My idea is to create a platform for creating plugins to customize the TouchBar.
|
||||
- Download lastest [release](https://github.com/Toxblh/MTMR/releases) from github
|
||||
- Or via Homebrew `brew cask install mtmr`
|
||||
|
||||
## Troubleshooting
|
||||
Problems:
|
||||
- "After the last update my mtmr is not working anymore!"
|
||||
- "Buttons sometimes do not trigger action"
|
||||
- "ESC don't work"
|
||||
- "Gestures don't work"
|
||||
|
||||
Re-tick or check a tick for access 🍏→ System Preferences → Security and Privacy → tab Privacy → Accessibility → MTMR
|
||||
|
||||
<img width="450" alt="screenshot 2019-02-24 at 23 19 20" src="https://user-images.githubusercontent.com/2198153/53307057-2b078200-388c-11e9-8212-8c2b1aff0aa6.png">
|
||||
|
||||
## Built-in button types:
|
||||
> Buttons
|
||||
- escape
|
||||
@@ -53,6 +64,7 @@ My idea is to create a platform for creating plugins to customize the TouchBar.
|
||||
- nightShift
|
||||
- dnd (Don't disturb)
|
||||
- pomodoro
|
||||
- network
|
||||
|
||||
> Media Keys
|
||||
- previous
|
||||
@@ -119,6 +131,16 @@ To close a group, use the button:
|
||||
```
|
||||
|
||||
## Native plugins
|
||||
#### `timeButton`
|
||||
> Attention! Works not all: https://en.wikipedia.org/wiki/List_of_time_zone_abbreviations
|
||||
```js
|
||||
{
|
||||
"type": "timeButton",
|
||||
"formatTemplate": "dd HH:mm",
|
||||
"timeZone": "UTC"
|
||||
}
|
||||
```
|
||||
|
||||
#### `weather`
|
||||
> Provider: https://openweathermap.org Need allowance location service
|
||||
```js
|
||||
@@ -161,6 +183,14 @@ To close a group, use the button:
|
||||
},
|
||||
```
|
||||
|
||||
#### `network`
|
||||
> Network plugin. The plugin to show usage a network
|
||||
```js
|
||||
{
|
||||
"type": "network",
|
||||
},
|
||||
```
|
||||
|
||||
## Actions:
|
||||
- `hidKey`
|
||||
> https://github.com/aosm/IOHIDFamily/blob/master/IOHIDSystem/IOKit/hidsystem/ev_keymap.h use only numbers
|
||||
|
||||
@@ -64,6 +64,7 @@ echo ""
|
||||
echo " version '${VERSION}'"
|
||||
echo " sha256 '${SHA256}'"
|
||||
echo ""
|
||||
echo "Update MTMR v${VERSION}"
|
||||
|
||||
scp MTMR\ ${VERSION}.dmg do:/var/www/mtmr
|
||||
scp appcast.xml do:/var/www/mtmr
|
||||
|
||||
@@ -1,8 +1,30 @@
|
||||
killall MTMR
|
||||
|
||||
NAME='MTMR'
|
||||
killall $NAME
|
||||
|
||||
rm -r Release 2>/dev/null
|
||||
|
||||
# xcodebuild \
|
||||
# -workspace ./MTMR.xcodeproj/project.xcworkspace \
|
||||
# -scheme MTMR \
|
||||
# -configuration Release CONFIGURATION_BUILD_DIR=./build/Release
|
||||
|
||||
xcodebuild archive \
|
||||
-scheme "$NAME" \
|
||||
-archivePath Release/App.xcarchive
|
||||
|
||||
xcodebuild \
|
||||
-workspace ./MTMR.xcodeproj/project.xcworkspace \
|
||||
-scheme MTMR \
|
||||
-configuration Release CONFIGURATION_BUILD_DIR=./build/Release
|
||||
-exportArchive \
|
||||
-archivePath Release/App.xcarchive \
|
||||
-exportOptionsPlist export-options.plist \
|
||||
-exportPath Release
|
||||
|
||||
open ./build/Release/MTMR.app
|
||||
cd Release
|
||||
rm -r App.xcarchive
|
||||
|
||||
# Prerequisite: npm i -g create-dmg
|
||||
NAME_DMG="${NAME}.app"
|
||||
echo $NAME_DMG
|
||||
create-dmg $NAME_DMG
|
||||
|
||||
open ./$NAME.app
|
||||
|
||||
Reference in New Issue
Block a user