improved actions, update logic, and uninstaller
Actions now populated by browse pane (ensures path/item is valid) Update logic now supports OS checking (min supported OS version) Uninstaller resets/removes preferences file
This commit is contained in:
parent
58c78d24c6
commit
aefbf06fd3
|
@ -371,21 +371,28 @@ bail:
|
|||
switch (result)
|
||||
{
|
||||
//error
|
||||
case -1:
|
||||
case Update_Error:
|
||||
|
||||
//err msg
|
||||
os_log_error(logHandle, "ERROR: update check failed");
|
||||
break;
|
||||
|
||||
//no updates
|
||||
case 0:
|
||||
case Update_None:
|
||||
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "no updates available");
|
||||
break;
|
||||
|
||||
//this version of macOS, not supported
|
||||
case Update_NotSupported:
|
||||
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "update available, but not for this version of macOS");
|
||||
break;
|
||||
|
||||
//new version
|
||||
case 1:
|
||||
case Update_Available:
|
||||
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "a new version (%@) is available", newVersion);
|
||||
|
|
|
@ -1,14 +1,15 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="18122" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="21225" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="18122"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="21225"/>
|
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="PrefsWindowController">
|
||||
<connections>
|
||||
<outlet property="actionView" destination="Jpg-nC-dWd" id="WHf-rQ-BXU"/>
|
||||
<outlet property="browseButton" destination="gVP-Ih-dFA" id="j7F-V3-hEq"/>
|
||||
<outlet property="executeArgsButton" destination="YqA-7j-gYp" id="tbC-AW-etO"/>
|
||||
<outlet property="executePath" destination="z32-0s-dpb" id="HAL-Mg-ygB"/>
|
||||
<outlet property="modesView" destination="K6i-xr-27e" id="DOb-L3-eeR"/>
|
||||
|
@ -25,7 +26,7 @@
|
|||
<window title="Window" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="F0z-JX-Cv5">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES"/>
|
||||
<rect key="contentRect" x="196" y="240" width="600" height="365"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1440" height="875"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="3440" height="1415"/>
|
||||
<view key="contentView" wantsLayer="YES" id="se5-gp-TjO">
|
||||
<rect key="frame" x="0.0" y="0.0" width="600" height="365"/>
|
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||
|
@ -41,21 +42,21 @@
|
|||
<allowedToolbarItems>
|
||||
<toolbarItem implicitItemIdentifier="NSToolbarSpaceItem" id="J66-tT-qAf"/>
|
||||
<toolbarItem implicitItemIdentifier="NSToolbarFlexibleSpaceItem" id="6nW-4K-zf4"/>
|
||||
<toolbarItem implicitItemIdentifier="3F78D487-BA4D-4E1B-8FC6-A844D292C69B" explicitItemIdentifier="mode" label="mode" paletteLabel="mode" image="PrefsMode" selectable="YES" id="k0w-Oi-kwd" userLabel="mode">
|
||||
<toolbarItem implicitItemIdentifier="3F78D487-BA4D-4E1B-8FC6-A844D292C69B" explicitItemIdentifier="mode" label="Mode" paletteLabel="Mode" image="PrefsMode" selectable="YES" id="k0w-Oi-kwd" userLabel="mode">
|
||||
<size key="minSize" width="22" height="22"/>
|
||||
<size key="maxSize" width="22" height="22"/>
|
||||
<connections>
|
||||
<action selector="toolbarButtonHandler:" target="-2" id="5Bh-RO-nSN"/>
|
||||
</connections>
|
||||
</toolbarItem>
|
||||
<toolbarItem implicitItemIdentifier="F54FFA8D-5F3A-4A92-BCB5-F0200A133E49" explicitItemIdentifier="action" label="action" paletteLabel="action" tag="1" image="PrefsAction" selectable="YES" id="gji-hP-t04">
|
||||
<toolbarItem implicitItemIdentifier="F54FFA8D-5F3A-4A92-BCB5-F0200A133E49" explicitItemIdentifier="action" label="Action" paletteLabel="Action" tag="1" image="PrefsAction" selectable="YES" id="gji-hP-t04">
|
||||
<size key="minSize" width="22" height="22"/>
|
||||
<size key="maxSize" width="22" height="22"/>
|
||||
<connections>
|
||||
<action selector="toolbarButtonHandler:" target="-2" id="c6F-yA-Qd8"/>
|
||||
</connections>
|
||||
</toolbarItem>
|
||||
<toolbarItem implicitItemIdentifier="384D69C6-2351-417E-9C93-B14039FE440F" explicitItemIdentifier="update" label="update" paletteLabel="update" tag="2" image="PrefsUpdate" selectable="YES" id="rrF-xj-cXp">
|
||||
<toolbarItem implicitItemIdentifier="384D69C6-2351-417E-9C93-B14039FE440F" explicitItemIdentifier="update" label="Update" paletteLabel="Update" tag="2" image="PrefsUpdate" selectable="YES" id="rrF-xj-cXp">
|
||||
<size key="minSize" width="22" height="22"/>
|
||||
<size key="maxSize" width="22" height="22"/>
|
||||
<connections>
|
||||
|
@ -197,25 +198,16 @@
|
|||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="117" translatesAutoresizingMaskIntoConstraints="NO" id="8Tb-Ih-SsC">
|
||||
<rect key="frame" x="72" y="224" width="114" height="15"/>
|
||||
<rect key="frame" x="72" y="224" width="59" height="15"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Execute Action" id="ncJ-bF-dAA">
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Execute" id="ncJ-bF-dAA">
|
||||
<font key="font" size="13" name="Menlo-Bold"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="GyI-og-F35">
|
||||
<rect key="frame" x="72" y="202" width="318" height="15"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Perform an action (script, binary, etc)." id="bky-MW-yBn">
|
||||
<font key="font" size="13" name="Menlo-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<button fixedFrame="YES" tag="5" translatesAutoresizingMaskIntoConstraints="NO" id="YqA-7j-gYp">
|
||||
<rect key="frame" x="39" y="161" width="29" height="18"/>
|
||||
<rect key="frame" x="39" y="151" width="29" height="18"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<buttonCell key="cell" type="check" bezelStyle="regularSquare" imagePosition="left" alignment="left" inset="2" id="egX-c0-Flf">
|
||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||
|
@ -226,7 +218,7 @@
|
|||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="dH0-Xi-Qnd">
|
||||
<rect key="frame" x="72" y="162" width="114" height="15"/>
|
||||
<rect key="frame" x="72" y="152" width="114" height="15"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" title="Pass Arguments" id="WL4-fV-4Wq">
|
||||
<font key="font" size="13" name="Menlo-Bold"/>
|
||||
|
@ -235,7 +227,7 @@
|
|||
</textFieldCell>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="GP0-UX-66J">
|
||||
<rect key="frame" x="72" y="98" width="427" height="60"/>
|
||||
<rect key="frame" x="72" y="82" width="427" height="60"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" id="7Ah-kZ-gGe">
|
||||
<font key="font" size="13" name="Menlo-Regular"/>
|
||||
|
@ -245,9 +237,9 @@
|
|||
</textFieldCell>
|
||||
</textField>
|
||||
<textField verticalHuggingPriority="750" fixedFrame="YES" preferredMaxLayoutWidth="382" translatesAutoresizingMaskIntoConstraints="NO" id="z32-0s-dpb">
|
||||
<rect key="frame" x="198" y="221" width="382" height="20"/>
|
||||
<rect key="frame" x="143" y="221" width="437" height="20"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" state="on" borderStyle="bezel" placeholderString="path" drawsBackground="YES" id="Oe0-3Y-Srk">
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" allowsUndo="NO" state="on" borderStyle="bezel" placeholderString="path" drawsBackground="YES" id="Oe0-3Y-Srk">
|
||||
<font key="font" size="13" name="Menlo-Regular"/>
|
||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||
|
@ -256,7 +248,35 @@
|
|||
<outlet property="delegate" destination="-2" id="dSg-PZ-Igl"/>
|
||||
</connections>
|
||||
</textField>
|
||||
<button verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="gVP-Ih-dFA">
|
||||
<rect key="frame" x="498" y="187" width="89" height="33"/>
|
||||
<constraints>
|
||||
<constraint firstAttribute="width" constant="75" id="0GJ-HY-4cb"/>
|
||||
<constraint firstAttribute="height" constant="21" id="J0H-v3-Re0"/>
|
||||
</constraints>
|
||||
<buttonCell key="cell" type="push" title="Browse" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="BTl-QV-9GT">
|
||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||
<font key="font" size="13" name="Menlo-Regular"/>
|
||||
</buttonCell>
|
||||
<connections>
|
||||
<action selector="browseButtonHandler:" target="-2" id="gXE-0h-DRz"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="471" translatesAutoresizingMaskIntoConstraints="NO" id="GyI-og-F35">
|
||||
<rect key="frame" x="72" y="181" width="427" height="30"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Execute a script or binary when an event is detected." id="bky-MW-yBn">
|
||||
<font key="font" size="13" name="Menlo-Regular"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
</subviews>
|
||||
<constraints>
|
||||
<constraint firstAttribute="trailing" secondItem="gVP-Ih-dFA" secondAttribute="trailing" constant="20" symbolic="YES" id="CvO-h8-LQr"/>
|
||||
<constraint firstItem="gVP-Ih-dFA" firstAttribute="top" secondItem="Jpg-nC-dWd" secondAttribute="top" constant="60" id="nxN-h0-hTd"/>
|
||||
<constraint firstAttribute="trailing" secondItem="gVP-Ih-dFA" secondAttribute="trailing" constant="20" symbolic="YES" id="wdb-4c-5GF"/>
|
||||
</constraints>
|
||||
<point key="canvasLocation" x="-166" y="738.5"/>
|
||||
</customView>
|
||||
<customView id="1OV-sl-cSe" userLabel="Update">
|
||||
|
@ -303,21 +323,21 @@
|
|||
<action selector="check4Update:" target="-2" id="GJb-mB-UIz"/>
|
||||
</connections>
|
||||
</button>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Oe2-Ye-1s6">
|
||||
<rect key="frame" x="201" y="101" width="216" height="34"/>
|
||||
<progressIndicator wantsLayer="YES" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" maxValue="100" displayedWhenStopped="NO" bezeled="NO" indeterminate="YES" controlSize="small" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="o0T-ra-4H0">
|
||||
<rect key="frame" x="378" y="145" width="16" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" scrollable="YES" lineBreakMode="clipping" sendsActionOnEndEditing="YES" alignment="center" id="5gt-xh-Ti5">
|
||||
</progressIndicator>
|
||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Oe2-Ye-1s6">
|
||||
<rect key="frame" x="118" y="60" width="383" height="74"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
<textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="center" id="5gt-xh-Ti5">
|
||||
<font key="font" size="13" name="Menlo-Bold"/>
|
||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||
</textFieldCell>
|
||||
</textField>
|
||||
<progressIndicator wantsLayer="YES" horizontalHuggingPriority="750" verticalHuggingPriority="750" fixedFrame="YES" maxValue="100" displayedWhenStopped="NO" bezeled="NO" indeterminate="YES" controlSize="small" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="o0T-ra-4H0">
|
||||
<rect key="frame" x="378" y="145" width="16" height="16"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||
</progressIndicator>
|
||||
</subviews>
|
||||
<point key="canvasLocation" x="694" y="709"/>
|
||||
<point key="canvasLocation" x="694" y="708.5"/>
|
||||
</customView>
|
||||
</objects>
|
||||
<resources>
|
||||
|
|
|
@ -47,6 +47,9 @@
|
|||
//path to action
|
||||
@property (weak) IBOutlet NSTextField *executePath;
|
||||
|
||||
//browse button
|
||||
@property (weak) IBOutlet NSButton *browseButton;
|
||||
|
||||
//execute args button
|
||||
@property (weak) IBOutlet NSButton *executeArgsButton;
|
||||
|
||||
|
|
|
@ -97,9 +97,9 @@ extern os_log_t logHandle;
|
|||
|
||||
break;
|
||||
|
||||
//modes
|
||||
//actions
|
||||
case TOOLBAR_ACTION:
|
||||
|
||||
{
|
||||
//set view
|
||||
view = self.actionView;
|
||||
|
||||
|
@ -112,7 +112,7 @@ extern os_log_t logHandle;
|
|||
//set
|
||||
self.executePath.stringValue = [NSUserDefaults.standardUserDefaults objectForKey:PREF_EXECUTE_PATH];
|
||||
}
|
||||
|
||||
|
||||
//set state of 'execute action' to match
|
||||
self.executePath.enabled = [NSUserDefaults.standardUserDefaults boolForKey:PREF_EXECUTE_ACTION];
|
||||
|
||||
|
@ -121,9 +121,19 @@ extern os_log_t logHandle;
|
|||
|
||||
//set state of 'execute action' to match
|
||||
self.executeArgsButton.enabled = [NSUserDefaults.standardUserDefaults boolForKey:PREF_EXECUTE_ACTION];
|
||||
|
||||
break;
|
||||
|
||||
//make 'Browse' button first responder
|
||||
// calling this without a timeout, sometimes fails :/
|
||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (100 * NSEC_PER_MSEC)), dispatch_get_main_queue(),
|
||||
^{
|
||||
|
||||
//set first responder
|
||||
[self.window makeFirstResponder:self.browseButton];
|
||||
|
||||
});
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
//update
|
||||
case TOOLBAR_UPDATE:
|
||||
|
@ -153,26 +163,6 @@ bail:
|
|||
return;
|
||||
}
|
||||
|
||||
//automatically called when 'enter' is hit
|
||||
// save values that were entered in text field
|
||||
-(void)controlTextDidEndEditing:(NSNotification *)notification
|
||||
{
|
||||
//execute path?
|
||||
if([notification object] != self.executePath)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//save & sync
|
||||
[NSUserDefaults.standardUserDefaults setObject:self.executePath.stringValue forKey:PREF_EXECUTE_PATH];
|
||||
[NSUserDefaults.standardUserDefaults synchronize];
|
||||
|
||||
bail:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
//invoked when user toggles button
|
||||
// update preferences for that button
|
||||
-(IBAction)togglePreference:(id)sender
|
||||
|
@ -237,6 +227,15 @@ bail:
|
|||
//set path field state to match
|
||||
self.executeArgsButton.enabled = state;
|
||||
|
||||
//enabled, but no path?
|
||||
// launch 'browse' pane for user to select
|
||||
if( (NSControlStateValueOn == state) &&
|
||||
(0 == self.executePath.stringValue.length) )
|
||||
{
|
||||
//show 'browse'
|
||||
[self browseButtonHandler:nil];
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -277,6 +276,7 @@ bail:
|
|||
return;
|
||||
}
|
||||
|
||||
//TODO: supported OS
|
||||
//'check for update' button handler
|
||||
-(IBAction)check4Update:(id)sender
|
||||
{
|
||||
|
@ -308,7 +308,7 @@ bail:
|
|||
}
|
||||
|
||||
//process update response
|
||||
// error, no update, update/new version
|
||||
// error, no update, update not compatible, update/new version
|
||||
-(void)updateResponse:(NSInteger)result newVersion:(NSString*)newVersion
|
||||
{
|
||||
//re-enable button
|
||||
|
@ -320,15 +320,15 @@ bail:
|
|||
switch(result)
|
||||
{
|
||||
//error
|
||||
case -1:
|
||||
case Update_Error:
|
||||
|
||||
//set label
|
||||
self.updateLabel.stringValue = @"error: update check failed";
|
||||
self.updateLabel.stringValue = @"Error: update check failed";
|
||||
|
||||
break;
|
||||
|
||||
//no updates
|
||||
case 0:
|
||||
case Update_None:
|
||||
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "no updates available");
|
||||
|
@ -337,10 +337,20 @@ bail:
|
|||
self.updateLabel.stringValue = [NSString stringWithFormat:@"Installed version (%@),\r\nis the latest.", getAppVersion()];
|
||||
|
||||
break;
|
||||
|
||||
|
||||
//this version of macOS, not supported
|
||||
case Update_NotSupported:
|
||||
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "update available, but not for this version of macOS");
|
||||
|
||||
//set label
|
||||
self.updateLabel.stringValue = [NSString stringWithFormat:@"Update available, but isn't supported on macOS %ld.%ld", NSProcessInfo.processInfo.operatingSystemVersion.majorVersion, NSProcessInfo.processInfo.operatingSystemVersion.minorVersion];
|
||||
|
||||
break;
|
||||
|
||||
//new version
|
||||
case 1:
|
||||
case Update_Available:
|
||||
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "a new version (%@) is available", newVersion);
|
||||
|
@ -391,4 +401,54 @@ bail:
|
|||
return;
|
||||
}
|
||||
|
||||
//'browse' button handler
|
||||
// open a panel for user to select file
|
||||
-(IBAction)browseButtonHandler:(id)sender
|
||||
{
|
||||
//'browse' panel
|
||||
NSOpenPanel *panel = nil;
|
||||
|
||||
//response to 'browse' panel
|
||||
NSInteger response = 0;
|
||||
|
||||
//init panel
|
||||
panel = [NSOpenPanel openPanel];
|
||||
|
||||
//allow files
|
||||
panel.canChooseFiles = YES;
|
||||
|
||||
//don't allow directories
|
||||
panel.canChooseDirectories = NO;
|
||||
|
||||
//disable multiple selections
|
||||
panel.allowsMultipleSelection = NO;
|
||||
|
||||
//can open app bundles
|
||||
panel.treatsFilePackagesAsDirectories = YES;
|
||||
|
||||
//start in user's home directory
|
||||
panel.directoryURL = [NSURL fileURLWithPath:NSHomeDirectory()];
|
||||
|
||||
//show it
|
||||
response = [panel runModal];
|
||||
|
||||
//ignore cancel
|
||||
if(NSModalResponseCancel == response)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//set path in ui
|
||||
self.executePath.stringValue = panel.URL.path;
|
||||
|
||||
//save path & sync
|
||||
[NSUserDefaults.standardUserDefaults setObject:self.executePath.stringValue forKey:PREF_EXECUTE_PATH];
|
||||
[NSUserDefaults.standardUserDefaults synchronize];
|
||||
|
||||
bail:
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -25,25 +25,66 @@ extern os_log_t logHandle;
|
|||
// ->will invoke app delegate method to update UI when check completes
|
||||
-(void)checkForUpdate:(void (^)(NSUInteger result, NSString* latestVersion))completionHandler
|
||||
{
|
||||
//latest version
|
||||
__block NSString* latestVersion = nil;
|
||||
//info
|
||||
__block NSDictionary* productInfo = nil;
|
||||
|
||||
//result
|
||||
__block NSInteger result = -1;
|
||||
__block NSInteger result = Update_None;
|
||||
|
||||
//get latest version in background
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
|
||||
|
||||
//grab latest version
|
||||
latestVersion = [self getLatestVersion];
|
||||
if(nil != latestVersion)
|
||||
//latest version
|
||||
NSString* latestVersion = nil;
|
||||
|
||||
//supported OS
|
||||
NSOperatingSystemVersion supportedOS = {0};
|
||||
|
||||
//get product info
|
||||
productInfo = [self getProductInfo:PRODUCT_NAME];
|
||||
if(nil == productInfo)
|
||||
{
|
||||
//check
|
||||
result = (NSOrderedAscending == [getAppVersion() compare:latestVersion options:NSNumericSearch]);
|
||||
//err msg
|
||||
os_log_error(logHandle, "ERROR: failed retrieve product info (for update check) from %{public}@", PRODUCT_VERSIONS_URL);
|
||||
|
||||
//error
|
||||
result = Update_Error;
|
||||
}
|
||||
//got remote product info
|
||||
// check supported OS and latest version
|
||||
else
|
||||
{
|
||||
//init supported OS
|
||||
supportedOS.majorVersion = [productInfo[SUPPORTED_OS_MAJOR] intValue];
|
||||
supportedOS.minorVersion = [productInfo[SUPPORTED_OS_MINOR] intValue];
|
||||
|
||||
//extract latest version
|
||||
latestVersion = productInfo[LATEST_VERSION];
|
||||
|
||||
//supported version of macOS?
|
||||
if(YES != [NSProcessInfo.processInfo isOperatingSystemAtLeastVersion:supportedOS])
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "latest version requires macOS %ld.%ld ...but current macOS is %{public}@", supportedOS.majorVersion, supportedOS.minorVersion, NSProcessInfo.processInfo.operatingSystemVersionString);
|
||||
|
||||
//unsupported
|
||||
result = Update_NotSupported;
|
||||
}
|
||||
|
||||
//latest version is new(er)?
|
||||
else if(nil != latestVersion)
|
||||
{
|
||||
//check app version and latest version
|
||||
if(NSOrderedAscending == [getAppVersion() compare:latestVersion options:NSNumericSearch])
|
||||
{
|
||||
//new update!
|
||||
result = Update_Available;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//invoke app delegate method
|
||||
// ->will update UI/show popup if necessart
|
||||
// will update UI/show popup if necessary
|
||||
dispatch_async(dispatch_get_main_queue(),
|
||||
^{
|
||||
completionHandler(result, latestVersion);
|
||||
|
@ -53,53 +94,27 @@ extern os_log_t logHandle;
|
|||
return;
|
||||
}
|
||||
|
||||
//query interwebz to get latest version
|
||||
-(NSString*)getLatestVersion
|
||||
//read JSON file w/ products
|
||||
// return dictionary w/ info about this product
|
||||
-(NSDictionary*)getProductInfo:(NSString*)product
|
||||
{
|
||||
//product version(s) data
|
||||
NSData* productsVersionData = nil;
|
||||
NSDictionary* products = nil;
|
||||
|
||||
//version dictionary
|
||||
NSDictionary* productsVersionDictionary = nil;
|
||||
|
||||
//latest version
|
||||
NSString* latestVersion = nil;
|
||||
|
||||
//get version from remote URL
|
||||
productsVersionData = [[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:PRODUCT_VERSIONS_URL]];
|
||||
if(nil == productsVersionData)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
|
||||
//convert JSON to dictionary
|
||||
// ->wrap as may throw exception
|
||||
//get json file (products) from remote URL
|
||||
@try
|
||||
{
|
||||
//convert
|
||||
productsVersionDictionary = [NSJSONSerialization JSONObjectWithData:productsVersionData options:0 error:nil];
|
||||
if(nil == productsVersionDictionary)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
}
|
||||
products = [NSJSONSerialization JSONObjectWithData:[[NSData alloc] initWithContentsOfURL:[NSURL URLWithString:PRODUCT_VERSIONS_URL]] options:0 error:nil];
|
||||
}
|
||||
@catch(NSException* exception)
|
||||
{
|
||||
//bail
|
||||
goto bail;
|
||||
;
|
||||
}
|
||||
|
||||
//extract latest version
|
||||
latestVersion = [[productsVersionDictionary objectForKey:@"OverSight"] objectForKey:@"version"];
|
||||
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "latest version: %{public}@", latestVersion);
|
||||
|
||||
bail:
|
||||
|
||||
return latestVersion;
|
||||
return products[product];
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -441,6 +441,9 @@ bail:
|
|||
//path to preferences dir
|
||||
NSString* prefsDirectory = nil;
|
||||
|
||||
//preferences file
|
||||
NSString* preferences = nil;
|
||||
|
||||
//path to login item
|
||||
NSURL* loginItem = nil;
|
||||
|
||||
|
@ -522,14 +525,25 @@ bail:
|
|||
}
|
||||
|
||||
//full?
|
||||
// delete prefs / allowed items
|
||||
// delete preferences
|
||||
if(YES == full)
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "removing preferences/allowed items");
|
||||
//init prefs file
|
||||
preferences = [NSHomeDirectory() stringByAppendingPathComponent:PREFERENCES];
|
||||
|
||||
//delete prefs via defaults
|
||||
execTask(DEFAULTS, @[@"delete", @BUNDLE_ID], YES, NO);
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "deleting preferences");
|
||||
|
||||
//delete preferences file
|
||||
// and if this fails, reset
|
||||
if(YES != [NSFileManager.defaultManager removeItemAtPath:preferences error:nil])
|
||||
{
|
||||
//dbg msg
|
||||
os_log_debug(logHandle, "deleting failed, will reset preferences");
|
||||
|
||||
//reset
|
||||
[NSUserDefaults.standardUserDefaults removePersistentDomainForName:@BUNDLE_ID];
|
||||
}
|
||||
}
|
||||
|
||||
//always remove application
|
||||
|
|
|
@ -70,6 +70,15 @@
|
|||
//error(s) url
|
||||
#define ERRORS_URL @"https://objective-see.com/errors.html"
|
||||
|
||||
//os major
|
||||
#define SUPPORTED_OS_MAJOR @"OSMajor"
|
||||
|
||||
//os minor
|
||||
#define SUPPORTED_OS_MINOR @"OSMinor"
|
||||
|
||||
//latest version
|
||||
#define LATEST_VERSION @"version"
|
||||
|
||||
//close category
|
||||
#define CATEGORY_CLOSE @"close"
|
||||
|
||||
|
@ -110,6 +119,9 @@
|
|||
//add rule, allow
|
||||
#define BUTTON_ALLOW 1
|
||||
|
||||
//preferences file
|
||||
#define PREFERENCES @"/Library/Preferences/com.objective-see.oversight.plist"
|
||||
|
||||
//prefs
|
||||
// disabled status
|
||||
#define PREF_IS_DISABLED @"disabled"
|
||||
|
@ -198,9 +210,6 @@
|
|||
//path to launchctl
|
||||
#define LAUNCHCTL @"/bin/launchctl"
|
||||
|
||||
//path to defaults
|
||||
#define DEFAULTS @"/usr/bin/defaults"
|
||||
|
||||
//path to kill all
|
||||
#define KILL_ALL @"/usr/bin/killall"
|
||||
|
||||
|
@ -237,6 +246,9 @@
|
|||
//av devices
|
||||
typedef enum {Device_Camera, Device_Microphone} AVDevice;
|
||||
|
||||
//updates
|
||||
typedef enum {Update_Error, Update_None, Update_NotSupported, Update_Available} UpdateStatus;
|
||||
|
||||
//log levels
|
||||
typedef enum {Log_Level_Default, Log_Level_Info, Log_Level_Debug} LogLevels;
|
||||
|
||||
|
|
Loading…
Reference in New Issue