From 739b94d15b3e08a1f6214a8048a816eca9943953 Mon Sep 17 00:00:00 2001 From: Robert McGovern Date: Mon, 31 May 2021 20:42:30 +0100 Subject: [PATCH] Too much in a single commit again - WIP Added UserDefaults support for 3 settings. App when run without files will either open in the dock and show the preferences window, or in the statusbar with no window shown (don't understand why yet). --- FSUserDefaults/FSUserDefaults.h | 48 +++++++ FSUserDefaults/FSUserDefaults.m | 191 +++++++++++++++++++++++++++ FSUserDefaults/LICENSE.txt | 21 +++ QuietUnrar.xcodeproj/project.pbxproj | 24 ++++ QuietUnrarAppDelegate.h | 4 +- QuietUnrarAppDelegate.m | 141 +++++++++++++++++--- README.md | 5 + Resources/PreferencesWindow.xib | 56 ++++++-- TDNPreferencesWindowController.h | 9 +- TDNPreferencesWindowController.m | 49 +++++-- TDNUserDefaults.h | 22 +++ TDNUserDefaults.m | 17 +++ en.lproj/MainMenu.xib | 11 +- 13 files changed, 550 insertions(+), 48 deletions(-) create mode 100644 FSUserDefaults/FSUserDefaults.h create mode 100644 FSUserDefaults/FSUserDefaults.m create mode 100644 FSUserDefaults/LICENSE.txt create mode 100644 TDNUserDefaults.h create mode 100644 TDNUserDefaults.m diff --git a/FSUserDefaults/FSUserDefaults.h b/FSUserDefaults/FSUserDefaults.h new file mode 100644 index 0000000..581a72a --- /dev/null +++ b/FSUserDefaults/FSUserDefaults.h @@ -0,0 +1,48 @@ +// +// FSUserDefaults.h +// +// Created by Christian Floisand. +// Copyright © 2017 Flyingsand. All rights reserved. +// +// ABSTRACT: +// This class facilitates the use of Apple's NSUserDefaults class for storing and retrieving user default data without +// all the boilerplate and tedious code that typically goes with using NSUserDefaults as-is. This is accomplished by +// utilizing dynamic properties together with the Objective-C runtime so that simple dot syntax can be used to +// access individual user defaults easily. +// +// USAGE: +// Simply subclass this class, and add user default properties to the class' interface, then declare them as @dynamic +// in the class implementation. +// e.g.: +// +// (MyUserDefaults.h) +// +// @interface MyUserDefaults : FSUserDefaults +// @property (nonatomic, strong) NSString *aDefaultString; +// @end +// +// (MyUserDefaults.m) +// +// @implementation MyUserDefaults +// @dynamic aDefaultString; +// @end +// +// (MyViewController.m) +// +// - (void)viewDidLoad { +// [super viewDidLoad]; +// MyUserDefaults *defaults = ... +// defaults.aDefaultString = @"New Setting"; +// } +// + +#import + + +@interface FSUserDefaults : NSObject +@property (nonatomic, strong, readonly) NSUserDefaults *userDefaults; + ++ (instancetype)sharedInstance; +- (instancetype)initWithSuiteName:(NSString *)suiteName; + +@end diff --git a/FSUserDefaults/FSUserDefaults.m b/FSUserDefaults/FSUserDefaults.m new file mode 100644 index 0000000..8a8e0a2 --- /dev/null +++ b/FSUserDefaults/FSUserDefaults.m @@ -0,0 +1,191 @@ +// +// FSUserDefaults.h +// +// Created by Christian Floisand. +// Copyright © 2017 Flyingsand. All rights reserved. +// + +#import "FSUserDefaults.h" +#import +#import + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wstrlcpy-strlcat-size" + +#define TYPE_ENCODING_STRING_SETTER "v@:_" +#define TYPE_ENCODING_STRING_GETTER "_@:" + +#define SELECTOR_SETTER_BOOL "setBool:forKey:" +#define SELECTOR_SETTER_int "setInteger:forKey:" +#define SELECTOR_SETTER_float "setFloat:forKey:" +#define SELECTOR_SETTER_double "setDouble:forKey:" +#define SELECTOR_SETTER_id "setObject:forKey:" +#define SELECTOR_SETTER_NSURL "setURL:forKey:" + +#define SELECTOR_GETTER_BOOL "boolForKey:" +#define SELECTOR_GETTER_int "integerForKey:" +#define SELECTOR_GETTER_float "floatForKey:" +#define SELECTOR_GETTER_double "doubleForKey:" +#define SELECTOR_GETTER_id "objectForKey:" +#define SELECTOR_GETTER_NSURL "URLForKey:" + +#define SELECTOR_STRING_SETTER(type) SELECTOR_SETTER_ ## type +#define SELECTOR_STRING_GETTER(type) SELECTOR_GETTER_ ## type + +#define METHOD_NAME_SETTER(type) type ## Setter +#define METHOD_NAME_GETTER(type) type ## Getter + +static const char * +CopyPropertyNameFromSetter(const char *setterName) { + char *propertyName = malloc(sizeof(char) * (strlen(setterName) - 3)); + strlcpy(propertyName, setterName + 3, strlen(setterName) - 3); + propertyName[0] = tolower(propertyName[0]); + return propertyName; +} + +static bool +IsPropertyURL(const char *attr) { + attr += 3; + static const char *URLClassName = "NSURL"; + size_t compareLen = MIN(strlen(attr), strlen(URLClassName)); + bool isUrl = strncmp(attr, URLClassName, compareLen) == 0; + + return isUrl; +} + +#define METHOD_IMPLEMENTATION_SETTER(tname, type) void METHOD_NAME_SETTER(tname)(id self, SEL _cmd, type value) { \ + const char *selectorString = SELECTOR_STRING_SETTER(tname); \ + SEL setterSelector = sel_registerName(selectorString); \ + const char *propertyName = CopyPropertyNameFromSetter(sel_getName(_cmd)); \ + NSCAssert([self isKindOfClass:[FSUserDefaults class]], @""); \ + NSUserDefaults *userDefaults = ((FSUserDefaults *)self).userDefaults; \ + ((void(*)(id,SEL,type,id))objc_msgSend)(userDefaults, setterSelector, value, [NSString stringWithUTF8String:propertyName]); \ + free((void *)propertyName); \ +} + +#define METHOD_IMPLEMENTATION_GETTER(tname, type) type METHOD_NAME_GETTER(tname)(id self, SEL _cmd) { \ + const char *selectorString = SELECTOR_STRING_GETTER(tname); \ + SEL getterSelector = sel_registerName(selectorString); \ + NSCAssert([self isKindOfClass:[FSUserDefaults class]], @""); \ + NSUserDefaults *userDefaults = ((FSUserDefaults *)self).userDefaults; \ + return ((type(*)(id,SEL,id))objc_msgSend)(userDefaults, getterSelector, [NSString stringWithUTF8String:sel_getName(_cmd)]); \ +} + +#define GENERATE_SETTER_GETTER_METHOD_PAIR(tname, type) \ + METHOD_IMPLEMENTATION_SETTER(tname, type) \ + METHOD_IMPLEMENTATION_GETTER(tname, type) + +GENERATE_SETTER_GETTER_METHOD_PAIR(BOOL, BOOL) +GENERATE_SETTER_GETTER_METHOD_PAIR(int, int) +GENERATE_SETTER_GETTER_METHOD_PAIR(float, float) +GENERATE_SETTER_GETTER_METHOD_PAIR(double, double) +GENERATE_SETTER_GETTER_METHOD_PAIR(id, id) +GENERATE_SETTER_GETTER_METHOD_PAIR(NSURL, NSURL*) + + +@implementation FSUserDefaults + ++ (instancetype)sharedInstance { + static id _instance = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + _instance = [self new]; + ((FSUserDefaults *)_instance)->_userDefaults = [NSUserDefaults standardUserDefaults]; + }); + return _instance; +} + +- (instancetype)init { + return (self = [self initWithSuiteName:nil]); +} + +- (instancetype)initWithSuiteName:(NSString *)suiteName { + self = [super init]; + if (self) { + _userDefaults = [[NSUserDefaults alloc] initWithSuiteName:suiteName]; + } + return self; +} + ++ (BOOL)resolveInstanceMethod:(SEL)sel { + const char *selectorName = sel_getName(sel); + const char *propertyName = selectorName; + BOOL isSetter = NO; + + if ((strlen(selectorName) > 3) && (strncmp("set", selectorName, 3) == 0)) { + propertyName = CopyPropertyNameFromSetter(selectorName); + isSetter = YES; + } + + objc_property_t property = class_getProperty(self, propertyName); + if (isSetter) { + free((void *)propertyName); + } + + if (property != NULL) { + const char *propertyAttrs = property_getAttributes(property); + char propertyType = propertyAttrs[1]; + + const char *methodTypeString; + int index; + if (isSetter) { + methodTypeString = TYPE_ENCODING_STRING_SETTER; + index = 3; + } else { + methodTypeString = TYPE_ENCODING_STRING_GETTER; + index = 0; + } + + char *typeEncodingString = malloc(sizeof(char) * (strlen(methodTypeString) + 1)); + strlcpy(typeEncodingString, methodTypeString, strlen(methodTypeString) + 1); + typeEncodingString[index] = propertyType; + +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wpointer-type-mismatch" + IMP methodImpl; + switch (propertyType) { + case 'c': + case 'B': + methodImpl = (IMP)(isSetter ? METHOD_NAME_SETTER(BOOL) : METHOD_NAME_GETTER(BOOL)); + break; + case 's': + case 'i': + case 'l': + case 'q': + case 'S': + case 'I': + case 'L': + case 'Q': + methodImpl = (IMP)(isSetter ? METHOD_NAME_SETTER(int) : METHOD_NAME_GETTER(int)); + break; + case 'f': + methodImpl = (IMP)(isSetter ? METHOD_NAME_SETTER(float) : METHOD_NAME_GETTER(float)); + break; + case 'd': + methodImpl = (IMP)(isSetter ? METHOD_NAME_SETTER(double) : METHOD_NAME_GETTER(double)); + break; + case '@': + if (IsPropertyURL(propertyAttrs)) { + methodImpl = (IMP)(isSetter ? METHOD_NAME_SETTER(NSURL) : METHOD_NAME_GETTER(NSURL)); + } else { + methodImpl = (IMP)(isSetter ? METHOD_NAME_SETTER(id) : METHOD_NAME_GETTER(id)); + } + break; + default: + NSAssert(NO, @"[FSUserDefaults] Unhandled property type."); + break; + } +#pragma clang diagnostic pop + + class_addMethod(self, sel, methodImpl, typeEncodingString); + free(typeEncodingString); + + return YES; + } + + return [super resolveInstanceMethod:sel]; +} + +@end + +#pragma clang diagnostic pop diff --git a/FSUserDefaults/LICENSE.txt b/FSUserDefaults/LICENSE.txt new file mode 100644 index 0000000..bc8fd65 --- /dev/null +++ b/FSUserDefaults/LICENSE.txt @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2017 Christian Floisand (Flyinsand) + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/QuietUnrar.xcodeproj/project.pbxproj b/QuietUnrar.xcodeproj/project.pbxproj index 21900ad..11821ed 100644 --- a/QuietUnrar.xcodeproj/project.pbxproj +++ b/QuietUnrar.xcodeproj/project.pbxproj @@ -27,6 +27,9 @@ E2A3B8862663C1FB00A6C0A3 /* PreferencesWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = E2A3B8852663C1FB00A6C0A3 /* PreferencesWindow.xib */; }; E2A3B8892663C60200A6C0A3 /* TDNPreferencesWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A3B8882663C60200A6C0A3 /* TDNPreferencesWindowController.m */; }; E2A3B8902664DE8900A6C0A3 /* TDNUnarchiver.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A3B88F2664DE8900A6C0A3 /* TDNUnarchiver.m */; }; + E2A3B895266521FF00A6C0A3 /* FSUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A3B894266521FF00A6C0A3 /* FSUserDefaults.m */; }; + E2A3B8972665222200A6C0A3 /* LICENSE.txt in Resources */ = {isa = PBXBuildFile; fileRef = E2A3B8962665222200A6C0A3 /* LICENSE.txt */; }; + E2A3B89A2665225A00A6C0A3 /* TDNUserDefaults.m in Sources */ = {isa = PBXBuildFile; fileRef = E2A3B8992665225A00A6C0A3 /* TDNUserDefaults.m */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -188,6 +191,11 @@ E2A3B8882663C60200A6C0A3 /* TDNPreferencesWindowController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDNPreferencesWindowController.m; sourceTree = ""; }; E2A3B88F2664DE8900A6C0A3 /* TDNUnarchiver.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDNUnarchiver.m; sourceTree = ""; }; E2A3B8912664DEE300A6C0A3 /* TDNUnarchiver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDNUnarchiver.h; sourceTree = ""; }; + E2A3B893266521FF00A6C0A3 /* FSUserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSUserDefaults.h; sourceTree = ""; }; + E2A3B894266521FF00A6C0A3 /* FSUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSUserDefaults.m; sourceTree = ""; }; + E2A3B8962665222200A6C0A3 /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.txt; sourceTree = ""; }; + E2A3B8982665225A00A6C0A3 /* TDNUserDefaults.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDNUserDefaults.h; sourceTree = ""; }; + E2A3B8992665225A00A6C0A3 /* TDNUserDefaults.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDNUserDefaults.m; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -211,12 +219,15 @@ 080E96DDFE201D6D7F000001 /* Classes */ = { isa = PBXGroup; children = ( + E2A3B892266521C500A6C0A3 /* FSUserDefaults */, 256AC3D80F4B6AC300CF3369 /* QuietUnrarAppDelegate.h */, 256AC3D90F4B6AC300CF3369 /* QuietUnrarAppDelegate.m */, E2A3B8872663C60200A6C0A3 /* TDNPreferencesWindowController.h */, E2A3B8882663C60200A6C0A3 /* TDNPreferencesWindowController.m */, E2A3B88F2664DE8900A6C0A3 /* TDNUnarchiver.m */, E2A3B8912664DEE300A6C0A3 /* TDNUnarchiver.h */, + E2A3B8982665225A00A6C0A3 /* TDNUserDefaults.h */, + E2A3B8992665225A00A6C0A3 /* TDNUserDefaults.m */, ); name = Classes; sourceTree = ""; @@ -411,6 +422,16 @@ name = libunrar; sourceTree = ""; }; + E2A3B892266521C500A6C0A3 /* FSUserDefaults */ = { + isa = PBXGroup; + children = ( + E2A3B8962665222200A6C0A3 /* LICENSE.txt */, + E2A3B893266521FF00A6C0A3 /* FSUserDefaults.h */, + E2A3B894266521FF00A6C0A3 /* FSUserDefaults.m */, + ); + path = FSUserDefaults; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXLegacyTarget section */ @@ -484,6 +505,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + E2A3B8972665222200A6C0A3 /* LICENSE.txt in Resources */, D4A49692105435C100BE38AE /* MainMenu.xib in Resources */, E2A3B8862663C1FB00A6C0A3 /* PreferencesWindow.xib in Resources */, D4A49691105435BE00BE38AE /* InfoPlist.strings in Resources */, @@ -534,10 +556,12 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + E2A3B895266521FF00A6C0A3 /* FSUserDefaults.m in Sources */, 8D11072D0486CEB800E47090 /* main.m in Sources */, E2A3B8892663C60200A6C0A3 /* TDNPreferencesWindowController.m in Sources */, E2A3B8902664DE8900A6C0A3 /* TDNUnarchiver.m in Sources */, 256AC3DA0F4B6AC300CF3369 /* QuietUnrarAppDelegate.m in Sources */, + E2A3B89A2665225A00A6C0A3 /* TDNUserDefaults.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/QuietUnrarAppDelegate.h b/QuietUnrarAppDelegate.h index 2a9f9f1..bf7e9c8 100644 --- a/QuietUnrarAppDelegate.h +++ b/QuietUnrarAppDelegate.h @@ -7,7 +7,6 @@ // #import -#import "TDNPreferencesWindowController.h" enum { @@ -24,6 +23,8 @@ enum #define BUF_LEN 64000 +@class TDNPreferencesWindowController; + @interface QuietUnrarAppDelegate : NSObject { NSWindow *__weak window; NSView *__weak passwordView; @@ -39,6 +40,7 @@ enum // UI Based methods - (BOOL) shouldFileBeReplaced:(NSString *) filename; - (void) alertUserOfMissing:(const char *) volume; +- (void) hideDockIcon: (BOOL) hide; - (NSString *) requestArchivePassword; @end diff --git a/QuietUnrarAppDelegate.m b/QuietUnrarAppDelegate.m index 6303547..d26095c 100644 --- a/QuietUnrarAppDelegate.m +++ b/QuietUnrarAppDelegate.m @@ -12,17 +12,23 @@ #import "QuietUnrarAppDelegate.h" #import "TDNUnarchiver.h" +#import "TDNUserDefaults.h" +#import "TDNPreferencesWindowController.h" @interface QuietUnrarAppDelegate () @property TDNUnarchiver * unarchiver; +@property TDNUserDefaults * userDefaults; +@property NSStatusItem * statusBarItem; + +@property NSArray * arrayOfFilesToProcess; @end #pragma mark @implementation QuietUnrarAppDelegate -@synthesize window, passwordView, passwordField, preferencesWindowController, unarchiver; +@synthesize window, passwordView, passwordField, preferencesWindowController, unarchiver, userDefaults, statusBarItem, arrayOfFilesToProcess; - (void) applicationWillFinishLaunching:(NSNotification *)notification { NSLog(@"applicationWillFinishLaunching"); @@ -32,18 +38,47 @@ GetKeys(map); if (KEYMAP_GET(map, kVKC_Shift) || KEYMAP_GET(map, kVKC_rShift)) NSLog(@"Shift or Right Shift"); + + userDefaults = [TDNUserDefaults sharedInstance]; } - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { NSLog(@"applicationDidFinishLaunching"); - // Having extracted our file or not, quit. Though should not if error is displayed. - //[[NSApplication sharedApplication] terminate:self]; [self requestUserPermissionForNotifications]; - preferencesWindowController = [[TDNPreferencesWindowController alloc] init]; + if (arrayOfFilesToProcess == nil || arrayOfFilesToProcess.count == 0) { + if (userDefaults.hideDock) { + [self hideDockIcon:TRUE]; + } - [preferencesWindowController showWindow:nil]; + preferencesWindowController = [[TDNPreferencesWindowController alloc] init]; + preferencesWindowController.quietUnrar = self; + + [preferencesWindowController showWindow:nil]; + + } else { + unarchiver = [[TDNUnarchiver alloc] init]; + unarchiver.quietUnrar = self; + + [self requestUserPermissionForNotifications]; + + if (userDefaults.hideDock) { + [self hideDockIcon:TRUE]; + } + + for (NSString * filename in arrayOfFilesToProcess) { + BOOL extracted = [unarchiver extractArchiveWithFilename:filename]; + if (extracted) { + // post notification based on user preference + if (userDefaults.showNotification && userDefaults.notificationsAllowed) { // if show notification + permission granted ... + [self postNotificationUncompressedFile:filename]; + } + } + } + + [[NSApplication sharedApplication] terminate:self]; + } } // Call one at a time for each file selected when app is run @@ -60,22 +95,31 @@ - (void)application:(NSApplication *)theApplication openFiles:(NSArray *) arrayOfFilenames { NSLog(@"openFiles: %@", arrayOfFilenames); - unarchiver = [[TDNUnarchiver alloc] init]; - unarchiver.quietUnrar = self; - [self requestUserPermissionForNotifications]; + arrayOfFilesToProcess = arrayOfFilenames; - for (NSString * filename in arrayOfFilenames) { - BOOL extracted = [unarchiver extractArchiveWithFilename:filename]; - if (extracted) { - // post notification based on user preference - if (true && true) { // if show notification + permission granted ... - [self postNotificationUncompressedFile:filename]; - } - } - } - - [[NSApplication sharedApplication] terminate:self]; +// unarchiver = [[TDNUnarchiver alloc] init]; +// unarchiver.quietUnrar = self; +// +// userDefaults = [TDNUserDefaults sharedInstance]; +// +// [self requestUserPermissionForNotifications]; +// +// if (userDefaults.hideDock) { +// [self hideDockIcon:TRUE]; +// } +// +// for (NSString * filename in arrayOfFilenames) { +// BOOL extracted = [unarchiver extractArchiveWithFilename:filename]; +// if (extracted) { +// // post notification based on user preference +// if (userDefaults.showNotification && userDefaults.notificationsAllowed) { // if show notification + permission granted ... +// [self postNotificationUncompressedFile:filename]; +// } +// } +// } +// +// [[NSApplication sharedApplication] terminate:self]; } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender { @@ -146,6 +190,63 @@ return password; } +- (void) hideDockIcon: (BOOL) hide { + BOOL result; + if (hide) { + NSLog(@"Setting Policy to Accesosry"); + result = [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory]; + + NSLog(@"Result of setting ActivationPolicy %d", result); + + NSLog(@"%@", [[[NSApplication sharedApplication]delegate] description]); + [self showStatusBarItem:TRUE]; + } else { + NSLog(@"Setting Policy to Regular"); + result = [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + NSLog(@"Result of setting ActivationPolicy %d", result); + [self showStatusBarItem:FALSE]; + } +} + +- (void) showStatusBarItem: (BOOL) show { + if (show) { +// if (statusBarItem == nil) { + statusBarItem = [NSStatusBar.systemStatusBar statusItemWithLength:NSVariableStatusItemLength]; + statusBarItem.button.title = @"🎫"; //RMCG + + // optional create a menu for the button + NSMenu * statusBarMenu = [[NSMenu alloc] init]; + [statusBarMenu setTitle:@"QuietUnrar Menu"]; + + NSMenuItem * preferencesMenuItem = [[NSMenuItem alloc] initWithTitle:@"Show Preferences" action:@selector(showPreferencesWindow) keyEquivalent:@""]; + [statusBarMenu addItem:preferencesMenuItem]; + + NSMenuItem * showDockItem = [[NSMenuItem alloc] initWithTitle:@"Show Dock" action:@selector(showPreferencesWindow) keyEquivalent:@""]; + [statusBarMenu addItem:showDockItem]; + + NSMenuItem * quitMenuItem = [[NSMenuItem alloc] initWithTitle:@"Quit QuietUnrar" action:@selector(quit) keyEquivalent:@""]; + [statusBarMenu addItem:quitMenuItem]; + + [statusBarItem setMenu:statusBarMenu]; +// } + } else { + [NSStatusBar.systemStatusBar removeStatusItem:statusBarItem]; + } +} + +- (void) showPreferencesWindow { + if (preferencesWindowController == nil) { + preferencesWindowController = [[TDNPreferencesWindowController alloc] init]; + preferencesWindowController.quietUnrar = self; + } + + [preferencesWindowController showWindow:nil]; +} + +- (void) quit { + [[NSApplication sharedApplication] terminate:self]; +} + #pragma mark "Notifications" - (void) requestUserPermissionForNotifications { @@ -157,11 +258,13 @@ if (granted) { // set some flag, that would be used to see if notifications should be posted NSLog(@"Notification Permission Granted"); + self->userDefaults.notificationsAllowed = TRUE; } }]; } - (void) postNotificationUncompressedFile:(NSString *) filename { // add details of notification + NSLog(@"Posting notification for %@", filename); } @end diff --git a/README.md b/README.md index df1d147..d59de92 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,11 @@ Original was written in 2009 as a little thing for me, and now its getting some * add model code for preferences * add support for 7zip https://github.com/OlehKulykov/PLzmaSDK * Investigate metal warning, something to ignore? +* Add testing +* Dock or status bar appearance? +* if keeping my extractRARArchiveWithFilename method rather than unrarkit, swap to using the wide text process method +* reduce menu to only essential - preferences + quit +* about box with thanks & liecense info ### Metal Warning diff --git a/Resources/PreferencesWindow.xib b/Resources/PreferencesWindow.xib index 0c4ffe5..c6d0920 100644 --- a/Resources/PreferencesWindow.xib +++ b/Resources/PreferencesWindow.xib @@ -8,6 +8,9 @@ + + + @@ -22,17 +25,54 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/TDNPreferencesWindowController.h b/TDNPreferencesWindowController.h index cc2241a..da0b758 100644 --- a/TDNPreferencesWindowController.h +++ b/TDNPreferencesWindowController.h @@ -5,12 +5,19 @@ // Created by Robert McGovern on 2021/05/30. // +#ifndef TDNPreferencesWindowController_h +#define TDNPreferencesWindowController_h + #import NS_ASSUME_NONNULL_BEGIN -@interface TDNPreferencesWindowController : NSWindowController +//@class QuietUnrarAppDelegate; +@interface TDNPreferencesWindowController : NSWindowController +@property QuietUnrarAppDelegate * quietUnrar; @end NS_ASSUME_NONNULL_END + +#endif // TDNPreferencesWindowController_h diff --git a/TDNPreferencesWindowController.m b/TDNPreferencesWindowController.m index 428287b..b237f9f 100644 --- a/TDNPreferencesWindowController.m +++ b/TDNPreferencesWindowController.m @@ -6,37 +6,58 @@ // #import "TDNPreferencesWindowController.h" +#import "TDNUserDefaults.h" +//#import "QuietUnrarAppDelegate.h" @interface TDNPreferencesWindowController () +@property (weak) IBOutlet NSSwitch *showNotificationsSwitch; +@property (weak) IBOutlet NSSwitch *playSoundSwitch; +@property (weak) IBOutlet NSSwitch *hideDockIconSwitch; + +@property TDNUserDefaults * userDefaults; + @end @implementation TDNPreferencesWindowController +@synthesize userDefaults, showNotificationsSwitch, playSoundSwitch, hideDockIconSwitch; +@synthesize quietUnrar; + - (id) init { return [super initWithWindowNibName:@"PreferencesWindow"]; } - (void)windowDidLoad { [super windowDidLoad]; - + + userDefaults = [TDNUserDefaults sharedInstance]; + // Implement this method to handle any initialization after your window controller's window has been loaded from its nib file. -} + if (userDefaults.hideDock) { + [hideDockIconSwitch setState:NSControlStateValueOn]; + } -BOOL showingDock = TRUE; + if (userDefaults.showNotification) { + [showNotificationsSwitch setState:NSControlStateValueOn]; + } -- (IBAction)showHideButtonPressed:(id)sender { - if (showingDock) { - showingDock = FALSE; - NSLog(@"Setting Policy to Accesosry"); - [NSApp setActivationPolicy:NSApplicationActivationPolicyAccessory]; - - NSLog(@"%@", [[[NSApplication sharedApplication]delegate] description]); - } else { - showingDock = TRUE; - NSLog(@"Setting Policy to Regular"); - [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular]; + if (userDefaults.playSounds) { + [playSoundSwitch setState:NSControlStateValueOn]; } } +- (IBAction)showNotificationsSwitchToggled:(id)sender { + userDefaults.showNotification = [showNotificationsSwitch state]; +} + +- (IBAction)playSoundSwitchToggled:(id)sender { + userDefaults.playSounds = [playSoundSwitch state]; +} + +- (IBAction)hideDockIconSwitchToggled:(id)sender { + userDefaults.hideDock = [hideDockIconSwitch state]; + [quietUnrar hideDockIcon: userDefaults.hideDock]; +} + @end diff --git a/TDNUserDefaults.h b/TDNUserDefaults.h new file mode 100644 index 0000000..1bcf1f0 --- /dev/null +++ b/TDNUserDefaults.h @@ -0,0 +1,22 @@ +// +// TDNUserDefaults.h +// QuietUnrar +// +// Created by Robert McGovern on 2021/05/31. +// + +#import +#import "FSUserDefaults.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface TDNUserDefaults : FSUserDefaults + +@property (nonatomic) BOOL playSounds; +@property (nonatomic) BOOL showNotification; +@property (nonatomic) BOOL hideDock; +@property (nonatomic) BOOL notificationsAllowed; + +@end + +NS_ASSUME_NONNULL_END diff --git a/TDNUserDefaults.m b/TDNUserDefaults.m new file mode 100644 index 0000000..32556ea --- /dev/null +++ b/TDNUserDefaults.m @@ -0,0 +1,17 @@ +// +// TDNUserDefaults.m +// QuietUnrar +// +// Created by Robert McGovern on 2021/05/31. +// + +#import "TDNUserDefaults.h" + +@implementation TDNUserDefaults + +@dynamic playSounds; +@dynamic showNotification; +@dynamic hideDock; +@dynamic notificationsAllowed; + +@end diff --git a/en.lproj/MainMenu.xib b/en.lproj/MainMenu.xib index 11bada9..c0576b7 100644 --- a/en.lproj/MainMenu.xib +++ b/en.lproj/MainMenu.xib @@ -1,8 +1,8 @@ - + - + @@ -12,13 +12,13 @@ - + - + @@ -653,11 +653,12 @@ - + +