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:
parent
19766c83d9
commit
739b94d15b
|
@ -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
|
|
@ -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
|
|
@ -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.
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue