From 15494e51ec88c9b5eb82a4781c4d14f4236fc1b2 Mon Sep 17 00:00:00 2001 From: Mark Jerde Date: Tue, 4 Jan 2022 23:16:03 -0600 Subject: [PATCH 01/19] Remove unused unimplemented protocol --- AppController.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppController.h b/AppController.h index 0ccfead..535a25c 100755 --- a/AppController.h +++ b/AppController.h @@ -22,7 +22,7 @@ @class SGHotKey; -@interface AppController : NSObject { +@interface AppController : NSObject { BezelWindow *bezel; SGHotKey *mainHotKey; IBOutlet SRRecorderControl *mainRecorder; From ca62006101e716c53660f513329c1a8c0e773e26 Mon Sep 17 00:00:00 2001 From: Mark Jerde Date: Mon, 10 Jan 2022 22:14:21 -0600 Subject: [PATCH 02/19] Move misplaced comment --- AppController.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AppController.m b/AppController.m index 7d308f8..deeb452 100755 --- a/AppController.m +++ b/AppController.m @@ -245,9 +245,9 @@ }); [self registerOrDeregisterICloudSync]; - // Check if the app has Accessibility permission [NSApp activateIgnoringOtherApps: YES]; + // Check if the app has Accessibility permission [self showAccessibilityAlert]; [self showOldOSXAlert]; } From acb100268d0b3caacf58539ef33126d991915ee7 Mon Sep 17 00:00:00 2001 From: Mark Jerde Date: Mon, 10 Jan 2022 23:08:22 -0600 Subject: [PATCH 03/19] Revert minimum deployment target to 10.7 It still builds fine, so I'm assuming increasing it was an accident. --- Flycut.xcodeproj/project.pbxproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Flycut.xcodeproj/project.pbxproj b/Flycut.xcodeproj/project.pbxproj index 253cf66..a220f68 100755 --- a/Flycut.xcodeproj/project.pbxproj +++ b/Flycut.xcodeproj/project.pbxproj @@ -1618,7 +1618,7 @@ INFOPLIST_FILE = Info.plist; INSTALL_PATH = /Applications; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.7; MARKETING_VERSION = 1.9.6; PRODUCT_BUNDLE_IDENTIFIER = com.generalarcade.flycut; PRODUCT_NAME = Flycut; @@ -1652,7 +1652,7 @@ INFOPLIST_FILE = Info.plist; INSTALL_PATH = /Applications; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks"; - MACOSX_DEPLOYMENT_TARGET = 10.10; + MACOSX_DEPLOYMENT_TARGET = 10.7; MARKETING_VERSION = 1.9.6; PRODUCT_BUNDLE_IDENTIFIER = com.generalarcade.flycut; PRODUCT_NAME = Flycut; From c41711599ed91ae80185383a6680adebdb7cfc11 Mon Sep 17 00:00:00 2001 From: Mark Jerde Date: Sat, 15 Jan 2022 06:35:48 -0600 Subject: [PATCH 04/19] Fix issue #253 and add documentation --- AppController.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/AppController.m b/AppController.m index deeb452..63b3fc5 100755 --- a/AppController.m +++ b/AppController.m @@ -687,6 +687,7 @@ } -(IBAction)toggleLoadOnStartup:(id)sender { + // Since the control in Interface Builder is bound to User Defaults and sends this action, this method is called after User Defaults already reflects the newly-selected state and merely conveys that value to the relevant mechanisms rather than acting to negate the User Defaults state. if ( [[NSUserDefaults standardUserDefaults] boolForKey:@"loadOnStartup"] ) { #ifdef SANDBOXING SMLoginItemSetEnabled((__bridge CFStringRef)kFlycutHelperId, YES); @@ -695,7 +696,7 @@ #endif } else { #ifdef SANDBOXING - SMLoginItemSetEnabled((__bridge CFStringRef)kFlycutHelperId, YES); + SMLoginItemSetEnabled((__bridge CFStringRef)kFlycutHelperId, NO); #else [UKLoginItemRegistry removeLoginItemWithPath:[[NSBundle mainBundle] bundlePath]]; #endif From 733897230de9848c99b1727802bac1bf5a01c088 Mon Sep 17 00:00:00 2001 From: Mark Jerde Date: Sat, 15 Jan 2022 06:37:35 -0600 Subject: [PATCH 05/19] Move macOS code out of cross-platform files --- AppController.m | 2 +- FlycutOperator.m | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/AppController.m b/AppController.m index 63b3fc5..be52259 100755 --- a/AppController.m +++ b/AppController.m @@ -858,7 +858,7 @@ if (largeCopyRisk) [self toggleMenuIconDisabled]; - if ( contents == nil || [flycutOperator shouldSkip:contents ofType:[jcPasteboard availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]]] ) { + if ( contents == nil || [flycutOperator shouldSkip:contents ofType:[jcPasteboard availableTypeFromArray:[NSArray arrayWithObject:NSStringPboardType]] fromAvailableTypes:[jcPasteboard types]] ) { DLog(@"Contents: Empty or skipped"); } else if ( ! [pbCount isEqualTo:pbBlockCount] ) { [flycutOperator addClipping:contents ofType:type fromApp:[currRunningApp localizedName] withAppBundleURL:currRunningApp.bundleURL.path target:self clippingAddedSelector:@selector(updateMenu)]; diff --git a/FlycutOperator.m b/FlycutOperator.m index 7a880d7..5e34a3b 100644 --- a/FlycutOperator.m +++ b/FlycutOperator.m @@ -303,7 +303,7 @@ return [self clippingStringWithCount:indexInt]; } --(BOOL)shouldSkip:(NSString *)contents ofType:(NSString *)type +-(BOOL)shouldSkip:(NSString *)contents ofType:(NSString *)type fromAvailableTypes:(NSArray *)availableTypes { // Check to see if we are skipping passwords based on length and characters. if ( [[NSUserDefaults standardUserDefaults] boolForKey:@"skipPasswordFields"] ) @@ -316,10 +316,10 @@ __block bool skipClipping = NO; // Check the array of types to skip. - if ( [[NSUserDefaults standardUserDefaults] boolForKey:@"skipPboardTypes"] ) + if ( availableTypes && [[NSUserDefaults standardUserDefaults] boolForKey:@"skipPboardTypes"] ) { NSSet *typesToSkip = [NSSet setWithArray: [[[[NSUserDefaults standardUserDefaults] stringForKey:@"skipPboardTypesList"] stringByReplacingOccurrencesOfString:@" " withString:@""] componentsSeparatedByString: @","]]; - NSSet *pasteBoardTypes = [NSSet setWithArray: [[NSPasteboard generalPasteboard] types]]; + NSSet *pasteBoardTypes = [NSSet setWithArray: availableTypes]; if ( [pasteBoardTypes intersectsSet: typesToSkip] ) { From 0129887c5f2a13e7c080ce245ea5171b7974efb6 Mon Sep 17 00:00:00 2001 From: Mark Jerde Date: Sat, 15 Jan 2022 06:39:43 -0600 Subject: [PATCH 06/19] Get Flycut iOS compiling and updated to Swift 5 --- Flycut-iOS/AppDelegate.swift | 2 +- Flycut-iOS/SettingsViewController.swift | 2 +- Flycut-iOS/ViewController.swift | 46 ++++++++++++------------- Flycut-iOS_Prefix.pch | 2 ++ Flycut.xcodeproj/project.pbxproj | 4 +-- 5 files changed, 29 insertions(+), 27 deletions(-) diff --git a/Flycut-iOS/AppDelegate.swift b/Flycut-iOS/AppDelegate.swift index 937669e..9a86619 100644 --- a/Flycut-iOS/AppDelegate.swift +++ b/Flycut-iOS/AppDelegate.swift @@ -14,7 +14,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD var window: UIWindow? - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Override point for customization after application launch. if #available(iOS 10.0, *) { let center = UNUserNotificationCenter.current() diff --git a/Flycut-iOS/SettingsViewController.swift b/Flycut-iOS/SettingsViewController.swift index c364638..499a951 100644 --- a/Flycut-iOS/SettingsViewController.swift +++ b/Flycut-iOS/SettingsViewController.swift @@ -15,7 +15,7 @@ class SettingsViewController: IASKAppSettingsViewController { } // - (id)initWithStyle:(UITableViewStyle)style { - required override init(style:UITableViewStyle) { + required override init(style:UITableView.Style) { super.init(style: style) commonInitContent() } diff --git a/Flycut-iOS/ViewController.swift b/Flycut-iOS/ViewController.swift index adba992..8cdbe3f 100644 --- a/Flycut-iOS/ViewController.swift +++ b/Flycut-iOS/ViewController.swift @@ -13,7 +13,7 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour let flycut:FlycutOperator = FlycutOperator() var activeUpdates:Int = 0 var tableView:UITableView! - var currentAnimation = UITableViewRowAnimation.none + var currentAnimation = UITableView.RowAnimation.none var pbCount:Int = -1 var rememberedSyncSettings:Bool = false var rememberedSyncClippings:Bool = false @@ -60,7 +60,7 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour let indexPath = self.tableView.indexPath(for: cell) if ( nil != indexPath ) { let previousAnimation = self.currentAnimation - self.currentAnimation = UITableViewRowAnimation.left // Use .left to look better with swiping left to delete. + self.currentAnimation = UITableView.RowAnimation.left // Use .left to look better with swiping left to delete. self.flycut.setStackPositionTo( Int32((indexPath?.row)! )) self.flycut.clearItemAtStackPosition() self.currentAnimation = previousAnimation @@ -79,7 +79,7 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour // Fallback on earlier versions UIApplication.shared.openURL(url!) } - self.tableView.reloadRows(at: [indexPath!], with: UITableViewRowAnimation.none) + self.tableView.reloadRows(at: [indexPath!], with: UITableView.RowAnimation.none) } return true; @@ -100,18 +100,18 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour flycut.awake(fromNibDisplaying: 10, withDisplayLength: 140, withSave: #selector(savePreferences(toDict:)), forTarget: self) // The 10 isn't used in iOS right now and 140 characters seems to be enough to cover the width of the largest screen. - NotificationCenter.default.addObserver(self, selector: #selector(self.checkForClippingAddedToClipboard), name: .UIPasteboardChanged, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(self.checkForClippingAddedToClipboard), name: UIPasteboard.changedNotification, object: nil) - NotificationCenter.default.addObserver(self, selector: #selector(self.applicationWillTerminate), name: .UIApplicationWillTerminate, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(self.applicationWillTerminate), name: UIApplication.willTerminateNotification, object: nil) // Check for clipping whenever we become active. - NotificationCenter.default.addObserver(self, selector: #selector(self.checkForClippingAddedToClipboard), name: .UIApplicationDidBecomeActive, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(self.checkForClippingAddedToClipboard), name: UIApplication.didBecomeActiveNotification, object: nil) checkForClippingAddedToClipboard() // Since the first-launch notification will occur before we add observer. // Register for notifications for the scenarios in which we should save the engine. - [ Notification.Name.UIApplicationWillResignActive, - Notification.Name.UIApplicationDidEnterBackground, - Notification.Name.UIApplicationWillTerminate ] + [ UIApplication.willResignActiveNotification, + UIApplication.didEnterBackgroundNotification, + UIApplication.willTerminateNotification ] .forEach { (notification) in NotificationCenter.default.addObserver(self, selector: #selector(self.saveEngine), @@ -148,7 +148,7 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour } } - func defaultsChanged() { + @objc func defaultsChanged() { // This seems to be the only way to respond to Settings changes, though it doesn't inform us what changed so we will have to check each to see if they were the one(s). // Don't use DispatchQueue.main.async since that will still end up blocking the UI draw until the user responds to what hasn't been drawn yet. @@ -209,7 +209,7 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour flycut.willShowPreferences() } - func savePreferences(toDict: NSMutableDictionary) + @objc func savePreferences(toDict: NSMutableDictionary) { } @@ -320,7 +320,7 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour return selection } - func checkForClippingAddedToClipboard() + @objc func checkForClippingAddedToClipboard() { pasteboardInteractionQueue.async { // This is a suitable place to prepare to possible eventual display of preferences, resetting values that should reset before each display of preferences. @@ -330,26 +330,26 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour { self.pbCount = UIPasteboard.general.changeCount; - if ( UIPasteboard.general.types.contains("public.utf8-plain-text") ) + if UIPasteboard.general.types.contains("public.utf8-plain-text"), + let pasteboard = UIPasteboard.general.value(forPasteboardType: "public.utf8-plain-text") as? String { - let pasteboard = UIPasteboard.general.value(forPasteboardType: "public.utf8-plain-text") - self.flycut.addClipping(pasteboard as! String!, ofType: "public.utf8-plain-text", fromApp: "iOS", withAppBundleURL: "iOS", target: nil, clippingAddedSelector: nil) + self.flycut.addClipping(pasteboard, ofType: "public.utf8-plain-text", fromApp: "iOS", withAppBundleURL: "iOS", target: nil, clippingAddedSelector: nil) } - else if ( UIPasteboard.general.types.contains("public.text") ) + else if UIPasteboard.general.types.contains("public.text"), + let pasteboard = UIPasteboard.general.value(forPasteboardType: "public.text") as? String { - let pasteboard = UIPasteboard.general.value(forPasteboardType: "public.text") - self.flycut.addClipping(pasteboard as! String!, ofType: "public.text", fromApp: "iOS", withAppBundleURL: "iOS", target: nil, clippingAddedSelector: nil) + self.flycut.addClipping(pasteboard, ofType: "public.text", fromApp: "iOS", withAppBundleURL: "iOS", target: nil, clippingAddedSelector: nil) } } } } - func applicationWillTerminate() + @objc func applicationWillTerminate() { saveEngine() } - func saveEngine() + @objc func saveEngine() { flycut.saveEngine() } @@ -371,7 +371,7 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let item: MGSwipeTableCell = tableView.dequeueReusableCell(withIdentifier: "FlycutCell", for: indexPath) as! MGSwipeTableCell - item.textLabel?.text = flycut.previousDisplayStrings(indexPath.row + 1, containing: nil).last as! String? + item.textLabel?.text = flycut.previousDisplayStrings(Int32(indexPath.row + 1), containing: nil).last as! String? //configure left buttons var removeAll:Bool = true @@ -382,7 +382,7 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour // NSTextCheckingResult.CheckingType.link.rawValue blocks things like single words that URL() would let in // URL() blocks things like paragraphs of text containing a URL that NSTextCheckingResult.CheckingType.link.rawValue would let in - let matches = isURLDetector?.matches(in: content, options: .reportCompletion, range: NSMakeRange(0, content.characters.count)) + let matches = isURLDetector?.matches(in: content, options: .reportCompletion, range: NSMakeRange(0, content.count)) if let matchesCount = matches?.count { if matchesCount > 0 @@ -445,7 +445,7 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour } func notifyCKAccountStatusNoAccount() { - if ( !ignoreCKAccountStatusNoAccount ) + if ( !self.ignoreCKAccountStatusNoAccount ) { let alert = UIAlertController(title: "No iCloud Account", message: "An iCloud account with iCloud Drive enabled is required for iCloud sync.", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "Preferences", style: .default, handler: { (_) in diff --git a/Flycut-iOS_Prefix.pch b/Flycut-iOS_Prefix.pch index d03ae67..1d6b697 100644 --- a/Flycut-iOS_Prefix.pch +++ b/Flycut-iOS_Prefix.pch @@ -4,6 +4,8 @@ #ifdef __OBJC__ +#define kiCloudId @"iCloud.com.mark-a-jerde.Flycut" + #ifdef DEBUG # define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); #else diff --git a/Flycut.xcodeproj/project.pbxproj b/Flycut.xcodeproj/project.pbxproj index a220f68..8d08e88 100755 --- a/Flycut.xcodeproj/project.pbxproj +++ b/Flycut.xcodeproj/project.pbxproj @@ -1302,7 +1302,7 @@ SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OBJC_BRIDGING_HEADER = "Flycut-iOS-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -1359,7 +1359,7 @@ SDKROOT = iphoneos; SWIFT_OBJC_BRIDGING_HEADER = "Flycut-iOS-Bridging-Header.h"; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; From 6a1539bb3dbe2ca55c5c90786cd8aada9ca236f8 Mon Sep 17 00:00:00 2001 From: Mark Jerde Date: Sat, 15 Jan 2022 06:40:16 -0600 Subject: [PATCH 07/19] Fix main thread bug --- Flycut-iOS/ViewController.swift | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Flycut-iOS/ViewController.swift b/Flycut-iOS/ViewController.swift index 8cdbe3f..96eb4b7 100644 --- a/Flycut-iOS/ViewController.swift +++ b/Flycut-iOS/ViewController.swift @@ -445,8 +445,9 @@ class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSour } func notifyCKAccountStatusNoAccount() { - if ( !self.ignoreCKAccountStatusNoAccount ) - { + DispatchQueue.main.async { + guard !self.ignoreCKAccountStatusNoAccount else { return } + let alert = UIAlertController(title: "No iCloud Account", message: "An iCloud account with iCloud Drive enabled is required for iCloud sync.", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "Preferences", style: .default, handler: { (_) in if #available(iOS 10.0, *) From 60a4ec20dfc70b60e66dd51612cb19240f6210ab Mon Sep 17 00:00:00 2001 From: Mark Jerde Date: Sat, 15 Jan 2022 06:55:57 -0600 Subject: [PATCH 08/19] Update tests to Swift 5 --- Flycut.xcodeproj/project.pbxproj | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Flycut.xcodeproj/project.pbxproj b/Flycut.xcodeproj/project.pbxproj index 8d08e88..d15ae5c 100755 --- a/Flycut.xcodeproj/project.pbxproj +++ b/Flycut.xcodeproj/project.pbxproj @@ -1415,7 +1415,7 @@ SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Flycut-iOS.app/Flycut-iOS"; }; name = Debug; @@ -1463,7 +1463,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Flycut-iOS.app/Flycut-iOS"; VALIDATE_PRODUCT = YES; }; @@ -1518,7 +1518,7 @@ SDKROOT = iphoneos; SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; TEST_TARGET_NAME = "Flycut-iOS"; }; name = Debug; @@ -1565,7 +1565,7 @@ PRODUCT_NAME = "$(TARGET_NAME)"; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; - SWIFT_VERSION = 3.0; + SWIFT_VERSION = 5.0; TEST_TARGET_NAME = "Flycut-iOS"; VALIDATE_PRODUCT = YES; }; From 2c0741b357738b84af27fe44605f15182e3f4274 Mon Sep 17 00:00:00 2001 From: Mark Jerde Date: Sat, 15 Jan 2022 13:41:57 -0600 Subject: [PATCH 09/19] Restore meaningful build number --- Flycut.xcodeproj/project.pbxproj | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/Flycut.xcodeproj/project.pbxproj b/Flycut.xcodeproj/project.pbxproj index d15ae5c..60a5566 100755 --- a/Flycut.xcodeproj/project.pbxproj +++ b/Flycut.xcodeproj/project.pbxproj @@ -779,6 +779,7 @@ 8D1107290486CEB800E47090 /* Resources */, 8D11072C0486CEB800E47090 /* Sources */, 8D11072E0486CEB800E47090 /* Frameworks */, + 8D60A1BA1BC8399900A26CBF /* Set meaningful build number */, AAE2036C0A27B2B9002DCC2A /* Headers */, 77AE730823D2D49100F6A44B /* Embed Frameworks */, 77192A3923D6F45F00EDB9BC /* CopyFiles */, @@ -1013,6 +1014,24 @@ }; /* End PBXResourcesBuildPhase section */ +/* Begin PBXShellScriptBuildPhase section */ + 8D60A1BA1BC8399900A26CBF /* Set meaningful build number */ = { + isa = PBXShellScriptBuildPhase; + buildActionMask = 12; + files = ( + ); + inputPaths = ( + $BUILT_PRODUCTS_DIR/$INFOPLIST_PATH, + ); + name = "Set meaningful build number"; + outputPaths = ( + ); + runOnlyForDeploymentPostprocessing = 0; + shellPath = /bin/sh; + shellScript = "# Sets the build number to identify, to some extent, the git version of the code.\n# Combines the hash of the origin commit, number of commits of divergence, local HEAD commit, local uncommitted lines of change, and year/month of build.\n# Eliminates all except for the origin commit if there are no local changes, since that can be easily tracked.\n# e.g. 1.b690b47.1.1.cb73ce6.35.1510 from origin b690b47, one and one different, locally at commit cb73ce6, with a further 35 lines of change, built in 2015 in the tenth month. Day numbers are excluded for brevity, as there is already much uncertainty in the local changes and this field is only to indicate a rough level of freshness. Build numer starts with \"1.\" to avoid strange compile errors.\ncd \"${SOURCE_ROOT}\"\n\n# Skip setting the build number if this is a SANDBOXING build, since the helper probably needs a matching build number. Making them match is as easy as putting this script in both targets, though it's also easy to have one target read it from the other, but that's a task best left to the developer doing SANDBOXING builds since they would be in the position to make sure it is done correctly.\ngrep -q '^#define SANDBOXING *$' Flycut_Prefix.pch\nif [ \"0\" != \"$?\" ]\nthen\n\t\n\tORIGIN=$(git rev-parse --short remotes/origin/master)\n\tOFFSET=\".$(git status|sed -n '1,/^# *$/ p'|grep \"[0-9]\"|head -1|sed 's/^[^0-9]*//;s/[^0-9]*$//'|sed 's/[^0-9][^0-9]*/./')\"\n\tLOCAL=\".$(git rev-parse --short HEAD)\"\n\tUNCOMMITTED=\".$(git diff -b -w HEAD|grep \"^[+\\-]\"|grep -v \"^[+\\-][+\\-][+\\-] [ab]\"|wc -l|sed 's/[^0-9]//g')\"\n\tBUILD_YEAR_MONTH=\".$(date +\"%y%m\")\"\n\tif [ \".$ORIGIN\" == \"$LOCAL\" ]\n\tthen\n\t\tOFFSET=\"\"\n\t\tLOCAL=\"\"\n\t\tif [ \".0\" == \"$UNCOMMITTED\" ]\n\t\tthen\n\t\t\tUNCOMMITTED=\"\"\n\t\t\tBUILD_YEAR_MONTH=\"\"\n\t\tfi\n\tfi\n\tNEWVERSIONSTRING=\"1.$ORIGIN$OFFSET$LOCAL$UNCOMMITTED$BUILD_YEAR_MONTH\"\n\t/usr/libexec/PlistBuddy -c \"Set :CFBundleVersion $NEWVERSIONSTRING\" \"${BUILT_PRODUCTS_DIR}/${INFOPLIST_PATH}\"\nfi\n"; + }; +/* End PBXShellScriptBuildPhase section */ + /* Begin PBXSourcesBuildPhase section */ 77192A2223D6EA7A00EDB9BC /* Sources */ = { isa = PBXSourcesBuildPhase; From 4562afa9f02461450f5ffbdd582f52364ae68662 Mon Sep 17 00:00:00 2001 From: Mark Jerde Date: Sat, 15 Jan 2022 13:48:28 -0600 Subject: [PATCH 10/19] Fix date formatting string Per https://twitter.com/vishalmalvi_/status/1475835430067052546?s=12 "YYYY" represents a so called 'week year' "yyyy" represents a four-digit calendar year They aren't the same. This has caused clippings near the end of the year to be saved with the following year number rather than the current year number. --- FlycutOperator.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/FlycutOperator.m b/FlycutOperator.m index 5e34a3b..d56bbc2 100644 --- a/FlycutOperator.m +++ b/FlycutOperator.m @@ -249,7 +249,7 @@ // Get the timestamp string: NSDate *currentDate = [NSDate date]; NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; - [dateFormatter setDateFormat:@"YYYY-MM-dd 'at' HH.mm.ss"]; + [dateFormatter setDateFormat:@"yyyy-MM-dd 'at' HH.mm.ss"]; NSString *dateString = [dateFormatter stringFromDate:currentDate]; // Make a file name to write the data to using the Desktop directory: From 4e7e4d13ef08093a7651eefa6bc6077bd4f21285 Mon Sep 17 00:00:00 2001 From: Mark Jerde Date: Sat, 15 Jan 2022 20:09:04 -0600 Subject: [PATCH 11/19] Convert PrefsPanel to Auto Layout This cleans up inconsistencies in the layout and makes it more durable. It retains the 4px spacing between rows even though that is lower than standard spacing. --- English.lproj/MainMenu.nib/designable.nib | 545 +++++++++++--------- English.lproj/MainMenu.nib/keyedobjects.nib | Bin 46302 -> 57622 bytes 2 files changed, 304 insertions(+), 241 deletions(-) diff --git a/English.lproj/MainMenu.nib/designable.nib b/English.lproj/MainMenu.nib/designable.nib index bf73366..f273f8a 100644 --- a/English.lproj/MainMenu.nib/designable.nib +++ b/English.lproj/MainMenu.nib/designable.nib @@ -1,8 +1,8 @@ - + - + @@ -111,7 +111,7 @@ - + @@ -123,20 +123,18 @@ - + - - - - - + + + + - - - - + + + + + + + + + + + + + + + + + + Clippings: + + + + + + + + + + Save + + + + + + + + + + - + @@ -164,86 +244,8 @@ - - - - - - - - - - Clippings: - - - - - - - - - - - - - - - - - - - - Save - - - - - - - - + + Remember @@ -252,19 +254,12 @@ - - - - - - - - - - - - - + + + + + + @@ -280,10 +275,28 @@ - - - - + + + + + + + + + + + + + + + + + + + + + + @@ -299,18 +312,8 @@ - - - - - - - - - - - - + + @@ -318,63 +321,20 @@ - - - - - - - + + - - - - + + + + + + @@ -390,18 +350,26 @@ - - - + + - + - - - - - - - - - - - - - - - - - + + @@ -456,18 +389,78 @@ - - - + + + + + + + + + + + + + + + + + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -564,18 +627,18 @@ - + - + - + @@ -586,7 +649,7 @@ - + diff --git a/English.lproj/MainMenu.nib/keyedobjects.nib b/English.lproj/MainMenu.nib/keyedobjects.nib index e006b6f33e49300ee9ace3bcdf06a517f20b499e..80b4bd1fa93151311f91cae838ce878e40b9ef1e 100644 GIT binary patch literal 57622 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%0Dbw@8mjuSoC6uE_4lzR1DI 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 Cm*aQ< literal 46302 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 Date: Fri, 21 Jan 2022 06:46:20 -0600 Subject: [PATCH 12/19] Add ability to select save locations Tighten up app-sandbox support. --- AppController.h | 6 + AppController.m | 66 ++++++ English.lproj/MainMenu.nib/designable.nib | 231 +++++++++++++------- English.lproj/MainMenu.nib/keyedobjects.nib | Bin 57622 -> 62346 bytes Flycut.entitlements | 2 + Flycut.xcodeproj/project.pbxproj | 7 +- FlycutDebug.entitlements | 2 + FlycutOperator.m | 61 +++++- Flycut_Prefix.pch | 1 + 9 files changed, 285 insertions(+), 91 deletions(-) diff --git a/AppController.h b/AppController.h index 535a25c..67b44ad 100755 --- a/AppController.h +++ b/AppController.h @@ -45,9 +45,13 @@ NSString *statusItemText; NSImage *statusItemImage; + IBOutlet NSTextField *savingSectionLabel; + IBOutlet NSTextField *saveFromBezelToLabel; IBOutlet NSTextField *forgottenItemLabel; IBOutlet NSButton *forgottenFavoritesCheckbox; IBOutlet NSButton *forgottenClippingsCheckbox; + IBOutlet NSButton *saveToLocationButton; + IBOutlet NSButton *autoSaveToLocationButton; // The menu attatched to same IBOutlet NSMenu *jcMenu; int jcMenuBaseItemsCount; @@ -75,6 +79,8 @@ BOOL needMenuUpdate; } ++ (BOOL)isAppSandboxed; + // Basic functionality -(void) pollPB:(NSTimer *)timer; -(void) addClipToPasteboard:(NSString*)pbFullText; diff --git a/AppController.m b/AppController.m index be52259..00848cb 100755 --- a/AppController.m +++ b/AppController.m @@ -26,6 +26,15 @@ @implementation AppController +/// Determines, through a hack of sorts, if the app is running sandboxed. The SANDBOXING define has no direct connection to being sandboxed, but this method identifies the state by looking for a directory which will have at least eight path components if sandboxed and is quite unlikely to have that many if not sandboxed. Of course, if this doesn't work for your unique case, just do a custom build with this method returning NO. ++ (BOOL)isAppSandboxed { + // Get the Desktop directory: + NSArray *paths = NSSearchPathForDirectoriesInDomains + (NSDesktopDirectory, NSUserDomainMask, YES); + NSString *desktopDirectory = [paths objectAtIndex:0]; + return ((NSArray*)[desktopDirectory componentsSeparatedByString:@"/"]).count >= 8; +} + - (id)init { [[NSUserDefaults standardUserDefaults] registerDefaults:[NSDictionary dictionaryWithObjectsAndKeys: @@ -134,6 +143,7 @@ - (void)showOldOSXAlert { + // FIXME: Should ask Gennadii if the "#ifdef SANDBOXING" should be removed and replaced with "if (![AppController isAppSandboxed]) { return; }" #ifdef SANDBOXING NSOperatingSystemVersion ver = [[NSProcessInfo processInfo] operatingSystemVersion]; if (ver.majorVersion == 10 && ver.minorVersion <= 13) { @@ -224,6 +234,7 @@ // The load-on-startup check can be really slow, so this will be dispatched out so our thread isn't blocked. dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); dispatch_async(queue, ^{ + // FIXME: Should ask Gennadii if the "#ifdef SANDBOXING" should be removed and replaced with "if ([AppController isAppSandboxed])" #ifdef SANDBOXING NSPredicate *predicate = [NSPredicate predicateWithFormat:@"bundleIdentifier == %@", kFlycutHelperId]; NSArray *helperApp = [[[NSWorkspace sharedWorkspace] runningApplications] filteredArrayUsingPredicate:predicate]; @@ -664,10 +675,22 @@ [appearancePanel addSubview:row]; nextYMax = row.frame.origin.y; #ifdef SANDBOXING + // Hide the Save Clippings preferences. These work fine when sandboxed. They just save to somwehere under ~/Library/Containers. If SANDBOXING isn't set, automatic saving of forgotten clippings will go somewhere under ~/Library/Containers while manual saving (s or S in the bezel) will open an NSSavePanel to prompt the user to pick. forgottenItemLabel.hidden = YES; forgottenClippingsCheckbox.hidden = YES; forgottenFavoritesCheckbox.hidden = YES; + savingSectionLabel.hidden = YES; + saveToLocationButton.hidden = YES; + autoSaveToLocationButton.hidden = YES; + saveFromBezelToLabel.hidden = YES; #endif + if ([AppController isAppSandboxed]) { + // Saving to a prior-selected location while sandboxed would be unpleasant, so these really should be disabled always when sandboxed but can still show where the saves happen so the user knows what to expect. + saveToLocationButton.enabled = NO; + [saveToLocationButton setTitle:@"Ask User"]; + autoSaveToLocationButton.enabled = NO; + [autoSaveToLocationButton setTitle:@"App Sandbox"]; + } } -(IBAction) showPreferencePanel:(id)sender @@ -683,18 +706,30 @@ encoding:NSUTF8StringEncoding error:NULL]; [acknowledgementsView setString:contents]; + if (![AppController isAppSandboxed]) { + NSURL* saveToLocation = [[NSUserDefaults standardUserDefaults] URLForKey:@"saveToLocation"]; + if (saveToLocation) { + [saveToLocationButton setTitle:[saveToLocation lastPathComponent]]; + } + NSURL* autoSaveToLocation = [[NSUserDefaults standardUserDefaults] URLForKey:@"autoSaveToLocation"]; + if (autoSaveToLocation) { + [autoSaveToLocationButton setTitle:[autoSaveToLocation lastPathComponent]]; + } + } [flycutOperator willShowPreferences]; } -(IBAction)toggleLoadOnStartup:(id)sender { // Since the control in Interface Builder is bound to User Defaults and sends this action, this method is called after User Defaults already reflects the newly-selected state and merely conveys that value to the relevant mechanisms rather than acting to negate the User Defaults state. if ( [[NSUserDefaults standardUserDefaults] boolForKey:@"loadOnStartup"] ) { + // FIXME: Should ask Gennadii if the "#ifdef SANDBOXING" should be removed and replaced with "if ([AppController isAppSandboxed])" #ifdef SANDBOXING SMLoginItemSetEnabled((__bridge CFStringRef)kFlycutHelperId, YES); #else [UKLoginItemRegistry addLoginItemWithPath:[[NSBundle mainBundle] bundlePath] hideIt:NO]; #endif } else { + // FIXME: Should ask Gennadii if the "#ifdef SANDBOXING" should be removed and replaced with "if ([AppController isAppSandboxed])" #ifdef SANDBOXING SMLoginItemSetEnabled((__bridge CFStringRef)kFlycutHelperId, NO); #else @@ -1178,6 +1213,37 @@ didFailToRegisterForRemoteNotificationsWithError:(NSError *)error { } } +- (IBAction)selectSaveLocation:(id)sender { + // Create and configure the panel. + NSOpenPanel* panel = [NSOpenPanel openPanel]; + [panel retain]; + [panel setCanChooseFiles:NO]; + [panel setCanChooseDirectories:YES]; + [panel setCanCreateDirectories:YES]; + [panel setAllowsMultipleSelection:NO]; + [panel setMessage:@"Select a directory."]; + + // Display the panel attached to the document's window. + [panel beginSheetModalForWindow:prefsPanel completionHandler:^(NSInteger result){ + if (result == NSFileHandlingPanelOKButton) { + NSURL* url = [[panel URLs] firstObject]; + + [panel release]; + + if (!url) { return; } + + if (sender == saveToLocationButton) { + [[NSUserDefaults standardUserDefaults] setURL:url forKey:@"saveToLocation"]; + } + else if (sender == autoSaveToLocationButton) { + [[NSUserDefaults standardUserDefaults] setURL:url forKey:@"autoSaveToLocation"]; + } + [sender setTitle:[url lastPathComponent]]; + } + + }]; +} + -(IBAction)clearClippingList:(id)sender { int choice; diff --git a/English.lproj/MainMenu.nib/designable.nib b/English.lproj/MainMenu.nib/designable.nib index f273f8a..ec49216 100644 --- a/English.lproj/MainMenu.nib/designable.nib +++ b/English.lproj/MainMenu.nib/designable.nib @@ -97,12 +97,16 @@ + + + + @@ -111,31 +115,31 @@ - + - + - + - + - + - - - - - + @@ -182,7 +186,7 @@ - - - - - + + + - Clippings: - - - + + Save @@ -223,8 +226,8 @@ - - + + @@ -244,8 +247,8 @@ - - + + Remember @@ -254,8 +257,8 @@ - - + + @@ -275,24 +278,24 @@ - - + + - - + + - - + + @@ -312,8 +315,8 @@ - - + + @@ -321,16 +324,16 @@ - - + + - - + + @@ -350,16 +353,24 @@ - - + + - - - - + + @@ -389,8 +400,8 @@ - - - + + @@ -410,8 +421,8 @@ - - - - - - + + + + + + + + + + + - + + + + + + + + + + - - - - - + + - - - - + + - - + + Save @@ -226,8 +226,8 @@ - - + + @@ -247,8 +247,8 @@ - - + + Remember @@ -257,8 +257,8 @@ - - + + @@ -278,24 +278,24 @@ - - + + - - + + - - + + @@ -315,8 +315,8 @@ - - + + @@ -324,16 +324,16 @@ - - + + - - + + @@ -353,24 +353,24 @@ - - + + - - + + - - - - + + @@ -400,8 +400,8 @@ - - - + + @@ -421,8 +421,8 @@ - - - + + - - - + @@ -468,7 +468,7 @@ - + @@ -476,7 +476,7 @@ - + @@ -494,7 +494,7 @@