mirror of
https://github.com/Toxblh/MTMR.git
synced 2026-01-10 00:58:37 +00:00
WIP Implementation of up next widget
This commit is contained in:
parent
14282b86a9
commit
8b5c2f10b7
@ -71,6 +71,7 @@
|
||||
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 */; };
|
||||
F29F6A2524BC7148004FF8E4 /* UpNextBarItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = F29F6A2424BC7148004FF8E4 /* UpNextBarItem.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
/* Begin PBXCopyFilesBuildPhase section */
|
||||
@ -163,6 +164,7 @@
|
||||
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>"; };
|
||||
F29F6A2424BC7148004FF8E4 /* UpNextBarItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UpNextBarItem.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */
|
||||
@ -322,6 +324,7 @@
|
||||
4CFF5E5B22E623DD00BFB1EE /* YandexWeatherBarItem.swift */,
|
||||
B08126F0217BE19000A98970 /* WidgetProtocol.swift */,
|
||||
B0F54A792295AC7D00B4C509 /* DarkModeBarItem.swift */,
|
||||
F29F6A2424BC7148004FF8E4 /* UpNextBarItem.swift */,
|
||||
);
|
||||
path = Widgets;
|
||||
sourceTree = "<group>";
|
||||
@ -488,6 +491,7 @@
|
||||
6027D1BA2080E52A004FFDC7 /* VolumeViewController.swift in Sources */,
|
||||
4CDC6E5022FCA93F0069ADD4 /* ShellScriptTouchBarItem.swift in Sources */,
|
||||
607EEA4B2087835F009DA5F0 /* WeatherBarItem.swift in Sources */,
|
||||
F29F6A2524BC7148004FF8E4 /* UpNextBarItem.swift in Sources */,
|
||||
B0F3112520C9E35F0076BB88 /* SupportNSTouchBar.swift in Sources */,
|
||||
4CFF5E5C22E623DD00BFB1EE /* YandexWeatherBarItem.swift in Sources */,
|
||||
6042B6AA2083E27000C525C8 /* DeprecatedCarbonAPI.c in Sources */,
|
||||
|
||||
@ -227,6 +227,7 @@ enum ItemType: Decodable {
|
||||
case network(flip: Bool)
|
||||
case darkMode
|
||||
case swipe(direction: String, fingers: Int, minOffset: Float, sourceApple: SourceProtocol?, sourceBash: SourceProtocol?)
|
||||
case upnext(from: Double, to: Double, nthEvent: Int)
|
||||
|
||||
private enum CodingKeys: String, CodingKey {
|
||||
case type
|
||||
@ -258,6 +259,7 @@ enum ItemType: Decodable {
|
||||
case direction
|
||||
case fingers
|
||||
case minOffset
|
||||
case nthEvent
|
||||
}
|
||||
|
||||
enum ItemTypeRaw: String, Decodable {
|
||||
@ -281,6 +283,7 @@ enum ItemType: Decodable {
|
||||
case network
|
||||
case darkMode
|
||||
case swipe
|
||||
case upnext
|
||||
}
|
||||
|
||||
init(from decoder: Decoder) throws {
|
||||
@ -378,6 +381,12 @@ enum ItemType: Decodable {
|
||||
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)
|
||||
|
||||
case .upnext:
|
||||
let from = try container.decodeIfPresent(Double.self, forKey: .from) ?? 0 // Lower bounds of period of time in hours to search for events
|
||||
let to = try container.decodeIfPresent(Double.self, forKey: .to) ?? 1 // Upper bounds of period of time in hours to search for events
|
||||
let nthEvent = try container.decodeIfPresent(Int.self, forKey: .nthEvent) ?? 1 // 1 indexed array. Get the 1st, 2nd, 3rd event to display multiple notifications
|
||||
self = .upnext(from: from, to: to, nthEvent: nthEvent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -59,6 +59,8 @@ extension ItemType {
|
||||
return DarkModeBarItem.identifier
|
||||
case .swipe(direction: _, fingers: _, minOffset: _, sourceApple: _, sourceBash: _):
|
||||
return "com.toxblh.mtmr.swipe."
|
||||
case .upnext:
|
||||
return "com.connorgmeehan.mtmrupnext."
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -301,6 +303,8 @@ class TouchBarController: NSObject, NSTouchBarDelegate {
|
||||
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)
|
||||
case let .upnext(from: from, to: to, nthEvent: nthEvent):
|
||||
barItem = UpNextBarItem(identifier: identifier, interval: 10, from: from, to: to, nthEvent: nthEvent)
|
||||
}
|
||||
|
||||
if let action = self.action(forItem: item), let item = barItem as? CustomButtonTouchBarItem {
|
||||
|
||||
155
MTMR/Widgets/UpNextBarItem.swift
Normal file
155
MTMR/Widgets/UpNextBarItem.swift
Normal file
@ -0,0 +1,155 @@
|
||||
//
|
||||
// UpNextBarItems.swift
|
||||
// MTMR
|
||||
//
|
||||
// Created by Connor Meehan on 13/7/20.
|
||||
// Copyright © 2020 Anton Palgunov. All rights reserved.
|
||||
//
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import EventKit
|
||||
|
||||
class UpNextBarItem: CustomButtonTouchBarItem {
|
||||
private let activity: NSBackgroundActivityScheduler // Update scheduler
|
||||
private let eventStore = EKEventStore() //
|
||||
private let df = DateFormatter()
|
||||
private let buttonTemplate = "🗓 %@ - %@ "
|
||||
|
||||
// Settings
|
||||
private var futureSearchCutoff: Double
|
||||
private var pastSearchCutoff: Double
|
||||
private var nthEvent: Int
|
||||
|
||||
// State
|
||||
private var hasPermission: Bool = false
|
||||
|
||||
|
||||
/// <#Description#>
|
||||
/// - Parameters:
|
||||
/// - identifier: Unique identifier of widget
|
||||
/// - interval: Update view interval in seconds
|
||||
/// - from: Relative to current time, how far back we search for events in hours
|
||||
/// - to: Relative to current time, how far forward we search for events in hours
|
||||
/// - nthEvent: Which event to show (1 is first, 2 is second, and so on)
|
||||
init(identifier: NSTouchBarItem.Identifier, interval: TimeInterval, from: Double, to: Double, nthEvent: Int) {
|
||||
activity = NSBackgroundActivityScheduler(identifier: "\(identifier.rawValue).updateCheck")
|
||||
activity.interval = interval
|
||||
self.pastSearchCutoff = from
|
||||
self.futureSearchCutoff = to
|
||||
self.nthEvent = nthEvent
|
||||
self.df.dateFormat = "HH:mm"
|
||||
|
||||
if (nthEvent <= 0) {
|
||||
fatalError("Error on UpNext bar item. nthEvent property must be greater than 0.")
|
||||
}
|
||||
|
||||
super.init(identifier: identifier, title: " ")
|
||||
let authorizationStatus = EKEventStore.authorizationStatus(for: EKEntityType.event)
|
||||
switch authorizationStatus {
|
||||
case .notDetermined:
|
||||
print("notDetermined")
|
||||
case .restricted:
|
||||
print("restricted")
|
||||
case .denied:
|
||||
print("denied")
|
||||
case .authorized:
|
||||
print("authorizded")
|
||||
default:
|
||||
print("Unkown EKEventStore authorization status")
|
||||
}
|
||||
eventStore.requestAccess(to: .event){ granted, error in
|
||||
self.hasPermission = granted;
|
||||
if(!granted) {
|
||||
NSLog("Error: MTMR UpNextBarWidget not given calendar access.")
|
||||
return
|
||||
}
|
||||
self.updateView()
|
||||
}
|
||||
|
||||
|
||||
tapClosure = { [weak self] in self?.gotoAppleCalendar() }
|
||||
|
||||
|
||||
// Start activity to update view
|
||||
activity.repeats = true
|
||||
activity.qualityOfService = .utility
|
||||
activity.schedule { (completion: NSBackgroundActivityScheduler.CompletionHandler) in
|
||||
self.updateView()
|
||||
completion(NSBackgroundActivityScheduler.Result.finished)
|
||||
}
|
||||
updateView()
|
||||
|
||||
}
|
||||
|
||||
required init?(coder _: NSCoder) {
|
||||
fatalError("init(coder:) has not been implemented")
|
||||
}
|
||||
|
||||
func updateView() {
|
||||
if (!self.hasPermission) {
|
||||
self.title = "🗓 No permissions"
|
||||
return
|
||||
}
|
||||
var upcomingEvents = self.getUpcomingEvents()
|
||||
upcomingEvents.sort(by: {$0.startDate.compare($1.startDate) == .orderedAscending})
|
||||
for event in upcomingEvents {
|
||||
print("\(event.title) - \(event.startDate)")
|
||||
}
|
||||
if (upcomingEvents.count >= self.nthEvent) {
|
||||
let event = upcomingEvents[self.nthEvent-1]
|
||||
let title = event.title
|
||||
let startDateString = self.df.string(for: event.startDate)
|
||||
print("TITLE: " + title + " STARTDATE: " + (startDateString ?? "nil"))
|
||||
|
||||
DispatchQueue.main.async {
|
||||
print("SHOW")
|
||||
self.image = nil
|
||||
self.title = String(format: self.buttonTemplate, title, startDateString ?? "No time")
|
||||
self.view.isHidden = false
|
||||
}
|
||||
} else {
|
||||
// Do not display any event
|
||||
DispatchQueue.main.async {
|
||||
print("HIDE " + String(upcomingEvents.count) + " " + String(self.nthEvent) + " " + String(upcomingEvents.count > self.nthEvent))
|
||||
self.image = nil
|
||||
self.title = ""
|
||||
self.view.isHidden = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func getUpcomingEvents() -> [UpNextEventModel] {
|
||||
var upcomingEvents: [UpNextEventModel] = []
|
||||
|
||||
NSLog("Getting calendar events...")
|
||||
// Calculate the range we're going to search for events in
|
||||
let dateLowerBounds = Date(timeIntervalSinceNow: self.pastSearchCutoff * 360)
|
||||
let dateUpperBounds = Date(timeIntervalSinceNow: self.futureSearchCutoff * 360)
|
||||
|
||||
let calendars = self.eventStore.calendars(for: .event)
|
||||
|
||||
|
||||
for calendar in calendars {
|
||||
|
||||
let predicate = self.eventStore.predicateForEvents(withStart: dateLowerBounds, end: dateUpperBounds, calendars: [calendar])
|
||||
|
||||
let events = self.eventStore.events(matching: predicate)
|
||||
for event in events {
|
||||
upcomingEvents.append(UpNextEventModel(title: event.title, startDate: event.startDate))
|
||||
}
|
||||
}
|
||||
|
||||
print("Found " + String(upcomingEvents.count) + " events.")
|
||||
return upcomingEvents
|
||||
}
|
||||
|
||||
func gotoAppleCalendar() {
|
||||
print("CLICK")
|
||||
NSWorkspace.shared.open(URL(fileURLWithPath: "/Applications/Photos.app"))
|
||||
}}
|
||||
|
||||
struct UpNextEventModel {
|
||||
var title: String
|
||||
var startDate: Date
|
||||
}
|
||||
16
README.md
16
README.md
@ -84,6 +84,7 @@ The pre-installed configuration contains less or more than you'll probably want,
|
||||
- darkMode
|
||||
- pomodoro
|
||||
- network
|
||||
- upnext (Calendar events)
|
||||
|
||||
> Media Keys
|
||||
|
||||
@ -343,6 +344,21 @@ To close a group, use the button:
|
||||
},
|
||||
```
|
||||
|
||||
#### `upnext`
|
||||
|
||||
> Calender next event plugin
|
||||
|
||||
```js
|
||||
{
|
||||
"type": "upnext",
|
||||
"from": 0, // Lower bound of search range for next event in hours. Default 0 (current time)
|
||||
"to": 1, // Upper bounds of search range for next event in hours. Default 1 (one hour in the future)
|
||||
"nthEvent": 1 // Sets this touchbar button to show the nthEvent. Default 1 (the first upcoming event)
|
||||
},
|
||||
```
|
||||
|
||||
|
||||
|
||||
## Actions:
|
||||
|
||||
- `hidKey`
|
||||
|
||||
Loading…
Reference in New Issue
Block a user