├── .DS_Store ├── Pods ├── .DS_Store ├── Target Support Files │ ├── FMDB │ │ ├── FMDB.modulemap │ │ ├── FMDB-dummy.m │ │ ├── FMDB-prefix.pch │ │ ├── FMDB-umbrella.h │ │ ├── FMDB.debug.xcconfig │ │ ├── FMDB.release.xcconfig │ │ └── FMDB-Info.plist │ ├── Pods-Roar │ │ ├── Pods-Roar.modulemap │ │ ├── Pods-Roar-dummy.m │ │ ├── Pods-Roar-frameworks-Debug-output-files.xcfilelist │ │ ├── Pods-Roar-frameworks-Release-output-files.xcfilelist │ │ ├── Pods-Roar-frameworks-Debug-input-files.xcfilelist │ │ ├── Pods-Roar-frameworks-Release-input-files.xcfilelist │ │ ├── Pods-Roar-umbrella.h │ │ ├── Pods-Roar-Info.plist │ │ ├── Pods-Roar.debug.xcconfig │ │ ├── Pods-Roar.release.xcconfig │ │ ├── Pods-Roar-acknowledgements.markdown │ │ └── Pods-Roar-acknowledgements.plist │ └── MASShortcut │ │ ├── MASShortcut.modulemap │ │ ├── MASShortcut-dummy.m │ │ ├── MASShortcut-prefix.pch │ │ ├── MASShortcut.debug.xcconfig │ │ ├── MASShortcut.release.xcconfig │ │ ├── MASShortcut-umbrella.h │ │ ├── ResourceBundle-MASShortcut-MASShortcut-Info.plist │ │ └── MASShortcut-Info.plist ├── MASShortcut │ ├── Framework │ │ ├── Shortcut.h │ │ ├── Monitoring │ │ │ ├── MASHotKey.h │ │ │ ├── MASShortcutMonitor.h │ │ │ ├── MASHotKey.m │ │ │ └── MASShortcutMonitor.m │ │ ├── UI │ │ │ ├── MASLocalization.h │ │ │ ├── MASShortcutView.h │ │ │ ├── MASShortcutView+Bindings.h │ │ │ ├── MASShortcutView+Bindings.m │ │ │ └── MASLocalization.m │ │ ├── User Defaults Storage │ │ │ ├── MASDictionaryTransformer.h │ │ │ ├── MASDictionaryTransformer.m │ │ │ ├── MASShortcutBinder.h │ │ │ └── MASShortcutBinder.m │ │ └── Model │ │ │ ├── MASKeyMasks.h │ │ │ ├── MASShortcutValidator.h │ │ │ ├── MASKeyCodes.h │ │ │ ├── MASShortcut.h │ │ │ └── MASShortcutValidator.m │ ├── LICENSE │ ├── Resources │ │ ├── zh-Hans.lproj │ │ │ └── Localizable.strings │ │ ├── zh-Hant.lproj │ │ │ └── Localizable.strings │ │ ├── ko.lproj │ │ │ └── Localizable.strings │ │ ├── ja.lproj │ │ │ └── Localizable.strings │ │ ├── pl.lproj │ │ │ └── Localizable.strings │ │ ├── cs.lproj │ │ │ └── Localizable.strings │ │ ├── en.lproj │ │ │ └── Localizable.strings │ │ ├── pt.lproj │ │ │ └── Localizable.strings │ │ ├── es.lproj │ │ │ └── Localizable.strings │ │ ├── ru.lproj │ │ │ └── Localizable.strings │ │ ├── nl.lproj │ │ │ └── Localizable.strings │ │ ├── de.lproj │ │ │ └── Localizable.strings │ │ ├── fr.lproj │ │ │ └── Localizable.strings │ │ ├── sv.lproj │ │ │ └── Localizable.strings │ │ └── it.lproj │ │ │ └── Localizable.strings │ └── README.md ├── FMDB │ ├── src │ │ └── fmdb │ │ │ ├── FMDB.h │ │ │ ├── FMDatabaseAdditions.h │ │ │ └── FMDatabaseAdditions.m │ └── LICENSE.txt └── Manifest.lock ├── Roar ├── winamp.mp4 ├── macintosh.ttf ├── Assets.xcassets │ ├── .DS_Store │ ├── Contents.json │ ├── Winamp.imageset │ │ ├── Winamp.png │ │ └── Contents.json │ ├── Macintosh.imageset │ │ ├── Macintosh.png │ │ └── Contents.json │ ├── iTunesMask.imageset │ │ ├── iTunesMask.png │ │ └── Contents.json │ ├── MusicWidget.imageset │ │ ├── MusicWidget.png │ │ └── Contents.json │ ├── AccentColor.colorset │ │ └── Contents.json │ └── AppIcon.appiconset │ │ └── Contents.json ├── Roar.entitlements ├── BridgingHeader.h ├── Info.plist ├── Helpers │ ├── Extensions.swift │ ├── AsyncOperation.swift │ └── Pipette.swift ├── Displays │ ├── NoteWindowController.swift │ ├── BezelWindowController.swift │ ├── MusicVideoWindowController.swift │ ├── MacintoshWindowController.swift │ ├── WinampWindowController.swift │ ├── iTunesWidgetWindowController.swift │ ├── MacintoshWindowController.xib │ ├── iTunesWidgetWindowController.xib │ ├── BezelWindowController.xib │ └── MusicVideoWindowController.xib ├── Windows │ ├── PrefsWindowController.swift │ ├── ActionWindowController.swift │ └── ActionWindowController.xib ├── Watcher │ ├── NoteDisplayOperation.swift │ └── NCWatcher.swift ├── AppDelegate.swift └── Base.lproj │ └── MainMenu.xib ├── Roar.xcodeproj └── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── Podfile ├── Roar.xcworkspace ├── contents.xcworkspacedata └── xcshareddata │ └── IDEWorkspaceChecks.plist ├── README.md ├── Podfile.lock ├── LICENSE └── .gitignore /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/roar/main/.DS_Store -------------------------------------------------------------------------------- /Pods/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/roar/main/Pods/.DS_Store -------------------------------------------------------------------------------- /Roar/winamp.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/roar/main/Roar/winamp.mp4 -------------------------------------------------------------------------------- /Roar/macintosh.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/roar/main/Roar/macintosh.ttf -------------------------------------------------------------------------------- /Roar/Assets.xcassets/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/roar/main/Roar/Assets.xcassets/.DS_Store -------------------------------------------------------------------------------- /Roar/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Roar/Assets.xcassets/Winamp.imageset/Winamp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/roar/main/Roar/Assets.xcassets/Winamp.imageset/Winamp.png -------------------------------------------------------------------------------- /Roar/Assets.xcassets/Macintosh.imageset/Macintosh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/roar/main/Roar/Assets.xcassets/Macintosh.imageset/Macintosh.png -------------------------------------------------------------------------------- /Roar/Assets.xcassets/iTunesMask.imageset/iTunesMask.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/roar/main/Roar/Assets.xcassets/iTunesMask.imageset/iTunesMask.png -------------------------------------------------------------------------------- /Pods/Target Support Files/FMDB/FMDB.modulemap: -------------------------------------------------------------------------------- 1 | framework module FMDB { 2 | umbrella header "FMDB-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Roar/Assets.xcassets/MusicWidget.imageset/MusicWidget.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tylerhall/roar/main/Roar/Assets.xcassets/MusicWidget.imageset/MusicWidget.png -------------------------------------------------------------------------------- /Pods/Target Support Files/FMDB/FMDB-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_FMDB : NSObject 3 | @end 4 | @implementation PodsDummy_FMDB 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-Roar/Pods-Roar.modulemap: -------------------------------------------------------------------------------- 1 | framework module Pods_Roar { 2 | umbrella header "Pods-Roar-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/MASShortcut/MASShortcut.modulemap: -------------------------------------------------------------------------------- 1 | framework module MASShortcut { 2 | umbrella header "MASShortcut-umbrella.h" 3 | 4 | export * 5 | module * { export * } 6 | } 7 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-Roar/Pods-Roar-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_Pods_Roar : NSObject 3 | @end 4 | @implementation PodsDummy_Pods_Roar 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/MASShortcut/MASShortcut-dummy.m: -------------------------------------------------------------------------------- 1 | #import 2 | @interface PodsDummy_MASShortcut : NSObject 3 | @end 4 | @implementation PodsDummy_MASShortcut 5 | @end 6 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-Roar/Pods-Roar-frameworks-Debug-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework 2 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MASShortcut.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-Roar/Pods-Roar-frameworks-Release-output-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/FMDB.framework 2 | ${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MASShortcut.framework -------------------------------------------------------------------------------- /Roar.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Roar/Roar.entitlements: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Roar/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-Roar/Pods-Roar-frameworks-Debug-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-Roar/Pods-Roar-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework 3 | ${BUILT_PRODUCTS_DIR}/MASShortcut/MASShortcut.framework -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-Roar/Pods-Roar-frameworks-Release-input-files.xcfilelist: -------------------------------------------------------------------------------- 1 | ${PODS_ROOT}/Target Support Files/Pods-Roar/Pods-Roar-frameworks.sh 2 | ${BUILT_PRODUCTS_DIR}/FMDB/FMDB.framework 3 | ${BUILT_PRODUCTS_DIR}/MASShortcut/MASShortcut.framework -------------------------------------------------------------------------------- /Podfile: -------------------------------------------------------------------------------- 1 | # Uncomment the next line to define a global platform for your project 2 | # platform :ios, '9.0' 3 | 4 | target 'Roar' do 5 | use_frameworks! 6 | inhibit_all_warnings! 7 | 8 | # Pods for Roar 9 | pod 'FMDB' 10 | pod 'MASShortcut' 11 | end 12 | -------------------------------------------------------------------------------- /Roar/BridgingHeader.h: -------------------------------------------------------------------------------- 1 | // 2 | // BridgingHeader.h 3 | // Roar 4 | // 5 | // Created by Tyler Hall on 1/3/22. 6 | // 7 | 8 | #ifndef BridgingHeader_h 9 | #define BridgingHeader_h 10 | 11 | #import 12 | 13 | #endif /* BridgingHeader_h */ 14 | -------------------------------------------------------------------------------- /Roar/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ATSApplicationFontsPath 6 | Fonts 7 | 8 | 9 | -------------------------------------------------------------------------------- /Pods/Target Support Files/FMDB/FMDB-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/Shortcut.h: -------------------------------------------------------------------------------- 1 | #import "MASKeyMasks.h" 2 | #import "MASShortcut.h" 3 | #import "MASShortcutValidator.h" 4 | #import "MASShortcutMonitor.h" 5 | #import "MASShortcutBinder.h" 6 | #import "MASDictionaryTransformer.h" 7 | #import "MASShortcutView.h" 8 | #import "MASShortcutView+Bindings.h" 9 | -------------------------------------------------------------------------------- /Pods/Target Support Files/MASShortcut/MASShortcut-prefix.pch: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | -------------------------------------------------------------------------------- /Roar.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /Roar.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Roar 2 | 3 | Let's reskin Notification Center. See [this blog post](https://tyler.io/roar-notifications). 4 | 5 | ## Thanks 6 | 7 | Big thanks to these open source projects used by Roar: 8 | 9 | * [FMDB](https://github.com/ccgus/fmdb) 10 | * [MASShortcut](https://github.com/shpakovski/MASShortcut) 11 | 12 | -------------------------------------------------------------------------------- /Roar.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Pods/FMDB/src/fmdb/FMDB.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | FOUNDATION_EXPORT double FMDBVersionNumber; 4 | FOUNDATION_EXPORT const unsigned char FMDBVersionString[]; 5 | 6 | #import "FMDatabase.h" 7 | #import "FMResultSet.h" 8 | #import "FMDatabaseAdditions.h" 9 | #import "FMDatabaseQueue.h" 10 | #import "FMDatabasePool.h" 11 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/Monitoring/MASHotKey.h: -------------------------------------------------------------------------------- 1 | #import "MASShortcut.h" 2 | 3 | extern FourCharCode const MASHotKeySignature; 4 | 5 | @interface MASHotKey : NSObject 6 | 7 | @property(readonly) UInt32 carbonID; 8 | @property(copy) dispatch_block_t action; 9 | 10 | + (instancetype) registeredHotKeyWithShortcut: (MASShortcut*) shortcut; 11 | 12 | @end 13 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-Roar/Pods-Roar-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | 14 | FOUNDATION_EXPORT double Pods_RoarVersionNumber; 15 | FOUNDATION_EXPORT const unsigned char Pods_RoarVersionString[]; 16 | 17 | -------------------------------------------------------------------------------- /Roar/Assets.xcassets/Winamp.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "Winamp.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Roar/Assets.xcassets/Macintosh.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "Macintosh.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Roar/Assets.xcassets/iTunesMask.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "iTunesMask.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Roar/Assets.xcassets/MusicWidget.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "filename" : "MusicWidget.png", 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /Podfile.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - FMDB (2.7.5): 3 | - FMDB/standard (= 2.7.5) 4 | - FMDB/standard (2.7.5) 5 | - MASShortcut (2.4.0) 6 | 7 | DEPENDENCIES: 8 | - FMDB 9 | - MASShortcut 10 | 11 | SPEC REPOS: 12 | trunk: 13 | - FMDB 14 | - MASShortcut 15 | 16 | SPEC CHECKSUMS: 17 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a 18 | MASShortcut: d9e4909e878661cc42877cc9d6efbe638273ab57 19 | 20 | PODFILE CHECKSUM: 95a1e664f5980a2e1420e3e1e591cbc30d7d1feb 21 | 22 | COCOAPODS: 1.11.2 23 | -------------------------------------------------------------------------------- /Pods/Manifest.lock: -------------------------------------------------------------------------------- 1 | PODS: 2 | - FMDB (2.7.5): 3 | - FMDB/standard (= 2.7.5) 4 | - FMDB/standard (2.7.5) 5 | - MASShortcut (2.4.0) 6 | 7 | DEPENDENCIES: 8 | - FMDB 9 | - MASShortcut 10 | 11 | SPEC REPOS: 12 | trunk: 13 | - FMDB 14 | - MASShortcut 15 | 16 | SPEC CHECKSUMS: 17 | FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a 18 | MASShortcut: d9e4909e878661cc42877cc9d6efbe638273ab57 19 | 20 | PODFILE CHECKSUM: 95a1e664f5980a2e1420e3e1e591cbc30d7d1feb 21 | 22 | COCOAPODS: 1.11.2 23 | -------------------------------------------------------------------------------- /Roar/Helpers/Extensions.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Extensions.swift 3 | // Roar 4 | // 5 | // Created by Tyler Hall on 12/21/21. 6 | // 7 | 8 | import Foundation 9 | 10 | extension Data { 11 | func writeToTempFile() -> URL? { 12 | let tempURL = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) 13 | do { 14 | try self.write(to: tempURL) 15 | return tempURL 16 | } catch { 17 | return nil 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /Roar/Displays/NoteWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NoteWindowController.swift 3 | // Roar 4 | // 5 | // Created by Tyler Hall on 12/21/21. 6 | // 7 | 8 | import AppKit 9 | 10 | protocol NoteWindowControllerDelegate { 11 | func didDisplayWindow() 12 | func didHideWindow() 13 | } 14 | 15 | class NoteWindowController: NSWindowController { 16 | 17 | var noteWindowDelegte: NoteWindowControllerDelegate? 18 | 19 | func display(note: Note) { 20 | 21 | } 22 | 23 | func hide() { 24 | 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/FMDB/FMDB-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "FMDatabase.h" 14 | #import "FMDatabaseAdditions.h" 15 | #import "FMDatabasePool.h" 16 | #import "FMDatabaseQueue.h" 17 | #import "FMDB.h" 18 | #import "FMResultSet.h" 19 | 20 | FOUNDATION_EXPORT double FMDBVersionNumber; 21 | FOUNDATION_EXPORT const unsigned char FMDBVersionString[]; 22 | 23 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/UI/MASLocalization.h: -------------------------------------------------------------------------------- 1 | /** 2 | Reads a localized string from the framework’s bundle. 3 | 4 | Normally you would use NSLocalizedString to read the localized 5 | strings, but that’s just a shortcut for loading the strings from 6 | the main bundle. And once the framework ends up in an app, the 7 | main bundle will be the app’s bundle and won’t contain our strings. 8 | So we introduced this helper function that makes sure to load the 9 | strings from the framework’s bundle. Please avoid using 10 | NSLocalizedString throughout the framework, it wouldn’t work 11 | properly. 12 | */ 13 | NSString *MASLocalizedString(NSString *key, NSString *comment); -------------------------------------------------------------------------------- /Pods/Target Support Files/FMDB/FMDB.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CODE_SIGN_IDENTITY = 3 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FMDB 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | OTHER_LDFLAGS = $(inherited) -l"sqlite3" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/FMDB 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 12 | SKIP_INSTALL = YES 13 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 14 | -------------------------------------------------------------------------------- /Pods/Target Support Files/FMDB/FMDB.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CODE_SIGN_IDENTITY = 3 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/FMDB 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | OTHER_LDFLAGS = $(inherited) -l"sqlite3" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/FMDB 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 12 | SKIP_INSTALL = YES 13 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 14 | -------------------------------------------------------------------------------- /Pods/Target Support Files/MASShortcut/MASShortcut.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CODE_SIGN_IDENTITY = 3 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/MASShortcut 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | OTHER_LDFLAGS = $(inherited) -framework "AppKit" -framework "Carbon" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/MASShortcut 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 12 | SKIP_INSTALL = YES 13 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 14 | -------------------------------------------------------------------------------- /Pods/Target Support Files/MASShortcut/MASShortcut.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | CODE_SIGN_IDENTITY = 3 | CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/MASShortcut 4 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 5 | OTHER_LDFLAGS = $(inherited) -framework "AppKit" -framework "Carbon" 6 | PODS_BUILD_DIR = ${BUILD_DIR} 7 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 8 | PODS_ROOT = ${SRCROOT} 9 | PODS_TARGET_SRCROOT = ${PODS_ROOT}/MASShortcut 10 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 11 | PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier} 12 | SKIP_INSTALL = YES 13 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 14 | -------------------------------------------------------------------------------- /Pods/Target Support Files/MASShortcut/MASShortcut-umbrella.h: -------------------------------------------------------------------------------- 1 | #ifdef __OBJC__ 2 | #import 3 | #else 4 | #ifndef FOUNDATION_EXPORT 5 | #if defined(__cplusplus) 6 | #define FOUNDATION_EXPORT extern "C" 7 | #else 8 | #define FOUNDATION_EXPORT extern 9 | #endif 10 | #endif 11 | #endif 12 | 13 | #import "MASKeyCodes.h" 14 | #import "MASKeyMasks.h" 15 | #import "MASShortcut.h" 16 | #import "MASShortcutValidator.h" 17 | #import "MASHotKey.h" 18 | #import "MASShortcutMonitor.h" 19 | #import "Shortcut.h" 20 | #import "MASLocalization.h" 21 | #import "MASShortcutView+Bindings.h" 22 | #import "MASShortcutView.h" 23 | #import "MASDictionaryTransformer.h" 24 | #import "MASShortcutBinder.h" 25 | 26 | FOUNDATION_EXPORT double MASShortcutVersionNumber; 27 | FOUNDATION_EXPORT const unsigned char MASShortcutVersionString[]; 28 | 29 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/User Defaults Storage/MASDictionaryTransformer.h: -------------------------------------------------------------------------------- 1 | extern NSString *const MASDictionaryTransformerName; 2 | 3 | /** 4 | Converts shortcuts for storage in user defaults. 5 | 6 | User defaults can’t stored custom types directly, they have to 7 | be serialized to `NSData` or some other supported type like an 8 | `NSDictionary`. In Cocoa Bindings, the conversion can be done 9 | using value transformers like this one. 10 | 11 | There’s a built-in transformer (`NSKeyedUnarchiveFromDataTransformerName`) 12 | that converts any `NSCoding` types to `NSData`, but with shortcuts 13 | it makes sense to use a dictionary instead – the defaults look better 14 | when inspected with the `defaults` command-line utility and the 15 | format is compatible with an older sortcut library called Shortcut 16 | Recorder. 17 | */ 18 | @interface MASDictionaryTransformer : NSValueTransformer 19 | @end 20 | -------------------------------------------------------------------------------- /Pods/Target Support Files/MASShortcut/ResourceBundle-MASShortcut-MASShortcut-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleIdentifier 8 | ${PRODUCT_BUNDLE_IDENTIFIER} 9 | CFBundleInfoDictionaryVersion 10 | 6.0 11 | CFBundleName 12 | ${PRODUCT_NAME} 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 2.4.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | NSPrincipalClass 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /Roar/Windows/PrefsWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // PrefsWindowController.swift 3 | // Roar 4 | // 5 | // Created by Tyler Hall on 1/3/22. 6 | // 7 | 8 | import Cocoa 9 | 10 | class PrefsWindowController: NSWindowController { 11 | 12 | static let kActionShortcutPref = "kActionShortcutPref" 13 | 14 | @IBOutlet weak var actionShortcutView: MASShortcutView! 15 | 16 | override func windowDidLoad() { 17 | super.windowDidLoad() 18 | actionShortcutView.associatedUserDefaultsKey = PrefsWindowController.kActionShortcutPref 19 | } 20 | 21 | @IBAction func showNotificationPreview(_ sender: AnyObject?) { 22 | let note = Note(title: "Test Notification", subtitle: "This is the subtitle", body: "The quick lazy apple jumped over the brown zune.", date: Date(), appID: "com.apple.Music") 23 | let op = NoteDisplayOperation(note: note) 24 | NCWatcher.shared.opQueue.addOperation(op) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Pods/Target Support Files/FMDB/FMDB-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 2.7.5 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/Monitoring/MASShortcutMonitor.h: -------------------------------------------------------------------------------- 1 | #import "MASShortcut.h" 2 | 3 | /** 4 | Executes action when a shortcut is pressed. 5 | 6 | There can only be one instance of this class, otherwise things 7 | will probably not work. (There’s a Carbon event handler inside 8 | and there can only be one Carbon event handler of a given type.) 9 | */ 10 | @interface MASShortcutMonitor : NSObject 11 | 12 | - (instancetype) init __unavailable; 13 | + (instancetype) sharedMonitor; 14 | 15 | /** 16 | Register a shortcut along with an action. 17 | 18 | Attempting to insert an already registered shortcut probably won’t work. 19 | It may burn your house or cut your fingers. You have been warned. 20 | */ 21 | - (BOOL) registerShortcut: (MASShortcut*) shortcut withAction: (dispatch_block_t) action; 22 | - (BOOL) isShortcutRegistered: (MASShortcut*) shortcut; 23 | 24 | - (void) unregisterShortcut: (MASShortcut*) shortcut; 25 | - (void) unregisterAllShortcuts; 26 | 27 | @end 28 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-Roar/Pods-Roar-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 1.0.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/Model/MASKeyMasks.h: -------------------------------------------------------------------------------- 1 | #import 2 | 3 | // https://github.com/shpakovski/MASShortcut/issues/99 4 | // 5 | // Long story short: NSControlKeyMask and friends were replaced with NSEventModifierFlagControl 6 | // and similar in macOS Sierra. The project builds fine & clean, but including MASShortcut in 7 | // a project with deployment target set to 10.12 results in several deprecation warnings because 8 | // of the control masks. Simply replacing the old symbols with the new ones isn’t an option, 9 | // since it breaks the build on older SDKs – in Travis, for example. 10 | // 11 | // It should be safe to remove this whole thing once the 10.12 SDK is ubiquitous. 12 | 13 | #if __MAC_OS_X_VERSION_MAX_ALLOWED < 101200 14 | #define NSEventModifierFlagCommand NSCommandKeyMask 15 | #define NSEventModifierFlagControl NSControlKeyMask 16 | #define NSEventModifierFlagOption NSAlternateKeyMask 17 | #define NSEventModifierFlagShift NSShiftKeyMask 18 | #endif 19 | -------------------------------------------------------------------------------- /Pods/Target Support Files/MASShortcut/MASShortcut-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ${PRODUCT_BUNDLE_IDENTIFIER} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | ${PRODUCT_NAME} 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 2.4.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | ${CURRENT_PROJECT_VERSION} 23 | NSPrincipalClass 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/UI/MASShortcutView.h: -------------------------------------------------------------------------------- 1 | @class MASShortcut, MASShortcutValidator; 2 | 3 | extern NSString *const MASShortcutBinding; 4 | 5 | typedef NS_ENUM(NSInteger, MASShortcutViewStyle) { 6 | MASShortcutViewStyleDefault = 0, // Height = 19 px 7 | MASShortcutViewStyleTexturedRect, // Height = 25 px 8 | MASShortcutViewStyleRounded, // Height = 43 px 9 | MASShortcutViewStyleFlat 10 | }; 11 | 12 | @interface MASShortcutView : NSView 13 | 14 | @property (nonatomic, strong) MASShortcut *shortcutValue; 15 | @property (nonatomic, strong) MASShortcutValidator *shortcutValidator; 16 | @property (nonatomic, getter = isRecording) BOOL recording; 17 | @property (nonatomic, getter = isEnabled) BOOL enabled; 18 | @property (nonatomic, copy) void (^shortcutValueChange)(MASShortcutView *sender); 19 | @property (nonatomic, assign) MASShortcutViewStyle style; 20 | 21 | /// Returns custom class for drawing control. 22 | + (Class)shortcutCellClass; 23 | 24 | - (void)setAcceptsFirstResponder:(BOOL)value; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/UI/MASShortcutView+Bindings.h: -------------------------------------------------------------------------------- 1 | #import "MASShortcutView.h" 2 | 3 | /** 4 | A simplified interface to bind the recorder value to user defaults. 5 | 6 | You can bind the `shortcutValue` to user defaults using the standard 7 | `bind:toObject:withKeyPath:options:` call, but since that’s a lot to type 8 | and read, here’s a simpler option. 9 | 10 | Setting the `associatedUserDefaultsKey` binds the view’s shortcut value 11 | to the given user defaults key. You can supply a value transformer to convert 12 | values between user defaults and `MASShortcut`. If you don’t supply 13 | a transformer, the `NSUnarchiveFromDataTransformerName` will be used 14 | automatically. 15 | 16 | Set `associatedUserDefaultsKey` to `nil` to disconnect the binding. 17 | */ 18 | @interface MASShortcutView (Bindings) 19 | 20 | @property(copy) NSString *associatedUserDefaultsKey; 21 | 22 | - (void) setAssociatedUserDefaultsKey: (NSString*) newKey withTransformer: (NSValueTransformer*) transformer; 23 | - (void) setAssociatedUserDefaultsKey: (NSString*) newKey withTransformerName: (NSString*) transformerName; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Tyler Hall 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/Monitoring/MASHotKey.m: -------------------------------------------------------------------------------- 1 | #import "MASHotKey.h" 2 | 3 | FourCharCode const MASHotKeySignature = 'MASS'; 4 | 5 | @interface MASHotKey () 6 | @property(assign) EventHotKeyRef hotKeyRef; 7 | @property(assign) UInt32 carbonID; 8 | @end 9 | 10 | @implementation MASHotKey 11 | 12 | - (instancetype) initWithShortcut: (MASShortcut*) shortcut 13 | { 14 | self = [super init]; 15 | 16 | static UInt32 CarbonHotKeyID = 0; 17 | 18 | _carbonID = ++CarbonHotKeyID; 19 | EventHotKeyID hotKeyID = { .signature = MASHotKeySignature, .id = _carbonID }; 20 | 21 | OSStatus status = RegisterEventHotKey([shortcut carbonKeyCode], [shortcut carbonFlags], 22 | hotKeyID, GetEventDispatcherTarget(), 0, &_hotKeyRef); 23 | 24 | if (status != noErr) { 25 | return nil; 26 | } 27 | 28 | return self; 29 | } 30 | 31 | + (instancetype) registeredHotKeyWithShortcut: (MASShortcut*) shortcut 32 | { 33 | return [[self alloc] initWithShortcut:shortcut]; 34 | } 35 | 36 | - (void) dealloc 37 | { 38 | if (_hotKeyRef) { 39 | UnregisterEventHotKey(_hotKeyRef); 40 | _hotKeyRef = NULL; 41 | } 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /Roar/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "mac", 5 | "scale" : "1x", 6 | "size" : "16x16" 7 | }, 8 | { 9 | "idiom" : "mac", 10 | "scale" : "2x", 11 | "size" : "16x16" 12 | }, 13 | { 14 | "idiom" : "mac", 15 | "scale" : "1x", 16 | "size" : "32x32" 17 | }, 18 | { 19 | "idiom" : "mac", 20 | "scale" : "2x", 21 | "size" : "32x32" 22 | }, 23 | { 24 | "idiom" : "mac", 25 | "scale" : "1x", 26 | "size" : "128x128" 27 | }, 28 | { 29 | "idiom" : "mac", 30 | "scale" : "2x", 31 | "size" : "128x128" 32 | }, 33 | { 34 | "idiom" : "mac", 35 | "scale" : "1x", 36 | "size" : "256x256" 37 | }, 38 | { 39 | "idiom" : "mac", 40 | "scale" : "2x", 41 | "size" : "256x256" 42 | }, 43 | { 44 | "idiom" : "mac", 45 | "scale" : "1x", 46 | "size" : "512x512" 47 | }, 48 | { 49 | "idiom" : "mac", 50 | "scale" : "2x", 51 | "size" : "512x512" 52 | } 53 | ], 54 | "info" : { 55 | "author" : "xcode", 56 | "version" : 1 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/Model/MASShortcutValidator.h: -------------------------------------------------------------------------------- 1 | #import "MASShortcut.h" 2 | 3 | /** 4 | This class is used by the recording control to tell which shortcuts are acceptable. 5 | 6 | There are two kinds of shortcuts that are not considered acceptable: shortcuts that 7 | are too simple (like single letter keys) and shortcuts that are already used by the 8 | operating system. 9 | */ 10 | @interface MASShortcutValidator : NSObject 11 | 12 | /** 13 | Set to `YES` if you want to accept Option-something shortcuts. 14 | 15 | `NO` by default, since Option-something shortcuts are often used by system, 16 | for example Option-G will type the © sign. This also applies to Option-Shift 17 | shortcuts – in other words, shortcut recorder will not accept shortcuts like 18 | Option-Shift-K by default. (Again, since Option-Shift-K inserts the Apple 19 | logo sign by default.) 20 | */ 21 | @property(assign) BOOL allowAnyShortcutWithOptionModifier; 22 | 23 | + (instancetype) sharedValidator; 24 | 25 | - (BOOL) isShortcutValid: (MASShortcut*) shortcut; 26 | - (BOOL) isShortcut: (MASShortcut*) shortcut alreadyTakenInMenu: (NSMenu*) menu explanation: (NSString**) explanation; 27 | - (BOOL) isShortcutAlreadyTakenBySystem: (MASShortcut*) shortcut explanation: (NSString**) explanation; 28 | 29 | @end 30 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-Roar/Pods-Roar.debug.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FMDB" "${PODS_CONFIGURATION_BUILD_DIR}/MASShortcut" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FMDB/FMDB.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MASShortcut/MASShortcut.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/Frameworks' 6 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_CONFIGURATION_BUILD_DIR}/FMDB/FMDB.framework/Headers" -isystem "${PODS_CONFIGURATION_BUILD_DIR}/MASShortcut/MASShortcut.framework/Headers" -iframework "${PODS_CONFIGURATION_BUILD_DIR}/FMDB" -iframework "${PODS_CONFIGURATION_BUILD_DIR}/MASShortcut" 7 | OTHER_LDFLAGS = $(inherited) -l"sqlite3" -framework "AppKit" -framework "Carbon" -framework "FMDB" -framework "MASShortcut" 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 13 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 14 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-Roar/Pods-Roar.release.xcconfig: -------------------------------------------------------------------------------- 1 | CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO 2 | FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FMDB" "${PODS_CONFIGURATION_BUILD_DIR}/MASShortcut" 3 | GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 4 | HEADER_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/FMDB/FMDB.framework/Headers" "${PODS_CONFIGURATION_BUILD_DIR}/MASShortcut/MASShortcut.framework/Headers" 5 | LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/../Frameworks' '@loader_path/Frameworks' 6 | OTHER_CFLAGS = $(inherited) -isystem "${PODS_CONFIGURATION_BUILD_DIR}/FMDB/FMDB.framework/Headers" -isystem "${PODS_CONFIGURATION_BUILD_DIR}/MASShortcut/MASShortcut.framework/Headers" -iframework "${PODS_CONFIGURATION_BUILD_DIR}/FMDB" -iframework "${PODS_CONFIGURATION_BUILD_DIR}/MASShortcut" 7 | OTHER_LDFLAGS = $(inherited) -l"sqlite3" -framework "AppKit" -framework "Carbon" -framework "FMDB" -framework "MASShortcut" 8 | PODS_BUILD_DIR = ${BUILD_DIR} 9 | PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) 10 | PODS_PODFILE_DIR_PATH = ${SRCROOT}/. 11 | PODS_ROOT = ${SRCROOT}/Pods 12 | PODS_XCFRAMEWORKS_BUILD_DIR = $(PODS_CONFIGURATION_BUILD_DIR)/XCFrameworkIntermediates 13 | USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES 14 | -------------------------------------------------------------------------------- /Roar/Windows/ActionWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ActionWindowController.swift 3 | // Roar 4 | // 5 | // Created by Tyler Hall on 1/3/22. 6 | // 7 | 8 | import Cocoa 9 | 10 | class ActionWindowController: NSWindowController, NSWindowDelegate { 11 | 12 | @IBOutlet weak var codeLabel: NSTextField! 13 | @IBOutlet weak var urlLabel: NSTextField! 14 | @IBOutlet weak var appLabel: NSTextField! 15 | @IBOutlet weak var copyLabel: NSTextField! 16 | 17 | var note: Note? { 18 | didSet { 19 | if let note = note { 20 | codeLabel.textColor = (note.code != nil) ? .labelColor : .tertiaryLabelColor 21 | urlLabel.textColor = (note.urls.count > 0) ? .labelColor : .tertiaryLabelColor 22 | appLabel.textColor = .labelColor 23 | copyLabel.textColor = .labelColor 24 | } else { 25 | codeLabel.textColor = .tertiaryLabelColor 26 | urlLabel.textColor = .tertiaryLabelColor 27 | appLabel.textColor = .tertiaryLabelColor 28 | copyLabel.textColor = .tertiaryLabelColor 29 | } 30 | } 31 | } 32 | 33 | override func windowDidLoad() { 34 | super.windowDidLoad() 35 | } 36 | 37 | func windowWillClose(_ notification: Notification) { 38 | NSApp.hide(nil) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /Pods/MASShortcut/LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012-2013, Vadim Shpakovski 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, this 8 | list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | -------------------------------------------------------------------------------- /Pods/FMDB/LICENSE.txt: -------------------------------------------------------------------------------- 1 | If you are using FMDB in your project, I'd love to hear about it. Let Gus know 2 | by sending an email to gus@flyingmeat.com. 3 | 4 | And if you happen to come across either Gus Mueller or Rob Ryan in a bar, you 5 | might consider purchasing a drink of their choosing if FMDB has been useful to 6 | you. 7 | 8 | Finally, and shortly, this is the MIT License. 9 | 10 | Copyright (c) 2008-2014 Flying Meat Inc. 11 | 12 | Permission is hereby granted, free of charge, to any person obtaining a copy 13 | of this software and associated documentation files (the "Software"), to deal 14 | in the Software without restriction, including without limitation the rights 15 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 16 | copies of the Software, and to permit persons to whom the Software is 17 | furnished to do so, subject to the following conditions: 18 | 19 | The above copyright notice and this permission notice shall be included in 20 | all copies or substantial portions of the Software. 21 | 22 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 23 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 25 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 27 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 28 | THE SOFTWARE. -------------------------------------------------------------------------------- /Roar/Displays/BezelWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BezelWindowController.swift 3 | // Roar 4 | // 5 | // Created by Tyler Hall on 12/21/21. 6 | // 7 | 8 | import AppKit 9 | 10 | class BezelWindowController: NoteWindowController { 11 | 12 | @IBOutlet weak var backgroundView: NSView! 13 | @IBOutlet weak var appIconView: NSImageView! 14 | @IBOutlet weak var titleLabel: NSTextField! 15 | @IBOutlet weak var subtitleLabel: NSTextField! 16 | @IBOutlet weak var bodyLabel: NSTextField! 17 | 18 | override func display(note: Note) { 19 | window?.backgroundColor = .clear 20 | window?.ignoresMouseEvents = true 21 | window?.level = NSWindow.Level.init(Int(CGWindowLevelForKey(CGWindowLevelKey.mainMenuWindow))) 22 | 23 | titleLabel.stringValue = note.title ?? "" 24 | subtitleLabel.stringValue = note.subtitle ?? "" 25 | bodyLabel.stringValue = note.body ?? "" 26 | 27 | if let appPath = NSWorkspace.shared.urlForApplication(withBundleIdentifier: note.appID)?.path { 28 | let icon = NSWorkspace.shared.icon(forFile: appPath) 29 | appIconView.image = icon 30 | } 31 | 32 | backgroundView.wantsLayer = true 33 | backgroundView.layer?.backgroundColor = NSColor.black.withAlphaComponent(0.45).cgColor 34 | backgroundView.layer?.cornerRadius = 16 35 | 36 | showWindow(nil) 37 | window?.center() 38 | 39 | DispatchQueue.main.asyncAfter(deadline: .now() + 2.5, execute: { 40 | self.noteWindowDelegte?.didDisplayWindow() 41 | }) 42 | } 43 | 44 | override func hide() { 45 | window?.close() 46 | noteWindowDelegte?.didHideWindow() 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Roar/Watcher/NoteDisplayOperation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NoteDisplayOperation.swift 3 | // Roar 4 | // 5 | // Created by Tyler Hall on 12/21/21. 6 | // 7 | 8 | import Foundation 9 | 10 | class NoteDisplayOperation: AsyncOperation, NoteWindowControllerDelegate { 11 | 12 | var note: Note 13 | var wc: NoteWindowController? 14 | 15 | init(note: Note) { 16 | self.note = note 17 | } 18 | 19 | override func main() { 20 | NCWatcher.shared.lastNote = note 21 | 22 | DispatchQueue.main.async { 23 | switch self.note.defaultDisplayStyle { 24 | case .MusicVideo: 25 | self.wc = MusicVideoWindowController(windowNibName: String(describing: MusicVideoWindowController.self)) 26 | case .Bezel: 27 | self.wc = BezelWindowController(windowNibName: String(describing: BezelWindowController.self)) 28 | case .Winamp: 29 | self.wc = WinampWindowController(windowNibName: String(describing: WinampWindowController.self)) 30 | case .iTunesWidget: 31 | self.wc = iTunesWidgetWindowController(windowNibName: String(describing: iTunesWidgetWindowController.self)) 32 | case .Macintosh: 33 | self.wc = MacintoshWindowController(windowNibName: String(describing: MacintoshWindowController.self)) 34 | } 35 | 36 | self.wc?.noteWindowDelegte = self 37 | self.wc?.display(note: self.note) 38 | } 39 | } 40 | 41 | func didDisplayWindow() { 42 | DispatchQueue.main.asyncAfter(deadline: .now() + 2.5, execute: { 43 | self.wc?.hide() 44 | }) 45 | } 46 | 47 | func didHideWindow() { 48 | finish() 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/Model/MASKeyCodes.h: -------------------------------------------------------------------------------- 1 | #import 2 | #import 3 | #import "MASKeyMasks.h" 4 | 5 | // These glyphs are missed in Carbon.h 6 | typedef NS_ENUM(unsigned short, kMASShortcutGlyph) { 7 | kMASShortcutGlyphEject = 0x23CF, 8 | kMASShortcutGlyphClear = 0x2715, 9 | kMASShortcutGlyphDeleteLeft = 0x232B, 10 | kMASShortcutGlyphDeleteRight = 0x2326, 11 | kMASShortcutGlyphLeftArrow = 0x2190, 12 | kMASShortcutGlyphRightArrow = 0x2192, 13 | kMASShortcutGlyphUpArrow = 0x2191, 14 | kMASShortcutGlyphDownArrow = 0x2193, 15 | kMASShortcutGlyphEscape = 0x238B, 16 | kMASShortcutGlyphHelp = 0x003F, 17 | kMASShortcutGlyphPageDown = 0x21DF, 18 | kMASShortcutGlyphPageUp = 0x21DE, 19 | kMASShortcutGlyphTabRight = 0x21E5, 20 | kMASShortcutGlyphReturn = 0x2305, 21 | kMASShortcutGlyphReturnR2L = 0x21A9, 22 | kMASShortcutGlyphPadClear = 0x2327, 23 | kMASShortcutGlyphNorthwestArrow = 0x2196, 24 | kMASShortcutGlyphSoutheastArrow = 0x2198, 25 | }; 26 | 27 | NS_INLINE NSString* NSStringFromMASKeyCode(unsigned short ch) 28 | { 29 | return [NSString stringWithFormat:@"%C", ch]; 30 | } 31 | 32 | NS_INLINE NSUInteger MASPickCocoaModifiers(NSUInteger flags) 33 | { 34 | return (flags & (NSEventModifierFlagControl | NSEventModifierFlagShift | NSEventModifierFlagOption | NSEventModifierFlagCommand)); 35 | } 36 | 37 | NS_INLINE UInt32 MASCarbonModifiersFromCocoaModifiers(NSUInteger cocoaFlags) 38 | { 39 | return 40 | (cocoaFlags & NSEventModifierFlagCommand ? cmdKey : 0) 41 | | (cocoaFlags & NSEventModifierFlagOption ? optionKey : 0) 42 | | (cocoaFlags & NSEventModifierFlagControl ? controlKey : 0) 43 | | (cocoaFlags & NSEventModifierFlagShift ? shiftKey : 0); 44 | } 45 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/UI/MASShortcutView+Bindings.m: -------------------------------------------------------------------------------- 1 | #import "MASShortcutView+Bindings.h" 2 | 3 | @implementation MASShortcutView (Bindings) 4 | 5 | - (NSString*) associatedUserDefaultsKey 6 | { 7 | NSDictionary* bindingInfo = [self infoForBinding:MASShortcutBinding]; 8 | if (bindingInfo != nil) { 9 | NSString *keyPath = [bindingInfo objectForKey:NSObservedKeyPathKey]; 10 | NSString *key = [keyPath stringByReplacingOccurrencesOfString:@"values." withString:@""]; 11 | return key; 12 | } else { 13 | return nil; 14 | } 15 | } 16 | 17 | - (void) setAssociatedUserDefaultsKey: (NSString*) newKey withTransformer: (NSValueTransformer*) transformer 18 | { 19 | // Break previous binding if any 20 | NSString *currentKey = [self associatedUserDefaultsKey]; 21 | if (currentKey != nil) { 22 | [self unbind:currentKey]; 23 | } 24 | 25 | // Stop if the new binding is nil 26 | if (newKey == nil) { 27 | return; 28 | } 29 | 30 | NSDictionary *options = transformer ? 31 | @{NSValueTransformerBindingOption:transformer} : 32 | nil; 33 | 34 | [self bind:MASShortcutBinding 35 | toObject:[NSUserDefaultsController sharedUserDefaultsController] 36 | withKeyPath:[@"values." stringByAppendingString:newKey] 37 | options:options]; 38 | } 39 | 40 | - (void) setAssociatedUserDefaultsKey: (NSString*) newKey withTransformerName: (NSString*) transformerName 41 | { 42 | [self setAssociatedUserDefaultsKey:newKey withTransformer:[NSValueTransformer valueTransformerForName:transformerName]]; 43 | } 44 | 45 | - (void) setAssociatedUserDefaultsKey: (NSString*) newKey 46 | { 47 | [self setAssociatedUserDefaultsKey:newKey withTransformerName:NSKeyedUnarchiveFromDataTransformerName]; 48 | } 49 | 50 | @end 51 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/User Defaults Storage/MASDictionaryTransformer.m: -------------------------------------------------------------------------------- 1 | #import "MASDictionaryTransformer.h" 2 | #import "MASShortcut.h" 3 | 4 | NSString *const MASDictionaryTransformerName = @"MASDictionaryTransformer"; 5 | 6 | static NSString *const MASKeyCodeKey = @"keyCode"; 7 | static NSString *const MASModifierFlagsKey = @"modifierFlags"; 8 | 9 | @implementation MASDictionaryTransformer 10 | 11 | + (BOOL) allowsReverseTransformation 12 | { 13 | return YES; 14 | } 15 | 16 | // Storing nil values as an empty dictionary lets us differ between 17 | // “not available, use default value” and “explicitly set to none”. 18 | // See http://stackoverflow.com/questions/5540760 for details. 19 | - (NSDictionary*) reverseTransformedValue: (MASShortcut*) shortcut 20 | { 21 | if (shortcut == nil) { 22 | return [NSDictionary dictionary]; 23 | } else { 24 | return @{ 25 | MASKeyCodeKey: @([shortcut keyCode]), 26 | MASModifierFlagsKey: @([shortcut modifierFlags]) 27 | }; 28 | } 29 | } 30 | 31 | - (MASShortcut*) transformedValue: (NSDictionary*) dictionary 32 | { 33 | // We have to be defensive here as the value may come from user defaults. 34 | if (![dictionary isKindOfClass:[NSDictionary class]]) { 35 | return nil; 36 | } 37 | 38 | id keyCodeBox = [dictionary objectForKey:MASKeyCodeKey]; 39 | id modifierFlagsBox = [dictionary objectForKey:MASModifierFlagsKey]; 40 | 41 | SEL integerValue = @selector(integerValue); 42 | if (![keyCodeBox respondsToSelector:integerValue] || ![modifierFlagsBox respondsToSelector:integerValue]) { 43 | return nil; 44 | } 45 | 46 | return [MASShortcut 47 | shortcutWithKeyCode:[keyCodeBox integerValue] 48 | modifierFlags:[modifierFlagsBox integerValue]]; 49 | } 50 | 51 | @end 52 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/UI/MASLocalization.m: -------------------------------------------------------------------------------- 1 | #import "MASLocalization.h" 2 | #import "MASShortcut.h" 3 | 4 | static NSString *const MASLocalizationTableName = @"Localizable"; 5 | static NSString *const MASPlaceholderLocalizationString = @"XXX"; 6 | 7 | // The CocoaPods trickery here is needed because when the code 8 | // is built as a part of CocoaPods, it won’t make a separate framework 9 | // and the Localized.strings file won’t be bundled correctly. 10 | // See https://github.com/shpakovski/MASShortcut/issues/74 11 | NSString *MASLocalizedString(NSString *key, NSString *comment) { 12 | static NSBundle *localizationBundle = nil; 13 | static dispatch_once_t onceToken; 14 | dispatch_once(&onceToken, ^{ 15 | NSBundle *frameworkBundle = [NSBundle bundleForClass:[MASShortcut class]]; 16 | // first we'll check if resources bundle was copied to MASShortcut framework bundle when !use_frameworks option is active 17 | NSURL *cocoaPodsBundleURL = [frameworkBundle URLForResource:@"MASShortcut" withExtension:@"bundle"]; 18 | if (cocoaPodsBundleURL) { 19 | localizationBundle = [NSBundle bundleWithURL: cocoaPodsBundleURL]; 20 | } else { 21 | // trying to fetch cocoapods bundle from main bundle 22 | cocoaPodsBundleURL = [[NSBundle mainBundle] URLForResource: @"MASShortcut" withExtension:@"bundle"]; 23 | if (cocoaPodsBundleURL) { 24 | localizationBundle = [NSBundle bundleWithURL: cocoaPodsBundleURL]; 25 | } else { 26 | // fallback to framework bundle 27 | localizationBundle = frameworkBundle; 28 | } 29 | } 30 | }); 31 | return [localizationBundle localizedStringForKey:key 32 | value:MASPlaceholderLocalizationString 33 | table:MASLocalizationTableName]; 34 | } 35 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Resources/zh-Hans.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Cancel action button in recording state */ 2 | "Cancel" = "取消"; 3 | 4 | /* Tooltip for non-empty shortcut button */ 5 | "Click to record new shortcut" = "点击以记录新快捷键"; 6 | 7 | /* Tooltip for hint button near the non-empty shortcut */ 8 | "Delete shortcut" = "删除快捷键"; 9 | 10 | /* VoiceOver title */ 11 | "keyboard shortcut" = "键盘快捷键"; 12 | 13 | /* Alert button when shortcut is already used */ 14 | "OK" = "好"; 15 | 16 | /* Empty shortcut button in normal state */ 17 | "Record Shortcut" = "记录快捷键"; 18 | 19 | /* VoiceOver: Shortcut cleared */ 20 | "Shortcut cleared" = "快捷键已清除"; 21 | 22 | /* VoiceOver: Shortcut set */ 23 | "Shortcut set" = "快捷键已设置"; 24 | 25 | /* Shortcut glyph name for SPACE key */ 26 | "Space" = "空格键"; 27 | 28 | /* Title for alert when shortcut is already used */ 29 | "The key combination %@ cannot be used" = "按键组合“%@”无法使用"; 30 | 31 | /* Message for alert when shortcut is already used by the system */ 32 | "This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "当前按键组合无法使用,因为它已经用作其他系统全局快捷键。\n如果您真的想使用这个按键组合,大部分系统全局快捷键能在“系统偏好设置”里的“键盘”和“鼠标”面板中重设。"; 33 | 34 | /* Message for alert when shortcut is already used */ 35 | "This shortcut cannot be used because it is already used by the menu item ‘%@’." = "当前快捷键无法使用,因为它已用作菜单项“%@”的快捷键。"; 36 | 37 | /* VoiceOver shortcut help */ 38 | "To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "若要记录新的快捷键,单击此按钮,然后键入新的快捷键,或者按“delete键”删除已经存在的快捷键。"; 39 | 40 | /* Non-empty shortcut button in recording state */ 41 | "Type New Shortcut" = "键入新快捷键"; 42 | 43 | /* Empty shortcut button in recording state */ 44 | "Type Shortcut" = "键入快捷键"; 45 | 46 | /* Cancel action button for non-empty shortcut in recording state */ 47 | "Use Old Shortcut" = "还原快捷键"; 48 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Resources/zh-Hant.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Cancel action button in recording state */ 2 | "Cancel" = "取消"; 3 | 4 | /* Tooltip for non-empty shortcut button */ 5 | "Click to record new shortcut" = "點選以記錄新快捷鍵"; 6 | 7 | /* Tooltip for hint button near the non-empty shortcut */ 8 | "Delete shortcut" = "刪除快捷鍵"; 9 | 10 | /* VoiceOver title */ 11 | "keyboard shortcut" = "鍵盤快捷鍵"; 12 | 13 | /* Alert button when shortcut is already used */ 14 | "OK" = "好"; 15 | 16 | /* Empty shortcut button in normal state */ 17 | "Record Shortcut" = "記錄快捷鍵"; 18 | 19 | /* VoiceOver: Shortcut cleared */ 20 | "Shortcut cleared" = "快捷鍵已清除"; 21 | 22 | /* VoiceOver: Shortcut set */ 23 | "Shortcut set" = "快捷鍵已設定"; 24 | 25 | /* Shortcut glyph name for SPACE key */ 26 | "Space" = "空格鍵"; 27 | 28 | /* Title for alert when shortcut is already used */ 29 | "The key combination %@ cannot be used" = "按鍵組合“%@”無法使用"; 30 | 31 | /* Message for alert when shortcut is already used by the system */ 32 | "This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "當前按鍵組合無法使用,因為它已經用作其他系統全局快捷鍵。\n如果您真的想使用這個按鍵組合,大部分系統全局快捷鍵能在“系統偏好設定”裡的“鍵盤”和“滑鼠”面板中重設。"; 33 | 34 | /* Message for alert when shortcut is already used */ 35 | "This shortcut cannot be used because it is already used by the menu item ‘%@’." = "當前快捷鍵無法使用,因為它已用作選單項“%@”的快捷鍵。"; 36 | 37 | /* VoiceOver shortcut help */ 38 | "To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "若要記錄新的快捷鍵,單擊此按鈕,然後鍵入新的快捷鍵,或者按“delete鍵”刪除已經存在的快捷鍵。"; 39 | 40 | /* Non-empty shortcut button in recording state */ 41 | "Type New Shortcut" = "鍵入新快捷鍵"; 42 | 43 | /* Empty shortcut button in recording state */ 44 | "Type Shortcut" = "鍵入快捷鍵"; 45 | 46 | /* Cancel action button for non-empty shortcut in recording state */ 47 | "Use Old Shortcut" = "還原快捷鍵"; 48 | -------------------------------------------------------------------------------- /Roar/Helpers/AsyncOperation.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MyOp.swift 3 | // AntiPhoto 4 | // 5 | // Created by Tyler Hall on 11/16/20. 6 | // 7 | 8 | import Foundation 9 | 10 | open class AsyncOperation: Operation { 11 | private let lockQueue = DispatchQueue(label: "io.tyler.Roar", attributes: .concurrent) 12 | 13 | override open var isAsynchronous: Bool { 14 | return true 15 | } 16 | 17 | private var _isExecuting: Bool = false 18 | override open private(set) var isExecuting: Bool { 19 | get { 20 | return lockQueue.sync { () -> Bool in 21 | return _isExecuting 22 | } 23 | } 24 | set { 25 | willChangeValue(forKey: "isExecuting") 26 | lockQueue.sync(flags: [.barrier]) { 27 | _isExecuting = newValue 28 | } 29 | didChangeValue(forKey: "isExecuting") 30 | } 31 | } 32 | 33 | private var _isFinished: Bool = false 34 | override open private(set) var isFinished: Bool { 35 | get { 36 | return lockQueue.sync { () -> Bool in 37 | return _isFinished 38 | } 39 | } 40 | set { 41 | willChangeValue(forKey: "isFinished") 42 | lockQueue.sync(flags: [.barrier]) { 43 | _isFinished = newValue 44 | } 45 | didChangeValue(forKey: "isFinished") 46 | } 47 | } 48 | 49 | override open func start() { 50 | guard !isCancelled else { 51 | finish() 52 | return 53 | } 54 | 55 | isFinished = false 56 | isExecuting = true 57 | main() 58 | } 59 | 60 | override open func main() { 61 | DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + DispatchTimeInterval.seconds(1), execute: { 62 | self.finish() 63 | }) 64 | } 65 | 66 | open func finish() { 67 | isExecuting = false 68 | isFinished = true 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Resources/ko.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Cancel action button in recording state */ 2 | "Cancel" = "취소"; 3 | 4 | /* Tooltip for non-empty shortcut button */ 5 | "Click to record new shortcut" = "클릭해 단축 키를 입력"; 6 | 7 | /* Tooltip for hint button near the non-empty shortcut */ 8 | "Delete shortcut" = "단축키 삭제"; 9 | 10 | /* VoiceOver title */ 11 | "keyboard shortcut" = "키보드 단축키"; 12 | 13 | /* Alert button when shortcut is already used */ 14 | "OK" = "좋아"; 15 | 16 | /* Empty shortcut button in normal state */ 17 | "Record Shortcut" = "단축키 입력"; 18 | 19 | /* VoiceOver: Shortcut cleared */ 20 | "Shortcut cleared" = "단축키 삭제됨"; 21 | 22 | /* VoiceOver: Shortcut set */ 23 | "Shortcut set" = "단축키 설정됨"; 24 | 25 | /* Shortcut glyph name for SPACE key */ 26 | "Space" = "스페이스 바"; 27 | 28 | /* Title for alert when shortcut is already used */ 29 | "The key combination %@ cannot be used" = "%@ 단축키로 설정할 수 없습니다"; 30 | 31 | /* Message for alert when shortcut is already used by the system */ 32 | "This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "이 결합은 시스템 전체에서 사용 때문에 단축키로 설정 할 수 없습니다.\n단축키를 사용하고 싶으면 시스템 환경 설정의 키보드, 마우스 패널에서 이미 설정되어있는 단축키를 변경하십시오."; 33 | 34 | /* Message for alert when shortcut is already used */ 35 | "This shortcut cannot be used because it is already used by the menu item ‘%@’." = "이 단축키는 ‘%@’ 메뉴 아이템에 사용되고 있기 때문에 설정할 수 없습니다."; 36 | 37 | /* VoiceOver shortcut help */ 38 | "To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "이 버튼을 클릭하고 단축키를 입력하면 새로운 단축키가 설정됩니다. 또한 삭제 버튼을 누르면 단축키가 삭제됩니다."; 39 | 40 | /* Non-empty shortcut button in recording state */ 41 | "Type New Shortcut" = "새 단축키 입력"; 42 | 43 | /* Empty shortcut button in recording state */ 44 | "Type Shortcut" = "단축키 입력"; 45 | 46 | /* Cancel action button for non-empty shortcut in recording state */ 47 | "Use Old Shortcut" = "오래된 단축키를 사용"; 48 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Resources/ja.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Cancel action button in recording state */ 2 | "Cancel" = "キャンセルする"; 3 | 4 | /* Tooltip for non-empty shortcut button */ 5 | "Click to record new shortcut" = "クリックしてショートカットを入力"; 6 | 7 | /* Tooltip for hint button near the non-empty shortcut */ 8 | "Delete shortcut" = "ショートカットを削除"; 9 | 10 | /* VoiceOver title */ 11 | "keyboard shortcut" = "キーボードショートカット"; 12 | 13 | /* Alert button when shortcut is already used */ 14 | "OK" = "OK"; 15 | 16 | /* Empty shortcut button in normal state */ 17 | "Record Shortcut" = "ショートカットを入力"; 18 | 19 | /* VoiceOver: Shortcut cleared */ 20 | "Shortcut cleared" = "ショートカットが削除されました"; 21 | 22 | /* VoiceOver: Shortcut set */ 23 | "Shortcut set" = "ショートカットが設定されました"; 24 | 25 | /* Shortcut glyph name for SPACE key */ 26 | "Space" = "スペース"; 27 | 28 | /* Title for alert when shortcut is already used */ 29 | "The key combination %@ cannot be used" = "%@ はショートカットに設定できません"; 30 | 31 | /* Message for alert when shortcut is already used by the system */ 32 | "This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "このショートカットは、システム全体で使用されているショートカットのため、設定することができません。\nもしこのショートカットを使用したい場合、「システム環境設定」の「キーボード」、「マウス」のパネルから既に設定されているショートカットを変更してください。"; 33 | 34 | /* Message for alert when shortcut is already used */ 35 | "This shortcut cannot be used because it is already used by the menu item ‘%@’." = "このショートカットは、メニュー操作の「%@」で使われているため、設定できません。"; 36 | 37 | /* VoiceOver shortcut help */ 38 | "To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "このボタンをクリックし、ショートカットを入力すると、新しいショートカットが設定されます。また、削除ボタンをおすと、ショートカットが削除されます。"; 39 | 40 | /* Non-empty shortcut button in recording state */ 41 | "Type New Shortcut" = "ショートカットを入力"; 42 | 43 | /* Empty shortcut button in recording state */ 44 | "Type Shortcut" = "ショートカットを入力"; 45 | 46 | /* Cancel action button for non-empty shortcut in recording state */ 47 | "Use Old Shortcut" = "古いショートカットを使用"; 48 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Resources/pl.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Cancel action button in recording state */ 2 | "Cancel" = "Anuluj"; 3 | 4 | /* Tooltip for non-empty shortcut button */ 5 | "Click to record new shortcut" = "Kliknij, by ustawić nowy skrót"; 6 | 7 | /* Tooltip for hint button near the non-empty shortcut */ 8 | "Delete shortcut" = "Usuń skrót"; 9 | 10 | /* VoiceOver title */ 11 | "keyboard shortcut" = "skrót klawiszowy"; 12 | 13 | /* Alert button when shortcut is already used */ 14 | "OK" = "OK"; 15 | 16 | /* Empty shortcut button in normal state */ 17 | "Record Shortcut" = "Utwórz skrót"; 18 | 19 | /* VoiceOver: Shortcut cleared */ 20 | "Shortcut cleared" = "Skrót usunięty"; 21 | 22 | /* VoiceOver: Shortcut set */ 23 | "Shortcut set" = "Skrót ustawiony"; 24 | 25 | /* Shortcut glyph name for SPACE key */ 26 | "Space" = "Spacja"; 27 | 28 | /* Title for alert when shortcut is already used */ 29 | "The key combination %@ cannot be used" = "Nie można użyć kombinacji klawiszy %@"; 30 | 31 | /* Message for alert when shortcut is already used by the system */ 32 | "This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "Nie można użyć tej kombinacji, ponieważ jest już zajęta przez skrót systemowy.\nMożesz to zmienić w panelu Klawiatura w Preferencjach systemowych."; 33 | 34 | /* Message for alert when shortcut is already used */ 35 | "This shortcut cannot be used because it is already used by the menu item ‘%@’." = "Ten skrót nie może być użyty, ponieważ w menu ma już przypisaną funkcję ‘%@’."; 36 | 37 | /* VoiceOver shortcut help */ 38 | "To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "Aby ustawić nowy skrót, użyj tego przycisku, a następnie wpisz nowy skrót albo naciśnij klawisz delete, by usunąć istniejący skrót"; 39 | 40 | /* Non-empty shortcut button in recording state */ 41 | "Type New Shortcut" = "Wpisz nowy skrót"; 42 | 43 | /* Empty shortcut button in recording state */ 44 | "Type Shortcut" = "Wpisz skrót"; 45 | 46 | /* Cancel action button for non-empty shortcut in recording state */ 47 | "Use Old Shortcut" = "Użyj starego skrótu"; -------------------------------------------------------------------------------- /Pods/MASShortcut/Resources/cs.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Cancel action button in recording state */ 2 | "Cancel" = "Zrušit"; 3 | 4 | /* Tooltip for non-empty shortcut button */ 5 | "Click to record new shortcut" = "Kliknutím nahrajete novou zkratku"; 6 | 7 | /* Tooltip for hint button near the non-empty shortcut */ 8 | "Delete shortcut" = "Smazat zkratku"; 9 | 10 | /* VoiceOver title */ 11 | "keyboard shortcut" = "klávesová zkratka"; 12 | 13 | /* Alert button when shortcut is already used */ 14 | "OK" = "OK"; 15 | 16 | /* Empty shortcut button in normal state */ 17 | "Record Shortcut" = "Nahrát zkratku"; 18 | 19 | /* VoiceOver: Shortcut cleared */ 20 | "Shortcut cleared" = "zkratka smazána"; 21 | 22 | /* VoiceOver: Shortcut set */ 23 | "Shortcut set" = "zkratka nastavena"; 24 | 25 | /* Shortcut glyph name for SPACE key */ 26 | "Space" = "Mezerník"; 27 | 28 | /* Title for alert when shortcut is already used */ 29 | "The key combination %@ cannot be used" = "Kombinace %@ se nedá použít"; 30 | 31 | /* Message for alert when shortcut is already used by the system */ 32 | "This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "Tato zkratka se nedá použít, protože už ji obsadil systém.\nKdybyste na ní trvali, většina systémových zkratek se dá přenastavit v Předvolbách systému."; 33 | 34 | /* Message for alert when shortcut is already used */ 35 | "This shortcut cannot be used because it is already used by the menu item ‘%@’." = "Tato zkratka se nedá použít, protože už je použita pro menu (%@)."; 36 | 37 | /* VoiceOver shortcut help */ 38 | "To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "Pokud chcete nahrát novou zkratku, stiskněte toto tlačítko a následně vybranou zkratku. Stisknutím Delete vymažete stávající zkratku."; 39 | 40 | /* Non-empty shortcut button in recording state */ 41 | "Type New Shortcut" = "Stiskněte zkratku"; 42 | 43 | /* Empty shortcut button in recording state */ 44 | "Type Shortcut" = "Stiskněte zkratku"; 45 | 46 | /* Cancel action button for non-empty shortcut in recording state */ 47 | "Use Old Shortcut" = "Vrátit se k původní"; 48 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Resources/en.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Cancel action button in recording state */ 2 | "Cancel" = "Cancel"; 3 | 4 | /* Tooltip for non-empty shortcut button */ 5 | "Click to record new shortcut" = "Click to record new shortcut"; 6 | 7 | /* Tooltip for hint button near the non-empty shortcut */ 8 | "Delete shortcut" = "Delete shortcut"; 9 | 10 | /* VoiceOver title */ 11 | "keyboard shortcut" = "keyboard shortcut"; 12 | 13 | /* Alert button when shortcut is already used */ 14 | "OK" = "OK"; 15 | 16 | /* Empty shortcut button in normal state */ 17 | "Record Shortcut" = "Record Shortcut"; 18 | 19 | /* VoiceOver: Shortcut cleared */ 20 | "Shortcut cleared" = "Shortcut cleared"; 21 | 22 | /* VoiceOver: Shortcut set */ 23 | "Shortcut set" = "Shortcut set"; 24 | 25 | /* Shortcut glyph name for SPACE key */ 26 | "Space" = "Space"; 27 | 28 | /* Title for alert when shortcut is already used */ 29 | "The key combination %@ cannot be used" = "The key combination %@ cannot be used"; 30 | 31 | /* Message for alert when shortcut is already used by the system */ 32 | "This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences."; 33 | 34 | /* Message for alert when shortcut is already used */ 35 | "This shortcut cannot be used because it is already used by the menu item ‘%@’." = "This shortcut cannot be used because it is already used by the menu item ‘%@’."; 36 | 37 | /* VoiceOver shortcut help */ 38 | "To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut."; 39 | 40 | /* Non-empty shortcut button in recording state */ 41 | "Type New Shortcut" = "Type New Shortcut"; 42 | 43 | /* Empty shortcut button in recording state */ 44 | "Type Shortcut" = "Type Shortcut"; 45 | 46 | /* Cancel action button for non-empty shortcut in recording state */ 47 | "Use Old Shortcut" = "Use Old Shortcut"; 48 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Resources/pt.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Cancel action button in recording state */ 2 | "Cancel" = "Cancelar"; 3 | 4 | /* Tooltip for non-empty shortcut button */ 5 | "Click to record new shortcut" ="Clique para gravar o atalho"; 6 | 7 | /* Tooltip for hint button near the non-empty shortcut */ 8 | "Delete shortcut" = "Apagar atalho"; 9 | 10 | /* VoiceOver title */ 11 | "keyboard shortcut" = "atalho de teclado"; 12 | 13 | /* Alert button when shortcut is already used */ 14 | "OK" = "OK"; 15 | 16 | /* Empty shortcut button in normal state */ 17 | "Record Shortcut" = "Gravar Atalho"; 18 | 19 | /* VoiceOver: Shortcut cleared */ 20 | "Shortcut cleared" = "Atalho limpo"; 21 | 22 | /* VoiceOver: Shortcut set */ 23 | "Shortcut set" = "Atalho definido"; 24 | 25 | /* Shortcut glyph name for SPACE key */ 26 | "Space" = "Espaço"; 27 | 28 | /* Title for alert when shortcut is already used */ 29 | "The key combination %@ cannot be used" = "A combinação de teclas “%@” não pode ser usada"; 30 | 31 | /* Message for alert when shortcut is already used by the system */ 32 | "This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "Esta combinação não pode ser usada porque ela já é usada por um atalho global do sistema.\nA maioria dos atalhos pode ser alterada no painel Teclado das Preferências do Sistema, caso realmente deseje usar esta combinação."; 33 | 34 | /* Message for alert when shortcut is already used */ 35 | "This shortcut cannot be used because it is already used by the menu item ‘%@’." = "Este atalho não pode ser usado porque ele já é usado pelo item de menu “%@”."; 36 | 37 | /* VoiceOver shortcut help */ 38 | "To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "Para gravar um atalho novo, clique neste botão e digite o novo atalho ou pressione apagar para limpar um atalho existente."; 39 | 40 | /* Non-empty shortcut button in recording state */ 41 | "Type New Shortcut" = "Digite o atalho"; 42 | 43 | /* Empty shortcut button in recording state */ 44 | "Type Shortcut" = "Digite o atalho"; 45 | 46 | /* Cancel action button for non-empty shortcut in recording state */ 47 | "Use Old Shortcut" = "Usar atalho antigo"; 48 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Resources/es.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Cancel action button in recording state */ 2 | "Cancel" = "Cancelar"; 3 | 4 | /* Tooltip for non-empty shortcut button */ 5 | "Click to record new shortcut" = "Haga clic para grabar nuevo atajo"; 6 | 7 | /* Tooltip for hint button near the non-empty shortcut */ 8 | "Delete shortcut" = "Borrar atajo"; 9 | 10 | /* VoiceOver title */ 11 | "keyboard shortcut" = "atajo de teklado"; 12 | 13 | /* Alert button when shortcut is already used */ 14 | "OK" = "OK"; 15 | 16 | /* Empty shortcut button in normal state */ 17 | "Record Shortcut" = "Grabar atajo"; 18 | 19 | /* VoiceOver: Shortcut cleared */ 20 | "Shortcut cleared" = "Atajo borrado"; 21 | 22 | /* VoiceOver: Shortcut set */ 23 | "Shortcut set" = "Atajo creado"; 24 | 25 | /* Shortcut glyph name for SPACE key */ 26 | "Space" = "Espacio"; 27 | 28 | /* Title for alert when shortcut is already used */ 29 | "The key combination %@ cannot be used" = "La combinación de claves %@ no se puede utilizada"; 30 | 31 | /* Message for alert when shortcut is already used by the system */ 32 | "This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "Esta combinación no se puede utilizar debido a que ya es en us como atajo del sistema.\nSi realmente desea utilizar esta combinación de teclas, la mayoría de los atajos se puede cambiar en el panel de Teclado y Ratón de Preferencias del Sistema."; 33 | 34 | /* Message for alert when shortcut is already used */ 35 | "This shortcut cannot be used because it is already used by the menu item ‘%@’." = "Este atajo no se puede utilizar debido a que ya es utilizado por el elemento de menú '%@'."; 36 | 37 | /* VoiceOver shortcut help */ 38 | "To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "Para grabar un nuevo atajo, haga clic en este botón, a continuar, escriba el nuevo atajo, o pulse borrar para qutar un atajo existente."; 39 | 40 | /* Non-empty shortcut button in recording state */ 41 | "Type New Shortcut" = "Escribir atajo"; 42 | 43 | /* Empty shortcut button in recording state */ 44 | "Type Shortcut" = "Escribir atajo"; 45 | 46 | /* Cancel action button for non-empty shortcut in recording state */ 47 | "Use Old Shortcut" = "Usa atajo anterior"; -------------------------------------------------------------------------------- /Pods/MASShortcut/Resources/ru.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Cancel action button in recording state */ 2 | "Cancel" = "Отмена"; 3 | 4 | /* Tooltip for non-empty shortcut button */ 5 | "Click to record new shortcut" = "Нажмите для записи сочетания клавиш"; 6 | 7 | /* Tooltip for hint button near the non-empty shortcut */ 8 | "Delete shortcut" = "Удалить горячую клавишу"; 9 | 10 | /* VoiceOver title */ 11 | "keyboard shortcut" = "сочетание клавиш"; 12 | 13 | /* Alert button when shortcut is already used */ 14 | "OK" = "ОК"; 15 | 16 | /* Empty shortcut button in normal state */ 17 | "Record Shortcut" = "Ввести сочетание"; 18 | 19 | /* VoiceOver: Shortcut cleared */ 20 | "Shortcut cleared" = "Сочетание клавиш удалено"; 21 | 22 | /* VoiceOver: Shortcut set */ 23 | "Shortcut set" = "Сочетание клавиш назначено"; 24 | 25 | /* Shortcut glyph name for SPACE key */ 26 | "Space" = "Пробел"; 27 | 28 | /* Title for alert when shortcut is already used */ 29 | "The key combination %@ cannot be used" = "Нельзя использовать сочетание клавиш %@"; 30 | 31 | /* Message for alert when shortcut is already used by the system */ 32 | "This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "Нельзя использовать это сочетание клавиш, потому что оно уже используется в системе.\n Если вы хотите использовать это сочетание, измените существующее системное сочетание клавиш через панель Клавиатура в Cистемных настройках."; 33 | 34 | /* Message for alert when shortcut is already used */ 35 | "This shortcut cannot be used because it is already used by the menu item ‘%@’." = "Нельзя использовать это сочетание, потому что оно уже связано с элементом ‘%@’."; 36 | 37 | /* VoiceOver shortcut help */ 38 | "To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "Чтобы назначить новое сочетание клавиш, нажмите эту кнопку и введите новое сочетание, или нажмите \"Удалить\", чтобы удалить действующее сочетание клавиш."; 39 | 40 | /* Non-empty shortcut button in recording state */ 41 | "Type New Shortcut" = "Введите сочетание"; 42 | 43 | /* Empty shortcut button in recording state */ 44 | "Type Shortcut" = "Введите сочетание"; 45 | 46 | /* Cancel action button for non-empty shortcut in recording state */ 47 | "Use Old Shortcut" = "Вернуть старое"; -------------------------------------------------------------------------------- /Pods/MASShortcut/Resources/nl.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Cancel action button in recording state */ 2 | "Cancel" = "Verbreken"; 3 | 4 | /* Tooltip for non-empty shortcut button */ 5 | "Click to record new shortcut" = "Druk om een nieuwe sneltoets in te voeren"; 6 | 7 | /* Tooltip for hint button near the non-empty shortcut */ 8 | "Delete shortcut" = "Verwijder sneltoets"; 9 | 10 | /* VoiceOver title */ 11 | "keyboard shortcut" = "sneltoets"; 12 | 13 | /* Alert button when shortcut is already used */ 14 | "OK" = "OK"; 15 | 16 | /* Empty shortcut button in normal state */ 17 | "Record Shortcut" = "Sneltoets opnemen"; 18 | 19 | /* VoiceOver: Shortcut cleared */ 20 | "Shortcut cleared" = "Sneltoets verwijderd"; 21 | 22 | /* VoiceOver: Shortcut set */ 23 | "Shortcut set" = "Sneltoets zetten"; 24 | 25 | /* Shortcut glyph name for SPACE key */ 26 | "Space" = "Spatie"; 27 | 28 | /* Title for alert when shortcut is already used */ 29 | "The key combination %@ cannot be used" = "De sneltoetsencombinatie kan niet worden gebruikt"; 30 | 31 | /* Message for alert when shortcut is already used by the system */ 32 | "This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "Deze combinatie kan niet worden gebruikt want hij wordt al gebruikt door een systeembreed sneltoets.\nAls je deze combinatie echt wilt gebruiken, kun je de meeste sneltoetsen binnen Toetsenbordinstellingen veranderen."; 33 | 34 | /* Message for alert when shortcut is already used */ 35 | "This shortcut cannot be used because it is already used by the menu item ‘%@’." = "Deze sneltoets kan niet worden gebruikt want hij wordt al gebruikt door het menu item ‘%@’."; 36 | 37 | /* VoiceOver shortcut help */ 38 | "To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "Om nieuwe sneltoets op te nemen, druk op deze knop, en voer een nieuwe sneltoets in, of druk op verwijder om bestaande sneltoets te verwijderen."; 39 | 40 | /* Non-empty shortcut button in recording state */ 41 | "Type New Shortcut" = "Voer Nieuwe Sneltoets in"; 42 | 43 | /* Empty shortcut button in recording state */ 44 | "Type Shortcut" = "Voer Sneltoets in"; 45 | 46 | /* Cancel action button for non-empty shortcut in recording state */ 47 | "Use Old Shortcut" = "Gebruik Oude Sneltoets"; -------------------------------------------------------------------------------- /Pods/MASShortcut/Resources/de.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Cancel action button in recording state */ 2 | "Cancel" = "Abbrechen"; 3 | 4 | /* Tooltip for non-empty shortcut button */ 5 | "Click to record new shortcut" = "Klicken um neuen Kurzbefehl aufzunehmen"; 6 | 7 | /* Tooltip for hint button near the non-empty shortcut */ 8 | "Delete shortcut" = "Kurzbefehl Löschen"; 9 | 10 | /* VoiceOver title */ 11 | "keyboard shortcut" = "Kurzbefehl"; 12 | 13 | /* Alert button when shortcut is already used */ 14 | "OK" = "OK"; 15 | 16 | /* Empty shortcut button in normal state */ 17 | "Record Shortcut" = "Kurzbefehl aufnehmen"; 18 | 19 | /* VoiceOver: Shortcut cleared */ 20 | "Shortcut cleared" = "Kurzbefehl gelöscht"; 21 | 22 | /* VoiceOver: Shortcut set */ 23 | "Shortcut set" = "Kurzbefehl gesetzt"; 24 | 25 | /* Shortcut glyph name for SPACE key */ 26 | "Space" = "Leertaste"; 27 | 28 | /* Title for alert when shortcut is already used */ 29 | "The key combination %@ cannot be used" = "Die Tastenkombination %@ kann nicht genutzt werden"; 30 | 31 | /* Message for alert when shortcut is already used by the system */ 32 | "This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "Diese Kombination kann nicht genutzt werden, weil sie bereits als systemweiter Kurzbefehl genutzt wird.\nFalls du diese Tastenkombination wirklich benutzen willst, können die meisten Kurzbefehle in den Tastatur Systemeinstellungen geändert werden."; 33 | 34 | /* Message for alert when shortcut is already used */ 35 | "This shortcut cannot be used because it is already used by the menu item ‘%@’." = "Dieser Kurzbefehl kann nicht genutzt werden, weil er bereits vom Menüpunkt „%@“ genutzt wird."; 36 | 37 | /* VoiceOver shortcut help */ 38 | "To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "Drücke diesen Button, um einen neuen Kurzbefehl aufzunehmen. Tippe dann den neuen Kurzbefehl oder drücke Löschen, um den aktuellen Kurzbefehl zu löschen."; 39 | 40 | /* Non-empty shortcut button in recording state */ 41 | "Type New Shortcut" = "Neuen eingeben"; 42 | 43 | /* Empty shortcut button in recording state */ 44 | "Type Shortcut" = "Kurzbefehl eingeben"; 45 | 46 | /* Cancel action button for non-empty shortcut in recording state */ 47 | "Use Old Shortcut" = "Alten nutzen"; 48 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Resources/fr.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Cancel action button in recording state */ 2 | "Cancel" = "Annuler"; 3 | 4 | /* Tooltip for non-empty shortcut button */ 5 | "Click to record new shortcut" = "Cliquez pour enregistrer le raccourci"; 6 | 7 | /* Tooltip for hint button near the non-empty shortcut */ 8 | "Delete shortcut" = "Supprimer le raccourci"; 9 | 10 | /* VoiceOver title */ 11 | "keyboard shortcut" = "raccourci clavier"; 12 | 13 | /* Alert button when shortcut is already used */ 14 | "OK" = "OK"; 15 | 16 | /* Empty shortcut button in normal state */ 17 | "Record Shortcut" = "Enregistrer le raccourci"; 18 | 19 | /* VoiceOver: Shortcut cleared */ 20 | "Shortcut cleared" = "Raccourci supprimé"; 21 | 22 | /* VoiceOver: Shortcut set */ 23 | "Shortcut set" = "Raccourci configuré"; 24 | 25 | /* Shortcut glyph name for SPACE key */ 26 | "Space" = "Espace"; 27 | 28 | /* Title for alert when shortcut is already used */ 29 | "The key combination %@ cannot be used" = "La combinaison %@ ne peut être utilisée"; 30 | 31 | /* Message for alert when shortcut is already used by the system */ 32 | "This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "Cette combinaison de touches ne peut être utilisée parce qu’elle est réservée pour un raccourci du système.\nSi vous désirez l’utiliser, la plupart des raccourcis peuvent être modifiés dans l’onglet Clavier, dans Préférences Système."; 33 | 34 | /* Message for alert when shortcut is already used */ 35 | "This shortcut cannot be used because it is already used by the menu item ‘%@’." = "Ce raccourci ne peut être utilisé parce qu’il est déjà utilisé par le point de menu «%@»."; 36 | 37 | /* VoiceOver shortcut help */ 38 | "To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "Pour enregistrer un nouveau raccourci, cliquez sur ce bouton et tapez le nouveau raccourci, ou bien, tapez sur «Supprimer» pour supprimer le raccourci configuré."; 39 | 40 | /* Non-empty shortcut button in recording state */ 41 | "Type New Shortcut" = "Saisir un raccourci"; 42 | 43 | /* Empty shortcut button in recording state */ 44 | "Type Shortcut" = "Saisir un raccourci"; 45 | 46 | /* Cancel action button for non-empty shortcut in recording state */ 47 | "Use Old Shortcut" = "Revenir au raccourci précédent"; 48 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Resources/sv.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Cancel action button in recording state */ 2 | "Cancel" = "Avbryt"; 3 | 4 | /* Tooltip for non-empty shortcut button */ 5 | "Click to record new shortcut" = "Klicka för att registrera ny kortkommando"; 6 | 7 | /* Tooltip for hint button near the non-empty shortcut */ 8 | "Delete shortcut" = "Ta bort en kortkommando"; 9 | 10 | /* VoiceOver title */ 11 | "keyboard shortcut" = "Tangentbordskortkommando"; 12 | 13 | /* Alert button when shortcut is already used */ 14 | "OK" = "OK"; 15 | 16 | /* Empty shortcut button in normal state */ 17 | "Record Shortcut" = "Registrera kortkommando"; 18 | 19 | /* VoiceOver: Shortcut cleared */ 20 | "Shortcut cleared" = "Kortkommando rensas"; 21 | 22 | /* VoiceOver: Shortcut set */ 23 | "Shortcut set" = "Kortkommando uppsättning"; 24 | 25 | /* Shortcut glyph name for SPACE key */ 26 | "Space" = "Utrymme"; 27 | 28 | /* Title for alert when shortcut is already used */ 29 | "The key combination %@ cannot be used" = "Tangentkombinationen %@ kan inte användas"; 30 | 31 | /* Message for alert when shortcut is already used by the system */ 32 | "This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "Den här kombinationen kan inte användas eftersom den redan används som en tangentbordskortkommando. Om du verkligen vill använda den här tangentkombinationen kan de flesta genvägar ändras under Tangentbord & Mus i Systeminställningar."; 33 | 34 | /* Message for alert when shortcut is already used */ 35 | "This shortcut cannot be used because it is already used by the menu item ‘%@’." = "Denna kortkommando kan inte användas eftersom det redan används av ett menyalternativ ‘%@’."; 36 | 37 | /* VoiceOver shortcut help */ 38 | "To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "För att registrera en ny kortkommando, klicka på den här knappen och skriv sedan in den nya kortkommando, eller tryck på radera för att rensa en befintlig kortkommando."; 39 | 40 | /* Non-empty shortcut button in recording state */ 41 | "Type New Shortcut" = "Skriv Ny Kortkommando"; 42 | 43 | /* Empty shortcut button in recording state */ 44 | "Type Shortcut" = "Skriv Kortkommando"; 45 | 46 | /* Cancel action button for non-empty shortcut in recording state */ 47 | "Use Old Shortcut" = "Använd Gammal Kortkommando"; 48 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Resources/it.lproj/Localizable.strings: -------------------------------------------------------------------------------- 1 | /* Cancel action button in recording state */ 2 | "Cancel" = "Annulla"; 3 | 4 | /* Tooltip for non-empty shortcut button */ 5 | "Click to record new shortcut" = "Cliccare per registrare una nuova combinazione"; 6 | 7 | /* Tooltip for hint button near the non-empty shortcut */ 8 | "Delete shortcut" = "Cancella scorciatoia"; 9 | 10 | /* VoiceOver title */ 11 | "keyboard shortcut" = "Scorciatoia da tastiera"; 12 | 13 | /* Alert button when shortcut is already used */ 14 | "OK" = "OK"; 15 | 16 | /* Empty shortcut button in normal state */ 17 | "Record Shortcut" = "Registra scorciatoia"; 18 | 19 | /* VoiceOver: Shortcut cleared */ 20 | "Shortcut cleared" = "Scorciatoia rimossa"; 21 | 22 | /* VoiceOver: Shortcut set */ 23 | "Shortcut set" = "Scorciatoia impostata"; 24 | 25 | /* Shortcut glyph name for SPACE key */ 26 | "Space" = "Spazio"; 27 | 28 | /* Title for alert when shortcut is already used */ 29 | "The key combination %@ cannot be used" = "Questa combinazione %@ di tasti non può essere usata"; 30 | 31 | /* Message for alert when shortcut is already used by the system */ 32 | "This combination cannot be used because it is already used by a system-wide keyboard shortcut.\nIf you really want to use this key combination, most shortcuts can be changed in the Keyboard & Mouse panel in System Preferences." = "Questa combinazione di tasti non può essere usata perchè è già usata da una scorciatoia da tastiera a livello di Sistema.\nSe volete davvero usare questa combinazione di tasti, la maggior parte delle scorciatoie possono essere cambiate nel pannello Tastiera e Mouse delle Preferenze di Sistema."; 33 | 34 | /* Message for alert when shortcut is already used */ 35 | "This shortcut cannot be used because it is already used by the menu item ‘%@’." = "Questa combinazione di tasti non può essere usata perchè è già usata dalla voce di menù ‘%@’."; 36 | 37 | /* VoiceOver shortcut help */ 38 | "To record a new shortcut, click this button, and then type the new shortcut, or press delete to clear an existing shortcut." = "Per registrare una nuova scorciatoia, cliccare su questo pulsante e poi inserire la muova scorciatoia o premere cancella per resettare una scorciatoia esistente."; 39 | 40 | /* Non-empty shortcut button in recording state */ 41 | "Type New Shortcut" = "Digita nuova"; 42 | 43 | /* Empty shortcut button in recording state */ 44 | "Type Shortcut" = "Digita scorciatoia"; 45 | 46 | /* Cancel action button for non-empty shortcut in recording state */ 47 | "Use Old Shortcut" = "Usare vecchia"; 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | # *.xcodeproj 44 | # 45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 46 | # hence it is not needed unless you have added a package configuration file to your project 47 | # .swiftpm 48 | 49 | .build/ 50 | 51 | # CocoaPods 52 | # 53 | # We recommend against adding the Pods directory to your .gitignore. However 54 | # you should judge for yourself, the pros and cons are mentioned at: 55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 56 | # 57 | # Pods/ 58 | # 59 | # Add this line if you want to avoid checking in source code from the Xcode workspace 60 | # *.xcworkspace 61 | 62 | # Carthage 63 | # 64 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 65 | # Carthage/Checkouts 66 | 67 | Carthage/Build/ 68 | 69 | # Accio dependency management 70 | Dependencies/ 71 | .accio/ 72 | 73 | # fastlane 74 | # 75 | # It is recommended to not store the screenshots in the git repo. 76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 77 | # For more information about the recommended setup visit: 78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 79 | 80 | fastlane/report.xml 81 | fastlane/Preview.html 82 | fastlane/screenshots/**/*.png 83 | fastlane/test_output 84 | 85 | # Code Injection 86 | # 87 | # After new code Injection tools there's a generated folder /iOSInjectionProject 88 | # https://github.com/johnno1962/injectionforxcode 89 | 90 | iOSInjectionProject/ 91 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/User Defaults Storage/MASShortcutBinder.h: -------------------------------------------------------------------------------- 1 | #import "MASShortcutMonitor.h" 2 | 3 | /** 4 | Binds actions to user defaults keys. 5 | 6 | If you store shortcuts in user defaults (for example by binding 7 | a `MASShortcutView` to user defaults), you can use this class to 8 | connect an action directly to a user defaults key. If the shortcut 9 | stored under the key changes, the action will get automatically 10 | updated to the new one. 11 | 12 | This class is mostly a wrapper around a `MASShortcutMonitor`. It 13 | watches the changes in user defaults and updates the shortcut monitor 14 | accordingly with the new shortcuts. 15 | */ 16 | @interface MASShortcutBinder : NSObject 17 | 18 | /** 19 | A convenience shared instance. 20 | 21 | You may use it so that you don’t have to manage an instance by hand, 22 | but it’s perfectly fine to allocate and use a separate instance instead. 23 | */ 24 | + (instancetype) sharedBinder; 25 | 26 | /** 27 | The underlying shortcut monitor. 28 | */ 29 | @property(strong) MASShortcutMonitor *shortcutMonitor; 30 | 31 | /** 32 | Binding options customizing the access to user defaults. 33 | 34 | As an example, you can use `NSValueTransformerNameBindingOption` to customize 35 | the storage format used for the shortcuts. By default the shortcuts are converted 36 | from `NSData` (`NSKeyedUnarchiveFromDataTransformerName`). Note that if the 37 | binder is to work with `MASShortcutView`, both object have to use the same storage 38 | format. 39 | */ 40 | @property(copy) NSDictionary *bindingOptions; 41 | 42 | /** 43 | Binds given action to a shortcut stored under the given defaults key. 44 | 45 | In other words, no matter what shortcut you store under the given key, 46 | pressing it will always trigger the given action. 47 | */ 48 | - (void) bindShortcutWithDefaultsKey: (NSString*) defaultsKeyName toAction: (dispatch_block_t) action; 49 | 50 | /** 51 | Disconnect the binding between user defaults and action. 52 | 53 | In other words, the shortcut stored under the given key will no longer trigger an action. 54 | */ 55 | - (void) breakBindingWithDefaultsKey: (NSString*) defaultsKeyName; 56 | 57 | /** 58 | Register default shortcuts in user defaults. 59 | 60 | This is a convenience frontent to `[NSUserDefaults registerDefaults]`. 61 | The dictionary should contain a map of user defaults’ keys to appropriate 62 | keyboard shortcuts. The shortcuts will be transformed according to 63 | `bindingOptions` and registered using `registerDefaults`. 64 | */ 65 | - (void) registerDefaultShortcuts: (NSDictionary*) defaultShortcuts; 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /Roar/Displays/MusicVideoWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MusicVideoWindowController.swift 3 | // Roar 4 | // 5 | // Created by Tyler Hall on 12/20/21. 6 | // 7 | 8 | import AppKit 9 | 10 | class MusicVideoWindowController: NoteWindowController { 11 | 12 | @IBOutlet weak var backgroundView: NSView! 13 | @IBOutlet weak var appIconView: NSImageView! 14 | @IBOutlet weak var titleLabel: NSTextField! 15 | @IBOutlet weak var subtitleLabel: NSTextField! 16 | @IBOutlet weak var bodyLabel: NSTextField! 17 | @IBOutlet weak var windowWidthConstraint: NSLayoutConstraint! 18 | 19 | override func display(note: Note) { 20 | guard let screen = NSScreen.main else { return } 21 | 22 | window?.backgroundColor = .clear 23 | window?.ignoresMouseEvents = true 24 | window?.level = NSWindow.Level.init(Int(CGWindowLevelForKey(CGWindowLevelKey.mainMenuWindow))) 25 | 26 | titleLabel.stringValue = note.title ?? "" 27 | subtitleLabel.stringValue = note.subtitle ?? "" 28 | bodyLabel.stringValue = note.body ?? "" 29 | 30 | if let appPath = NSWorkspace.shared.urlForApplication(withBundleIdentifier: note.appID)?.path { 31 | let icon = NSWorkspace.shared.icon(forFile: appPath) 32 | appIconView.image = icon 33 | } 34 | 35 | windowWidthConstraint.constant = screen.frame.size.width 36 | backgroundView.wantsLayer = true 37 | backgroundView.layer?.backgroundColor = NSColor.black.withAlphaComponent(0.45).cgColor 38 | 39 | showWindow(nil) 40 | let height = window?.frame.size.height ?? 0 41 | window?.setFrameOrigin(CGPoint(x: 0, y: -height)) 42 | 43 | let rect = NSRect(origin: .zero, size: CGSize(width: windowWidthConstraint.constant, height: height)) 44 | window?.setFrame(rect, display: true, animate: true) 45 | 46 | let duration = window?.animationResizeTime(rect) ?? 1 47 | DispatchQueue.main.asyncAfter(deadline: .now() + duration, execute: { 48 | self.noteWindowDelegte?.didDisplayWindow() 49 | }) 50 | } 51 | 52 | override func hide() { 53 | let height = window?.frame.size.height ?? 0 54 | let rect = NSRect(origin: .zero, size: CGSize(width: windowWidthConstraint.constant, height: -height)) 55 | window?.setFrame(rect, display: true, animate: true) 56 | 57 | let duration = window?.animationResizeTime(rect) ?? 1 58 | DispatchQueue.main.asyncAfter(deadline: .now() + duration, execute: { 59 | self.noteWindowDelegte?.didHideWindow() 60 | }) 61 | } 62 | } 63 | 64 | class MusicVideoWindow: NSWindow { 65 | 66 | } 67 | -------------------------------------------------------------------------------- /Roar/Helpers/Pipette.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Pipette.swift 3 | // TextBuddy 4 | // 5 | // Created by Tyler Hall on 1/23/21. 6 | // 7 | 8 | import Foundation 9 | 10 | class Pipette { 11 | 12 | static let shared = Pipette() 13 | 14 | class func execute(_ cmd: URL, args: [String]?, text: String?, completion: @escaping (String?, Int?) -> ()) { 15 | DispatchQueue.global(qos: .userInitiated).async { 16 | let textData = text?.data(using: .utf8) ?? Data() 17 | 18 | let sh = Process() 19 | sh.launchPath = cmd.path 20 | sh.arguments = args ?? [] 21 | 22 | let outPipe = Pipe() 23 | sh.standardOutput = outPipe 24 | let outHandle = outPipe.fileHandleForReading 25 | 26 | let inPipe = Pipe() 27 | sh.standardInput = inPipe 28 | let inHandle = inPipe.fileHandleForWriting 29 | inHandle.write(textData) 30 | try? inHandle.close() 31 | 32 | sh.terminationHandler = { process in 33 | var data = Data() 34 | var chunk = outHandle.readDataToEndOfFile() 35 | data.append(chunk) 36 | while !chunk.isEmpty { 37 | chunk = outHandle.readDataToEndOfFile() 38 | data.append(chunk) 39 | } 40 | 41 | DispatchQueue.main.async { 42 | completion(String(data: data, encoding: .utf8), Int(sh.terminationStatus)) 43 | } 44 | } 45 | 46 | sh.launch() 47 | } 48 | } 49 | 50 | class func executeRawString(_ cmd: String, text: String?, completion: @escaping (String?, Int?) -> ()) { 51 | DispatchQueue.global(qos: .userInitiated).async { 52 | let textData = text?.data(using: .utf8) ?? Data() 53 | 54 | let sh = Process() 55 | sh.launchPath = "/bin/bash" 56 | sh.arguments = ["-c", cmd] 57 | 58 | let outPipe = Pipe() 59 | sh.standardOutput = outPipe 60 | let outHandle = outPipe.fileHandleForReading 61 | 62 | let inPipe = Pipe() 63 | sh.standardInput = inPipe 64 | let inHandle = inPipe.fileHandleForWriting 65 | inHandle.write(textData) 66 | try? inHandle.close() 67 | 68 | sh.terminationHandler = { process in 69 | var data = Data() 70 | var chunk = outHandle.readDataToEndOfFile() 71 | data.append(chunk) 72 | while !chunk.isEmpty { 73 | chunk = outHandle.readDataToEndOfFile() 74 | data.append(chunk) 75 | } 76 | 77 | DispatchQueue.main.async { 78 | completion(String(data: data, encoding: .utf8), Int(sh.terminationStatus)) 79 | } 80 | } 81 | 82 | sh.launch() 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/Model/MASShortcut.h: -------------------------------------------------------------------------------- 1 | #import "MASKeyCodes.h" 2 | 3 | /** 4 | A model class to hold a key combination. 5 | 6 | This class just represents a combination of keys. It does not care if 7 | the combination is valid or can be used as a hotkey, it doesn’t watch 8 | the input system for the shortcut appearance, nor it does access user 9 | defaults. 10 | */ 11 | @interface MASShortcut : NSObject 12 | 13 | /** 14 | The virtual key code for the keyboard key. 15 | 16 | Hardware independent, same as in `NSEvent`. See `Events.h` in the HIToolbox 17 | framework for a complete list, or Command-click this symbol: `kVK_ANSI_A`. 18 | */ 19 | @property (nonatomic, readonly) NSInteger keyCode; 20 | 21 | /** 22 | Cocoa keyboard modifier flags. 23 | 24 | Same as in `NSEvent`: `NSCommandKeyMask`, `NSAlternateKeyMask`, etc. 25 | */ 26 | @property (nonatomic, readonly) NSEventModifierFlags modifierFlags; 27 | 28 | /** 29 | Same as `keyCode`, just a different type. 30 | */ 31 | @property (nonatomic, readonly) UInt32 carbonKeyCode; 32 | 33 | /** 34 | Carbon modifier flags. 35 | 36 | A bit sum of `cmdKey`, `optionKey`, etc. 37 | */ 38 | @property (nonatomic, readonly) UInt32 carbonFlags; 39 | 40 | /** 41 | A string representing the “key” part of a shortcut, like the `5` in `⌘5`. 42 | 43 | @warning The value may change depending on the active keyboard layout. 44 | For example for the `^2` keyboard shortcut (`kVK_ANSI_2+NSControlKeyMask` 45 | to be precise) the `keyCodeString` is `2` on the US keyboard, but `ě` when 46 | the Czech keyboard layout is active. See the spec for details. 47 | */ 48 | @property (nonatomic, readonly) NSString *keyCodeString; 49 | 50 | /** 51 | A key-code string used in key equivalent matching. 52 | 53 | For precise meaning of “key equivalents” see the `keyEquivalent` 54 | property of `NSMenuItem`. Here the string is used to support shortcut 55 | validation (“is the shortcut already taken in this menu?”) and 56 | for display in `NSMenu`. 57 | 58 | The value of this property may differ from `keyCodeString`. For example 59 | the Russian keyboard has a `Г` (Ge) Cyrillic character in place of the 60 | latin `U` key. This means you can create a `^Г` shortcut, but in menus 61 | that’s always displayed as `^U`. So the `keyCodeString` returns `Г` 62 | and `keyCodeStringForKeyEquivalent` returns `U`. 63 | */ 64 | @property (nonatomic, readonly) NSString *keyCodeStringForKeyEquivalent; 65 | 66 | /** 67 | A string representing the shortcut modifiers, like the `⌘` in `⌘5`. 68 | */ 69 | @property (nonatomic, readonly) NSString *modifierFlagsString; 70 | 71 | - (instancetype)initWithKeyCode:(NSInteger)code modifierFlags:(NSEventModifierFlags)flags; 72 | + (instancetype)shortcutWithKeyCode:(NSInteger)code modifierFlags:(NSEventModifierFlags)flags; 73 | 74 | /** 75 | Creates a new shortcut from an `NSEvent` object. 76 | 77 | This is just a convenience initializer that reads the key code and modifiers from an `NSEvent`. 78 | */ 79 | + (instancetype)shortcutWithEvent:(NSEvent *)anEvent; 80 | 81 | @end 82 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-Roar/Pods-Roar-acknowledgements.markdown: -------------------------------------------------------------------------------- 1 | # Acknowledgements 2 | This application makes use of the following third party libraries: 3 | 4 | ## FMDB 5 | 6 | If you are using FMDB in your project, I'd love to hear about it. Let Gus know 7 | by sending an email to gus@flyingmeat.com. 8 | 9 | And if you happen to come across either Gus Mueller or Rob Ryan in a bar, you 10 | might consider purchasing a drink of their choosing if FMDB has been useful to 11 | you. 12 | 13 | Finally, and shortly, this is the MIT License. 14 | 15 | Copyright (c) 2008-2014 Flying Meat Inc. 16 | 17 | Permission is hereby granted, free of charge, to any person obtaining a copy 18 | of this software and associated documentation files (the "Software"), to deal 19 | in the Software without restriction, including without limitation the rights 20 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 21 | copies of the Software, and to permit persons to whom the Software is 22 | furnished to do so, subject to the following conditions: 23 | 24 | The above copyright notice and this permission notice shall be included in 25 | all copies or substantial portions of the Software. 26 | 27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 28 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 29 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 30 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 31 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 32 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 33 | THE SOFTWARE. 34 | 35 | ## MASShortcut 36 | 37 | Copyright (c) 2012-2013, Vadim Shpakovski 38 | All rights reserved. 39 | 40 | Redistribution and use in source and binary forms, with or without 41 | modification, are permitted provided that the following conditions are met: 42 | 43 | 1. Redistributions of source code must retain the above copyright notice, this 44 | list of conditions and the following disclaimer. 45 | 2. Redistributions in binary form must reproduce the above copyright notice, 46 | this list of conditions and the following disclaimer in the documentation 47 | and/or other materials provided with the distribution. 48 | 49 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 50 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 51 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 52 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 53 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 54 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 55 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 56 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 57 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 58 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 59 | 60 | Generated by CocoaPods - https://cocoapods.org 61 | -------------------------------------------------------------------------------- /Roar/Displays/MacintoshWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // MacintoshWindowController.swift 3 | // Roar 4 | // 5 | // Created by Tyler Hall on 1/3/22. 6 | // 7 | 8 | import Cocoa 9 | 10 | class MacintoshWindowController: NoteWindowController { 11 | 12 | @IBOutlet weak var appLabel: NSTextField! 13 | @IBOutlet weak var titleLabel: NSTextField! 14 | @IBOutlet weak var subtitleLabel: NSTextField! 15 | @IBOutlet weak var bodyLabel: NSTextField! 16 | 17 | override func display(note: Note) { 18 | guard let screen = NSScreen.main else { return } 19 | 20 | window?.backgroundColor = .clear 21 | window?.ignoresMouseEvents = true 22 | window?.level = NSWindow.Level.init(Int(CGWindowLevelForKey(CGWindowLevelKey.mainMenuWindow))) 23 | 24 | let font0 = NSFont(name: "ChicagoIllinois", size: 9) 25 | appLabel.font = font0 26 | if let url = NSWorkspace.shared.urlForApplication(withBundleIdentifier: note.appID) { 27 | let appName = url.deletingPathExtension().lastPathComponent 28 | appLabel.stringValue = appName 29 | } else { 30 | appLabel.stringValue = "Notification" 31 | } 32 | 33 | let font1 = NSFont(name: "ChicagoIllinois", size: 13) 34 | titleLabel.font = font1 35 | 36 | let font2 = NSFont(name: "ChicagoIllinois", size: 11) 37 | subtitleLabel.font = font2 38 | bodyLabel.font = font2 39 | 40 | titleLabel.stringValue = note.title ?? "" 41 | 42 | if let subtitle = note.subtitle { 43 | subtitleLabel.stringValue = subtitle 44 | subtitleLabel.isHidden = false 45 | } else { 46 | subtitleLabel.isHidden = true 47 | } 48 | 49 | if let body = note.body { 50 | bodyLabel.stringValue = body 51 | bodyLabel.isHidden = false 52 | } else { 53 | bodyLabel.isHidden = true 54 | } 55 | 56 | showWindow(nil) 57 | let width = window?.frame.size.width ?? 0 58 | let height = window?.frame.size.height ?? 0 59 | window?.setFrameOrigin(NSPoint(x: screen.frame.size.width, y: screen.frame.size.height - height - 35)) 60 | 61 | let destOrigin = NSPoint(x: screen.frame.size.width - width - 20, y: screen.frame.size.height - height - 35) 62 | window?.setFrame(NSRect(origin: destOrigin, size: CGSize(width: width, height: height)), display: true, animate: true) 63 | 64 | DispatchQueue.main.asyncAfter(deadline: .now() + 2.5, execute: { 65 | self.noteWindowDelegte?.didDisplayWindow() 66 | }) 67 | } 68 | 69 | override func hide() { 70 | guard let screen = NSScreen.main else { return } 71 | 72 | let width = window?.frame.size.width ?? 0 73 | let height = window?.frame.size.height ?? 0 74 | let destOrigin = NSPoint(x: screen.frame.size.width, y: screen.frame.size.height - height - 35) 75 | window?.setFrame(NSRect(origin: destOrigin, size: CGSize(width: width, height: height)), display: true, animate: true) 76 | 77 | DispatchQueue.main.asyncAfter(deadline: .now() + 2.5, execute: { 78 | self.window?.close() 79 | self.noteWindowDelegte?.didHideWindow() 80 | }) 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /Roar/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Roar 4 | // 5 | // Created by Tyler Hall on 12/20/21. 6 | // 7 | 8 | import Cocoa 9 | 10 | @main 11 | class AppDelegate: NSObject, NSApplicationDelegate { 12 | 13 | lazy var prefsWindowController: PrefsWindowController = { PrefsWindowController(windowNibName: String(describing: PrefsWindowController.self)) }() 14 | lazy var actionWindowController: ActionWindowController = { ActionWindowController(windowNibName: String(describing: ActionWindowController.self)) }() 15 | 16 | func applicationDidFinishLaunching(_ aNotification: Notification) { 17 | bindActionShortcut() 18 | NCWatcher.shared.setup { success in 19 | NCWatcher.shared.startWatching() 20 | } 21 | } 22 | 23 | override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 24 | if keyPath == PrefsWindowController.kActionShortcutPref { 25 | self.bindActionShortcut() 26 | } 27 | } 28 | 29 | @IBAction func showPreferencesWindow(_ sender: AnyObject?) { 30 | prefsWindowController.showWindow(nil) 31 | } 32 | 33 | func bindActionShortcut() { 34 | MASShortcutBinder.shared()?.breakBinding(withDefaultsKey: PrefsWindowController.kActionShortcutPref) 35 | MASShortcutBinder.shared()?.bindShortcut(withDefaultsKey: PrefsWindowController.kActionShortcutPref, toAction: { 36 | NSApp.activate(ignoringOtherApps: true) 37 | self.actionWindowController.window?.makeKeyAndOrderFront(nil) 38 | self.actionWindowController.note = NCWatcher.shared.lastNote 39 | }) 40 | } 41 | 42 | @IBAction func activateNotificationApp(_ sender: AnyObject?) { 43 | NSApp.hide(nil) 44 | if let note = NCWatcher.shared.lastNote { 45 | if let appURL = NSWorkspace.shared.urlForApplication(withBundleIdentifier: note.appID) { 46 | let config = NSWorkspace.OpenConfiguration() 47 | config.activates = true 48 | NSWorkspace.shared.openApplication(at: appURL, configuration: config, completionHandler: nil) 49 | } 50 | } 51 | } 52 | 53 | @IBAction func openURLs(_ sender: AnyObject?) { 54 | NSApp.hide(nil) 55 | if let note = NCWatcher.shared.lastNote { 56 | for url in note.urls { 57 | NSWorkspace.shared.open(url) 58 | } 59 | } 60 | } 61 | 62 | @IBAction func copy2FA(_ sender: AnyObject?) { 63 | NSApp.hide(nil) 64 | 65 | if let note = NCWatcher.shared.lastNote { 66 | if let code = note.code { 67 | NSPasteboard.general.declareTypes([.string], owner: nil) 68 | NSPasteboard.general.setString(code, forType: .string) 69 | } 70 | } 71 | } 72 | 73 | @IBAction func copyMessage(_ sender: AnyObject?) { 74 | NSApp.hide(nil) 75 | if let note = NCWatcher.shared.lastNote { 76 | let strings = [note.title, note.subtitle, note.body].compactMap { $0 } 77 | let str = strings.joined(separator: "\n") 78 | 79 | NSPasteboard.general.declareTypes([.string], owner: nil) 80 | NSPasteboard.general.setString(str, forType: .string) 81 | } 82 | } 83 | } 84 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/Monitoring/MASShortcutMonitor.m: -------------------------------------------------------------------------------- 1 | #import "MASShortcutMonitor.h" 2 | #import "MASHotKey.h" 3 | 4 | @interface MASShortcutMonitor () 5 | @property(assign) EventHandlerRef eventHandlerRef; 6 | @property(strong) NSMutableDictionary *hotKeys; 7 | @end 8 | 9 | static OSStatus MASCarbonEventCallback(EventHandlerCallRef, EventRef, void*); 10 | 11 | @implementation MASShortcutMonitor 12 | 13 | #pragma mark Initialization 14 | 15 | - (instancetype) init 16 | { 17 | self = [super init]; 18 | [self setHotKeys:[NSMutableDictionary dictionary]]; 19 | EventTypeSpec hotKeyPressedSpec = { .eventClass = kEventClassKeyboard, .eventKind = kEventHotKeyPressed }; 20 | OSStatus status = InstallEventHandler(GetEventDispatcherTarget(), MASCarbonEventCallback, 21 | 1, &hotKeyPressedSpec, (__bridge void*)self, &_eventHandlerRef); 22 | if (status != noErr) { 23 | return nil; 24 | } 25 | return self; 26 | } 27 | 28 | - (void) dealloc 29 | { 30 | if (_eventHandlerRef) { 31 | RemoveEventHandler(_eventHandlerRef); 32 | _eventHandlerRef = NULL; 33 | } 34 | } 35 | 36 | + (instancetype) sharedMonitor 37 | { 38 | static dispatch_once_t once; 39 | static MASShortcutMonitor *sharedInstance; 40 | dispatch_once(&once, ^{ 41 | sharedInstance = [[self alloc] init]; 42 | }); 43 | return sharedInstance; 44 | } 45 | 46 | #pragma mark Registration 47 | 48 | - (BOOL) registerShortcut: (MASShortcut*) shortcut withAction: (dispatch_block_t) action 49 | { 50 | MASHotKey *hotKey = [MASHotKey registeredHotKeyWithShortcut:shortcut]; 51 | if (hotKey) { 52 | [hotKey setAction:action]; 53 | [_hotKeys setObject:hotKey forKey:shortcut]; 54 | return YES; 55 | } else { 56 | return NO; 57 | } 58 | } 59 | 60 | - (void) unregisterShortcut: (MASShortcut*) shortcut 61 | { 62 | if (shortcut) { 63 | [_hotKeys removeObjectForKey:shortcut]; 64 | } 65 | } 66 | 67 | - (void) unregisterAllShortcuts 68 | { 69 | [_hotKeys removeAllObjects]; 70 | } 71 | 72 | - (BOOL) isShortcutRegistered: (MASShortcut*) shortcut 73 | { 74 | return !![_hotKeys objectForKey:shortcut]; 75 | } 76 | 77 | #pragma mark Event Handling 78 | 79 | - (void) handleEvent: (EventRef) event 80 | { 81 | if (GetEventClass(event) != kEventClassKeyboard) { 82 | return; 83 | } 84 | 85 | EventHotKeyID hotKeyID; 86 | OSStatus status = GetEventParameter(event, kEventParamDirectObject, typeEventHotKeyID, NULL, sizeof(hotKeyID), NULL, &hotKeyID); 87 | if (status != noErr || hotKeyID.signature != MASHotKeySignature) { 88 | return; 89 | } 90 | 91 | [_hotKeys enumerateKeysAndObjectsUsingBlock:^(MASShortcut *shortcut, MASHotKey *hotKey, BOOL *stop) { 92 | if (hotKeyID.id == [hotKey carbonID]) { 93 | if ([hotKey action]) { 94 | dispatch_async(dispatch_get_main_queue(), [hotKey action]); 95 | } 96 | *stop = YES; 97 | } 98 | }]; 99 | } 100 | 101 | @end 102 | 103 | static OSStatus MASCarbonEventCallback(EventHandlerCallRef _, EventRef event, void *context) 104 | { 105 | MASShortcutMonitor *dispatcher = (__bridge id)context; 106 | [dispatcher handleEvent:event]; 107 | return noErr; 108 | } 109 | -------------------------------------------------------------------------------- /Roar/Displays/WinampWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BezelWindowController.swift 3 | // Roar 4 | // 5 | // Created by Tyler Hall on 12/21/21. 6 | // 7 | 8 | import AppKit 9 | import AVKit 10 | 11 | class WinampWindowController: NoteWindowController { 12 | 13 | @IBOutlet weak var titleLabel: NSTextField! 14 | @IBOutlet weak var subtitleLabel: NSTextField! 15 | @IBOutlet weak var bodyLabel: NSTextField! 16 | @IBOutlet weak var playerView: AVPlayerView! 17 | 18 | @IBOutlet weak var titleLabelConstraint: NSLayoutConstraint! 19 | 20 | override func display(note: Note) { 21 | guard let screen = NSScreen.main else { return } 22 | 23 | window?.backgroundColor = .clear 24 | window?.ignoresMouseEvents = true 25 | window?.level = NSWindow.Level.init(Int(CGWindowLevelForKey(CGWindowLevelKey.mainMenuWindow))) 26 | 27 | titleLabel.stringValue = note.title ?? "" 28 | 29 | if let subtitle = note.subtitle { 30 | subtitleLabel.stringValue = subtitle 31 | subtitleLabel.isHidden = false 32 | } else { 33 | subtitleLabel.isHidden = true 34 | } 35 | 36 | if let body = note.body { 37 | bodyLabel.stringValue = body 38 | bodyLabel.isHidden = false 39 | } else { 40 | bodyLabel.isHidden = true 41 | } 42 | 43 | showWindow(nil) 44 | let width = window?.frame.size.width ?? 0 45 | let height = window?.frame.size.height ?? 0 46 | window?.setFrameOrigin(NSPoint(x: screen.frame.size.width, y: screen.frame.size.height - height - 35)) 47 | 48 | let destOrigin = NSPoint(x: screen.frame.size.width - width - 20, y: screen.frame.size.height - height - 35) 49 | window?.setFrame(NSRect(origin: destOrigin, size: CGSize(width: width, height: height)), display: true, animate: true) 50 | 51 | DispatchQueue.main.asyncAfter(deadline: .now() + 2.5, execute: { 52 | self.noteWindowDelegte?.didDisplayWindow() 53 | }) 54 | 55 | let playerItem = AVPlayerItem(url: Bundle.main.url(forResource: "winamp", withExtension: "mp4")!) 56 | let player = AVPlayer(playerItem: playerItem) 57 | playerView.player = player 58 | player.play() 59 | 60 | animateLabels() 61 | } 62 | 63 | func animateLabels() { 64 | titleLabelConstraint.constant = -titleLabel.bounds.width 65 | 66 | NSAnimationContext.runAnimationGroup { context in 67 | context.duration = 7 68 | context.allowsImplicitAnimation = true 69 | context.timingFunction = CAMediaTimingFunction(name: .linear) 70 | self.window?.contentView?.updateConstraints() 71 | self.window?.contentView?.layoutSubtreeIfNeeded() 72 | } 73 | } 74 | 75 | override func hide() { 76 | guard let screen = NSScreen.main else { return } 77 | 78 | let width = window?.frame.size.width ?? 0 79 | let height = window?.frame.size.height ?? 0 80 | let destOrigin = NSPoint(x: screen.frame.size.width, y: screen.frame.size.height - height - 35) 81 | window?.setFrame(NSRect(origin: destOrigin, size: CGSize(width: width, height: height)), display: true, animate: true) 82 | 83 | DispatchQueue.main.asyncAfter(deadline: .now() + 2.5, execute: { 84 | self.window?.close() 85 | self.noteWindowDelegte?.didHideWindow() 86 | }) 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /Roar/Displays/iTunesWidgetWindowController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // iTunesWidgetWindowController.swift 3 | // Roar 4 | // 5 | // Created by Tyler Hall on 1/3/22. 6 | // 7 | 8 | import Cocoa 9 | 10 | class iTunesWidgetWindowController: NoteWindowController { 11 | 12 | @IBOutlet weak var maskView: NSView! 13 | 14 | @IBOutlet weak var titleLabel: NSTextField! 15 | @IBOutlet weak var subtitleLabel: NSTextField! 16 | @IBOutlet weak var bodyLabel: NSTextField! 17 | 18 | @IBOutlet weak var titleLabelConstraint: NSLayoutConstraint! 19 | @IBOutlet weak var subtitleLabelConstraint: NSLayoutConstraint! 20 | @IBOutlet weak var bodyLabelConstraint: NSLayoutConstraint! 21 | 22 | override func display(note: Note) { 23 | guard let screen = NSScreen.main else { return } 24 | 25 | window?.backgroundColor = .clear 26 | window?.ignoresMouseEvents = true 27 | window?.level = NSWindow.Level.init(Int(CGWindowLevelForKey(CGWindowLevelKey.mainMenuWindow))) 28 | 29 | titleLabel.stringValue = note.title ?? "" 30 | 31 | if let subtitle = note.subtitle { 32 | subtitleLabel.stringValue = subtitle 33 | subtitleLabel.isHidden = false 34 | } else { 35 | subtitleLabel.isHidden = true 36 | } 37 | 38 | if let body = note.body { 39 | bodyLabel.stringValue = body 40 | bodyLabel.isHidden = false 41 | } else { 42 | bodyLabel.isHidden = true 43 | } 44 | 45 | showWindow(nil) 46 | let width = window?.frame.size.width ?? 0 47 | let height = window?.frame.size.height ?? 0 48 | window?.setFrameOrigin(NSPoint(x: screen.frame.size.width, y: screen.frame.size.height - height - 35)) 49 | 50 | let destOrigin = NSPoint(x: screen.frame.size.width - width - 20, y: screen.frame.size.height - height - 35) 51 | window?.setFrame(NSRect(origin: destOrigin, size: CGSize(width: width, height: height)), display: true, animate: true) 52 | 53 | DispatchQueue.main.asyncAfter(deadline: .now() + 2.5, execute: { 54 | self.noteWindowDelegte?.didDisplayWindow() 55 | }) 56 | 57 | let shape = CAShapeLayer() 58 | shape.path = CGPath(ellipseIn: maskView.bounds, transform: nil) 59 | maskView.wantsLayer = true 60 | maskView.layer?.mask = shape 61 | maskView.layer?.masksToBounds = true 62 | 63 | animateLabels() 64 | } 65 | 66 | func animateLabels() { 67 | var maxWidth = max(titleLabel.bounds.width, subtitleLabel.bounds.width) 68 | maxWidth = max(maxWidth, bodyLabel.bounds.width) 69 | 70 | titleLabelConstraint.constant = -maxWidth 71 | subtitleLabelConstraint.constant = -maxWidth 72 | bodyLabelConstraint.constant = -maxWidth 73 | 74 | NSAnimationContext.runAnimationGroup { context in 75 | context.duration = 7 76 | context.allowsImplicitAnimation = true 77 | context.timingFunction = CAMediaTimingFunction(name: .linear) 78 | self.window?.contentView?.updateConstraints() 79 | self.window?.contentView?.layoutSubtreeIfNeeded() 80 | } 81 | } 82 | 83 | override func hide() { 84 | guard let screen = NSScreen.main else { return } 85 | 86 | let width = window?.frame.size.width ?? 0 87 | let height = window?.frame.size.height ?? 0 88 | let destOrigin = NSPoint(x: screen.frame.size.width, y: screen.frame.size.height - height - 35) 89 | window?.setFrame(NSRect(origin: destOrigin, size: CGSize(width: width, height: height)), display: true, animate: true) 90 | 91 | DispatchQueue.main.asyncAfter(deadline: .now() + 2.5, execute: { 92 | self.window?.close() 93 | self.noteWindowDelegte?.didHideWindow() 94 | }) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Pods/Target Support Files/Pods-Roar/Pods-Roar-acknowledgements.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PreferenceSpecifiers 6 | 7 | 8 | FooterText 9 | This application makes use of the following third party libraries: 10 | Title 11 | Acknowledgements 12 | Type 13 | PSGroupSpecifier 14 | 15 | 16 | FooterText 17 | If you are using FMDB in your project, I'd love to hear about it. Let Gus know 18 | by sending an email to gus@flyingmeat.com. 19 | 20 | And if you happen to come across either Gus Mueller or Rob Ryan in a bar, you 21 | might consider purchasing a drink of their choosing if FMDB has been useful to 22 | you. 23 | 24 | Finally, and shortly, this is the MIT License. 25 | 26 | Copyright (c) 2008-2014 Flying Meat Inc. 27 | 28 | Permission is hereby granted, free of charge, to any person obtaining a copy 29 | of this software and associated documentation files (the "Software"), to deal 30 | in the Software without restriction, including without limitation the rights 31 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 32 | copies of the Software, and to permit persons to whom the Software is 33 | furnished to do so, subject to the following conditions: 34 | 35 | The above copyright notice and this permission notice shall be included in 36 | all copies or substantial portions of the Software. 37 | 38 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 39 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 40 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 41 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 42 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 43 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 44 | THE SOFTWARE. 45 | License 46 | MIT 47 | Title 48 | FMDB 49 | Type 50 | PSGroupSpecifier 51 | 52 | 53 | FooterText 54 | Copyright (c) 2012-2013, Vadim Shpakovski 55 | All rights reserved. 56 | 57 | Redistribution and use in source and binary forms, with or without 58 | modification, are permitted provided that the following conditions are met: 59 | 60 | 1. Redistributions of source code must retain the above copyright notice, this 61 | list of conditions and the following disclaimer. 62 | 2. Redistributions in binary form must reproduce the above copyright notice, 63 | this list of conditions and the following disclaimer in the documentation 64 | and/or other materials provided with the distribution. 65 | 66 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 67 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 68 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 69 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 70 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 71 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 72 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 73 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 74 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 75 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 76 | 77 | License 78 | BSD 2-clause 79 | Title 80 | MASShortcut 81 | Type 82 | PSGroupSpecifier 83 | 84 | 85 | FooterText 86 | Generated by CocoaPods - https://cocoapods.org 87 | Title 88 | 89 | Type 90 | PSGroupSpecifier 91 | 92 | 93 | StringsTable 94 | Acknowledgements 95 | Title 96 | Acknowledgements 97 | 98 | 99 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/User Defaults Storage/MASShortcutBinder.m: -------------------------------------------------------------------------------- 1 | #import "MASShortcutBinder.h" 2 | #import "MASShortcut.h" 3 | 4 | @interface MASShortcutBinder () 5 | @property(strong) NSMutableDictionary *actions; 6 | @property(strong) NSMutableDictionary *shortcuts; 7 | @end 8 | 9 | @implementation MASShortcutBinder 10 | 11 | #pragma mark Initialization 12 | 13 | - (id) init 14 | { 15 | self = [super init]; 16 | [self setActions:[NSMutableDictionary dictionary]]; 17 | [self setShortcuts:[NSMutableDictionary dictionary]]; 18 | [self setShortcutMonitor:[MASShortcutMonitor sharedMonitor]]; 19 | [self setBindingOptions:@{NSValueTransformerNameBindingOption: NSKeyedUnarchiveFromDataTransformerName}]; 20 | return self; 21 | } 22 | 23 | - (void) dealloc 24 | { 25 | for (NSString *bindingName in [_actions allKeys]) { 26 | [self unbind:bindingName]; 27 | } 28 | } 29 | 30 | + (instancetype) sharedBinder 31 | { 32 | static dispatch_once_t once; 33 | static MASShortcutBinder *sharedInstance; 34 | dispatch_once(&once, ^{ 35 | sharedInstance = [[self alloc] init]; 36 | }); 37 | return sharedInstance; 38 | } 39 | 40 | #pragma mark Registration 41 | 42 | - (void) bindShortcutWithDefaultsKey: (NSString*) defaultsKeyName toAction: (dispatch_block_t) action 43 | { 44 | NSAssert([defaultsKeyName rangeOfString:@"."].location == NSNotFound, 45 | @"Illegal character in binding name (“.”), please see http://git.io/x5YS."); 46 | NSAssert([defaultsKeyName rangeOfString:@" "].location == NSNotFound, 47 | @"Illegal character in binding name (“ ”), please see http://git.io/x5YS."); 48 | [_actions setObject:[action copy] forKey:defaultsKeyName]; 49 | [self bind:defaultsKeyName 50 | toObject:[NSUserDefaultsController sharedUserDefaultsController] 51 | withKeyPath:[@"values." stringByAppendingString:defaultsKeyName] 52 | options:_bindingOptions]; 53 | } 54 | 55 | - (void) breakBindingWithDefaultsKey: (NSString*) defaultsKeyName 56 | { 57 | [_shortcutMonitor unregisterShortcut:[_shortcuts objectForKey:defaultsKeyName]]; 58 | [_shortcuts removeObjectForKey:defaultsKeyName]; 59 | [_actions removeObjectForKey:defaultsKeyName]; 60 | [self unbind:defaultsKeyName]; 61 | } 62 | 63 | - (void) registerDefaultShortcuts: (NSDictionary*) defaultShortcuts 64 | { 65 | NSValueTransformer *transformer = [_bindingOptions valueForKey:NSValueTransformerBindingOption]; 66 | if (transformer == nil) { 67 | NSString *transformerName = [_bindingOptions valueForKey:NSValueTransformerNameBindingOption]; 68 | if (transformerName) { 69 | transformer = [NSValueTransformer valueTransformerForName:transformerName]; 70 | } 71 | } 72 | 73 | NSAssert(transformer != nil, @"Can’t register default shortcuts without a transformer."); 74 | 75 | [defaultShortcuts enumerateKeysAndObjectsUsingBlock:^(NSString *defaultsKey, MASShortcut *shortcut, BOOL *stop) { 76 | id value = [transformer reverseTransformedValue:shortcut]; 77 | [[NSUserDefaults standardUserDefaults] registerDefaults:@{defaultsKey:value}]; 78 | }]; 79 | } 80 | 81 | #pragma mark Bindings 82 | 83 | - (BOOL) isRegisteredAction: (NSString*) name 84 | { 85 | return !![_actions objectForKey:name]; 86 | } 87 | 88 | - (id) valueForUndefinedKey: (NSString*) key 89 | { 90 | return [self isRegisteredAction:key] ? 91 | [_shortcuts objectForKey:key] : 92 | [super valueForUndefinedKey:key]; 93 | } 94 | 95 | - (void) setValue: (id) value forUndefinedKey: (NSString*) key 96 | { 97 | if (![self isRegisteredAction:key]) { 98 | [super setValue:value forUndefinedKey:key]; 99 | return; 100 | } 101 | 102 | MASShortcut *newShortcut = value; 103 | MASShortcut *currentShortcut = [_shortcuts objectForKey:key]; 104 | 105 | // Unbind previous shortcut if any 106 | if (currentShortcut != nil) { 107 | [_shortcutMonitor unregisterShortcut:currentShortcut]; 108 | } 109 | 110 | // Just deleting the old shortcut 111 | if (newShortcut == nil) { 112 | [_shortcuts removeObjectForKey:key]; 113 | return; 114 | } 115 | 116 | // Bind new shortcut 117 | [_shortcuts setObject:newShortcut forKey:key]; 118 | [_shortcutMonitor registerShortcut:newShortcut withAction:[_actions objectForKey:key]]; 119 | } 120 | 121 | @end 122 | -------------------------------------------------------------------------------- /Pods/MASShortcut/Framework/Model/MASShortcutValidator.m: -------------------------------------------------------------------------------- 1 | #import "MASShortcutValidator.h" 2 | #import "MASLocalization.h" 3 | 4 | @implementation MASShortcutValidator 5 | 6 | + (instancetype) sharedValidator 7 | { 8 | static dispatch_once_t once; 9 | static MASShortcutValidator *sharedInstance; 10 | dispatch_once(&once, ^{ 11 | sharedInstance = [[self alloc] init]; 12 | }); 13 | return sharedInstance; 14 | } 15 | 16 | - (BOOL) isShortcutValid: (MASShortcut*) shortcut 17 | { 18 | NSInteger keyCode = [shortcut keyCode]; 19 | NSEventModifierFlags modifiers = [shortcut modifierFlags]; 20 | 21 | // Allow any function key with any combination of modifiers 22 | BOOL includesFunctionKey = ((keyCode == kVK_F1) || (keyCode == kVK_F2) || (keyCode == kVK_F3) || (keyCode == kVK_F4) || 23 | (keyCode == kVK_F5) || (keyCode == kVK_F6) || (keyCode == kVK_F7) || (keyCode == kVK_F8) || 24 | (keyCode == kVK_F9) || (keyCode == kVK_F10) || (keyCode == kVK_F11) || (keyCode == kVK_F12) || 25 | (keyCode == kVK_F13) || (keyCode == kVK_F14) || (keyCode == kVK_F15) || (keyCode == kVK_F16) || 26 | (keyCode == kVK_F17) || (keyCode == kVK_F18) || (keyCode == kVK_F19) || (keyCode == kVK_F20)); 27 | if (includesFunctionKey) return YES; 28 | 29 | // Do not allow any other key without modifiers 30 | BOOL hasModifierFlags = (modifiers > 0); 31 | if (!hasModifierFlags) return NO; 32 | 33 | // Allow any hotkey containing Control or Command modifier 34 | BOOL includesCommand = ((modifiers & NSCommandKeyMask) > 0); 35 | BOOL includesControl = ((modifiers & NSControlKeyMask) > 0); 36 | if (includesCommand || includesControl) return YES; 37 | 38 | // Allow Option key only in selected cases 39 | BOOL includesOption = ((modifiers & NSAlternateKeyMask) > 0); 40 | if (includesOption) { 41 | 42 | // Always allow Option-Space and Option-Escape because they do not have any bind system commands 43 | if ((keyCode == kVK_Space) || (keyCode == kVK_Escape)) return YES; 44 | 45 | // Allow Option modifier with any key even if it will break the system binding 46 | if (_allowAnyShortcutWithOptionModifier) return YES; 47 | } 48 | 49 | // The hotkey does not have any modifiers or violates system bindings 50 | return NO; 51 | } 52 | 53 | - (BOOL) isShortcut: (MASShortcut*) shortcut alreadyTakenInMenu: (NSMenu*) menu explanation: (NSString**) explanation 54 | { 55 | NSString *keyEquivalent = [shortcut keyCodeStringForKeyEquivalent]; 56 | NSEventModifierFlags flags = [shortcut modifierFlags]; 57 | 58 | for (NSMenuItem *menuItem in menu.itemArray) { 59 | if (menuItem.hasSubmenu && [self isShortcut:shortcut alreadyTakenInMenu:[menuItem submenu] explanation:explanation]) return YES; 60 | 61 | BOOL equalFlags = (MASPickCocoaModifiers(menuItem.keyEquivalentModifierMask) == flags); 62 | BOOL equalHotkeyLowercase = [menuItem.keyEquivalent.lowercaseString isEqualToString:keyEquivalent]; 63 | 64 | // Check if the cases are different, we know ours is lower and that shift is included in our modifiers 65 | // If theirs is capitol, we need to add shift to their modifiers 66 | if (equalHotkeyLowercase && ![menuItem.keyEquivalent isEqualToString:keyEquivalent]) { 67 | equalFlags = (MASPickCocoaModifiers(menuItem.keyEquivalentModifierMask | NSShiftKeyMask) == flags); 68 | } 69 | 70 | if (equalFlags && equalHotkeyLowercase) { 71 | if (explanation) { 72 | *explanation = MASLocalizedString(@"This shortcut cannot be used because it is already used by the menu item ‘%@’.", 73 | @"Message for alert when shortcut is already used"); 74 | *explanation = [NSString stringWithFormat:*explanation, menuItem.title]; 75 | } 76 | return YES; 77 | } 78 | } 79 | return NO; 80 | } 81 | 82 | - (BOOL) isShortcutAlreadyTakenBySystem: (MASShortcut*) shortcut explanation: (NSString**) explanation 83 | { 84 | CFArrayRef globalHotKeys; 85 | if (CopySymbolicHotKeys(&globalHotKeys) == noErr) { 86 | 87 | // Enumerate all global hotkeys and check if any of them matches current shortcut 88 | for (CFIndex i = 0, count = CFArrayGetCount(globalHotKeys); i < count; i++) { 89 | CFDictionaryRef hotKeyInfo = CFArrayGetValueAtIndex(globalHotKeys, i); 90 | CFNumberRef code = CFDictionaryGetValue(hotKeyInfo, kHISymbolicHotKeyCode); 91 | CFNumberRef flags = CFDictionaryGetValue(hotKeyInfo, kHISymbolicHotKeyModifiers); 92 | CFNumberRef enabled = CFDictionaryGetValue(hotKeyInfo, kHISymbolicHotKeyEnabled); 93 | 94 | if (([(__bridge NSNumber *)code integerValue] == [shortcut keyCode]) && 95 | ([(__bridge NSNumber *)flags unsignedIntegerValue] == [shortcut carbonFlags]) && 96 | ([(__bridge NSNumber *)enabled boolValue])) { 97 | 98 | if (explanation) { 99 | *explanation = MASLocalizedString(@"This combination cannot be used because it is already used by a system-wide " 100 | @"keyboard shortcut.\nIf you really want to use this key combination, most shortcuts " 101 | @"can be changed in the Keyboard & Mouse panel in System Preferences.", 102 | @"Message for alert when shortcut is already used by the system"); 103 | } 104 | return YES; 105 | } 106 | } 107 | CFRelease(globalHotKeys); 108 | } 109 | return [self isShortcut:shortcut alreadyTakenInMenu:[NSApp mainMenu] explanation:explanation]; 110 | } 111 | 112 | @end 113 | -------------------------------------------------------------------------------- /Roar/Watcher/NCWatcher.swift: -------------------------------------------------------------------------------- 1 | // 2 | // NCWatcher.swift 3 | // Roar 4 | // 5 | // Created by Tyler Hall on 12/20/21. 6 | // 7 | 8 | import Foundation 9 | import FMDB 10 | 11 | struct Note { 12 | var title: String? 13 | var subtitle: String? 14 | var body: String? 15 | var date: Date 16 | var appID: String 17 | 18 | enum DisplayStyle: Int { 19 | case MusicVideo = 0 20 | case Bezel = 1 21 | case Winamp = 2 22 | case iTunesWidget = 3 23 | case Macintosh = 4 24 | } 25 | 26 | var defaultDisplayStyle: DisplayStyle { 27 | return DisplayStyle(rawValue: UserDefaults.standard.integer(forKey: "noteDisplayStyle")) ?? .MusicVideo 28 | } 29 | 30 | var code: String? { 31 | let strings = [title, subtitle, body].compactMap { $0 } 32 | let str = strings.joined(separator: "\n") 33 | 34 | guard let regex = try? NSRegularExpression(pattern: "[0-9]{4,8}", options: [.dotMatchesLineSeparators]) else { return nil } 35 | let nsString = str as NSString 36 | let matches = regex.matches(in: str, options: [.withoutAnchoringBounds], range: NSMakeRange(0, nsString.length)) 37 | if let first = matches.first { 38 | let code = nsString.substring(with: first.range) 39 | return code 40 | } 41 | 42 | return nil 43 | } 44 | 45 | var urls: [URL] { 46 | var urls = [URL]() 47 | 48 | let strings = [title, subtitle, body].compactMap { $0 } 49 | let str = strings.joined(separator: "\n") 50 | 51 | let detector = try! NSDataDetector(types: NSTextCheckingResult.CheckingType.link.rawValue) 52 | let matches = detector.matches(in: str, options: [], range: NSRange(location: 0, length: str.utf16.count)) 53 | for match in matches { 54 | guard let range = Range(match.range, in: str) else { continue } 55 | let urlStr = String(str[range]) 56 | if let url = URL(string: urlStr) { 57 | urls.append(url) 58 | } 59 | } 60 | return urls 61 | } 62 | } 63 | 64 | class NCWatcher { 65 | 66 | static let shared = NCWatcher() 67 | 68 | var databaseURL: URL? 69 | var db: FMDatabase! 70 | 71 | let opQueue = OperationQueue() 72 | 73 | var cutoffDate = Date() 74 | var timer: Timer? 75 | 76 | var lastNote: Note? 77 | 78 | func setup(_ completion: ((Bool) -> ())? = nil) { 79 | opQueue.maxConcurrentOperationCount = 1 80 | 81 | Pipette.execute(URL(fileURLWithPath: "/usr/bin/getconf"), args: ["DARWIN_USER_DIR"], text: nil) { [weak self] stdout, _ in 82 | guard let self = self else { completion?(false); return } 83 | if let userPath = stdout?.trimmingCharacters(in: .whitespacesAndNewlines) { 84 | var url = URL(fileURLWithPath: userPath) 85 | url.appendPathComponent("com.apple.notificationcenter") 86 | url.appendPathComponent("db2") 87 | url.appendPathComponent("db") 88 | if FileManager.default.isReadableFile(atPath: url.path) { 89 | self.databaseURL = url 90 | let success = self.openDatabase() 91 | completion?(success) 92 | } else { 93 | completion?(false) 94 | } 95 | } else { 96 | completion?(false) 97 | } 98 | } 99 | } 100 | 101 | func startWatching() { 102 | timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block: { [weak self] _ in 103 | self?.fetchNewNotifications() 104 | }) 105 | } 106 | 107 | func openDatabase() -> Bool { 108 | guard let url = databaseURL else { return false } 109 | guard FileManager.default.isReadableFile(atPath: url.path) else { return false } 110 | 111 | db = FMDatabase(url: url) 112 | return db.open() 113 | } 114 | 115 | func fetchNewNotifications() { 116 | var notes = [Note]() 117 | 118 | do { 119 | let results = try db.executeQuery("SELECT app.identifier as app_name, record.delivered_date as delivered_date, record.data as notification_content FROM app INNER JOIN record ON app.app_id=record.app_id;", values: nil) 120 | while results.next() { 121 | guard let appName = results.string(forColumn: "app_name") else { continue } 122 | let deliveredTimestamp = results.double(forColumn: "delivered_date") 123 | guard deliveredTimestamp > 0 else { continue } 124 | let deliveredDate = Date(timeIntervalSinceReferenceDate: deliveredTimestamp) 125 | guard let data = results.data(forColumn: "notification_content") else { continue } 126 | if let note = parseNote(appName: appName, date: deliveredDate, data: data) { 127 | if note.date > cutoffDate { 128 | notes.append(note) 129 | } 130 | } 131 | } 132 | } catch { 133 | 134 | } 135 | 136 | for note in notes { 137 | if note.date > cutoffDate { 138 | cutoffDate = note.date 139 | } 140 | 141 | let op = NoteDisplayOperation(note: note) 142 | opQueue.addOperation(op) 143 | } 144 | } 145 | 146 | func parseNote(appName: String, date: Date, data: Data) -> Note? { 147 | var tempURL: URL? 148 | defer { 149 | if let url = tempURL { 150 | try? FileManager.default.removeItem(at: url) 151 | } 152 | } 153 | 154 | tempURL = data.writeToTempFile() 155 | 156 | guard let tempURL = tempURL else { return nil } 157 | guard let dict = try? NSDictionary(contentsOf: tempURL, error: ()) else { return nil } 158 | 159 | guard let bundleID = dict.value(forKey: "app") as? String else { return nil } 160 | guard let req = dict.value(forKey: "req") as? NSDictionary else { return nil } 161 | let body = req.value(forKey: "body") as? String 162 | let title = req.value(forKey: "titl") as? String 163 | let subtitle = req.value(forKey: "subt") as? String 164 | 165 | let note = Note(title: title, subtitle: subtitle, body: body, date: date, appID: bundleID) 166 | return note 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /Pods/MASShortcut/README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/shpakovski/MASShortcut.svg?branch=master)](https://travis-ci.org/shpakovski/MASShortcut) 2 | [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) 3 | 4 | # Intro 5 | 6 | Some time ago Cocoa developers used a brilliant framework [ShortcutRecorder](http://wafflesoftware.net/shortcut/) for managing keyboard shortcuts in application preferences. However, it became incompatible with the new plugin architecture of Xcode 4. 7 | 8 | The MASShortcut project introduces a modern API and user interface for recording, storing and using system-wide keyboard shortcuts. 9 | 10 | ![Screenshot of the demo project](https://raw.githubusercontent.com/shpakovski/MASShortcut/master/Demo/screenshot.png "This is how the demo looks like") 11 | 12 | Features: 13 | 14 | * Record and display keyboard shortcuts 15 | * Watch for shortcuts and execute actions, system-wide 16 | * A nice, [documented API](http://cocoadocs.org/docsets/MASShortcut/) 17 | * Can be configured to be compatible with Shortcut Recorder 18 | * Can be installed both through CocoaPods and as a Git submodule 19 | * Mac App Store friendly 20 | * Works on OS X 10.10 and up 21 | * Hacking-friendly codebase covered with tests 22 | 23 | Partially done: 24 | 25 | * Accessibility support. There’s some basic accessibility code, testers and feedback welcome. 26 | * Localisation. The English and Czech localization should be complete, there’s basic support for German, French, Spanish, Italian, and Japanese. If you’re a native speaker in one of the mentioned languages, please test the localization and report issues or add missing strings. 27 | 28 | Pull requests welcome :) 29 | 30 | # Installation 31 | 32 | You can use [CocoaPods](http://cocoapods.org/), adding the following line to your Podfile: 33 | 34 | pod 'MASShortcut' 35 | 36 | If you want to stick to the 1.x branch, you can use the version smart match operator: 37 | 38 | pod 'MASShortcut', '~> 1' 39 | 40 | You can also install via [Carthage](https://github.com/Carthage/Carthage), or you can use Git submodules and link against the MASShortcut framework manually. 41 | 42 | To build from the command line, type 'make release'. The framework will be created in a temporary directory and revealed in Finder when the build is complete. 43 | 44 | # Usage 45 | 46 | I hope, it is really easy: 47 | 48 | ```objective-c 49 | #import 50 | 51 | // Drop a custom view into XIB, set its class to MASShortcutView 52 | // and its height to 19. If you select another appearance style, 53 | // look up the correct height values in MASShortcutView.h. 54 | @property (nonatomic, weak) IBOutlet MASShortcutView *shortcutView; 55 | 56 | // Pick a preference key to store the shortcut between launches 57 | static NSString *const kPreferenceGlobalShortcut = @"GlobalShortcut"; 58 | 59 | // Associate the shortcut view with user defaults 60 | self.shortcutView.associatedUserDefaultsKey = kPreferenceGlobalShortcut; 61 | 62 | // Associate the preference key with an action 63 | [[MASShortcutBinder sharedBinder] 64 | bindShortcutWithDefaultsKey:kPreferenceGlobalShortcut 65 | toAction:^{ 66 | // Let me know if you find a better or a more convenient API. 67 | }]; 68 | ``` 69 | 70 | You can see a real usage example in the Demo target. Enjoy! 71 | 72 | # Shortcut Recorder Compatibility 73 | 74 | By default, MASShortcut uses a different User Defaults storage format incompatible with Shortcut Recorder. But it’s easily possible to change that, so that you can replace Shortcut Recorder with MASShortcut without having to migrate the shortcuts previously stored by your apps. There are two parts of the story: 75 | 76 | If you bind the recorder control (`MASShortcutView`) to User defaults, set the Value Transformer field in the Interface Builder to `MASDictionaryTransformer`. This makes sure the shortcuts are written in the Shortcut Recorder format. 77 | 78 | If you use `MASShortcutBinder` to automatically load shortcuts from User Defaults, set the `bindingOptions` accordingly: 79 | 80 | ```objective-c 81 | [[MASShortcutBinder sharedBinder] setBindingOptions:@{NSValueTransformerNameBindingOption:MASDictionaryTransformerName}]; 82 | ``` 83 | 84 | This makes sure that the shortcuts in the Shortcut Recorder format are loaded correctly. 85 | 86 | # Notifications 87 | 88 | By registering for KVO notifications from `NSUserDefaultsController`, you can get a callback whenever a user changes the shortcut, allowing you to perform any UI updates, or other code handling tasks. 89 | 90 | This is just as easy to implement: 91 | 92 | ```objective-c 93 | // Declare an ivar for key path in the user defaults controller 94 | NSString *_observableKeyPath; 95 | 96 | // Make a global context reference 97 | void *kGlobalShortcutContext = &kGlobalShortcutContext; 98 | 99 | // Implement when loading view 100 | _observableKeyPath = [@"values." stringByAppendingString:kPreferenceGlobalShortcut]; 101 | [[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeyPath:_observableKeyPath 102 | options:NSKeyValueObservingOptionInitial 103 | context:kGlobalShortcutContext]; 104 | 105 | // Capture the KVO change and do something 106 | - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)obj 107 | change:(NSDictionary *)change context:(void *)ctx 108 | { 109 | if (ctx == kGlobalShortcutContext) { 110 | NSLog(@"Shortcut has changed"); 111 | } 112 | else { 113 | [super observeValueForKeyPath:keyPath ofObject:obj change:change context:ctx]; 114 | } 115 | } 116 | 117 | // Do not forget to remove the observer 118 | [[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self 119 | forKeyPath:_observableKeyPath 120 | context:kGlobalShortcutContext]; 121 | ``` 122 | 123 | # Using in Swift projects 124 | 125 | 1. Install as a Pod using the latest CocoaPods with Swift support. 126 | 2. Create a bridging header file [using the instructions here](http://swiftalicio.us/2014/11/using-cocoapods-from-swift/) 127 | 3. Your bridging header file should contain the following [two](https://github.com/shpakovski/MASShortcut/issues/36) imports: 128 | 129 | ```objective-c 130 | #import 131 | #import 132 | ``` 133 | 134 | # Copyright 135 | 136 | MASShortcut is licensed under the 2-clause BSD license. 137 | -------------------------------------------------------------------------------- /Roar/Windows/ActionWindowController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | -------------------------------------------------------------------------------- /Pods/FMDB/src/fmdb/FMDatabaseAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabaseAdditions.h 3 | // fmdb 4 | // 5 | // Created by August Mueller on 10/30/05. 6 | // Copyright 2005 Flying Meat Inc.. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "FMDatabase.h" 11 | 12 | NS_ASSUME_NONNULL_BEGIN 13 | 14 | /** Category of additions for `` class. 15 | 16 | ### See also 17 | 18 | - `` 19 | */ 20 | 21 | @interface FMDatabase (FMDatabaseAdditions) 22 | 23 | ///---------------------------------------- 24 | /// @name Return results of SQL to variable 25 | ///---------------------------------------- 26 | 27 | /** Return `int` value for query 28 | 29 | @param query The SQL query to be performed. 30 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 31 | 32 | @return `int` value. 33 | 34 | @note This is not available from Swift. 35 | */ 36 | 37 | - (int)intForQuery:(NSString*)query, ...; 38 | 39 | /** Return `long` value for query 40 | 41 | @param query The SQL query to be performed. 42 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 43 | 44 | @return `long` value. 45 | 46 | @note This is not available from Swift. 47 | */ 48 | 49 | - (long)longForQuery:(NSString*)query, ...; 50 | 51 | /** Return `BOOL` value for query 52 | 53 | @param query The SQL query to be performed. 54 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 55 | 56 | @return `BOOL` value. 57 | 58 | @note This is not available from Swift. 59 | */ 60 | 61 | - (BOOL)boolForQuery:(NSString*)query, ...; 62 | 63 | /** Return `double` value for query 64 | 65 | @param query The SQL query to be performed. 66 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 67 | 68 | @return `double` value. 69 | 70 | @note This is not available from Swift. 71 | */ 72 | 73 | - (double)doubleForQuery:(NSString*)query, ...; 74 | 75 | /** Return `NSString` value for query 76 | 77 | @param query The SQL query to be performed. 78 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 79 | 80 | @return `NSString` value. 81 | 82 | @note This is not available from Swift. 83 | */ 84 | 85 | - (NSString * _Nullable)stringForQuery:(NSString*)query, ...; 86 | 87 | /** Return `NSData` value for query 88 | 89 | @param query The SQL query to be performed. 90 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 91 | 92 | @return `NSData` value. 93 | 94 | @note This is not available from Swift. 95 | */ 96 | 97 | - (NSData * _Nullable)dataForQuery:(NSString*)query, ...; 98 | 99 | /** Return `NSDate` value for query 100 | 101 | @param query The SQL query to be performed. 102 | @param ... A list of parameters that will be bound to the `?` placeholders in the SQL query. 103 | 104 | @return `NSDate` value. 105 | 106 | @note This is not available from Swift. 107 | */ 108 | 109 | - (NSDate * _Nullable)dateForQuery:(NSString*)query, ...; 110 | 111 | 112 | // Notice that there's no dataNoCopyForQuery:. 113 | // That would be a bad idea, because we close out the result set, and then what 114 | // happens to the data that we just didn't copy? Who knows, not I. 115 | 116 | 117 | ///-------------------------------- 118 | /// @name Schema related operations 119 | ///-------------------------------- 120 | 121 | /** Does table exist in database? 122 | 123 | @param tableName The name of the table being looked for. 124 | 125 | @return `YES` if table found; `NO` if not found. 126 | */ 127 | 128 | - (BOOL)tableExists:(NSString*)tableName; 129 | 130 | /** The schema of the database. 131 | 132 | This will be the schema for the entire database. For each entity, each row of the result set will include the following fields: 133 | 134 | - `type` - The type of entity (e.g. table, index, view, or trigger) 135 | - `name` - The name of the object 136 | - `tbl_name` - The name of the table to which the object references 137 | - `rootpage` - The page number of the root b-tree page for tables and indices 138 | - `sql` - The SQL that created the entity 139 | 140 | @return `FMResultSet` of schema; `nil` on error. 141 | 142 | @see [SQLite File Format](http://www.sqlite.org/fileformat.html) 143 | */ 144 | 145 | - (FMResultSet * _Nullable)getSchema; 146 | 147 | /** The schema of the database. 148 | 149 | This will be the schema for a particular table as report by SQLite `PRAGMA`, for example: 150 | 151 | PRAGMA table_info('employees') 152 | 153 | This will report: 154 | 155 | - `cid` - The column ID number 156 | - `name` - The name of the column 157 | - `type` - The data type specified for the column 158 | - `notnull` - whether the field is defined as NOT NULL (i.e. values required) 159 | - `dflt_value` - The default value for the column 160 | - `pk` - Whether the field is part of the primary key of the table 161 | 162 | @param tableName The name of the table for whom the schema will be returned. 163 | 164 | @return `FMResultSet` of schema; `nil` on error. 165 | 166 | @see [table_info](http://www.sqlite.org/pragma.html#pragma_table_info) 167 | */ 168 | 169 | - (FMResultSet * _Nullable)getTableSchema:(NSString*)tableName; 170 | 171 | /** Test to see if particular column exists for particular table in database 172 | 173 | @param columnName The name of the column. 174 | 175 | @param tableName The name of the table. 176 | 177 | @return `YES` if column exists in table in question; `NO` otherwise. 178 | */ 179 | 180 | - (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName; 181 | 182 | /** Test to see if particular column exists for particular table in database 183 | 184 | @param columnName The name of the column. 185 | 186 | @param tableName The name of the table. 187 | 188 | @return `YES` if column exists in table in question; `NO` otherwise. 189 | 190 | @see columnExists:inTableWithName: 191 | 192 | @warning Deprecated - use `` instead. 193 | */ 194 | 195 | - (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __deprecated_msg("Use columnExists:inTableWithName: instead"); 196 | 197 | 198 | /** Validate SQL statement 199 | 200 | This validates SQL statement by performing `sqlite3_prepare_v2`, but not returning the results, but instead immediately calling `sqlite3_finalize`. 201 | 202 | @param sql The SQL statement being validated. 203 | 204 | @param error This is a pointer to a `NSError` object that will receive the autoreleased `NSError` object if there was any error. If this is `nil`, no `NSError` result will be returned. 205 | 206 | @return `YES` if validation succeeded without incident; `NO` otherwise. 207 | 208 | */ 209 | 210 | - (BOOL)validateSQL:(NSString*)sql error:(NSError * _Nullable *)error; 211 | 212 | 213 | ///----------------------------------- 214 | /// @name Application identifier tasks 215 | ///----------------------------------- 216 | 217 | /** Retrieve application ID 218 | 219 | @return The `uint32_t` numeric value of the application ID. 220 | 221 | @see setApplicationID: 222 | */ 223 | 224 | @property (nonatomic) uint32_t applicationID; 225 | 226 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 227 | 228 | /** Retrieve application ID string 229 | 230 | @see setApplicationIDString: 231 | */ 232 | 233 | @property (nonatomic, retain) NSString *applicationIDString; 234 | 235 | #endif 236 | 237 | ///----------------------------------- 238 | /// @name user version identifier tasks 239 | ///----------------------------------- 240 | 241 | /** Retrieve user version 242 | 243 | @see setUserVersion: 244 | */ 245 | 246 | @property (nonatomic) uint32_t userVersion; 247 | 248 | @end 249 | 250 | NS_ASSUME_NONNULL_END 251 | -------------------------------------------------------------------------------- /Roar/Displays/MacintoshWindowController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /Roar/Displays/iTunesWidgetWindowController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /Roar/Base.lproj/MainMenu.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /Pods/FMDB/src/fmdb/FMDatabaseAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // FMDatabaseAdditions.m 3 | // fmdb 4 | // 5 | // Created by August Mueller on 10/30/05. 6 | // Copyright 2005 Flying Meat Inc.. All rights reserved. 7 | // 8 | 9 | #import "FMDatabase.h" 10 | #import "FMDatabaseAdditions.h" 11 | #import "TargetConditionals.h" 12 | 13 | #if FMDB_SQLITE_STANDALONE 14 | #import 15 | #else 16 | #import 17 | #endif 18 | 19 | @interface FMDatabase (PrivateStuff) 20 | - (FMResultSet *)executeQuery:(NSString *)sql withArgumentsInArray:(NSArray * _Nullable)arrayArgs orDictionary:(NSDictionary * _Nullable)dictionaryArgs orVAList:(va_list)args; 21 | @end 22 | 23 | @implementation FMDatabase (FMDatabaseAdditions) 24 | 25 | #define RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(type, sel) \ 26 | va_list args; \ 27 | va_start(args, query); \ 28 | FMResultSet *resultSet = [self executeQuery:query withArgumentsInArray:0x00 orDictionary:0x00 orVAList:args]; \ 29 | va_end(args); \ 30 | if (![resultSet next]) { return (type)0; } \ 31 | type ret = [resultSet sel:0]; \ 32 | [resultSet close]; \ 33 | [resultSet setParentDB:nil]; \ 34 | return ret; 35 | 36 | 37 | - (NSString *)stringForQuery:(NSString*)query, ... { 38 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSString *, stringForColumnIndex); 39 | } 40 | 41 | - (int)intForQuery:(NSString*)query, ... { 42 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(int, intForColumnIndex); 43 | } 44 | 45 | - (long)longForQuery:(NSString*)query, ... { 46 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(long, longForColumnIndex); 47 | } 48 | 49 | - (BOOL)boolForQuery:(NSString*)query, ... { 50 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(BOOL, boolForColumnIndex); 51 | } 52 | 53 | - (double)doubleForQuery:(NSString*)query, ... { 54 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(double, doubleForColumnIndex); 55 | } 56 | 57 | - (NSData*)dataForQuery:(NSString*)query, ... { 58 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSData *, dataForColumnIndex); 59 | } 60 | 61 | - (NSDate*)dateForQuery:(NSString*)query, ... { 62 | RETURN_RESULT_FOR_QUERY_WITH_SELECTOR(NSDate *, dateForColumnIndex); 63 | } 64 | 65 | 66 | - (BOOL)tableExists:(NSString*)tableName { 67 | 68 | tableName = [tableName lowercaseString]; 69 | 70 | FMResultSet *rs = [self executeQuery:@"select [sql] from sqlite_master where [type] = 'table' and lower(name) = ?", tableName]; 71 | 72 | //if at least one next exists, table exists 73 | BOOL returnBool = [rs next]; 74 | 75 | //close and free object 76 | [rs close]; 77 | 78 | return returnBool; 79 | } 80 | 81 | /* 82 | get table with list of tables: result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] 83 | check if table exist in database (patch from OZLB) 84 | */ 85 | - (FMResultSet * _Nullable)getSchema { 86 | 87 | //result colums: type[STRING], name[STRING],tbl_name[STRING],rootpage[INTEGER],sql[STRING] 88 | FMResultSet *rs = [self executeQuery:@"SELECT type, name, tbl_name, rootpage, sql FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type != 'meta' AND name NOT LIKE 'sqlite_%' ORDER BY tbl_name, type DESC, name"]; 89 | 90 | return rs; 91 | } 92 | 93 | /* 94 | get table schema: result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] 95 | */ 96 | - (FMResultSet * _Nullable)getTableSchema:(NSString*)tableName { 97 | 98 | //result colums: cid[INTEGER], name,type [STRING], notnull[INTEGER], dflt_value[],pk[INTEGER] 99 | FMResultSet *rs = [self executeQuery:[NSString stringWithFormat: @"pragma table_info('%@')", tableName]]; 100 | 101 | return rs; 102 | } 103 | 104 | - (BOOL)columnExists:(NSString*)columnName inTableWithName:(NSString*)tableName { 105 | 106 | BOOL returnBool = NO; 107 | 108 | tableName = [tableName lowercaseString]; 109 | columnName = [columnName lowercaseString]; 110 | 111 | FMResultSet *rs = [self getTableSchema:tableName]; 112 | 113 | //check if column is present in table schema 114 | while ([rs next]) { 115 | if ([[[rs stringForColumn:@"name"] lowercaseString] isEqualToString:columnName]) { 116 | returnBool = YES; 117 | break; 118 | } 119 | } 120 | 121 | //If this is not done FMDatabase instance stays out of pool 122 | [rs close]; 123 | 124 | return returnBool; 125 | } 126 | 127 | 128 | 129 | - (uint32_t)applicationID { 130 | #if SQLITE_VERSION_NUMBER >= 3007017 131 | uint32_t r = 0; 132 | 133 | FMResultSet *rs = [self executeQuery:@"pragma application_id"]; 134 | 135 | if ([rs next]) { 136 | r = (uint32_t)[rs longLongIntForColumnIndex:0]; 137 | } 138 | 139 | [rs close]; 140 | 141 | return r; 142 | #else 143 | NSString *errorMessage = NSLocalizedStringFromTable(@"Application ID functions require SQLite 3.7.17", @"FMDB", nil); 144 | if (self.logsErrors) NSLog(@"%@", errorMessage); 145 | return 0; 146 | #endif 147 | } 148 | 149 | - (void)setApplicationID:(uint32_t)appID { 150 | #if SQLITE_VERSION_NUMBER >= 3007017 151 | NSString *query = [NSString stringWithFormat:@"pragma application_id=%d", appID]; 152 | FMResultSet *rs = [self executeQuery:query]; 153 | [rs next]; 154 | [rs close]; 155 | #else 156 | NSString *errorMessage = NSLocalizedStringFromTable(@"Application ID functions require SQLite 3.7.17", @"FMDB", nil); 157 | if (self.logsErrors) NSLog(@"%@", errorMessage); 158 | #endif 159 | } 160 | 161 | 162 | #if TARGET_OS_MAC && !TARGET_OS_IPHONE 163 | 164 | - (NSString*)applicationIDString { 165 | #if SQLITE_VERSION_NUMBER >= 3007017 166 | NSString *s = NSFileTypeForHFSTypeCode([self applicationID]); 167 | 168 | assert([s length] == 6); 169 | 170 | s = [s substringWithRange:NSMakeRange(1, 4)]; 171 | 172 | 173 | return s; 174 | #else 175 | NSString *errorMessage = NSLocalizedStringFromTable(@"Application ID functions require SQLite 3.7.17", @"FMDB", nil); 176 | if (self.logsErrors) NSLog(@"%@", errorMessage); 177 | return nil; 178 | #endif 179 | } 180 | 181 | - (void)setApplicationIDString:(NSString*)s { 182 | #if SQLITE_VERSION_NUMBER >= 3007017 183 | if ([s length] != 4) { 184 | NSLog(@"setApplicationIDString: string passed is not exactly 4 chars long. (was %ld)", [s length]); 185 | } 186 | 187 | [self setApplicationID:NSHFSTypeCodeFromFileType([NSString stringWithFormat:@"'%@'", s])]; 188 | #else 189 | NSString *errorMessage = NSLocalizedStringFromTable(@"Application ID functions require SQLite 3.7.17", @"FMDB", nil); 190 | if (self.logsErrors) NSLog(@"%@", errorMessage); 191 | #endif 192 | } 193 | 194 | #endif 195 | 196 | - (uint32_t)userVersion { 197 | uint32_t r = 0; 198 | 199 | FMResultSet *rs = [self executeQuery:@"pragma user_version"]; 200 | 201 | if ([rs next]) { 202 | r = (uint32_t)[rs longLongIntForColumnIndex:0]; 203 | } 204 | 205 | [rs close]; 206 | return r; 207 | } 208 | 209 | - (void)setUserVersion:(uint32_t)version { 210 | NSString *query = [NSString stringWithFormat:@"pragma user_version = %d", version]; 211 | FMResultSet *rs = [self executeQuery:query]; 212 | [rs next]; 213 | [rs close]; 214 | } 215 | 216 | #pragma clang diagnostic push 217 | #pragma clang diagnostic ignored "-Wdeprecated-implementations" 218 | 219 | - (BOOL)columnExists:(NSString*)tableName columnName:(NSString*)columnName __attribute__ ((deprecated)) { 220 | return [self columnExists:columnName inTableWithName:tableName]; 221 | } 222 | 223 | #pragma clang diagnostic pop 224 | 225 | - (BOOL)validateSQL:(NSString*)sql error:(NSError**)error { 226 | sqlite3_stmt *pStmt = NULL; 227 | BOOL validationSucceeded = YES; 228 | 229 | int rc = sqlite3_prepare_v2([self sqliteHandle], [sql UTF8String], -1, &pStmt, 0); 230 | if (rc != SQLITE_OK) { 231 | validationSucceeded = NO; 232 | if (error) { 233 | *error = [NSError errorWithDomain:NSCocoaErrorDomain 234 | code:[self lastErrorCode] 235 | userInfo:[NSDictionary dictionaryWithObject:[self lastErrorMessage] 236 | forKey:NSLocalizedDescriptionKey]]; 237 | } 238 | } 239 | 240 | sqlite3_finalize(pStmt); 241 | 242 | return validationSucceeded; 243 | } 244 | 245 | @end 246 | -------------------------------------------------------------------------------- /Roar/Displays/BezelWindowController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | -------------------------------------------------------------------------------- /Roar/Displays/MusicVideoWindowController.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | --------------------------------------------------------------------------------