Compare commits

...
Author SHA1 Message Date
toxblh b6721f0274 return normal trigggers in workflows 2020-05-14 00:05:17 +01:00
toxblh 75df82a567 ignore sign error 2020-05-13 23:34:45 +01:00
toxblh a1f64028cc Correct file for release 2020-05-13 23:23:03 +01:00
toxblh 3fc75ca8f0 Updated workflows. For delivery unsign app in gihub 2020-05-13 23:22:31 +01:00
toxblh 6d266394a4 Revert "More Productive Gestures (#289)"
This reverts commit f61550e510.
2020-05-13 23:11:45 +01:00
Fedor ZaytsevandFedor Zaitsev 52758f947d Fix shell crash (#297)
* Updated README

Added explanation for missing parameters (background, title and image)

* Implemented changable icons for AppleScriptTouchBarItem

AppleScriptTouchBarItem now allow to specify any number of icons which can be changed from the script. You cannot change icon from touch event. To change icon, you need to return array from your script with 2 values - title and icn name. More info in readme

* Fixed error related to ShellButton

When you execute Process from swift you cannot relay solely on pipe.fileHandleForReading.readDataToEndOfFile()
Sometimes when I close notebook I get exception saying that you cannot access process.terminationStatus variable while process is running.
Apparently it seems that this call can be finished when OS X put disks into sleep mode(?)

What I did:
1. Added Process.waitUntilExit() call
2. Added timeout (equal to the update interval)

Co-authored-by: Fedor Zaitsev <lobster@Fedors-MacBook-Pro.local>
2020-04-21 13:34:03 +01:00
Simon Rogersandmedden 502f989417 Currency bar update (#293)
* Updated CurrenyBarItem to display second currency (TO FROM>RATE) and also correct number of decimal places.
Added INR to list of currencies.

* Update CurrencyBarItem.swift

* Updated else statements

Co-authored-by: medden <si@medden.co.uk>
2020-04-09 18:49:39 +01:00
Jæy f61550e510 More Productive Gestures (#289)
* Scroll Functionality Works

* updated md

* Update README.md

* Update README.md

* attempted to fix readme

* fixed readme

* fixed readme
2020-04-09 00:24:43 +01:00
Fedor ZaytsevandFedor Zaitsev a0fc0b33c5 Custom gestures support (#288)
* Updated README

Added explanation for missing parameters (background, title and image)

* Implemented changable icons for AppleScriptTouchBarItem

AppleScriptTouchBarItem now allow to specify any number of icons which can be changed from the script. You cannot change icon from touch event. To change icon, you need to return array from your script with 2 values - title and icn name. More info in readme

* Implemented custom swipe actions

Co-authored-by: Fedor Zaitsev <lobster@Fedors-MacBook-Pro.local>
2020-04-01 22:11:35 +01:00
Peter Hrvola 42ce95b72e Add Music app (#279) 2020-03-16 12:06:20 +00:00
Fedor Zaytsev 642f0807bb Changeable icons for AppleScriptTouchBarItem & tests (#276)
* Implemented changable icons for AppleScriptTouchBarItem

AppleScriptTouchBarItem now allow to specify any number of icons which can be changed from the script. You cannot change icon from touch event. To change icon, you need to return array from your script with 2 values - title and icn name. More info in readme

* Fixed tests

Some tests started to fail after implementing alternativeIcons field for appleScriptBarItem
2020-02-29 11:23:40 +00:00
Fedor Zaytsev dbb2f16222 Implemented changable icons for AppleScriptTouchBarItem (#275)
AppleScriptTouchBarItem now allow to specify any number of icons which can be changed from the script. You cannot change icon from touch event. To change icon, you need to return array from your script with 2 values - title and icn name. More info in readme
2020-02-28 21:59:14 +00:00
Anton Palgunov 3864591777 Update build-test.yml 2020-02-28 21:27:09 +00:00
Fedor Zaytsev 7e0db70fab Updated README (#274)
Added explanation for missing parameters (background, title and image)
2020-02-28 19:35:09 +00:00
Anton Palgunov 40c684f528 GitHub actions (#271)
* build xcode
* final build test
* delete travisCI
2020-02-11 23:44:19 +00:00
Anton Palgunov 093faa2c02 Create swift.yml 2020-01-14 10:24:24 +00:00
Anton Palgunov aeee9983d1 Merge pull request #260 from samflattery/master
fix pomodoro icon not showing up on catalina
2020-01-08 14:57:23 +00:00
Sam Flattery bdfb7118c9 fix pomodoro icon not showing up on catalina 2020-01-06 19:17:29 +00:00
Anton Palgunov 878cd346c1 Merge pull request #256 from bobrosoft/master
YandexWeather: update matching array with English translations as some users getting English version instead of Russian
2019-12-30 09:18:09 +00:00
bobrosoft 712448f207 YandexWeather: update matching array with English translations as some users getting English version instead of Russian 2019-12-30 11:51:27 +04:00
toxblh e9e5a6f739 fix yandex wheather, for correct lang 2019-11-26 17:33:18 +03:00
23 changed files with 560 additions and 137 deletions
+22
View File
@@ -0,0 +1,22 @@
name: Build-and-test
on: [push, pull_request]
jobs:
test:
runs-on: macOS-latest
steps:
- uses: actions/checkout@v1
- name: Run tests
run: xcodebuild test -project MTMR.xcodeproj -scheme 'UnitTests' | xcpretty -c && exit ${PIPESTATUS[0]}
build:
runs-on: macOS-latest
steps:
- uses: actions/checkout@v1
- name: Build
run: xcodebuild archive -project "MTMR.xcodeproj" -scheme "MTMR" -archivePath Release/App.xcarchive DEVELOPMENT_TEAM="" CODE_SIGN_IDENTITY="" | xcpretty -c && exit ${PIPESTATUS[0]}
+41
View File
@@ -0,0 +1,41 @@
name: Publish unsign version
on:
push:
branches:
- master
tags:
- "v*"
jobs:
Build-and-release:
runs-on: macOS-latest
steps:
- uses: actions/checkout@v1
- name: Set up Node.js
uses: actions/setup-node@v1
with:
node-version: 12.x
- name: Install create-dmg
run: npm i -g create-dmg
- name: Build Archive
run: xcodebuild archive -project "MTMR.xcodeproj" -scheme "MTMR" -archivePath Release/App.xcarchive DEVELOPMENT_TEAM="" CODE_SIGN_IDENTITY="" | xcpretty -c && exit ${PIPESTATUS[0]}
- name: Build App
run: xcodebuild -project "MTMR.xcodeproj" -exportArchive -archivePath Release/App.xcarchive -exportOptionsPlist export-options.plist -exportPath Release | xcpretty -c && exit ${PIPESTATUS[0]}
- name: Create DMG
run: |
cd Release
create-dmg MTMR.app || true
- name: GitHub Release
uses: "marvinpinto/action-automatic-releases@latest"
with:
repo_token: "${{ secrets.GITHUB_TOKEN }}"
prerelease: false
files: Release/MTMR*.dmg
-6
View File
@@ -1,6 +0,0 @@
language: swift
xcode_project: MTMR.xcodeproj
xcode_scheme: UnitTests
osx_image: xcode11.1
install: gem install xcpretty
script: "xcodebuild test -project MTMR.xcodeproj -scheme 'UnitTests' | xcpretty -c && exit ${PIPESTATUS[0]}"
+16
View File
@@ -22,6 +22,8 @@
4CC9FEDC22FDEA65001512EB /* AMR_ANSIEscapeHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC9FEDB22FDEA65001512EB /* AMR_ANSIEscapeHelper.m */; }; 4CC9FEDC22FDEA65001512EB /* AMR_ANSIEscapeHelper.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CC9FEDB22FDEA65001512EB /* AMR_ANSIEscapeHelper.m */; };
4CDC6E5022FCA93F0069ADD4 /* ShellScriptTouchBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDC6E4F22FCA93F0069ADD4 /* ShellScriptTouchBarItem.swift */; }; 4CDC6E5022FCA93F0069ADD4 /* ShellScriptTouchBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CDC6E4F22FCA93F0069ADD4 /* ShellScriptTouchBarItem.swift */; };
4CFF5E5C22E623DD00BFB1EE /* YandexWeatherBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF5E5B22E623DD00BFB1EE /* YandexWeatherBarItem.swift */; }; 4CFF5E5C22E623DD00BFB1EE /* YandexWeatherBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4CFF5E5B22E623DD00BFB1EE /* YandexWeatherBarItem.swift */; };
5DC6CA02241F92CB005CD5E8 /* Music.nowPlaying.scpt in Resources */ = {isa = PBXBuildFile; fileRef = 5DC6CA00241F92CB005CD5E8 /* Music.nowPlaying.scpt */; };
5DC6CA03241F92CB005CD5E8 /* Music.next.scpt in Resources */ = {isa = PBXBuildFile; fileRef = 5DC6CA01241F92CB005CD5E8 /* Music.next.scpt */; };
60173D3E20C0031B002C305F /* LaunchAtLoginController.m in Sources */ = {isa = PBXBuildFile; fileRef = 60173D3D20C0031B002C305F /* LaunchAtLoginController.m */; }; 60173D3E20C0031B002C305F /* LaunchAtLoginController.m in Sources */ = {isa = PBXBuildFile; fileRef = 60173D3D20C0031B002C305F /* LaunchAtLoginController.m */; };
6027D1B92080E52A004FFDC7 /* BrightnessViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6027D1B72080E52A004FFDC7 /* BrightnessViewController.swift */; }; 6027D1B92080E52A004FFDC7 /* BrightnessViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6027D1B72080E52A004FFDC7 /* BrightnessViewController.swift */; };
6027D1BA2080E52A004FFDC7 /* VolumeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6027D1B82080E52A004FFDC7 /* VolumeViewController.swift */; }; 6027D1BA2080E52A004FFDC7 /* VolumeViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6027D1B82080E52A004FFDC7 /* VolumeViewController.swift */; };
@@ -67,6 +69,8 @@
B0F3112520C9E35F0076BB88 /* SupportNSTouchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0F3112420C9E35F0076BB88 /* SupportNSTouchBar.swift */; }; B0F3112520C9E35F0076BB88 /* SupportNSTouchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0F3112420C9E35F0076BB88 /* SupportNSTouchBar.swift */; };
B0F54A7A2295AC7D00B4C509 /* DarkModeBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0F54A792295AC7D00B4C509 /* DarkModeBarItem.swift */; }; B0F54A7A2295AC7D00B4C509 /* DarkModeBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = B0F54A792295AC7D00B4C509 /* DarkModeBarItem.swift */; };
B0F8771A207AC1EA00D6E430 /* TouchBarSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = B0F87719207AC1EA00D6E430 /* TouchBarSupport.m */; }; B0F8771A207AC1EA00D6E430 /* TouchBarSupport.m in Sources */ = {isa = PBXBuildFile; fileRef = B0F87719207AC1EA00D6E430 /* TouchBarSupport.m */; };
BAF5AB5724317B4300B04904 /* BasicView.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAF5AB5624317B4300B04904 /* BasicView.swift */; };
BAF5AB5924317CAF00B04904 /* SwipeItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = BAF5AB5824317CAF00B04904 /* SwipeItem.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
@@ -100,6 +104,8 @@
4CC9FEDB22FDEA65001512EB /* AMR_ANSIEscapeHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AMR_ANSIEscapeHelper.m; sourceTree = "<group>"; }; 4CC9FEDB22FDEA65001512EB /* AMR_ANSIEscapeHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AMR_ANSIEscapeHelper.m; sourceTree = "<group>"; };
4CDC6E4F22FCA93F0069ADD4 /* ShellScriptTouchBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShellScriptTouchBarItem.swift; sourceTree = "<group>"; }; 4CDC6E4F22FCA93F0069ADD4 /* ShellScriptTouchBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShellScriptTouchBarItem.swift; sourceTree = "<group>"; };
4CFF5E5B22E623DD00BFB1EE /* YandexWeatherBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YandexWeatherBarItem.swift; sourceTree = "<group>"; }; 4CFF5E5B22E623DD00BFB1EE /* YandexWeatherBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = YandexWeatherBarItem.swift; sourceTree = "<group>"; };
5DC6CA00241F92CB005CD5E8 /* Music.nowPlaying.scpt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Music.nowPlaying.scpt; sourceTree = "<group>"; };
5DC6CA01241F92CB005CD5E8 /* Music.next.scpt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = Music.next.scpt; sourceTree = "<group>"; };
60173D3C20C0031B002C305F /* LaunchAtLoginController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LaunchAtLoginController.h; sourceTree = "<group>"; }; 60173D3C20C0031B002C305F /* LaunchAtLoginController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LaunchAtLoginController.h; sourceTree = "<group>"; };
60173D3D20C0031B002C305F /* LaunchAtLoginController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LaunchAtLoginController.m; sourceTree = "<group>"; }; 60173D3D20C0031B002C305F /* LaunchAtLoginController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = LaunchAtLoginController.m; sourceTree = "<group>"; };
6027D1B72080E52A004FFDC7 /* BrightnessViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrightnessViewController.swift; sourceTree = "<group>"; }; 6027D1B72080E52A004FFDC7 /* BrightnessViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BrightnessViewController.swift; sourceTree = "<group>"; };
@@ -155,6 +161,8 @@
B0F54A792295AC7D00B4C509 /* DarkModeBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DarkModeBarItem.swift; sourceTree = "<group>"; }; B0F54A792295AC7D00B4C509 /* DarkModeBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DarkModeBarItem.swift; sourceTree = "<group>"; };
B0F87719207AC1EA00D6E430 /* TouchBarSupport.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TouchBarSupport.m; sourceTree = "<group>"; }; B0F87719207AC1EA00D6E430 /* TouchBarSupport.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TouchBarSupport.m; sourceTree = "<group>"; };
B0F8771B207AC92700D6E430 /* TouchBarSupport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TouchBarSupport.h; sourceTree = "<group>"; }; B0F8771B207AC92700D6E430 /* TouchBarSupport.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TouchBarSupport.h; sourceTree = "<group>"; };
BAF5AB5624317B4300B04904 /* BasicView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasicView.swift; sourceTree = "<group>"; };
BAF5AB5824317CAF00B04904 /* SwipeItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwipeItem.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
@@ -230,8 +238,10 @@
36FEF871235A1CFC00A0ABCE /* AppSettings.swift */, 36FEF871235A1CFC00A0ABCE /* AppSettings.swift */,
B059D623205E04F3006E6B86 /* CustomButtonTouchBarItem.swift */, B059D623205E04F3006E6B86 /* CustomButtonTouchBarItem.swift */,
36C2ECD8207B74B4003CDA33 /* AppleScriptTouchBarItem.swift */, 36C2ECD8207B74B4003CDA33 /* AppleScriptTouchBarItem.swift */,
BAF5AB5824317CAF00B04904 /* SwipeItem.swift */,
4CDC6E4F22FCA93F0069ADD4 /* ShellScriptTouchBarItem.swift */, 4CDC6E4F22FCA93F0069ADD4 /* ShellScriptTouchBarItem.swift */,
B059D621205E03F5006E6B86 /* TouchBarController.swift */, B059D621205E03F5006E6B86 /* TouchBarController.swift */,
BAF5AB5624317B4300B04904 /* BasicView.swift */,
36C2ECDA207C3FE7003CDA33 /* ItemsParsing.swift */, 36C2ECDA207C3FE7003CDA33 /* ItemsParsing.swift */,
B0008E542080286C003AD4DD /* SupportHelpers.swift */, B0008E542080286C003AD4DD /* SupportHelpers.swift */,
B09EB1E3207C082000D5C1E0 /* HapticFeedback.swift */, B09EB1E3207C082000D5C1E0 /* HapticFeedback.swift */,
@@ -258,6 +268,8 @@
B0B17426207D6AFE0004B740 /* AppleScripts */ = { B0B17426207D6AFE0004B740 /* AppleScripts */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
5DC6CA01241F92CB005CD5E8 /* Music.next.scpt */,
5DC6CA00241F92CB005CD5E8 /* Music.nowPlaying.scpt */,
B0B1742A207D6B580004B740 /* Battery.scpt */, B0B1742A207D6B580004B740 /* Battery.scpt */,
B0B17429207D6B580004B740 /* Finder.scpt */, B0B17429207D6B580004B740 /* Finder.scpt */,
B0B1742C207D6B590004B740 /* iTunes.next.scpt */, B0B1742C207D6B590004B740 /* iTunes.next.scpt */,
@@ -407,6 +419,8 @@
B0B1743A207D6B590004B740 /* iTunes.nowPlaying.scpt in Resources */, B0B1743A207D6B590004B740 /* iTunes.nowPlaying.scpt in Resources */,
B082B257205C7D8000BC04DC /* Assets.xcassets in Resources */, B082B257205C7D8000BC04DC /* Assets.xcassets in Resources */,
B0B17437207D6B590004B740 /* Spotify.nowPlaying.scpt in Resources */, B0B17437207D6B590004B740 /* Spotify.nowPlaying.scpt in Resources */,
5DC6CA02241F92CB005CD5E8 /* Music.nowPlaying.scpt in Resources */,
5DC6CA03241F92CB005CD5E8 /* Music.next.scpt in Resources */,
B0B17436207D6B590004B740 /* iTunes.next.scpt in Resources */, B0B17436207D6B590004B740 /* iTunes.next.scpt in Resources */,
B082B25A205C7D8000BC04DC /* Main.storyboard in Resources */, B082B25A205C7D8000BC04DC /* Main.storyboard in Resources */,
B0B17435207D6B590004B740 /* Spotify.next.scpt in Resources */, B0B17435207D6B590004B740 /* Spotify.next.scpt in Resources */,
@@ -457,11 +471,13 @@
B059D622205E03F5006E6B86 /* TouchBarController.swift in Sources */, B059D622205E03F5006E6B86 /* TouchBarController.swift in Sources */,
B05600D32083E9BB00EB218D /* CustomSlider.swift in Sources */, B05600D32083E9BB00EB218D /* CustomSlider.swift in Sources */,
36C2ECD9207B74B4003CDA33 /* AppleScriptTouchBarItem.swift in Sources */, 36C2ECD9207B74B4003CDA33 /* AppleScriptTouchBarItem.swift in Sources */,
BAF5AB5724317B4300B04904 /* BasicView.swift in Sources */,
B0846A752220C968000288A7 /* NetworkBarItem.swift in Sources */, B0846A752220C968000288A7 /* NetworkBarItem.swift in Sources */,
B0F8771A207AC1EA00D6E430 /* TouchBarSupport.m in Sources */, B0F8771A207AC1EA00D6E430 /* TouchBarSupport.m in Sources */,
B08126F1217BE19000A98970 /* WidgetProtocol.swift in Sources */, B08126F1217BE19000A98970 /* WidgetProtocol.swift in Sources */,
B0008E552080286C003AD4DD /* SupportHelpers.swift in Sources */, B0008E552080286C003AD4DD /* SupportHelpers.swift in Sources */,
6042B6A72083E03A00C525C8 /* AppScrubberTouchBarItem.swift in Sources */, 6042B6A72083E03A00C525C8 /* AppScrubberTouchBarItem.swift in Sources */,
BAF5AB5924317CAF00B04904 /* SwipeItem.swift in Sources */,
B082B253205C7D8000BC04DC /* AppDelegate.swift in Sources */, B082B253205C7D8000BC04DC /* AppDelegate.swift in Sources */,
B0F54A7A2295AC7D00B4C509 /* DarkModeBarItem.swift in Sources */, B0F54A7A2295AC7D00B4C509 /* DarkModeBarItem.swift in Sources */,
B08126EF217BD0B900A98970 /* PomodoroBarItem.swift in Sources */, B08126EF217BD0B900A98970 /* PomodoroBarItem.swift in Sources */,
+1 -1
View File
@@ -92,7 +92,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
@objc func toggleMultitouch(_ item: NSMenuItem) { @objc func toggleMultitouch(_ item: NSMenuItem) {
item.state = item.state == .on ? .off : .on item.state = item.state == .on ? .off : .on
AppSettings.multitouchGestures = item.state == .on AppSettings.multitouchGestures = item.state == .on
TouchBarController.shared.scrollArea?.gesturesEnabled = item.state == .on TouchBarController.shared.basicView?.legacyGesturesEnabled = item.state == .on
} }
@objc func openPreset(_: Any?) { @objc func openPreset(_: Any?) {
+25 -1
View File
@@ -4,9 +4,11 @@ class AppleScriptTouchBarItem: CustomButtonTouchBarItem {
private var script: NSAppleScript! private var script: NSAppleScript!
private let interval: TimeInterval private let interval: TimeInterval
private var forceHideConstraint: NSLayoutConstraint! private var forceHideConstraint: NSLayoutConstraint!
private let alternativeImages: [String: SourceProtocol]
init?(identifier: NSTouchBarItem.Identifier, source: SourceProtocol, interval: TimeInterval) { init?(identifier: NSTouchBarItem.Identifier, source: SourceProtocol, interval: TimeInterval, alternativeImages: [String: SourceProtocol]) {
self.interval = interval self.interval = interval
self.alternativeImages = alternativeImages
super.init(identifier: identifier, title: "⏳") super.init(identifier: identifier, title: "⏳")
forceHideConstraint = view.widthAnchor.constraint(equalToConstant: 0) forceHideConstraint = view.widthAnchor.constraint(equalToConstant: 0)
title = "scheduled" title = "scheduled"
@@ -57,6 +59,16 @@ class AppleScriptTouchBarItem: CustomButtonTouchBarItem {
} }
} }
func updateIcon(iconLabel: String) {
if alternativeImages[iconLabel] != nil {
DispatchQueue.main.async {
self.image = self.alternativeImages[iconLabel]!.image
}
} else {
print("Cannot find icon with label \"\(iconLabel)\"")
}
}
func execute() -> String { func execute() -> String {
var error: NSDictionary? var error: NSDictionary?
let output = script.executeAndReturnError(&error) let output = script.executeAndReturnError(&error)
@@ -64,6 +76,18 @@ class AppleScriptTouchBarItem: CustomButtonTouchBarItem {
print(error) print(error)
return "error" return "error"
} }
if output.descriptorType == typeAEList {
let arr = Array(1...output.numberOfItems).compactMap({ output.atIndex($0)!.stringValue ?? "" })
if arr.count <= 0 {
return ""
} else if arr.count == 1 {
return arr[0]
} else {
updateIcon(iconLabel: arr[1])
return arr[0]
}
}
return output.stringValue ?? "" return output.stringValue ?? ""
} }
} }
+7
View File
@@ -0,0 +1,7 @@
if application "Music" is running then
tell application "Music"
if player state is playing then
next track
end if
end tell
end if
+10
View File
@@ -0,0 +1,10 @@
if application "Music" is running then
tell application "Music"
if player state is playing then
return (get artist of current track) & " – " & (get name of current track)
else
return ""
end if
end tell
end if
return ""
+4
View File
@@ -2,6 +2,10 @@ if application "iTunes" is running then
tell application "iTunes" to playpause tell application "iTunes" to playpause
end if end if
if application "Music" is running then
tell application "Music" to playpause
end if
if application "Spotify" is running then if application "Spotify" is running then
tell application "Spotify" to playpause tell application "Spotify" to playpause
end if end if
+107
View File
@@ -0,0 +1,107 @@
//
// BasicView.swift
// MTMR
//
// Created by Fedor Zaitsev on 3/29/20.
// Copyright © 2020 Anton Palgunov. All rights reserved.
//
import Foundation
class BasicView: NSCustomTouchBarItem, NSGestureRecognizerDelegate {
var twofingers: NSPanGestureRecognizer!
var threefingers: NSPanGestureRecognizer!
var fourfingers: NSPanGestureRecognizer!
var swipeItems: [SwipeItem] = []
var prevPositions: [Int: CGFloat] = [2:0, 3:0, 4:0]
// legacy gesture positions
// by legacy I mean gestures to increse/decrease volume/brigtness which can be checked from app menu
var legacyPrevPositions: [Int: CGFloat] = [2:0, 3:0, 4:0]
var legacyGesturesEnabled = false
init(identifier: NSTouchBarItem.Identifier, items: [NSTouchBarItem], swipeItems: [SwipeItem]) {
super.init(identifier: identifier)
self.swipeItems = swipeItems
let views = items.compactMap { $0.view }
let stackView = NSStackView(views: views)
stackView.spacing = 1
stackView.orientation = .horizontal
view = stackView
twofingers = NSPanGestureRecognizer(target: self, action: #selector(twofingersHandler(_:)))
twofingers.numberOfTouchesRequired = 2
twofingers.allowedTouchTypes = .direct
view.addGestureRecognizer(twofingers)
threefingers = NSPanGestureRecognizer(target: self, action: #selector(threefingersHandler(_:)))
threefingers.numberOfTouchesRequired = 3
threefingers.allowedTouchTypes = .direct
view.addGestureRecognizer(threefingers)
fourfingers = NSPanGestureRecognizer(target: self, action: #selector(fourfingersHandler(_:)))
fourfingers.numberOfTouchesRequired = 4
fourfingers.allowedTouchTypes = .direct
view.addGestureRecognizer(fourfingers)
}
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func gestureHandler(position: CGFloat, fingers: Int, state: NSGestureRecognizer.State) {
switch state {
case .began:
prevPositions[fingers] = position
legacyPrevPositions[fingers] = position
case .changed:
if self.legacyGesturesEnabled {
if fingers == 2 {
let prevPos = legacyPrevPositions[fingers]!
if ((position - prevPos) > 10) || ((prevPos - position) > 10) {
if position > prevPos {
HIDPostAuxKey(NX_KEYTYPE_SOUND_UP)
} else if position < prevPos {
HIDPostAuxKey(NX_KEYTYPE_SOUND_DOWN)
}
legacyPrevPositions[fingers] = position
}
}
if fingers == 3 {
let prevPos = legacyPrevPositions[fingers]!
if ((position - prevPos) > 15) || ((prevPos - position) > 15) {
if position > prevPos {
GenericKeyPress(keyCode: CGKeyCode(144)).send()
} else if position < prevPos {
GenericKeyPress(keyCode: CGKeyCode(145)).send()
}
legacyPrevPositions[fingers] = position
}
}
}
case .ended:
print("gesture ended \(position - prevPositions[fingers]!) \(fingers)")
for item in swipeItems {
item.processEvent(offset: position - prevPositions[fingers]!, fingers: fingers)
}
default:
break
}
}
@objc func twofingersHandler(_ sender: NSGestureRecognizer?) {
let position = (sender?.location(in: sender?.view).x)!
self.gestureHandler(position: position, fingers: 2, state: sender!.state)
}
@objc func threefingersHandler(_ sender: NSGestureRecognizer?) {
let position = (sender?.location(in: sender?.view).x)!
self.gestureHandler(position: position, fingers: 3, state: sender!.state)
}
@objc func fourfingersHandler(_ sender: NSGestureRecognizer?) {
let position = (sender?.location(in: sender?.view).x)!
self.gestureHandler(position: position, fingers: 4, state: sender!.state)
}
}
+2 -2
View File
@@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key> <key>CFBundleShortVersionString</key>
<string>0.25</string> <string>0.25</string>
<key>CFBundleVersion</key> <key>CFBundleVersion</key>
<string>297</string> <string>385</string>
<key>LSApplicationCategoryType</key> <key>LSApplicationCategoryType</key>
<string>public.app-category.utilities</string> <string>public.app-category.utilities</string>
<key>LSMinimumSystemVersion</key> <key>LSMinimumSystemVersion</key>
@@ -39,7 +39,7 @@
<key>NSHomeKitUsageDescription</key> <key>NSHomeKitUsageDescription</key>
<string>MTMR needs access to HomeKit for work</string> <string>MTMR needs access to HomeKit for work</string>
<key>NSHumanReadableCopyright</key> <key>NSHumanReadableCopyright</key>
<string>Copyright © 2018 Anton Palgunov. All rights reserved.</string> <string>Copyright © 2018 - 2020 Anton Palgunov. All rights reserved.</string>
<key>NSLocationAlwaysAndWhenInUseUsageDescription</key> <key>NSLocationAlwaysAndWhenInUseUsageDescription</key>
<string>Weather widget need your location for correct work</string> <string>Weather widget need your location for correct work</string>
<key>NSLocationAlwaysUsageDescription</key> <key>NSLocationAlwaysUsageDescription</key>
+19 -2
View File
@@ -208,7 +208,7 @@ class SupportedTypesHolder {
enum ItemType: Decodable { enum ItemType: Decodable {
case staticButton(title: String) case staticButton(title: String)
case appleScriptTitledButton(source: SourceProtocol, refreshInterval: Double) case appleScriptTitledButton(source: SourceProtocol, refreshInterval: Double, alternativeImages: [String: SourceProtocol])
case shellScriptTitledButton(source: SourceProtocol, refreshInterval: Double) case shellScriptTitledButton(source: SourceProtocol, refreshInterval: Double)
case timeButton(formatTemplate: String, timeZone: String?, locale: String?) case timeButton(formatTemplate: String, timeZone: String?, locale: String?)
case battery case battery
@@ -226,6 +226,7 @@ enum ItemType: Decodable {
case pomodoro(workTime: Double, restTime: Double) case pomodoro(workTime: Double, restTime: Double)
case network(flip: Bool) case network(flip: Bool)
case darkMode case darkMode
case swipe(direction: String, fingers: Int, minOffset: Float, sourceApple: SourceProtocol?, sourceBash: SourceProtocol?)
private enum CodingKeys: String, CodingKey { private enum CodingKeys: String, CodingKey {
case type case type
@@ -251,6 +252,12 @@ enum ItemType: Decodable {
case autoResize case autoResize
case filter case filter
case disableMarquee case disableMarquee
case alternativeImages
case sourceApple
case sourceBash
case direction
case fingers
case minOffset
} }
enum ItemTypeRaw: String, Decodable { enum ItemTypeRaw: String, Decodable {
@@ -273,6 +280,7 @@ enum ItemType: Decodable {
case pomodoro case pomodoro
case network case network
case darkMode case darkMode
case swipe
} }
init(from decoder: Decoder) throws { init(from decoder: Decoder) throws {
@@ -282,7 +290,8 @@ enum ItemType: Decodable {
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) let alternativeImages = try container.decodeIfPresent([String: Source].self, forKey: .alternativeImages) ?? [:]
self = .appleScriptTitledButton(source: source, refreshInterval: interval, alternativeImages: alternativeImages)
case .shellScriptTitledButton: case .shellScriptTitledButton:
let source = try container.decode(Source.self, forKey: .source) let source = try container.decode(Source.self, forKey: .source)
@@ -361,6 +370,14 @@ enum ItemType: Decodable {
case .darkMode: case .darkMode:
self = .darkMode self = .darkMode
case .swipe:
let sourceApple = try container.decodeIfPresent(Source.self, forKey: .sourceApple)
let sourceBash = try container.decodeIfPresent(Source.self, forKey: .sourceBash)
let direction = try container.decode(String.self, forKey: .direction)
let fingers = try container.decode(Int.self, forKey: .fingers)
let minOffset = try container.decodeIfPresent(Float.self, forKey: .minOffset) ?? 0.0
self = .swipe(direction: direction, fingers: fingers, minOffset: minOffset, sourceApple: sourceApple, sourceBash: sourceBash)
} }
} }
} }
+1 -65
View File
@@ -1,10 +1,6 @@
import Foundation import Foundation
class ScrollViewItem: NSCustomTouchBarItem, NSGestureRecognizerDelegate { class ScrollViewItem: NSCustomTouchBarItem/*, NSGestureRecognizerDelegate*/ {
var twofingersPrev: CGFloat = 0.0
var threefingersPrev: CGFloat = 0.0
var twofingers: NSPanGestureRecognizer!
var threefingers: NSPanGestureRecognizer!
init(identifier: NSTouchBarItem.Identifier, items: [NSTouchBarItem]) { init(identifier: NSTouchBarItem.Identifier, items: [NSTouchBarItem]) {
super.init(identifier: identifier) super.init(identifier: identifier)
@@ -15,70 +11,10 @@ class ScrollViewItem: NSCustomTouchBarItem, NSGestureRecognizerDelegate {
let scrollView = NSScrollView(frame: CGRect(origin: .zero, size: stackView.fittingSize)) let scrollView = NSScrollView(frame: CGRect(origin: .zero, size: stackView.fittingSize))
scrollView.documentView = stackView scrollView.documentView = stackView
view = scrollView view = scrollView
twofingers = NSPanGestureRecognizer(target: self, action: #selector(twofingersHandler(_:)))
twofingers.allowedTouchTypes = .direct
twofingers.numberOfTouchesRequired = 2
view.addGestureRecognizer(twofingers)
threefingers = NSPanGestureRecognizer(target: self, action: #selector(threefingersHandler(_:)))
threefingers.allowedTouchTypes = .direct
threefingers.numberOfTouchesRequired = 3
view.addGestureRecognizer(threefingers)
}
var gesturesEnabled = true {
didSet {
twofingers.isEnabled = gesturesEnabled
threefingers.isEnabled = gesturesEnabled
}
} }
required init?(coder _: NSCoder) { required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented") fatalError("init(coder:) has not been implemented")
} }
@objc func twofingersHandler(_ sender: NSGestureRecognizer?) { // Volume
let position = (sender?.location(in: sender?.view).x)!
switch sender!.state {
case .began:
twofingersPrev = position
case .changed:
if ((position - twofingersPrev) > 10) || ((twofingersPrev - position) > 10) {
if position > twofingersPrev {
HIDPostAuxKey(NX_KEYTYPE_SOUND_UP)
} else if position < twofingersPrev {
HIDPostAuxKey(NX_KEYTYPE_SOUND_DOWN)
}
twofingersPrev = position
}
case .ended:
twofingersPrev = 0.0
default:
break
}
}
@objc func threefingersHandler(_ sender: NSGestureRecognizer?) { // Brightness
let position = (sender?.location(in: sender?.view).x)!
switch sender!.state {
case .began:
threefingersPrev = position
case .changed:
if ((position - threefingersPrev) > 15) || ((threefingersPrev - position) > 15) {
if position > threefingersPrev {
GenericKeyPress(keyCode: CGKeyCode(144)).send()
} else if position < threefingersPrev {
GenericKeyPress(keyCode: CGKeyCode(145)).send()
}
threefingersPrev = position
}
case .ended:
threefingersPrev = 0.0
default:
break
}
}
} }
+8
View File
@@ -62,11 +62,19 @@ class ShellScriptTouchBarItem: CustomButtonTouchBarItem {
let pipe = Pipe() let pipe = Pipe()
task.standardOutput = pipe task.standardOutput = pipe
// kill process if it is over update interval
DispatchQueue.main.asyncAfter(deadline: .now() + interval) { [weak task] in
task?.terminate()
}
task.launch() task.launch()
let data = pipe.fileHandleForReading.readDataToEndOfFile() let data = pipe.fileHandleForReading.readDataToEndOfFile()
var output: String = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as String? ?? "" var output: String = NSString(data: data, encoding: String.Encoding.utf8.rawValue) as String? ?? ""
//always wait until task end or you can catch "task still running" error while accessing task.terminationStatus variable
task.waitUntilExit()
if (output == "" && task.terminationStatus != 0) { if (output == "" && task.terminationStatus != 0) {
output = "error" output = "error"
} }
+66
View File
@@ -0,0 +1,66 @@
//
// SwipeItem.swift
// MTMR
//
// Created by Fedor Zaitsev on 3/29/20.
// Copyright © 2020 Anton Palgunov. All rights reserved.
//
import Foundation
import Foundation
class SwipeItem: NSCustomTouchBarItem {
private var scriptApple: NSAppleScript?
private var scriptBash: String?
private var direction: String
private var fingers: Int
private var minOffset: Float
init?(identifier: NSTouchBarItem.Identifier, direction: String, fingers: Int, minOffset: Float, sourceApple: SourceProtocol?, sourceBash: SourceProtocol?) {
self.direction = direction
self.fingers = fingers
self.scriptBash = sourceBash?.string
self.scriptApple = sourceApple?.appleScript
self.minOffset = minOffset
super.init(identifier: identifier)
}
required init?(coder _: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
func processEvent(offset: CGFloat, fingers: Int) {
if direction == "right" && Float(offset) > self.minOffset && self.fingers == fingers {
self.execute()
}
if direction == "left" && Float(offset) < -self.minOffset && self.fingers == fingers {
self.execute()
}
}
func execute() {
if scriptApple != nil {
DispatchQueue.appleScriptQueue.async {
var error: NSDictionary?
self.scriptApple?.executeAndReturnError(&error)
if let error = error {
print("SwipeItem apple script error: \(error)")
return
}
}
}
if scriptBash != nil {
DispatchQueue.shellScriptQueue.async {
let task = Process()
task.launchPath = "/bin/bash"
task.arguments = ["-c", self.scriptBash!]
task.launch()
task.waitUntilExit()
if (task.terminationStatus != 0) {
print("SwipeItem bash script error. Status: \(task.terminationStatus)")
}
}
}
}
}
+32 -23
View File
@@ -57,6 +57,8 @@ extension ItemType {
return NetworkBarItem.identifier return NetworkBarItem.identifier
case .darkMode: case .darkMode:
return DarkModeBarItem.identifier return DarkModeBarItem.identifier
case .swipe(direction: _, fingers: _, minOffset: _, sourceApple: _, sourceBash: _):
return "com.toxblh.mtmr.swipe."
} }
} }
} }
@@ -76,10 +78,10 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
var items: [NSTouchBarItem.Identifier: NSTouchBarItem] = [:] var items: [NSTouchBarItem.Identifier: NSTouchBarItem] = [:]
var leftIdentifiers: [NSTouchBarItem.Identifier] = [] var leftIdentifiers: [NSTouchBarItem.Identifier] = []
var centerIdentifiers: [NSTouchBarItem.Identifier] = [] var centerIdentifiers: [NSTouchBarItem.Identifier] = []
var centerItems: [NSTouchBarItem] = []
var rightIdentifiers: [NSTouchBarItem.Identifier] = [] var rightIdentifiers: [NSTouchBarItem.Identifier] = []
var scrollArea: ScrollViewItem? var basicViewIdentifier = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollView.".appending(UUID().uuidString))
var centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea.".appending(UUID().uuidString)) var basicView: BasicView?
var swipeItems: [SwipeItem] = []
var blacklistAppIdentifiers: [String] = [] var blacklistAppIdentifiers: [String] = []
var frontmostApplicationIdentifier: String? { var frontmostApplicationIdentifier: String? {
@@ -114,24 +116,29 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
jsonItems = newJsonItems jsonItems = newJsonItems
itemDefinitions = [:] itemDefinitions = [:]
items = [:] items = [:]
leftIdentifiers = []
centerItems = []
rightIdentifiers = []
loadItemDefinitions(jsonItems: jsonItems) loadItemDefinitions(jsonItems: jsonItems)
createItems() createItems()
centerItems = centerIdentifiers.compactMap({ (identifier) -> NSTouchBarItem? in let centerItems = centerIdentifiers.compactMap({ (identifier) -> NSTouchBarItem? in
items[identifier] items[identifier]
}) })
centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea.".appending(UUID().uuidString)) let centerScrollArea = NSTouchBarItem.Identifier("com.toxblh.mtmr.scrollArea.".appending(UUID().uuidString))
scrollArea = ScrollViewItem(identifier: centerScrollArea, items: centerItems) let scrollArea = ScrollViewItem(identifier: centerScrollArea, items: centerItems)
scrollArea?.gesturesEnabled = AppSettings.multitouchGestures
touchBar.delegate = self touchBar.delegate = self
touchBar.defaultItemIdentifiers = [] touchBar.defaultItemIdentifiers = [basicViewIdentifier]
touchBar.defaultItemIdentifiers = leftIdentifiers + [centerScrollArea] + rightIdentifiers
let leftItems = leftIdentifiers.compactMap({ (identifier) -> NSTouchBarItem? in
items[identifier]
})
let rightItems = rightIdentifiers.compactMap({ (identifier) -> NSTouchBarItem? in
items[identifier]
})
basicView = BasicView(identifier: basicViewIdentifier, items:leftItems + [scrollArea] + rightItems, swipeItems: swipeItems)
basicView?.legacyGesturesEnabled = AppSettings.multitouchGestures
updateActiveApp() updateActiveApp()
} }
@@ -187,7 +194,12 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
func createItems() { func createItems() {
for (identifier, definition) in itemDefinitions { for (identifier, definition) in itemDefinitions {
items[identifier] = createItem(forIdentifier: identifier, definition: definition) let item = createItem(forIdentifier: identifier, definition: definition)
if item is SwipeItem {
swipeItems.append(item as! SwipeItem)
} else {
items[identifier] = item
}
} }
} }
@@ -223,16 +235,11 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
} }
func touchBar(_: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? { func touchBar(_: NSTouchBar, makeItemForIdentifier identifier: NSTouchBarItem.Identifier) -> NSTouchBarItem? {
if identifier == centerScrollArea { if identifier == basicViewIdentifier {
return scrollArea return basicView
} }
guard let item = self.items[identifier], return nil
let definition = self.itemDefinitions[identifier],
definition.align != .center else {
return nil
}
return item
} }
func createItem(forIdentifier identifier: NSTouchBarItem.Identifier, definition item: BarItemDefinition) -> NSTouchBarItem? { func createItem(forIdentifier identifier: NSTouchBarItem.Identifier, definition item: BarItemDefinition) -> NSTouchBarItem? {
@@ -240,8 +247,8 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
switch item.type { switch item.type {
case let .staticButton(title: title): case let .staticButton(title: title):
barItem = CustomButtonTouchBarItem(identifier: identifier, title: title) barItem = CustomButtonTouchBarItem(identifier: identifier, title: title)
case let .appleScriptTitledButton(source: source, refreshInterval: interval): case let .appleScriptTitledButton(source: source, refreshInterval: interval, alternativeImages: alternativeImages):
barItem = AppleScriptTouchBarItem(identifier: identifier, source: source, interval: interval) barItem = AppleScriptTouchBarItem(identifier: identifier, source: source, interval: interval, alternativeImages: alternativeImages)
case let .shellScriptTitledButton(source: source, refreshInterval: interval): case let .shellScriptTitledButton(source: source, refreshInterval: interval):
barItem = ShellScriptTouchBarItem(identifier: identifier, source: source, interval: interval) barItem = ShellScriptTouchBarItem(identifier: identifier, source: source, interval: interval)
case let .timeButton(formatTemplate: template, timeZone: timeZone, locale: locale): case let .timeButton(formatTemplate: template, timeZone: timeZone, locale: locale):
@@ -292,6 +299,8 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
barItem = NetworkBarItem(identifier: identifier, flip: flip) barItem = NetworkBarItem(identifier: identifier, flip: flip)
case .darkMode: case .darkMode:
barItem = DarkModeBarItem(identifier: identifier) barItem = DarkModeBarItem(identifier: identifier)
case let .swipe(direction: direction, fingers: fingers, minOffset: minOffset, sourceApple: sourceApple, sourceBash: sourceBash):
barItem = SwipeItem(identifier: identifier, direction: direction, fingers: fingers, minOffset: minOffset, sourceApple: sourceApple, sourceBash: sourceBash)
} }
if let action = self.action(forItem: item), let item = barItem as? CustomButtonTouchBarItem { if let action = self.action(forItem: item), let item = barItem as? CustomButtonTouchBarItem {
+33 -2
View File
@@ -15,6 +15,9 @@ class CurrencyBarItem: CustomButtonTouchBarItem {
private var postfix: String private var postfix: String
private var from: String private var from: String
private var to: String private var to: String
private var decimal: Int
private var decimalValue: Float32!
private var decimalString: String!
private var oldValue: Float32! private var oldValue: Float32!
private var full: Bool = false private var full: Bool = false
@@ -32,11 +35,29 @@ class CurrencyBarItem: CustomButtonTouchBarItem {
"IDR": "Rp", "IDR": "Rp",
"MXN": "$", "MXN": "$",
"SGD": "$", "SGD": "$",
"CHF": "Fr.",
"BTC": "฿", "BTC": "฿",
"LTC": "Ł", "LTC": "Ł",
"ETH": "Ξ", "ETH": "Ξ",
] ]
private let decimals = [
"USD": 4,
"EUR": 4,
"RUB": 2,
"JPY": 2,
"GBP": 4,
"CAD": 4,
"KRW": 4,
"CNY": 4,
"AUD": 4,
"BRL": 4,
"IDR": 1,
"MXN": 2,
"SGD": 4,
"CHF": 4,
"BTC": 2,
"LTC": 2,
"ETH": 2,
]
init(identifier: NSTouchBarItem.Identifier, interval: TimeInterval, from: String, to: String, full: Bool) { init(identifier: NSTouchBarItem.Identifier, interval: TimeInterval, from: String, to: String, full: Bool) {
activity = NSBackgroundActivityScheduler(identifier: "\(identifier.rawValue).updatecheck") activity = NSBackgroundActivityScheduler(identifier: "\(identifier.rawValue).updatecheck")
@@ -57,6 +78,14 @@ class CurrencyBarItem: CustomButtonTouchBarItem {
postfix = to postfix = to
} }
if let decimal = decimals[to] {
self.decimal = decimal
} else {
decimal = 2
}
super.init(identifier: identifier, title: "⏳") super.init(identifier: identifier, title: "⏳")
activity.repeats = true activity.repeats = true
@@ -114,10 +143,12 @@ class CurrencyBarItem: CustomButtonTouchBarItem {
} }
oldValue = value oldValue = value
decimalValue = (value * pow(10,Float(decimal))).rounded() / pow(10,Float(decimal))
decimalString = String(decimalValue)
var title = "" var title = ""
if full { if full {
title = String(format: "%@‣%.2f%@", prefix, value, postfix) title = String(format: "%@%@‣%@", prefix, postfix, decimalString)
} else { } else {
title = String(format: "%@%.2f", prefix, value) title = String(format: "%@%.2f", prefix, value)
} }
+36
View File
@@ -11,6 +11,7 @@ import ScriptingBridge
class MusicBarItem: CustomButtonTouchBarItem { class MusicBarItem: CustomButtonTouchBarItem {
private enum Player: String { private enum Player: String {
case Music = "com.apple.Music"
case iTunes = "com.apple.iTunes" case iTunes = "com.apple.iTunes"
case Spotify = "com.spotify.client" case Spotify = "com.spotify.client"
case VOX = "com.coppertino.Vox" case VOX = "com.coppertino.Vox"
@@ -19,6 +20,7 @@ class MusicBarItem: CustomButtonTouchBarItem {
} }
private let playerBundleIdentifiers = [ private let playerBundleIdentifiers = [
Player.Music,
Player.iTunes, Player.iTunes,
Player.Spotify, Player.Spotify,
Player.VOX, Player.VOX,
@@ -71,6 +73,10 @@ class MusicBarItem: CustomButtonTouchBarItem {
let mp = (musicPlayer as iTunesApplication) let mp = (musicPlayer as iTunesApplication)
mp.playpause!() mp.playpause!()
return return
} else if ident == .Music {
let mp = (musicPlayer as MusicApplication)
mp.playpause!()
return
} else if ident == .VOX { } else if ident == .VOX {
let mp = (musicPlayer as VoxApplication) let mp = (musicPlayer as VoxApplication)
mp.playpause!() mp.playpause!()
@@ -134,6 +140,11 @@ class MusicBarItem: CustomButtonTouchBarItem {
mp.nextTrack!() mp.nextTrack!()
updatePlayer() updatePlayer()
return return
} else if ident == .Music {
let mp = (musicPlayer as MusicApplication)
mp.nextTrack!()
updatePlayer()
return
} else if ident == .VOX { } else if ident == .VOX {
let mp = (musicPlayer as VoxApplication) let mp = (musicPlayer as VoxApplication)
mp.next!() mp.next!()
@@ -188,6 +199,8 @@ class MusicBarItem: CustomButtonTouchBarItem {
tempTitle = (musicPlayer as SpotifyApplication).title tempTitle = (musicPlayer as SpotifyApplication).title
} else if ident == .iTunes { } else if ident == .iTunes {
tempTitle = (musicPlayer as iTunesApplication).title tempTitle = (musicPlayer as iTunesApplication).title
} else if ident == .Music {
tempTitle = (musicPlayer as MusicApplication).title
} else if ident == .VOX { } else if ident == .VOX {
tempTitle = (musicPlayer as VoxApplication).title tempTitle = (musicPlayer as VoxApplication).title
} else if ident == .Safari { } else if ident == .Safari {
@@ -321,6 +334,29 @@ extension iTunesApplication {
} }
} }
@objc protocol MusicApplication {
@objc optional var currentTrack: MusicTrack { get }
@objc optional func playpause()
@objc optional func nextTrack()
@objc optional func previousTrack()
}
extension SBApplication: MusicApplication {}
@objc protocol MusicTrack {
@objc optional var artist: String { get }
@objc optional var name: String { get }
}
extension SBObject: MusicTrack {}
extension MusicApplication {
var title: String {
guard let t = currentTrack else { return "" }
return (t.artist ?? "") + " — " + (t.name ?? "")
}
}
@objc protocol VoxApplication { @objc protocol VoxApplication {
@objc optional func playpause() @objc optional func playpause()
@objc optional func next() @objc optional func next()
+1 -1
View File
@@ -35,7 +35,7 @@ class PomodoroBarItem: CustomButtonTouchBarItem, Widget {
case none case none
} }
private let defaultTitle = "🍅" private let defaultTitle = "🍅 "
private let workTime: TimeInterval private let workTime: TimeInterval
private let restTime: TimeInterval private let restTime: TimeInterval
private var typeTime: TimeTypes = .none private var typeTime: TimeTypes = .none
+8 -5
View File
@@ -12,7 +12,10 @@ import CoreLocation
class YandexWeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate { class YandexWeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate {
private let activity: NSBackgroundActivityScheduler private let activity: NSBackgroundActivityScheduler
private let unitsStr = "°C" private let unitsStr = "°C"
private let iconsSource = ["Ясно": "☀️", "Малооблачно": "🌤", "Облачно с прояснениями": "⛅️", "Пасмурно": "☁️", "Небольшой дождь": "🌦", "Дождь": "🌧", "Ливень": "⛈", "Гроза": "🌩", "Дождь со снегом": "☔️", "Небольшой снег": "❄️", "Снег": "🌨", "Туман": "🌫"] private let iconsSource = [
"Ясно": "☀️", "Малооблачно": "🌤", "Облачно с прояснениями": "⛅️", "Пасмурно": "☁️", "Небольшой дождь": "🌦", "Дождь": "🌧", "Ливень": "⛈", "Гроза": "🌩", "Дождь со снегом": "☔️", "Небольшой снег": "❄️", "Снег": "🌨", "Туман": "🌫",
"Clear": "☀️", "Mostly clear": "🌤", "Partly cloudy": "⛅️", "Overcast": "☁️", "Light rain": "🌦", "Rain": "🌧", "Heavy rain": "⛈", "Storm": "🌩", "Sleet": "☔️", "Light snow": "❄️", "Snow": "🌨", "Fog": "🌫"
]
private var location: CLLocation! private var location: CLLocation!
private var prevLocation: CLLocation! private var prevLocation: CLLocation!
private var manager: CLLocationManager! private var manager: CLLocationManager!
@@ -88,9 +91,9 @@ class YandexWeatherBarItem: CustomButtonTouchBarItem, CLLocationManagerDelegate
func getWeatherUrl() -> String { func getWeatherUrl() -> String {
if location != nil { if location != nil {
return "https://yandex.ru/pogoda/?lat=\(location.coordinate.latitude)&lon=\(location.coordinate.longitude)" return "https://yandex.ru/pogoda/?lat=\(location.coordinate.latitude)&lon=\(location.coordinate.longitude)?lang=ru"
} else { } else {
return "https://yandex.ru/pogoda/" // Yandex will try to determine your location by default return "https://yandex.ru/pogoda/?lang=ru" // Yandex will try to determine your location by default
} }
} }
@@ -131,9 +134,9 @@ extension String {
func matchingStrings(regex: String) -> [[String]] { func matchingStrings(regex: String) -> [[String]] {
guard let regex = try? NSRegularExpression(pattern: regex, options: []) else { return [] } guard let regex = try? NSRegularExpression(pattern: regex, options: []) else { return [] }
let nsString = self as NSString let nsString = self as NSString
let results = regex.matches(in: self, options: [], range: NSMakeRange(0, nsString.length)) let results = regex.matches(in: self, options: [], range: NSMakeRange(0, nsString.length))
return results.map { result in return results.map { result in
(0..<result.numberOfRanges).map { (0 ..< result.numberOfRanges).map {
result.range(at: $0).location != NSNotFound result.range(at: $0).location != NSNotFound
? nsString.substring(with: result.range(at: $0)) ? nsString.substring(with: result.range(at: $0))
: "" : ""
+20
View File
@@ -28,6 +28,26 @@
} }
}, },
// Music
{
"type": "appleScriptTitledButton",
"source": {
"inline": "if application \"Music\" is running then\rtell application \"Music\"\rif player state is playing then\rreturn (get artist of current track) & \" – \" & (get name of current track)\relse\rreturn \"\"\rend if\rend tell\rend if\rreturn \"\"\r"
},
"action": "appleScript",
"actionAppleScript": {
"inline": "if application \"Music\" is running then\rtell application \"Music\"\rif player state is playing then\rnext track\rend if\rend tell\rend if\r"
},
"longAction": "appleScript",
"longActionAppleScript": {
"inline": "if application \"Music\" is running then\rtell application \"Music\"\rif player state is playing then\rprev track\rend if\rend tell\rend if\r"
},
"refreshInterval": 2,
"image": {
"base64": "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAABGdBTUEAALGPC/xhBQAAAAFzUkdCAK7OHOkAAADAUExURUdwTOVVZCzB+3qc0gkDBgEBAgcKEwAAAA4EBP5aVU2V95iJv7V3rtBOvH5W6jaOyclScKZGX3wuQCMuUqZN7+NQYXtDvFd9/sxYni2z6UhBhyhvnIp7sf38/PXz9ePm69/k6fHv8/j29+3q7/v6+ufq7uvu8fTw8+1egOFki/dbboVj/HNy/T+j/dNtnEul81vC8Vmf3OeRqOBVofK4xZfF7sDb7PLe6LxU1KKK79PL6vrW3fh4g5Zi4bi16daa0A3Qc90AAAAddFJOUwD3/v0uOlYNG/z+/v7998OYYztt/Le2/eDqi5jEo2rNTwAABMtJREFUWMPdl1tjqjoQhauC0Hqvta26JVxUQBQFRPBS/f//as8kISBqd/twXs5KjBDyrZkEFfP09D+WoigqFxz+mlbVXncweEZVBoNuD1x+E1vtMVZoURn01J/mob52KRNuj4k5mZjJcRueFotFpfv6EwdVRfy0tSdXSranheN0/zkRSB7x42Q6udExdBy3972Fog4o/kBg4X6bhPJaeX7eTqeT6b0MJtPpdOu6n49XQgX+dOQ8vpWEvYn/2AHiL052PpoROcsOtND17ztQ3rwTuCQz9O/moKiMf6BkG/puKBzurKQ64PmbU2bDzUxk3Uql4lZcl3Vpvt9VbxLoLZwjY7E1WcNZoB0XpbELie/3Sg6KVHG2jGPs1LTCE2UXFfgIgtBgyq8d/E/pehJq1zmZGc7kAPsMX4Ec932T25uX5vUklFcHJlDU1OT4wllkvOtn9lrSbF7dCUggNEtaMOXhQZq4WkpBcksJQBCOnyjvM4P8KqQgFW9BFJka2NMKB1gw+VMxvN9smnwI1EuzpxS+g9FWYySjsTpOtnq+H162iW01m/wyXLUPzT/5HKQoSjQmU8vE6TAElvWggbhuNRpScQa002bVtJmBCz9qNusWBkJmoyHmoHajC4yybVujhR26mJVha7lDo2FrhnA4N0aq+BpE24zjgsMoEsfU0AADaKCwemiIRZA+o6N9oygyMi/EAWk0DMNgFvCmN/5IwqCV3PCGzzIwbINrzgwykVq2iorUalm2UTZotXKWqVYz5uBjzDUoxrxWyzKQWy061LZsNIJ3PAMDIcbVauwdGmxrNblgYNnCgStN54ylBSsYoAxerwwgJsCWTS0sepym0Mdp1gYBw5lmwgDXIDEoaeHLYE36BafzuQWFQ9RASM/XQPpMD5YQ2gA/AwPArQJyZWDsgo64C+/pBRkDG4s31hdmwFNAGz1mBjPukBs8qdSgLDBA1LJm1lw/14IgWAdAQ5nhax4HY/FR7qfpHQMPUChzS0c6eFmv17MZo7HZBP3MQJHTNCnzxPMgOFUteAGtMwMmfRPIijBgc+AmNK6+9zw+9Iw05YsG8aaT/7Kro7eUcoSWw3n/1W57SxgGOZCYxl+VDDabcf6LpNTf3g6IQ4XY7TbiyyUBmhqsViswWK02cE7ITIdmtxnWlcJz6f1tPyMsha+2R4UGyJPdywotwGSHOKHdm+IMYA40BRhtkXOb42DAh8crppjw8CyB4nMBlvFtD/0WSfZebkDHguLNar2JdyTXptqRrx6OmMKZkISQc4Yv9yyDXHiiEx1qXL1OAFdhBJPAAQeRQDEiRZEm+kwnu2p1XHo64yQ8j47bL1kCZ87pDKWxuW4mQJ9O9ba31xE5Y/rnA4VoTCJQwvnyBNgk+pkDi8sSJjlKRPxhX7r3Lytz0LPMi1H1Qv7VuzwuAzh4h1ukKFi/YV9+9E8THZbne2Ezxd/xsNGQ6u+wgoeH4SH9Tl367t+2Ko/acA8Oj/DhWP7X/30Zkvj4WMYlj10MOISXf7DlkPvvH6g43u0oCzDS1U5f/sHWC3d7cn3UAQf4HeHfwxXQY4yu/HTDKNXro3Gngw4vw2FnPKrXJfUXu0fqIdeFZOnXm08FTRSxcf391pW7oNGT8vRf6i9jqljwYzAm6AAAAABJRU5ErkJggg=="
}
},
// iTunes // iTunes
{ {
"type": "appleScriptTitledButton", "type": "appleScriptTitledButton",
+4 -4
View File
@@ -6,7 +6,7 @@ class AppleScriptDefinitionTests: XCTestCase {
[ { "type": "appleScriptTitledButton", "source": { "inline": "tell everything fine" } } ] [ { "type": "appleScriptTitledButton", "source": { "inline": "tell everything fine" } } ]
""".data(using: .utf8)! """.data(using: .utf8)!
let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonNoActionFixture) let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonNoActionFixture)
guard case .appleScriptTitledButton(let source, _)? = result?.first?.type else { guard case .appleScriptTitledButton(let source, _, _)? = result?.first?.type else {
XCTFail() XCTFail()
return return
} }
@@ -18,7 +18,7 @@ class AppleScriptDefinitionTests: XCTestCase {
[ { "type": "appleScriptTitledButton", "source": { "filePath": "/ololo/pew" } } ] [ { "type": "appleScriptTitledButton", "source": { "filePath": "/ololo/pew" } } ]
""".data(using: .utf8)! """.data(using: .utf8)!
let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonNoActionFixture) let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonNoActionFixture)
guard case .appleScriptTitledButton(let source, _)? = result?.first?.type else { guard case .appleScriptTitledButton(let source, _, _)? = result?.first?.type else {
XCTFail() XCTFail()
return return
} }
@@ -32,7 +32,7 @@ class AppleScriptDefinitionTests: XCTestCase {
[ { "type": "appleScriptTitledButton", "source": { "filePath": "~/pew" } } ] [ { "type": "appleScriptTitledButton", "source": { "filePath": "~/pew" } } ]
""".data(using: .utf8)! """.data(using: .utf8)!
let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonNoActionFixture) let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonNoActionFixture)
guard case .appleScriptTitledButton(let source, _)? = result?.first?.type else { guard case .appleScriptTitledButton(let source, _, _)? = result?.first?.type else {
XCTFail() XCTFail()
return return
} }
@@ -58,7 +58,7 @@ class AppleScriptDefinitionTests: XCTestCase {
[ { "type": "appleScriptTitledButton", "source": { "inline": "tell everything fine" }, "refreshInterval": 305} ] [ { "type": "appleScriptTitledButton", "source": { "inline": "tell everything fine" }, "refreshInterval": 305} ]
""".data(using: .utf8)! """.data(using: .utf8)!
let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonNoActionFixture) let result = try? JSONDecoder().decode([BarItemDefinition].self, from: buttonNoActionFixture)
guard case .appleScriptTitledButton(_, 305)? = result?.first?.type else { guard case .appleScriptTitledButton(_, 305, _)? = result?.first?.type else {
XCTFail() XCTFail()
return return
} }
+75 -3
View File
@@ -102,11 +102,31 @@ The pre-installed configuration contains less or more than you'll probably want,
- appleScriptTitledButton - appleScriptTitledButton
- shellScriptTitledButton - shellScriptTitledButton
## Gestures on central part: ## Gestures
By default you can enable basic gestures from application menu (status bar -> MTMR icon -> Volume/Brightness gestures):
- two finger slide: change you Volume - two finger slide: change you Volume
- three finger slide: change you Brightness - three finger slide: change you Brightness
### Custom gestures
You can add custom actions for two/three/four finger swipes. To do it, you need to use `swipe` type:
```json
"type": "swipe",
"fingers": 2, // number of fingers required (2,3 or 4)
"direction": "right", // direction of swipe (right/left)
"minOffset" 10, // optional: minimal required offset for gesture to emit event
"sourceApple": { // optional: apple script to run
"inline": "beep"
},
"sourceBash": { // optional: bash script to run
"inline": "touch /Users/lobster/test"
}
```
You may create as many `swipe` objects in the preset as you want.
## Built-in slider types: ## Built-in slider types:
- brightness - brightness
@@ -133,10 +153,37 @@ The pre-installed configuration contains less or more than you'll probably want,
"inline": "tell application \"Finder\"\rif not (exists window 1) then\rmake new Finder window\rset target of front window to path to home folder as string\rend if\ractivate\rend tell", "inline": "tell application \"Finder\"\rif not (exists window 1) then\rmake new Finder window\rset target of front window to path to home folder as string\rend if\ractivate\rend tell",
// or // or
"base64": "StringInbase64" "base64": "StringInbase64"
} },
} }
``` ```
> Note: appleScriptTitledButton can change its icon. To do it, you need to do the following things:
1. Declarate dictionary of icons in `alternativeImages` field
2. Make you script return array of two values - `{"TITLE", "IMAGE_LABEL"}`
3. Make sure that your `IMAGE_LABEL` is declared in `alternativeImages` field
Example:
```js
{
"type": "appleScriptTitledButton",
"source": {
"inline": "if (random number from 1 to 2) = 1 then\n\tset val to {\"title\", \"play\"}\nelse\n\tset val to {\"title\", \"pause\"}\nend if\nreturn val"
},
"refreshInterval": 1,
"image": {
"base64": "iVBORw0KGgoAAAANSUhEUgA..."
},
"alternativeImages": {
"play": {
"base64": "iVBORw0KGgoAAAANSUhEUgAAAAAA..."
},
"pause": {
"base64": "iVBORw0KGgoAAAANSUhEUgAAAIAA..."
}
}
},
```
#### `shellScriptTitledButton` #### `shellScriptTitledButton`
> Note: script may return also colors using escape sequences (read more here https://misc.flogisoft.com/bash/tip_colors_and_formatting) > Note: script may return also colors using escape sequences (read more here https://misc.flogisoft.com/bash/tip_colors_and_formatting)
> Only "16 Colors" mode supported atm. If background color returned, button will pick it up as own background color. > Only "16 Colors" mode supported atm. If background color returned, button will pick it up as own background color.
@@ -375,6 +422,31 @@ If you want to longPress for some operations, it is similar to the configuration
"bordered": "false" // "true" or "false" "bordered": "false" // "true" or "false"
``` ```
- `background` allow to specify you button background color
```js
"background": "#FF0000",
```
by using background with color "#000000" and bordered == false you can create button without gray background but with background when the button is pressed
- `title` specify button title
```js
"title": "hello"
```
- `image` specify button icon
```js
"image": {
//Can be either of those
"base64": "iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAMAAACdt4HsAAAABGdB...."
//or
"filePath": "~/img.png"
}
```
### Roadmap ### Roadmap
- [x] Create the first prototype with TouchBar in Storyboard - [x] Create the first prototype with TouchBar in Storyboard
@@ -403,7 +475,7 @@ Settings:
- [x] Startup at login - [x] Startup at login
- [ ] Show on/off in Dock - [ ] Show on/off in Dock
- [ ] Show on/off in StatusBar - [ ] Show on/off in StatusBar
- [ ] On/off Haptic Feedback - [ x] On/off Haptic Feedback
Maybe: Maybe: