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).
This commit is contained in:
Robert McGovern 2021-05-31 20:42:30 +01:00
parent 19766c83d9
commit 739b94d15b
13 changed files with 550 additions and 48 deletions

View File

@ -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 <Foundation/Foundation.h>
@interface FSUserDefaults : NSObject
@property (nonatomic, strong, readonly) NSUserDefaults *userDefaults;
+ (instancetype)sharedInstance;
- (instancetype)initWithSuiteName:(NSString *)suiteName;
@end

View File

@ -0,0 +1,191 @@
//
// FSUserDefaults.h
//
// Created by Christian Floisand.
// Copyright © 2017 Flyingsand. All rights reserved.
//
#import "FSUserDefaults.h"
#import <objc/runtime.h>
#import <objc/message.h>
#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

View File

@ -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.

View File

@ -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 = "<group>"; };
E2A3B88F2664DE8900A6C0A3 /* TDNUnarchiver.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDNUnarchiver.m; sourceTree = "<group>"; };
E2A3B8912664DEE300A6C0A3 /* TDNUnarchiver.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDNUnarchiver.h; sourceTree = "<group>"; };
E2A3B893266521FF00A6C0A3 /* FSUserDefaults.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FSUserDefaults.h; sourceTree = "<group>"; };
E2A3B894266521FF00A6C0A3 /* FSUserDefaults.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FSUserDefaults.m; sourceTree = "<group>"; };
E2A3B8962665222200A6C0A3 /* LICENSE.txt */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = LICENSE.txt; sourceTree = "<group>"; };
E2A3B8982665225A00A6C0A3 /* TDNUserDefaults.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TDNUserDefaults.h; sourceTree = "<group>"; };
E2A3B8992665225A00A6C0A3 /* TDNUserDefaults.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = TDNUserDefaults.m; sourceTree = "<group>"; };
/* 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 = "<group>";
@ -411,6 +422,16 @@
name = libunrar;
sourceTree = "<group>";
};
E2A3B892266521C500A6C0A3 /* FSUserDefaults */ = {
isa = PBXGroup;
children = (
E2A3B8962665222200A6C0A3 /* LICENSE.txt */,
E2A3B893266521FF00A6C0A3 /* FSUserDefaults.h */,
E2A3B894266521FF00A6C0A3 /* FSUserDefaults.m */,
);
path = FSUserDefaults;
sourceTree = "<group>";
};
/* 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;
};

View File

@ -7,7 +7,6 @@
//
#import <Cocoa/Cocoa.h>
#import "TDNPreferencesWindowController.h"
enum
{
@ -24,6 +23,8 @@ enum
#define BUF_LEN 64000
@class TDNPreferencesWindowController;
@interface QuietUnrarAppDelegate : NSObject <NSApplicationDelegate> {
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

View File

@ -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

View File

@ -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

View File

@ -8,6 +8,9 @@
<objects>
<customObject id="-2" userLabel="File's Owner" customClass="TDNPreferencesWindowController">
<connections>
<outlet property="hideDockIconSwitch" destination="KPW-cp-6Re" id="Sck-s2-15r"/>
<outlet property="playSoundSwitch" destination="xzV-rR-eGE" id="hFw-vR-ipg"/>
<outlet property="showNotificationsSwitch" destination="AbV-bl-h0l" id="nmN-a2-cs5"/>
<outlet property="window" destination="QvC-M9-y7g" id="kY2-3a-gXb"/>
</connections>
</customObject>
@ -22,17 +25,54 @@
<rect key="frame" x="0.0" y="0.0" width="480" height="270"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="V7e-wf-zha">
<rect key="frame" x="154" y="118" width="172" height="32"/>
<switch horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" baseWritingDirection="leftToRight" alignment="left" translatesAutoresizingMaskIntoConstraints="NO" id="AbV-bl-h0l">
<rect key="frame" x="219" y="201" width="42" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<buttonCell key="cell" type="push" title="Hide / Show Dock Icon" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="us0-hR-9qi">
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="system"/>
</buttonCell>
<connections>
<action selector="showHideButtonPressed:" target="-2" id="Rrk-Jt-cra"/>
<action selector="showNotificationsSwitchToggled:" target="-2" id="gVt-fX-gt8"/>
</connections>
</button>
</switch>
<switch horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" baseWritingDirection="leftToRight" alignment="left" translatesAutoresizingMaskIntoConstraints="NO" id="xzV-rR-eGE">
<rect key="frame" x="219" y="171" width="42" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<connections>
<action selector="playSoundSwitchToggled:" target="-2" id="cmK-q0-qeF"/>
</connections>
</switch>
<switch horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" baseWritingDirection="leftToRight" alignment="left" translatesAutoresizingMaskIntoConstraints="NO" id="KPW-cp-6Re">
<rect key="frame" x="219" y="141" width="42" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<connections>
<action selector="hideDockIconSwitchToggled:" target="-2" id="Twi-D0-lfn"/>
</connections>
</switch>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Ee6-6J-BIN">
<rect key="frame" x="18" y="206" width="118" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Show Notifications" id="4E0-UX-vGz">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="zkE-LX-MqG">
<rect key="frame" x="18" y="146" width="196" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Hide Dock Icon (For Status Bar)" id="Wje-Z6-ntL">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qLe-Dp-U7I">
<rect key="frame" x="18" y="176" width="72" height="16"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<textFieldCell key="cell" lineBreakMode="clipping" title="Play Sound" id="nmu-nV-0Mx">
<font key="font" metaFont="system"/>
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
</textFieldCell>
</textField>
</subviews>
</view>
<connections>

View File

@ -5,12 +5,19 @@
// Created by Robert McGovern on 2021/05/30.
//
#ifndef TDNPreferencesWindowController_h
#define TDNPreferencesWindowController_h
#import <Cocoa/Cocoa.h>
NS_ASSUME_NONNULL_BEGIN
@interface TDNPreferencesWindowController : NSWindowController
//@class QuietUnrarAppDelegate;
@interface TDNPreferencesWindowController : NSWindowController
@property QuietUnrarAppDelegate * quietUnrar;
@end
NS_ASSUME_NONNULL_END
#endif // TDNPreferencesWindowController_h

View File

@ -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

22
TDNUserDefaults.h Normal file
View File

@ -0,0 +1,22 @@
//
// TDNUserDefaults.h
// QuietUnrar
//
// Created by Robert McGovern on 2021/05/31.
//
#import <Foundation/Foundation.h>
#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

17
TDNUserDefaults.m Normal file
View File

@ -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

View File

@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="17132.0.2" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="18122" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES">
<dependencies>
<deployment identifier="macosx"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="17132.0.2"/>
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="18122"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
@ -12,13 +12,13 @@
</connections>
</customObject>
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
<customObject id="-3" userLabel="Application"/>
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
<menu title="AMainMenu" systemMenu="main" id="29">
<items>
<menuItem title="QuietUnrar" id="56">
<menu key="submenu" title="QuietUnrar" systemMenu="apple" id="57">
<items>
<menuItem title="About QuietUnrar" id="58">
<menuItem title="About QuietUnrar" state="on" id="58">
<modifierMask key="keyEquivalentModifierMask"/>
<connections>
<action selector="orderFrontStandardAboutPanel:" target="-2" id="142"/>
@ -653,11 +653,12 @@
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
<rect key="contentRect" x="335" y="390" width="480" height="360"/>
<rect key="screenRect" x="0.0" y="0.0" width="1920" height="1055"/>
<rect key="screenRect" x="0.0" y="0.0" width="1366" height="743"/>
<view key="contentView" id="372">
<rect key="frame" x="0.0" y="0.0" width="480" height="360"/>
<autoresizingMask key="autoresizingMask"/>
</view>
<point key="canvasLocation" x="15" y="-123"/>
</window>
<customObject id="494" customClass="QuietUnrarAppDelegate">
<connections>