mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2025-02-01 22:41:28 +01:00
Clover.app v1.15 with themes manager
Themes can be downloaded without git. The parser allows users to chose the Github user and the repository name, and so load themes from forks or any repo that has compatible directories structure (the repository must contains only themes, at first level).
This commit is contained in:
parent
27de9a9c9a
commit
99e9fc5d89
@ -23,6 +23,11 @@
|
|||||||
955689DB23A2728000AD323C /* IO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955689DA23A2728000AD323C /* IO.swift */; };
|
955689DB23A2728000AD323C /* IO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955689DA23A2728000AD323C /* IO.swift */; };
|
||||||
9556CAF5238DF75600082671 /* InstallerOutline.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9556CAF3238DF75600082671 /* InstallerOutline.xib */; };
|
9556CAF5238DF75600082671 /* InstallerOutline.xib in Resources */ = {isa = PBXBuildFile; fileRef = 9556CAF3238DF75600082671 /* InstallerOutline.xib */; };
|
||||||
9558518E23BA3486002CB3D8 /* Speaker.png in Resources */ = {isa = PBXBuildFile; fileRef = 9558518D23BA3485002CB3D8 /* Speaker.png */; };
|
9558518E23BA3486002CB3D8 /* Speaker.png in Resources */ = {isa = PBXBuildFile; fileRef = 9558518D23BA3485002CB3D8 /* Speaker.png */; };
|
||||||
|
955BEE1523C6B49C00425AB0 /* ThemeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955BEE1223C6B49C00425AB0 /* ThemeView.swift */; };
|
||||||
|
955BEE1623C6B49C00425AB0 /* ThemeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955BEE1323C6B49C00425AB0 /* ThemeManager.swift */; };
|
||||||
|
955BEE1723C6B49C00425AB0 /* ThemeManagerVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955BEE1423C6B49C00425AB0 /* ThemeManagerVC.swift */; };
|
||||||
|
955BEE1923C6B4B300425AB0 /* ThemeManager.xib in Resources */ = {isa = PBXBuildFile; fileRef = 955BEE1823C6B4B300425AB0 /* ThemeManager.xib */; };
|
||||||
|
955BEE1B23C7171100425AB0 /* check.png in Resources */ = {isa = PBXBuildFile; fileRef = 955BEE1A23C7171000425AB0 /* check.png */; };
|
||||||
955F7C6D238DCD170019D088 /* DiskArbitration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 955F7C6C238DCD160019D088 /* DiskArbitration.framework */; };
|
955F7C6D238DCD170019D088 /* DiskArbitration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 955F7C6C238DCD160019D088 /* DiskArbitration.framework */; };
|
||||||
9560906A238C61E200ACD7F7 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 95609068238C61E200ACD7F7 /* MainMenu.xib */; };
|
9560906A238C61E200ACD7F7 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 95609068238C61E200ACD7F7 /* MainMenu.xib */; };
|
||||||
956090B7238C890600ACD7F7 /* Installer.xib in Resources */ = {isa = PBXBuildFile; fileRef = 956090B9238C890600ACD7F7 /* Installer.xib */; };
|
956090B7238C890600ACD7F7 /* Installer.xib in Resources */ = {isa = PBXBuildFile; fileRef = 956090B9238C890600ACD7F7 /* Installer.xib */; };
|
||||||
@ -188,6 +193,11 @@
|
|||||||
955689DA23A2728000AD323C /* IO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IO.swift; sourceTree = "<group>"; };
|
955689DA23A2728000AD323C /* IO.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IO.swift; sourceTree = "<group>"; };
|
||||||
9556CAF4238DF75600082671 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/InstallerOutline.xib; sourceTree = "<group>"; };
|
9556CAF4238DF75600082671 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/InstallerOutline.xib; sourceTree = "<group>"; };
|
||||||
9558518D23BA3485002CB3D8 /* Speaker.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Speaker.png; sourceTree = "<group>"; };
|
9558518D23BA3485002CB3D8 /* Speaker.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Speaker.png; sourceTree = "<group>"; };
|
||||||
|
955BEE1223C6B49C00425AB0 /* ThemeView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemeView.swift; sourceTree = "<group>"; };
|
||||||
|
955BEE1323C6B49C00425AB0 /* ThemeManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemeManager.swift; sourceTree = "<group>"; };
|
||||||
|
955BEE1423C6B49C00425AB0 /* ThemeManagerVC.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ThemeManagerVC.swift; sourceTree = "<group>"; };
|
||||||
|
955BEE1823C6B4B300425AB0 /* ThemeManager.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ThemeManager.xib; sourceTree = "<group>"; };
|
||||||
|
955BEE1A23C7171000425AB0 /* check.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = check.png; sourceTree = "<group>"; };
|
||||||
955F7C6C238DCD160019D088 /* DiskArbitration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiskArbitration.framework; path = System/Library/Frameworks/DiskArbitration.framework; sourceTree = SDKROOT; };
|
955F7C6C238DCD160019D088 /* DiskArbitration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = DiskArbitration.framework; path = System/Library/Frameworks/DiskArbitration.framework; sourceTree = SDKROOT; };
|
||||||
95609069238C61E200ACD7F7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
95609069238C61E200ACD7F7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/MainMenu.xib; sourceTree = "<group>"; };
|
||||||
9560906C238C624200ACD7F7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/MainMenu.strings; sourceTree = "<group>"; };
|
9560906C238C624200ACD7F7 /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/MainMenu.strings; sourceTree = "<group>"; };
|
||||||
@ -388,6 +398,17 @@
|
|||||||
path = images;
|
path = images;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
955BEE1123C6B43C00425AB0 /* ThemeManager */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
955BEE1323C6B49C00425AB0 /* ThemeManager.swift */,
|
||||||
|
955BEE1423C6B49C00425AB0 /* ThemeManagerVC.swift */,
|
||||||
|
955BEE1223C6B49C00425AB0 /* ThemeView.swift */,
|
||||||
|
955BEE1823C6B4B300425AB0 /* ThemeManager.xib */,
|
||||||
|
);
|
||||||
|
path = ThemeManager;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
95C51578236B21AE00E4A3A8 /* Products */ = {
|
95C51578236B21AE00E4A3A8 /* Products */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -423,6 +444,7 @@
|
|||||||
95E68AC8235B862F002B37A5 /* Clover */ = {
|
95E68AC8235B862F002B37A5 /* Clover */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
|
955BEE1123C6B43C00425AB0 /* ThemeManager */,
|
||||||
95E68AC9235B862F002B37A5 /* AppDelegate.swift */,
|
95E68AC9235B862F002B37A5 /* AppDelegate.swift */,
|
||||||
95C5152E236A0A7400E4A3A8 /* SettingsView.swift */,
|
95C5152E236A0A7400E4A3A8 /* SettingsView.swift */,
|
||||||
95C51535236B1F7700E4A3A8 /* RunAtLogin.swift */,
|
95C51535236B1F7700E4A3A8 /* RunAtLogin.swift */,
|
||||||
@ -438,6 +460,7 @@
|
|||||||
95E50075238ABA56002F3869 /* Tasks.swift */,
|
95E50075238ABA56002F3869 /* Tasks.swift */,
|
||||||
953BC20223720C0A0039755D /* FixedWidthViews.swift */,
|
953BC20223720C0A0039755D /* FixedWidthViews.swift */,
|
||||||
9533718223709517003F1AF4 /* bootsectors-install */,
|
9533718223709517003F1AF4 /* bootsectors-install */,
|
||||||
|
955BEE1A23C7171000425AB0 /* check.png */,
|
||||||
9569EC44238DD772003AD72C /* Settings.xib */,
|
9569EC44238DD772003AD72C /* Settings.xib */,
|
||||||
95609068238C61E200ACD7F7 /* MainMenu.xib */,
|
95609068238C61E200ACD7F7 /* MainMenu.xib */,
|
||||||
95E68AD9235B8666002B37A5 /* Installer */,
|
95E68AD9235B8666002B37A5 /* Installer */,
|
||||||
@ -639,8 +662,10 @@
|
|||||||
954DECD523899F5F006A9876 /* Bootmanager.png in Resources */,
|
954DECD523899F5F006A9876 /* Bootmanager.png in Resources */,
|
||||||
95E68ACE235B8632002B37A5 /* Assets.xcassets in Resources */,
|
95E68ACE235B8632002B37A5 /* Assets.xcassets in Resources */,
|
||||||
9569EC42238DD772003AD72C /* Settings.xib in Resources */,
|
9569EC42238DD772003AD72C /* Settings.xib in Resources */,
|
||||||
|
955BEE1B23C7171100425AB0 /* check.png in Resources */,
|
||||||
9560906A238C61E200ACD7F7 /* MainMenu.xib in Resources */,
|
9560906A238C61E200ACD7F7 /* MainMenu.xib in Resources */,
|
||||||
9533718323709517003F1AF4 /* bootsectors-install in Resources */,
|
9533718323709517003F1AF4 /* bootsectors-install in Resources */,
|
||||||
|
955BEE1923C6B4B300425AB0 /* ThemeManager.xib in Resources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -698,6 +723,7 @@
|
|||||||
95E68ADF235B86A1002B37A5 /* Releases.swift in Sources */,
|
95E68ADF235B86A1002B37A5 /* Releases.swift in Sources */,
|
||||||
954BBE99238196EE0032425F /* Locale.swift in Sources */,
|
954BBE99238196EE0032425F /* Locale.swift in Sources */,
|
||||||
95E68ACA235B862F002B37A5 /* AppDelegate.swift in Sources */,
|
95E68ACA235B862F002B37A5 /* AppDelegate.swift in Sources */,
|
||||||
|
955BEE1523C6B49C00425AB0 /* ThemeView.swift in Sources */,
|
||||||
958861DA235F75FB00B64173 /* Driver.swift in Sources */,
|
958861DA235F75FB00B64173 /* Driver.swift in Sources */,
|
||||||
95E68AE3235B86A1002B37A5 /* bdmesg.swift in Sources */,
|
95E68AE3235B86A1002B37A5 /* bdmesg.swift in Sources */,
|
||||||
95C5152F236A0A7400E4A3A8 /* SettingsView.swift in Sources */,
|
95C5152F236A0A7400E4A3A8 /* SettingsView.swift in Sources */,
|
||||||
@ -709,6 +735,8 @@
|
|||||||
95E68AE0235B86A1002B37A5 /* Extensions.swift in Sources */,
|
95E68AE0235B86A1002B37A5 /* Extensions.swift in Sources */,
|
||||||
955689DB23A2728000AD323C /* IO.swift in Sources */,
|
955689DB23A2728000AD323C /* IO.swift in Sources */,
|
||||||
9555AF26238EE53300108C33 /* InstallerOutline.swift in Sources */,
|
9555AF26238EE53300108C33 /* InstallerOutline.swift in Sources */,
|
||||||
|
955BEE1723C6B49C00425AB0 /* ThemeManagerVC.swift in Sources */,
|
||||||
|
955BEE1623C6B49C00425AB0 /* ThemeManager.swift in Sources */,
|
||||||
);
|
);
|
||||||
runOnlyForDeploymentPostprocessing = 0;
|
runOnlyForDeploymentPostprocessing = 0;
|
||||||
};
|
};
|
||||||
@ -1021,7 +1049,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "-";
|
CODE_SIGN_IDENTITY = "-";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 1.14;
|
CURRENT_PROJECT_VERSION = 1.15;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Clover/Frameworks",
|
"$(PROJECT_DIR)/Clover/Frameworks",
|
||||||
@ -1037,7 +1065,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Clover/Frameworks",
|
"$(PROJECT_DIR)/Clover/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.14;
|
MARKETING_VERSION = 1.15;
|
||||||
OTHER_LDFLAGS = "";
|
OTHER_LDFLAGS = "";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = org.slice.Clover;
|
PRODUCT_BUNDLE_IDENTIFIER = org.slice.Clover;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
@ -1057,7 +1085,7 @@
|
|||||||
CODE_SIGN_IDENTITY = "-";
|
CODE_SIGN_IDENTITY = "-";
|
||||||
CODE_SIGN_STYLE = Automatic;
|
CODE_SIGN_STYLE = Automatic;
|
||||||
COMBINE_HIDPI_IMAGES = YES;
|
COMBINE_HIDPI_IMAGES = YES;
|
||||||
CURRENT_PROJECT_VERSION = 1.14;
|
CURRENT_PROJECT_VERSION = 1.15;
|
||||||
FRAMEWORK_SEARCH_PATHS = (
|
FRAMEWORK_SEARCH_PATHS = (
|
||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Clover/Frameworks",
|
"$(PROJECT_DIR)/Clover/Frameworks",
|
||||||
@ -1072,7 +1100,7 @@
|
|||||||
"$(inherited)",
|
"$(inherited)",
|
||||||
"$(PROJECT_DIR)/Clover/Frameworks",
|
"$(PROJECT_DIR)/Clover/Frameworks",
|
||||||
);
|
);
|
||||||
MARKETING_VERSION = 1.14;
|
MARKETING_VERSION = 1.15;
|
||||||
OTHER_LDFLAGS = "";
|
OTHER_LDFLAGS = "";
|
||||||
PRODUCT_BUNDLE_IDENTIFIER = org.slice.Clover;
|
PRODUCT_BUNDLE_IDENTIFIER = org.slice.Clover;
|
||||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||||
|
@ -16,6 +16,11 @@ let localeBundle = Bundle(path: Bundle.main.sharedSupportPath! + "/Lang.bundle")
|
|||||||
class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
|
class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
|
||||||
var isInstalling : Bool = false
|
var isInstalling : Bool = false
|
||||||
var isInstallerOpen : Bool = false
|
var isInstallerOpen : Bool = false
|
||||||
|
var themeUser = UDs.string(forKey: kThemeUserKey) ?? kDefaultThemeUser
|
||||||
|
var themeRepo = UDs.string(forKey: kThemeRepoKey) ?? kDefaultThemeRepo
|
||||||
|
|
||||||
|
var themes : [String] = [String]()
|
||||||
|
var installedThemes : [String] = [String]()
|
||||||
var popover : NSPopover?
|
var popover : NSPopover?
|
||||||
|
|
||||||
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
|
let statusItem = NSStatusBar.system.statusItem(withLength: NSStatusItem.variableLength)
|
||||||
@ -23,6 +28,7 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
|
|||||||
var settingsWC: SettingsWindowController? = nil
|
var settingsWC: SettingsWindowController? = nil
|
||||||
var installerWC : InstallerWindowController? = nil
|
var installerWC : InstallerWindowController? = nil
|
||||||
var installerOutWC : InstallerOutWindowController? = nil
|
var installerOutWC : InstallerOutWindowController? = nil
|
||||||
|
var themeManagerWC : ThemeManagerWC?
|
||||||
|
|
||||||
var daSession : DASession? = nil
|
var daSession : DASession? = nil
|
||||||
var daContext : UnsafeMutablePointer<Int> = UnsafeMutablePointer<Int>.allocate(capacity: 1)
|
var daContext : UnsafeMutablePointer<Int> = UnsafeMutablePointer<Int>.allocate(capacity: 1)
|
||||||
@ -87,8 +93,6 @@ class AppDelegate: NSObject, NSApplicationDelegate, NSPopoverDelegate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
self.settingsWC = SettingsWindowController.loadFromNib()
|
self.settingsWC = SettingsWindowController.loadFromNib()
|
||||||
|
|
||||||
NotificationCenter.default.addObserver(self,
|
NotificationCenter.default.addObserver(self,
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<buttonCell key="cell" type="push" title="Check now" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="UyZ-5I-L9X">
|
<buttonCell key="cell" type="push" title="Check now" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="UyZ-5I-L9X">
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="checkNow:" target="tSJ-3G-dnL" id="UY0-EP-xVG"/>
|
<action selector="checkNow:" target="tSJ-3G-dnL" id="UY0-EP-xVG"/>
|
||||||
@ -35,7 +35,7 @@
|
|||||||
<rect key="frame" x="14" y="206" width="311" height="16"/>
|
<rect key="frame" x="14" y="206" width="311" height="16"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Update" id="58l-pb-zEc">
|
<textFieldCell key="cell" lineBreakMode="clipping" title="Update" id="58l-pb-zEc">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -45,7 +45,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<buttonCell key="cell" type="check" title="Run at login" bezelStyle="regularSquare" imagePosition="left" inset="2" id="J8R-ej-fRl">
|
<buttonCell key="cell" type="check" title="Run at login" bezelStyle="regularSquare" imagePosition="left" inset="2" id="J8R-ej-fRl">
|
||||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="runAtLogin:" target="tSJ-3G-dnL" id="Kfi-uU-9Tq"/>
|
<action selector="runAtLogin:" target="tSJ-3G-dnL" id="Kfi-uU-9Tq"/>
|
||||||
@ -64,7 +64,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="lkK-DQ-QK6">
|
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="lkK-DQ-QK6">
|
||||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
<menu key="menu" id="tIP-gO-fKT"/>
|
<menu key="menu" id="tIP-gO-fKT"/>
|
||||||
</popUpButtonCell>
|
</popUpButtonCell>
|
||||||
<userDefinedRuntimeAttributes>
|
<userDefinedRuntimeAttributes>
|
||||||
@ -80,7 +80,7 @@
|
|||||||
<rect key="frame" x="14" y="186" width="311" height="14"/>
|
<rect key="frame" x="14" y="186" width="311" height="14"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" title="Check update:" id="fMZ-r2-dlm">
|
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" title="Check update:" id="fMZ-r2-dlm">
|
||||||
<font key="font" metaFont="message" size="11"/>
|
<font key="font" metaFont="label" size="11"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -89,7 +89,7 @@
|
|||||||
<rect key="frame" x="14" y="91" width="311" height="14"/>
|
<rect key="frame" x="14" y="91" width="311" height="14"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" title="Label" id="v3d-HG-AeW">
|
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" title="Label" id="v3d-HG-AeW">
|
||||||
<font key="font" metaFont="message" size="11"/>
|
<font key="font" metaFont="label" size="11"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -103,7 +103,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<buttonCell key="cell" type="push" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="E23-ao-JFs">
|
<buttonCell key="cell" type="push" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="E23-ao-JFs">
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="installClover:" target="tSJ-3G-dnL" id="9VG-7Q-ccY"/>
|
<action selector="installClover:" target="tSJ-3G-dnL" id="9VG-7Q-ccY"/>
|
||||||
@ -114,7 +114,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<buttonCell key="cell" type="push" title="Button" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="EJg-qm-L18">
|
<buttonCell key="cell" type="push" title="Button" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="EJg-qm-L18">
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="updateClover:" target="tSJ-3G-dnL" id="kpg-zk-tVv"/>
|
<action selector="updateClover:" target="tSJ-3G-dnL" id="kpg-zk-tVv"/>
|
||||||
@ -138,7 +138,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<buttonCell key="cell" type="push" title="Uninstall" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="w6z-A1-CZt">
|
<buttonCell key="cell" type="push" title="Uninstall" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="w6z-A1-CZt">
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="unInstallDaemon:" target="tSJ-3G-dnL" id="9K2-E3-t1N"/>
|
<action selector="unInstallDaemon:" target="tSJ-3G-dnL" id="9K2-E3-t1N"/>
|
||||||
@ -153,7 +153,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<buttonCell key="cell" type="push" title="Install" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="omz-9K-nb4">
|
<buttonCell key="cell" type="push" title="Install" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="omz-9K-nb4">
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="installDaemon:" target="tSJ-3G-dnL" id="lQr-TV-nz0"/>
|
<action selector="installDaemon:" target="tSJ-3G-dnL" id="lQr-TV-nz0"/>
|
||||||
@ -164,7 +164,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<buttonCell key="cell" type="check" title="*Disable Sleep Proxy Client" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="kZm-NL-hOA">
|
<buttonCell key="cell" type="check" title="*Disable Sleep Proxy Client" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="kZm-NL-hOA">
|
||||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="disableSleepProxy:" target="tSJ-3G-dnL" id="jia-ue-L5p"/>
|
<action selector="disableSleepProxy:" target="tSJ-3G-dnL" id="jia-ue-L5p"/>
|
||||||
@ -174,7 +174,7 @@
|
|||||||
<rect key="frame" x="21" y="265" width="304" height="11"/>
|
<rect key="frame" x="21" y="265" width="304" height="11"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" controlSize="mini" lineBreakMode="clipping" title="*Require CloverDaemon" id="yQ9-cU-wtc">
|
<textFieldCell key="cell" controlSize="mini" lineBreakMode="clipping" title="*Require CloverDaemon" id="yQ9-cU-wtc">
|
||||||
<font key="font" metaFont="label" size="9"/>
|
<font key="font" metaFont="menu" size="9"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -184,7 +184,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<buttonCell key="cell" type="check" title="*Make filesystem read-write" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="v3W-6S-CK6">
|
<buttonCell key="cell" type="check" title="*Make filesystem read-write" bezelStyle="regularSquare" imagePosition="left" state="on" inset="2" id="v3W-6S-CK6">
|
||||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="makeRootRW:" target="tSJ-3G-dnL" id="KQZ-a6-GKv"/>
|
<action selector="makeRootRW:" target="tSJ-3G-dnL" id="KQZ-a6-GKv"/>
|
||||||
@ -195,7 +195,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<buttonCell key="cell" type="push" title="Read daemon log" bezelStyle="rounded" alignment="center" controlSize="small" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="UZY-ie-enb">
|
<buttonCell key="cell" type="push" title="Read daemon log" bezelStyle="rounded" alignment="center" controlSize="small" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="UZY-ie-enb">
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="message" size="11"/>
|
<font key="font" metaFont="label" size="11"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="readDaemonLog:" target="tSJ-3G-dnL" id="Mo0-RL-dK0"/>
|
<action selector="readDaemonLog:" target="tSJ-3G-dnL" id="Mo0-RL-dK0"/>
|
||||||
@ -206,7 +206,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<buttonCell key="cell" type="push" title="Read bdmesg" bezelStyle="rounded" alignment="center" controlSize="small" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="bhg-iF-USh">
|
<buttonCell key="cell" type="push" title="Read bdmesg" bezelStyle="rounded" alignment="center" controlSize="small" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="bhg-iF-USh">
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="message" size="11"/>
|
<font key="font" metaFont="label" size="11"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="readbdmesg:" target="tSJ-3G-dnL" id="eFP-wf-VyP"/>
|
<action selector="readbdmesg:" target="tSJ-3G-dnL" id="eFP-wf-VyP"/>
|
||||||
@ -216,7 +216,7 @@
|
|||||||
<rect key="frame" x="61" y="9" width="224" height="15"/>
|
<rect key="frame" x="61" y="9" width="224" height="15"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="Label" id="goU-fD-Ng6">
|
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="center" title="Label" id="goU-fD-Ng6">
|
||||||
<font key="font" metaFont="message" size="11"/>
|
<font key="font" metaFont="label" size="11"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -226,7 +226,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<buttonCell key="cell" type="bevel" bezelStyle="rounded" image="NSInfo" imagePosition="only" alignment="center" focusRingType="none" imageScaling="proportionallyDown" inset="2" id="8hx-sN-OfR">
|
<buttonCell key="cell" type="bevel" bezelStyle="rounded" image="NSInfo" imagePosition="only" alignment="center" focusRingType="none" imageScaling="proportionallyDown" inset="2" id="8hx-sN-OfR">
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="goToTopic:" target="tSJ-3G-dnL" id="azU-qH-5SJ"/>
|
<action selector="goToTopic:" target="tSJ-3G-dnL" id="azU-qH-5SJ"/>
|
||||||
@ -237,7 +237,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<buttonCell key="cell" type="bevel" bezelStyle="rounded" image="NSStopProgressFreestandingTemplate" imagePosition="only" alignment="center" focusRingType="none" imageScaling="proportionallyDown" inset="2" id="2fO-JJ-w1L">
|
<buttonCell key="cell" type="bevel" bezelStyle="rounded" image="NSStopProgressFreestandingTemplate" imagePosition="only" alignment="center" focusRingType="none" imageScaling="proportionallyDown" inset="2" id="2fO-JJ-w1L">
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="closeApp:" target="tSJ-3G-dnL" id="Hjx-e6-JXH"/>
|
<action selector="closeApp:" target="tSJ-3G-dnL" id="Hjx-e6-JXH"/>
|
||||||
@ -246,7 +246,7 @@
|
|||||||
<tabView fixedFrame="YES" type="noTabsNoBorder" translatesAutoresizingMaskIntoConstraints="NO" id="PGs-4a-XRc" customClass="LITabView" customModule="Clover" customModuleProvider="target">
|
<tabView fixedFrame="YES" type="noTabsNoBorder" translatesAutoresizingMaskIntoConstraints="NO" id="PGs-4a-XRc" customClass="LITabView" customModule="Clover" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="522" width="342" height="120"/>
|
<rect key="frame" x="0.0" y="522" width="342" height="120"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
<tabViewItems>
|
<tabViewItems>
|
||||||
<tabViewItem label="Tab" identifier="" id="BAk-3x-mLp">
|
<tabViewItem label="Tab" identifier="" id="BAk-3x-mLp">
|
||||||
<view key="view" ambiguous="YES" id="ENG-5U-eLE">
|
<view key="view" ambiguous="YES" id="ENG-5U-eLE">
|
||||||
@ -257,7 +257,7 @@
|
|||||||
<rect key="frame" x="18" y="101" width="306" height="16"/>
|
<rect key="frame" x="18" y="101" width="306" height="16"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Current revision" id="Re2-vf-XQ6">
|
<textFieldCell key="cell" lineBreakMode="clipping" title="Current revision" id="Re2-vf-XQ6">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -266,7 +266,7 @@
|
|||||||
<rect key="frame" x="18" y="78" width="306" height="16"/>
|
<rect key="frame" x="18" y="78" width="306" height="16"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Boot Device:" id="omZ-xs-Wjn">
|
<textFieldCell key="cell" lineBreakMode="clipping" title="Boot Device:" id="omZ-xs-Wjn">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -275,7 +275,7 @@
|
|||||||
<rect key="frame" x="18" y="39" width="306" height="16"/>
|
<rect key="frame" x="18" y="39" width="306" height="16"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" lineBreakMode="clipping" title="config path:" id="iii-3P-wo8">
|
<textFieldCell key="cell" lineBreakMode="clipping" title="config path:" id="iii-3P-wo8">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -284,7 +284,7 @@
|
|||||||
<rect key="frame" x="30" y="20" width="294" height="14"/>
|
<rect key="frame" x="30" y="20" width="294" height="14"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="truncatingHead" selectable="YES" allowsUndo="NO" focusRingType="none" title="N/A" id="EX6-6q-G8U">
|
<textFieldCell key="cell" controlSize="small" lineBreakMode="truncatingHead" selectable="YES" allowsUndo="NO" focusRingType="none" title="N/A" id="EX6-6q-G8U">
|
||||||
<font key="font" metaFont="message" size="11"/>
|
<font key="font" metaFont="label" size="11"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -298,7 +298,7 @@
|
|||||||
<rect key="frame" x="30" y="56" width="294" height="14"/>
|
<rect key="frame" x="30" y="56" width="294" height="14"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" allowsUndo="NO" title="N/A" id="EFW-lW-i6c">
|
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" allowsUndo="NO" title="N/A" id="EFW-lW-i6c">
|
||||||
<font key="font" metaFont="message" size="11"/>
|
<font key="font" metaFont="label" size="11"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -324,7 +324,7 @@
|
|||||||
<rect key="frame" x="30" y="79" width="294" height="14"/>
|
<rect key="frame" x="30" y="79" width="294" height="14"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" focusRingType="none" title="N/A" id="PZZ-nm-ERe">
|
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" focusRingType="none" title="N/A" id="PZZ-nm-ERe">
|
||||||
<font key="font" metaFont="message" size="11"/>
|
<font key="font" metaFont="label" size="11"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -342,7 +342,7 @@
|
|||||||
<rect key="frame" x="30" y="39" width="294" height="14"/>
|
<rect key="frame" x="30" y="39" width="294" height="14"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" focusRingType="none" title="N/A" id="oPZ-3Y-89o">
|
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" focusRingType="none" title="N/A" id="oPZ-3Y-89o">
|
||||||
<font key="font" metaFont="message" size="11"/>
|
<font key="font" metaFont="label" size="11"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -360,7 +360,7 @@
|
|||||||
<rect key="frame" x="30" y="0.0" width="294" height="14"/>
|
<rect key="frame" x="30" y="0.0" width="294" height="14"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" focusRingType="none" title="N/A" id="okN-IH-2al">
|
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" focusRingType="none" title="N/A" id="okN-IH-2al">
|
||||||
<font key="font" metaFont="message" size="11"/>
|
<font key="font" metaFont="label" size="11"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -386,7 +386,7 @@
|
|||||||
<rect key="frame" x="30" y="79" width="294" height="14"/>
|
<rect key="frame" x="30" y="79" width="294" height="14"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" focusRingType="none" title="N/A" id="HZg-rD-gZv">
|
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" focusRingType="none" title="N/A" id="HZg-rD-gZv">
|
||||||
<font key="font" metaFont="message" size="11"/>
|
<font key="font" metaFont="label" size="11"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -413,7 +413,7 @@
|
|||||||
<rect key="frame" x="30" y="39" width="294" height="14"/>
|
<rect key="frame" x="30" y="39" width="294" height="14"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" focusRingType="none" title="Label" id="J7N-7a-sdN">
|
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" focusRingType="none" title="Label" id="J7N-7a-sdN">
|
||||||
<font key="font" metaFont="message" size="11"/>
|
<font key="font" metaFont="label" size="11"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -422,7 +422,7 @@
|
|||||||
<rect key="frame" x="30" y="0.0" width="294" height="14"/>
|
<rect key="frame" x="30" y="0.0" width="294" height="14"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" focusRingType="none" title="Label" id="0dT-GZ-Ytt">
|
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" selectable="YES" focusRingType="none" title="Label" id="0dT-GZ-Ytt">
|
||||||
<font key="font" metaFont="message" size="11"/>
|
<font key="font" metaFont="label" size="11"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -448,7 +448,7 @@
|
|||||||
<rect key="frame" x="18" y="64" width="306" height="16"/>
|
<rect key="frame" x="18" y="64" width="306" height="16"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Boot type:" id="pWw-6m-fZo">
|
<textFieldCell key="cell" lineBreakMode="clipping" title="Boot type:" id="pWw-6m-fZo">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -457,7 +457,7 @@
|
|||||||
<rect key="frame" x="18" y="27" width="306" height="16"/>
|
<rect key="frame" x="18" y="27" width="306" height="16"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<textFieldCell key="cell" lineBreakMode="clipping" title="firmware:" id="kyW-hT-U5H">
|
<textFieldCell key="cell" lineBreakMode="clipping" title="firmware:" id="kyW-hT-U5H">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -474,7 +474,7 @@
|
|||||||
<rect key="frame" x="256" y="497" width="69" height="21"/>
|
<rect key="frame" x="256" y="497" width="69" height="21"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<segmentedCell key="cell" controlSize="small" borderStyle="border" alignment="left" style="rounded" trackingMode="momentary" id="3O5-bI-89P">
|
<segmentedCell key="cell" controlSize="small" borderStyle="border" alignment="left" style="rounded" trackingMode="momentary" id="3O5-bI-89P">
|
||||||
<font key="font" metaFont="message" size="11"/>
|
<font key="font" metaFont="label" size="11"/>
|
||||||
<segments>
|
<segments>
|
||||||
<segment image="NSLeftFacingTriangleTemplate" width="31"/>
|
<segment image="NSLeftFacingTriangleTemplate" width="31"/>
|
||||||
<segment image="NSRightFacingTriangleTemplate" width="31" tag="1"/>
|
<segment image="NSRightFacingTriangleTemplate" width="31" tag="1"/>
|
||||||
@ -487,10 +487,10 @@
|
|||||||
<tabView fixedFrame="YES" type="noTabsNoBorder" translatesAutoresizingMaskIntoConstraints="NO" id="vwp-hc-6yE" customClass="LITabView" customModule="Clover" customModuleProvider="target">
|
<tabView fixedFrame="YES" type="noTabsNoBorder" translatesAutoresizingMaskIntoConstraints="NO" id="vwp-hc-6yE" customClass="LITabView" customModule="Clover" customModuleProvider="target">
|
||||||
<rect key="frame" x="0.0" y="358" width="342" height="113"/>
|
<rect key="frame" x="0.0" y="358" width="342" height="113"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
<tabViewItems>
|
<tabViewItems>
|
||||||
<tabViewItem identifier="Mount" id="F4n-I1-4Gq">
|
<tabViewItem identifier="Mount" id="F4n-I1-4Gq">
|
||||||
<view key="view" ambiguous="YES" id="E05-QZ-1bf">
|
<view key="view" id="E05-QZ-1bf">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="342" height="113"/>
|
<rect key="frame" x="0.0" y="0.0" width="342" height="113"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
@ -499,7 +499,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="Hzi-CJ-xVH">
|
<popUpButtonCell key="cell" type="push" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" id="Hzi-CJ-xVH">
|
||||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
<menu key="menu" id="Vb3-8W-CMc"/>
|
<menu key="menu" id="Vb3-8W-CMc"/>
|
||||||
</popUpButtonCell>
|
</popUpButtonCell>
|
||||||
<userDefinedRuntimeAttributes>
|
<userDefinedRuntimeAttributes>
|
||||||
@ -515,7 +515,7 @@
|
|||||||
<rect key="frame" x="21" y="74" width="122" height="16"/>
|
<rect key="frame" x="21" y="74" width="122" height="16"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Mount" id="s5K-bS-gZa">
|
<textFieldCell key="cell" lineBreakMode="clipping" title="Mount" id="s5K-bS-gZa">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -524,7 +524,7 @@
|
|||||||
<rect key="frame" x="21" y="58" width="52" height="11"/>
|
<rect key="frame" x="21" y="58" width="52" height="11"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" controlSize="mini" lineBreakMode="clipping" title="(ESP)" id="TTH-hz-cX2">
|
<textFieldCell key="cell" controlSize="mini" lineBreakMode="clipping" title="(ESP)" id="TTH-hz-cX2">
|
||||||
<font key="font" metaFont="label" size="9"/>
|
<font key="font" metaFont="menu" size="9"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -534,7 +534,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<buttonCell key="cell" type="check" title="*auto mount" bezelStyle="regularSquare" imagePosition="left" inset="2" id="tdl-nw-YFd">
|
<buttonCell key="cell" type="check" title="*auto mount" bezelStyle="regularSquare" imagePosition="left" inset="2" id="tdl-nw-YFd">
|
||||||
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="autoMount:" target="tSJ-3G-dnL" id="FNN-jm-HUm"/>
|
<action selector="autoMount:" target="tSJ-3G-dnL" id="FNN-jm-HUm"/>
|
||||||
@ -545,7 +545,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<buttonCell key="cell" type="push" title="umount" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="bhl-e0-nVD">
|
<buttonCell key="cell" type="push" title="umount" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="bhl-e0-nVD">
|
||||||
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
</buttonCell>
|
</buttonCell>
|
||||||
<connections>
|
<connections>
|
||||||
<action selector="umount:" target="tSJ-3G-dnL" id="KqE-Db-Uf1"/>
|
<action selector="umount:" target="tSJ-3G-dnL" id="KqE-Db-Uf1"/>
|
||||||
@ -555,32 +555,88 @@
|
|||||||
</view>
|
</view>
|
||||||
</tabViewItem>
|
</tabViewItem>
|
||||||
<tabViewItem identifier="Theme" id="Th2-UC-6Hh">
|
<tabViewItem identifier="Theme" id="Th2-UC-6Hh">
|
||||||
<view key="view" id="hLu-g7-21T">
|
<view key="view" ambiguous="YES" id="hLu-g7-21T">
|
||||||
<rect key="frame" x="0.0" y="0.0" width="342" height="113"/>
|
<rect key="frame" x="0.0" y="0.0" width="342" height="113"/>
|
||||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
<subviews>
|
<subviews>
|
||||||
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3iW-Mp-ZEr">
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="3iW-Mp-ZEr">
|
||||||
<rect key="frame" x="21" y="74" width="303" height="16"/>
|
<rect key="frame" x="21" y="96" width="303" height="16"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" lineBreakMode="clipping" title="Theme:" id="7yo-8b-ZHc">
|
<textFieldCell key="cell" lineBreakMode="clipping" title="Theme:" id="7yo-8b-ZHc">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
</textField>
|
</textField>
|
||||||
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="0Zs-Un-dNa" customClass="FWTextField" customModule="Clover" customModuleProvider="target">
|
<comboBox verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="MMH-mb-fPM">
|
||||||
<rect key="frame" x="20" y="46" width="199" height="21"/>
|
<rect key="frame" x="23" y="65" width="302" height="25"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<textFieldCell key="cell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" drawsBackground="YES" id="DVf-rV-Hrc">
|
<comboBoxCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" placeholderString="NVRAM" drawsBackground="YES" completes="NO" numberOfVisibleItems="5" id="kdy-IM-YSv">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<objectValues>
|
||||||
|
<string>Item 1</string>
|
||||||
|
<string>Item 2</string>
|
||||||
|
<string>Item 3</string>
|
||||||
|
</objectValues>
|
||||||
|
</comboBoxCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="themeBoxSelected:" target="tSJ-3G-dnL" id="76K-Tu-HPV"/>
|
||||||
|
</connections>
|
||||||
|
</comboBox>
|
||||||
|
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="AzG-cL-pFW">
|
||||||
|
<rect key="frame" x="17" y="33" width="311" height="32"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="push" title="Manager" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="I4v-1L-brN">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="label" size="13"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="openThemeManager:" target="tSJ-3G-dnL" id="PE4-2e-cP2"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6VD-VJ-phW">
|
||||||
|
<rect key="frame" x="21" y="20" width="75" height="14"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" title="GitHub user" id="Bi4-5Q-YMR">
|
||||||
|
<font key="font" metaFont="label" size="11"/>
|
||||||
|
<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="QbU-PE-PmE">
|
||||||
|
<rect key="frame" x="21" y="2" width="75" height="14"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" title="GitHub repo" id="dE6-xG-swG">
|
||||||
|
<font key="font" metaFont="label" size="11"/>
|
||||||
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="2Va-F7-vYB">
|
||||||
|
<rect key="frame" x="102" y="1" width="220" height="16"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<textFieldCell key="cell" controlSize="mini" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" id="dmw-9Z-gN5">
|
||||||
|
<font key="font" metaFont="menu" size="9"/>
|
||||||
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
<userDefinedRuntimeAttributes>
|
<connections>
|
||||||
<userDefinedRuntimeAttribute type="number" keyPath="fixedWidth">
|
<outlet property="delegate" destination="tSJ-3G-dnL" id="tWZ-Mw-jdD"/>
|
||||||
<real key="value" value="199"/>
|
</connections>
|
||||||
</userDefinedRuntimeAttribute>
|
</textField>
|
||||||
</userDefinedRuntimeAttributes>
|
<textField verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="rfY-Ds-j3c">
|
||||||
|
<rect key="frame" x="102" y="19" width="220" height="16"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<textFieldCell key="cell" controlSize="mini" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" id="glm-s6-df6">
|
||||||
|
<font key="font" metaFont="menu" size="9"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
<connections>
|
||||||
|
<outlet property="delegate" destination="tSJ-3G-dnL" id="IJL-eP-tCC"/>
|
||||||
|
</connections>
|
||||||
</textField>
|
</textField>
|
||||||
</subviews>
|
</subviews>
|
||||||
</view>
|
</view>
|
||||||
@ -595,7 +651,7 @@
|
|||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="hlk-UE-ZPw" id="7ZL-JE-fT7">
|
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="hlk-UE-ZPw" id="7ZL-JE-fT7">
|
||||||
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
<menu key="menu" id="zSa-aR-ghV">
|
<menu key="menu" id="zSa-aR-ghV">
|
||||||
<items>
|
<items>
|
||||||
<menuItem title="Item 1" state="on" id="hlk-UE-ZPw"/>
|
<menuItem title="Item 1" state="on" id="hlk-UE-ZPw"/>
|
||||||
@ -620,7 +676,7 @@
|
|||||||
<rect key="frame" x="18" y="94" width="306" height="14"/>
|
<rect key="frame" x="18" y="94" width="306" height="14"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="right" title="Startup Sound" id="Vif-FP-OaO">
|
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" alignment="right" title="Startup Sound" id="Vif-FP-OaO">
|
||||||
<font key="font" metaFont="message" size="11"/>
|
<font key="font" metaFont="label" size="11"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -634,7 +690,7 @@
|
|||||||
<rect key="frame" x="42" y="4" width="37" height="11"/>
|
<rect key="frame" x="42" y="4" width="37" height="11"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<textFieldCell key="cell" controlSize="mini" lineBreakMode="clipping" title="0%" id="vRT-SW-j4L">
|
<textFieldCell key="cell" controlSize="mini" lineBreakMode="clipping" title="0%" id="vRT-SW-j4L">
|
||||||
<font key="font" metaFont="label" size="9"/>
|
<font key="font" metaFont="menu" size="9"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -643,7 +699,7 @@
|
|||||||
<rect key="frame" x="18" y="25" width="306" height="14"/>
|
<rect key="frame" x="18" y="25" width="306" height="14"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" title="Volume level:" id="ebr-lB-pTD">
|
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" title="Volume level:" id="ebr-lB-pTD">
|
||||||
<font key="font" metaFont="message" size="11"/>
|
<font key="font" metaFont="label" size="11"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -652,7 +708,7 @@
|
|||||||
<rect key="frame" x="18" y="79" width="241" height="14"/>
|
<rect key="frame" x="18" y="79" width="241" height="14"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" title="Device:" id="sIi-by-bNC">
|
<textFieldCell key="cell" controlSize="small" lineBreakMode="clipping" title="Device:" id="sIi-by-bNC">
|
||||||
<font key="font" metaFont="message" size="11"/>
|
<font key="font" metaFont="label" size="11"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -661,7 +717,7 @@
|
|||||||
<rect key="frame" x="263" y="80" width="61" height="11"/>
|
<rect key="frame" x="263" y="80" width="61" height="11"/>
|
||||||
<autoresizingMask key="autoresizingMask"/>
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
<textFieldCell key="cell" controlSize="mini" lineBreakMode="clipping" alignment="right" title="r5102 +" id="JZg-ju-g1k">
|
<textFieldCell key="cell" controlSize="mini" lineBreakMode="clipping" alignment="right" title="r5102 +" id="JZg-ju-g1k">
|
||||||
<font key="font" metaFont="label" size="9"/>
|
<font key="font" metaFont="menu" size="9"/>
|
||||||
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
</textFieldCell>
|
</textFieldCell>
|
||||||
@ -675,7 +731,7 @@
|
|||||||
<rect key="frame" x="18" y="477" width="104" height="24"/>
|
<rect key="frame" x="18" y="477" width="104" height="24"/>
|
||||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
<segmentedCell key="cell" borderStyle="border" alignment="left" style="rounded" trackingMode="selectOne" id="dvq-Ib-bsz">
|
<segmentedCell key="cell" borderStyle="border" alignment="left" style="rounded" trackingMode="selectOne" id="dvq-Ib-bsz">
|
||||||
<font key="font" metaFont="system"/>
|
<font key="font" metaFont="label" size="13"/>
|
||||||
<segments>
|
<segments>
|
||||||
<segment width="32"/>
|
<segment width="32"/>
|
||||||
<segment width="32" selected="YES" tag="1"/>
|
<segment width="32" selected="YES" tag="1"/>
|
||||||
@ -726,6 +782,7 @@
|
|||||||
<outlet property="oemBoardIdField" destination="GcV-id-YTZ" id="yvt-rO-i17"/>
|
<outlet property="oemBoardIdField" destination="GcV-id-YTZ" id="yvt-rO-i17"/>
|
||||||
<outlet property="oemProductField" destination="Aad-0P-4R6" id="O85-Y0-ZXY"/>
|
<outlet property="oemProductField" destination="Aad-0P-4R6" id="O85-Y0-ZXY"/>
|
||||||
<outlet property="oemVendorField" destination="84n-SC-fET" id="UbL-NZ-faa"/>
|
<outlet property="oemVendorField" destination="84n-SC-fET" id="UbL-NZ-faa"/>
|
||||||
|
<outlet property="openThemeButton" destination="AzG-cL-pFW" id="U9N-0u-T2f"/>
|
||||||
<outlet property="progressBar" destination="DtR-XE-DfU" id="7sf-c8-y5u"/>
|
<outlet property="progressBar" destination="DtR-XE-DfU" id="7sf-c8-y5u"/>
|
||||||
<outlet property="runAtLoginButton" destination="g5h-bF-3le" id="tXL-6T-4Mj"/>
|
<outlet property="runAtLoginButton" destination="g5h-bF-3le" id="tXL-6T-4Mj"/>
|
||||||
<outlet property="snField" destination="0u3-c1-rfb" id="TUb-GS-mTb"/>
|
<outlet property="snField" destination="0u3-c1-rfb" id="TUb-GS-mTb"/>
|
||||||
@ -735,7 +792,9 @@
|
|||||||
<outlet property="tabViewFunc" destination="vwp-hc-6yE" id="gQE-Kf-hSJ"/>
|
<outlet property="tabViewFunc" destination="vwp-hc-6yE" id="gQE-Kf-hSJ"/>
|
||||||
<outlet property="tabViewFuncSelector" destination="4ox-0p-Q9L" id="Tes-Eu-6Tt"/>
|
<outlet property="tabViewFuncSelector" destination="4ox-0p-Q9L" id="Tes-Eu-6Tt"/>
|
||||||
<outlet property="tabViewInfo" destination="PGs-4a-XRc" id="ghG-r0-tYY"/>
|
<outlet property="tabViewInfo" destination="PGs-4a-XRc" id="ghG-r0-tYY"/>
|
||||||
<outlet property="themeField" destination="0Zs-Un-dNa" id="gHl-ys-oZv"/>
|
<outlet property="themeBox" destination="MMH-mb-fPM" id="2nx-c0-WqX"/>
|
||||||
|
<outlet property="themeRepoField" destination="2Va-F7-vYB" id="o15-c9-jRd"/>
|
||||||
|
<outlet property="themeUserField" destination="rfY-Ds-j3c" id="RNj-Rn-fsb"/>
|
||||||
<outlet property="timeIntervalPopUp" destination="1qf-uO-CvA" id="774-SY-GdB"/>
|
<outlet property="timeIntervalPopUp" destination="1qf-uO-CvA" id="774-SY-GdB"/>
|
||||||
<outlet property="unInstallDaemonButton" destination="MWn-i4-CYn" id="r2Y-WW-wd9"/>
|
<outlet property="unInstallDaemonButton" destination="MWn-i4-CYn" id="r2Y-WW-wd9"/>
|
||||||
<outlet property="unmountButton" destination="Zc5-Dl-jIh" id="5wb-ye-REX"/>
|
<outlet property="unmountButton" destination="Zc5-Dl-jIh" id="5wb-ye-REX"/>
|
||||||
|
@ -60,3 +60,106 @@ extension String {
|
|||||||
return UnsafePointer<UInt8>(buffer)
|
return UnsafePointer<UInt8>(buffer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
extension URL {
|
||||||
|
// https://stackoverflow.com/questions/38343186/write-extend-file-attributes-swift-example?answertab=active#tab-top
|
||||||
|
/// Get extended attribute.
|
||||||
|
func extendedAttribute(forName name: String) throws -> Data {
|
||||||
|
|
||||||
|
let data = try self.withUnsafeFileSystemRepresentation { fileSystemPath -> Data in
|
||||||
|
|
||||||
|
// Determine attribute size:
|
||||||
|
let length = getxattr(fileSystemPath, name, nil, 0, 0, 0)
|
||||||
|
guard length >= 0 else { throw URL.posixError(errno) }
|
||||||
|
|
||||||
|
// Create buffer with required size:
|
||||||
|
var data = Data(count: length)
|
||||||
|
|
||||||
|
// Retrieve attribute:
|
||||||
|
let result = data.withUnsafeMutableBytes { [count = data.count] in
|
||||||
|
getxattr(fileSystemPath, name, $0.baseAddress, count, 0, 0)
|
||||||
|
}
|
||||||
|
guard result >= 0 else { throw URL.posixError(errno) }
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
return data
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set extended attribute.
|
||||||
|
func setExtendedAttribute(data: Data, forName name: String) throws {
|
||||||
|
|
||||||
|
try self.withUnsafeFileSystemRepresentation { fileSystemPath in
|
||||||
|
let result = data.withUnsafeBytes {
|
||||||
|
setxattr(fileSystemPath, name, $0.baseAddress, data.count, 0, 0)
|
||||||
|
}
|
||||||
|
guard result >= 0 else { throw URL.posixError(errno) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove extended attribute.
|
||||||
|
func removeExtendedAttribute(forName name: String) throws {
|
||||||
|
|
||||||
|
try self.withUnsafeFileSystemRepresentation { fileSystemPath in
|
||||||
|
let result = removexattr(fileSystemPath, name, 0)
|
||||||
|
guard result >= 0 else { throw URL.posixError(errno) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get list of all extended attributes.
|
||||||
|
func listExtendedAttributes() throws -> [String] {
|
||||||
|
|
||||||
|
let list = try self.withUnsafeFileSystemRepresentation { fileSystemPath -> [String] in
|
||||||
|
let length = listxattr(fileSystemPath, nil, 0, 0)
|
||||||
|
guard length >= 0 else { throw URL.posixError(errno) }
|
||||||
|
|
||||||
|
// Create buffer with required size:
|
||||||
|
var namebuf = Array<CChar>(repeating: 0, count: length)
|
||||||
|
|
||||||
|
// Retrieve attribute list:
|
||||||
|
let result = listxattr(fileSystemPath, &namebuf, namebuf.count, 0)
|
||||||
|
guard result >= 0 else { throw URL.posixError(errno) }
|
||||||
|
|
||||||
|
// Extract attribute names:
|
||||||
|
let list = namebuf.split(separator: 0).compactMap {
|
||||||
|
$0.withUnsafeBufferPointer {
|
||||||
|
$0.withMemoryRebound(to: UInt8.self) {
|
||||||
|
String(bytes: $0, encoding: .utf8)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
return list
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Helper function to create an NSError from a Unix errno.
|
||||||
|
private static func posixError(_ err: Int32) -> NSError {
|
||||||
|
return NSError(domain: NSPOSIXErrorDomain, code: Int(err),
|
||||||
|
userInfo: [NSLocalizedDescriptionKey: String(cString: strerror(err))])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
extension io_object_t {
|
||||||
|
/// - Returns: The device's name.
|
||||||
|
func name() -> String? {
|
||||||
|
let buf = UnsafeMutablePointer<io_name_t>.allocate(capacity: 1)
|
||||||
|
defer { buf.deallocate() }
|
||||||
|
return buf.withMemoryRebound(to: CChar.self, capacity: MemoryLayout<io_name_t>.size) {
|
||||||
|
if IORegistryEntryGetName(self, $0) == KERN_SUCCESS {
|
||||||
|
return String(cString: $0)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func info() -> NSDictionary? {
|
||||||
|
var serviceDictionary : Unmanaged<CFMutableDictionary>?
|
||||||
|
if IORegistryEntryCreateCFProperties(self, &serviceDictionary, kCFAllocatorDefault, 0) == KERN_SUCCESS {
|
||||||
|
if let info : NSDictionary = serviceDictionary?.takeRetainedValue() {
|
||||||
|
return info
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -43,9 +43,9 @@ func getFirmawareVendor() -> String? {
|
|||||||
cleanedData.append(data[i])
|
cleanedData.append(data[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cleanedData.append(0x00)
|
|
||||||
return String(bytes: cleanedData, encoding: .utf8)
|
return String(bytes: cleanedData, encoding: .utf8)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,7 +80,9 @@ func getOEMVendor() -> String? {
|
|||||||
if let data = getEFIPlatform()?.object(forKey: "OEMVendor") as? Data {
|
if let data = getEFIPlatform()?.object(forKey: "OEMVendor") as? Data {
|
||||||
return String(bytes: data, encoding: .utf8)
|
return String(bytes: data, encoding: .utf8)
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
let ockey = "4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102:oem-vendor"
|
||||||
|
return getNVRAM(variable: ockey)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get OEMProduct string.
|
/// Get OEMProduct string.
|
||||||
@ -88,7 +90,9 @@ func getOEMProduct() -> String? {
|
|||||||
if let data = getEFIPlatform()?.object(forKey: "OEMProduct") as? Data {
|
if let data = getEFIPlatform()?.object(forKey: "OEMProduct") as? Data {
|
||||||
return String(bytes: data, encoding: .utf8)
|
return String(bytes: data, encoding: .utf8)
|
||||||
}
|
}
|
||||||
return nil
|
|
||||||
|
let ockey = "4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102:oem-product"
|
||||||
|
return getNVRAM(variable: ockey)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get OEMBoard string.
|
/// Get OEMBoard string.
|
||||||
@ -96,6 +100,63 @@ func getOEMBoard() -> String? {
|
|||||||
if let data = getEFIPlatform()?.object(forKey: "OEMBoard") as? Data {
|
if let data = getEFIPlatform()?.object(forKey: "OEMBoard") as? Data {
|
||||||
return String(bytes: data, encoding: .utf8)
|
return String(bytes: data, encoding: .utf8)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let ockey = "4D1FDA02-38C7-4A6A-9CC6-4BCCA8B30102:oem-board"
|
||||||
|
return getNVRAM(variable: ockey)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get OEMVendor Short string.
|
||||||
|
func getOEMVendorShort() -> String? {
|
||||||
|
if let vendor = getOEMVendor() {
|
||||||
|
switch vendor {
|
||||||
|
case "ASRock": fallthrough
|
||||||
|
case "Alienware": fallthrough
|
||||||
|
case "ECS": fallthrough
|
||||||
|
case "EVGA": fallthrough
|
||||||
|
case "FUJITSU": fallthrough
|
||||||
|
case "IBM": fallthrough
|
||||||
|
case "Intel": fallthrough
|
||||||
|
case "Shuttle": fallthrough
|
||||||
|
case "TOSHIBA": fallthrough
|
||||||
|
case "XFX":
|
||||||
|
return vendor
|
||||||
|
case "Apple Inc.":
|
||||||
|
return "Apple"
|
||||||
|
case "ASUSTeK Computer INC.": fallthrough
|
||||||
|
case "ASUSTeK COMPUTER INC.":
|
||||||
|
return "ASUS"
|
||||||
|
case "Dell Inc.":
|
||||||
|
return "Dell"
|
||||||
|
case "DFI": fallthrough
|
||||||
|
case "DFI Inc.":
|
||||||
|
return "DFI"
|
||||||
|
case "EPoX COMPUTER CO., LTD":
|
||||||
|
return "EPoX"
|
||||||
|
case "First International Computer, Inc.":
|
||||||
|
return "FIC"
|
||||||
|
case "FUJITSU SIEMENS":
|
||||||
|
return "FUJITSU"
|
||||||
|
case "Gigabyte Technology Co., Ltd.":
|
||||||
|
return "Gigabyte"
|
||||||
|
case "Hewlett-Packard":
|
||||||
|
return "HP"
|
||||||
|
case "Intel Corp.": fallthrough
|
||||||
|
case "Intel Corporation": fallthrough
|
||||||
|
case "INTEL Corporation":
|
||||||
|
return "Intel"
|
||||||
|
case "Lenovo": fallthrough
|
||||||
|
case "LENOVO":
|
||||||
|
return "Lenovo"
|
||||||
|
case "Micro-Star International": fallthrough
|
||||||
|
case "MICRO-STAR INTERNATIONAL CO., LTD": fallthrough
|
||||||
|
case "MICRO-STAR INTERNATIONAL CO.,LTD": fallthrough
|
||||||
|
case "MSI":
|
||||||
|
return "MSI"
|
||||||
|
case "To be filled by O.E.M.": break
|
||||||
|
default:
|
||||||
|
return vendor
|
||||||
|
}
|
||||||
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -108,7 +169,6 @@ func getSystemSerialNumber() -> String? {
|
|||||||
cleanedData.append(data[i])
|
cleanedData.append(data[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cleanedData.append(0x00)
|
|
||||||
return String(bytes: cleanedData, encoding: .utf8)
|
return String(bytes: cleanedData, encoding: .utf8)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -123,7 +183,6 @@ func getEFIModel() -> String? {
|
|||||||
cleanedData.append(data[i])
|
cleanedData.append(data[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cleanedData.append(0x00)
|
|
||||||
return String(bytes: cleanedData, encoding: .utf8)
|
return String(bytes: cleanedData, encoding: .utf8)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -138,7 +197,6 @@ func getEFIBoardID() -> String? {
|
|||||||
cleanedData.append(data[i])
|
cleanedData.append(data[i])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cleanedData.append(0x00)
|
|
||||||
return String(bytes: cleanedData, encoding: .utf8)
|
return String(bytes: cleanedData, encoding: .utf8)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
@ -159,3 +217,49 @@ func isLegacyFirmware() -> Bool {
|
|||||||
|
|
||||||
return !isUEFI
|
return !isUEFI
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the property value from the given IOService dictionary. You’re responsible for releasing the result (if not transferred to Swift objects).
|
||||||
|
func IOServiceGetPropertyFrom(matching name: String, property: String) -> Any? {
|
||||||
|
var obj : Any? = nil
|
||||||
|
var iter : io_iterator_t = 0
|
||||||
|
var rl : uint32 = 0
|
||||||
|
|
||||||
|
var result : kern_return_t = IORegistryCreateIterator(kIOMasterPortDefault,
|
||||||
|
kIOServicePlane,
|
||||||
|
0,
|
||||||
|
&iter)
|
||||||
|
|
||||||
|
if result == KERN_SUCCESS && iter != 0 {
|
||||||
|
var entry : io_object_t
|
||||||
|
repeat {
|
||||||
|
|
||||||
|
entry = IOIteratorNext(iter)
|
||||||
|
if entry != IO_OBJECT_NULL {
|
||||||
|
if entry.name() == name {
|
||||||
|
let ref = IORegistryEntryCreateCFProperty(entry,
|
||||||
|
property as CFString,
|
||||||
|
kCFAllocatorDefault,
|
||||||
|
0)
|
||||||
|
if ref != nil {
|
||||||
|
obj = ref!.takeRetainedValue()
|
||||||
|
IOObjectRelease(entry)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rl += 1
|
||||||
|
result = IORegistryIteratorEnterEntry(iter)
|
||||||
|
} else {
|
||||||
|
if rl == 0 {
|
||||||
|
IOObjectRelease(entry)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
result = IORegistryIteratorExitEntry(iter)
|
||||||
|
rl -= 1
|
||||||
|
}
|
||||||
|
} while (true)
|
||||||
|
IOObjectRelease(iter)
|
||||||
|
}
|
||||||
|
|
||||||
|
return obj
|
||||||
|
}
|
||||||
|
@ -37,6 +37,43 @@ func getNVRAM() -> NSMutableDictionary? {
|
|||||||
return dict?.takeRetainedValue()
|
return dict?.takeRetainedValue()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get a single nvram variable
|
||||||
|
func getNVRAM(variable name: String) -> String? {
|
||||||
|
var value : String? = nil
|
||||||
|
var ref: io_registry_entry_t
|
||||||
|
var masterPort = mach_port_t()
|
||||||
|
var oResult: kern_return_t
|
||||||
|
oResult = IOMasterPort(bootstrap_port, &masterPort)
|
||||||
|
|
||||||
|
if oResult != KERN_SUCCESS {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
ref = IORegistryEntryFromPath(masterPort, "IODeviceTree:/options")
|
||||||
|
if ref == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
let vref = IORegistryEntryCreateCFProperty(ref,
|
||||||
|
name as CFString,
|
||||||
|
kCFAllocatorDefault, 0)
|
||||||
|
if (vref != nil) {
|
||||||
|
let data = vref?.takeRetainedValue() as! Data
|
||||||
|
var cleanedData = Data()
|
||||||
|
for i in 0..<data.count {
|
||||||
|
if data[i] != 0x00 {
|
||||||
|
cleanedData.append(data[i])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
value = String(bytes: cleanedData, encoding: .utf8)
|
||||||
|
}
|
||||||
|
|
||||||
|
IOObjectRelease(ref)
|
||||||
|
|
||||||
|
return value
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: set NVRAM key
|
// MARK: set NVRAM key
|
||||||
func setNVRAM(key: String, stringValue: String) {
|
func setNVRAM(key: String, stringValue: String) {
|
||||||
var cmd : String = "do shell script \""
|
var cmd : String = "do shell script \""
|
||||||
|
@ -19,7 +19,6 @@ class LITabView: NSTabView {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class SoundSlider : NSSlider {
|
class SoundSlider : NSSlider {
|
||||||
var field : NSTextField?
|
var field : NSTextField?
|
||||||
}
|
}
|
||||||
@ -51,7 +50,10 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD
|
|||||||
@IBOutlet var autoMountButton : NSButton!
|
@IBOutlet var autoMountButton : NSButton!
|
||||||
@IBOutlet var unmountButton : NSButton!
|
@IBOutlet var unmountButton : NSButton!
|
||||||
// tab 1
|
// tab 1
|
||||||
@IBOutlet var themeField : FWTextField!
|
@IBOutlet var themeBox : NSComboBox!
|
||||||
|
@IBOutlet var openThemeButton : NSButton!
|
||||||
|
@IBOutlet var themeUserField : NSTextField!
|
||||||
|
@IBOutlet var themeRepoField : NSTextField!
|
||||||
// tab 2
|
// tab 2
|
||||||
@IBOutlet var soundDevicePopUp : NSPopUpButton!
|
@IBOutlet var soundDevicePopUp : NSPopUpButton!
|
||||||
@IBOutlet var soundVolumeSlider : SoundSlider!
|
@IBOutlet var soundVolumeSlider : SoundSlider!
|
||||||
@ -89,8 +91,6 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD
|
|||||||
|
|
||||||
var loaded : Bool = false
|
var loaded : Bool = false
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
override func awakeFromNib() {
|
override func awakeFromNib() {
|
||||||
super.awakeFromNib()
|
super.awakeFromNib()
|
||||||
if !self.loaded {
|
if !self.loaded {
|
||||||
@ -121,7 +121,38 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD
|
|||||||
self.tabViewFuncSelector.selectSegment(withTag: 0)
|
self.tabViewFuncSelector.selectSegment(withTag: 0)
|
||||||
self.tabViewFunc.selectTabViewItem(at: 0)
|
self.tabViewFunc.selectTabViewItem(at: 0)
|
||||||
|
|
||||||
self.themeField.delegate = self
|
AppSD.themeUser = UDs.string(forKey: kThemeUserKey) ?? kDefaultThemeUser
|
||||||
|
AppSD.themeRepo = UDs.string(forKey: kThemeRepoKey) ?? kDefaultThemeRepo
|
||||||
|
|
||||||
|
self.themeUserField.stringValue = AppSD.themeUser
|
||||||
|
self.themeRepoField.stringValue = AppSD.themeRepo
|
||||||
|
|
||||||
|
if #available(OSX 10.10, *) {
|
||||||
|
self.themeUserField.placeholderString = kDefaultThemeUser
|
||||||
|
self.themeRepoField.placeholderString = kDefaultThemeRepo
|
||||||
|
}
|
||||||
|
|
||||||
|
self.themeBox.removeAllItems()
|
||||||
|
let themeManagerIndexDir = NSHomeDirectory().addPath("Library/Application Support/CloverApp/Themeindex/\(AppSD.themeUser)_\(AppSD.themeRepo)")
|
||||||
|
|
||||||
|
let tm = ThemeManager(user: AppSD.themeUser,
|
||||||
|
repo: AppSD.themeRepo,
|
||||||
|
basePath: themeManagerIndexDir,
|
||||||
|
indexDir: themeManagerIndexDir,
|
||||||
|
delegate: nil)
|
||||||
|
|
||||||
|
let indexedThemes = tm.getIndexedThemes()
|
||||||
|
self.themeBox.addItems(withObjectValues: indexedThemes)
|
||||||
|
|
||||||
|
if indexedThemes.contains("embedded") {
|
||||||
|
self.themeBox.addItem(withObjectValue: "embedded")
|
||||||
|
}
|
||||||
|
|
||||||
|
if indexedThemes.contains("random") {
|
||||||
|
self.themeBox.addItem(withObjectValue: "random")
|
||||||
|
}
|
||||||
|
|
||||||
|
self.themeBox.completes = true
|
||||||
|
|
||||||
self.soundVolumeSlider.field = self.soundVolumeField
|
self.soundVolumeSlider.field = self.soundVolumeField
|
||||||
self.soundVolumeField.stringValue = kNotAvailable.locale
|
self.soundVolumeField.stringValue = kNotAvailable.locale
|
||||||
@ -170,10 +201,10 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD
|
|||||||
var nvdata = nvram?.object(forKey: "Clover.Theme") as? Data
|
var nvdata = nvram?.object(forKey: "Clover.Theme") as? Data
|
||||||
|
|
||||||
if #available(OSX 10.10, *) {
|
if #available(OSX 10.10, *) {
|
||||||
self.themeField.placeholderString = kNotAvailable.locale
|
self.themeBox.placeholderString = "NVRAM"
|
||||||
}
|
}
|
||||||
self.themeField.stringValue = (nvdata != nil) ? String(decoding: nvdata!, as: UTF8.self) : ""
|
self.themeBox.stringValue = (nvdata != nil) ? String(decoding: nvdata!, as: UTF8.self) : ""
|
||||||
self.themeField.cell?.representedObject = self.themeField.stringValue
|
self.themeBox.cell?.representedObject = self.themeBox.stringValue
|
||||||
|
|
||||||
nvdata = nvram?.object(forKey: "Clover.RootRW") as? Data
|
nvdata = nvram?.object(forKey: "Clover.RootRW") as? Data
|
||||||
var value : String = String(decoding: nvdata ?? Data(), as: UTF8.self)
|
var value : String = String(decoding: nvdata ?? Data(), as: UTF8.self)
|
||||||
@ -487,6 +518,52 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: Controls actions
|
// MARK: Controls actions
|
||||||
|
@IBAction func openThemeManager(_ sender: NSButton!) {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
if #available(OSX 10.11, *) {
|
||||||
|
if (AppSD.themeManagerWC == nil) {
|
||||||
|
AppSD.themeManagerWC = ThemeManagerWC.loadFromNib()
|
||||||
|
}
|
||||||
|
|
||||||
|
AppSD.themeManagerWC?.showWindow(self)
|
||||||
|
} else {
|
||||||
|
if (AppSD.themeManagerWC == nil) {
|
||||||
|
AppSD.themeManagerWC = ThemeManagerWC.loadFromNib()
|
||||||
|
}
|
||||||
|
|
||||||
|
AppSD.themeManagerWC?.showWindow(self)
|
||||||
|
}
|
||||||
|
NSApp.activate(ignoringOtherApps: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func controlTextDidEndEditing(_ obj: Notification) {
|
||||||
|
var updateThemeRepo = false
|
||||||
|
if let field = obj.object as? NSTextField {
|
||||||
|
|
||||||
|
if field == self.themeUserField {
|
||||||
|
if field.stringValue.count > 0 {
|
||||||
|
UDs.set(field.stringValue, forKey: kThemeUserKey)
|
||||||
|
} else {
|
||||||
|
UDs.set(kDefaultThemeUser, forKey: kThemeUserKey)
|
||||||
|
}
|
||||||
|
updateThemeRepo = true
|
||||||
|
} else if field == self.themeRepoField {
|
||||||
|
if field.stringValue.count > 0 {
|
||||||
|
UDs.set(field.stringValue, forKey: kThemeRepoKey)
|
||||||
|
} else {
|
||||||
|
UDs.set(kDefaultThemeRepo, forKey: kThemeRepoKey)
|
||||||
|
}
|
||||||
|
updateThemeRepo = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if updateThemeRepo {
|
||||||
|
AppSD.themeUser = UDs.string(forKey: kThemeUserKey) ?? kDefaultThemeUser
|
||||||
|
AppSD.themeRepo = UDs.string(forKey: kThemeRepoKey) ?? kDefaultThemeRepo
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@IBAction func installClover(_ sender: NSButton!) {
|
@IBAction func installClover(_ sender: NSButton!) {
|
||||||
|
|
||||||
let myPath = Bundle.main.bundlePath.lowercased()
|
let myPath = Bundle.main.bundlePath.lowercased()
|
||||||
@ -635,28 +712,30 @@ class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionD
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MARK: NVRAM editing
|
// MARK: NVRAM editing
|
||||||
func controlTextDidEndEditing(_ obj: Notification) {
|
@IBAction func themeBoxSelected(_ sender: NSComboBox!) {
|
||||||
if let field = obj.object as? NSTextField {
|
let key = "Clover.Theme"
|
||||||
let delete : Bool = field.stringValue.count == 0
|
if let old = sender.cell?.representedObject as? String {
|
||||||
if field == self.themeField {
|
let theme = sender.stringValue
|
||||||
if let old = field.cell?.representedObject as? String {
|
if old != theme {
|
||||||
let key = "Clover.Theme"
|
if theme.count == 0 {
|
||||||
if old != field.stringValue {
|
deleteNVRAM(key: key)
|
||||||
if delete {
|
} else {
|
||||||
deleteNVRAM(key: key)
|
setNVRAM(key: key, stringValue: theme)
|
||||||
} else {
|
|
||||||
setNVRAM(key: key, stringValue: field.stringValue/*, error: &error*/)
|
|
||||||
}
|
|
||||||
|
|
||||||
let nvdata = getNVRAM()?.object(forKey: key) as? Data
|
|
||||||
field.stringValue = (nvdata != nil) ? String(decoding: nvdata!, as: UTF8.self) : ""
|
|
||||||
field.cell?.representedObject = field.stringValue
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 4.0) {
|
||||||
|
var value = ""
|
||||||
|
if let nvram = getNVRAM() {
|
||||||
|
let nvdata = nvram.object(forKey: key) as? Data
|
||||||
|
value = String(decoding: nvdata ?? Data(), as: UTF8.self)
|
||||||
|
}
|
||||||
|
sender.stringValue = value
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@IBAction func soundSliderDidMove(_ sender: SoundSlider!) {
|
@IBAction func soundSliderDidMove(_ sender: SoundSlider!) {
|
||||||
sender.field?.stringValue = "\(Int(sender.doubleValue))%"
|
sender.field?.stringValue = "\(Int(sender.doubleValue))%"
|
||||||
|
|
||||||
@ -1139,13 +1218,7 @@ class SettingsWindowController: NSWindowController, NSWindowDelegate {
|
|||||||
self.viewController = newValue
|
self.viewController = newValue
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
class func loadFromStoryBoard() -> SettingsWindowController {
|
|
||||||
let wc = NSStoryboard(name: "Settings",
|
|
||||||
bundle: nil).instantiateController(withIdentifier: "SettingsWindowController") as! SettingsWindowController
|
|
||||||
return wc
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
class func loadFromNib() -> SettingsWindowController? {
|
class func loadFromNib() -> SettingsWindowController? {
|
||||||
var topLevel: NSArray? = nil
|
var topLevel: NSArray? = nil
|
||||||
Bundle.main.loadNibNamed("Settings", owner: self, topLevelObjects: &topLevel)
|
Bundle.main.loadNibNamed("Settings", owner: self, topLevelObjects: &topLevel)
|
||||||
|
477
CloverApp/Clover/ThemeManager/ThemeManager.swift
Normal file
477
CloverApp/Clover/ThemeManager/ThemeManager.swift
Normal file
@ -0,0 +1,477 @@
|
|||||||
|
//
|
||||||
|
// ThemeManager.swift
|
||||||
|
// ThemeManager
|
||||||
|
//
|
||||||
|
// Created by vector sigma on 04/01/2020.
|
||||||
|
// Copyright © 2020 vectorsigma. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
|
||||||
|
let kThemeUserKey = "themeUser"
|
||||||
|
let kThemeRepoKey = "themeRepo"
|
||||||
|
|
||||||
|
let kDefaultThemeUser = "CloverHackyColor" // CloverHackyColor
|
||||||
|
let kDefaultThemeRepo = "CloverThemes"
|
||||||
|
|
||||||
|
enum ThemeDownload {
|
||||||
|
case indexOnly
|
||||||
|
case thumbnail
|
||||||
|
case complete
|
||||||
|
}
|
||||||
|
|
||||||
|
let kCloverThemeAttributeKey = "org.cloverTheme.sha"
|
||||||
|
|
||||||
|
class ThemeManager: NSObject, URLSessionDataDelegate {
|
||||||
|
var delegate : ThemeManagerVC?
|
||||||
|
private var user : String
|
||||||
|
private var repo : String
|
||||||
|
var basePath : String
|
||||||
|
private var urlBaseStr : String
|
||||||
|
private var themeManagerIndexDir : String
|
||||||
|
|
||||||
|
let userAgent = "Clover"
|
||||||
|
|
||||||
|
required init(user: String, repo: String,
|
||||||
|
basePath: String,
|
||||||
|
indexDir : String,
|
||||||
|
delegate: ThemeManagerVC?) {
|
||||||
|
self.user = user
|
||||||
|
self.repo = repo
|
||||||
|
self.basePath = basePath
|
||||||
|
self.urlBaseStr = "https://api.github.com/repos/\(user)/\(repo)/git/trees/master?recursive=1"
|
||||||
|
self.themeManagerIndexDir = indexDir
|
||||||
|
self.delegate = delegate
|
||||||
|
if !fm.fileExists(atPath: self.themeManagerIndexDir) {
|
||||||
|
try? fm.createDirectory(atPath: self.themeManagerIndexDir,
|
||||||
|
withIntermediateDirectories: true,
|
||||||
|
attributes: nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getIndexedThemes() -> [String] {
|
||||||
|
var themes = [String]()
|
||||||
|
if self.getSha() != nil {
|
||||||
|
let themesIndexPath = self.themeManagerIndexDir.addPath("Themes")
|
||||||
|
if let files = try? fm.contentsOfDirectory(atPath: themesIndexPath) {
|
||||||
|
for f in files {
|
||||||
|
let theme = f.deletingFileExtension
|
||||||
|
let ext = f.fileExtension
|
||||||
|
if ext == "plist" {
|
||||||
|
themes.append(theme)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return themes.sorted()
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getThemes(completion: @escaping ([String]) -> ()) {
|
||||||
|
var themes = [String]()
|
||||||
|
let themesIndexPath = self.themeManagerIndexDir.addPath("Themes")
|
||||||
|
|
||||||
|
self.getInfo(urlString: urlBaseStr) { (success) in
|
||||||
|
|
||||||
|
do {
|
||||||
|
let files = try fm.contentsOfDirectory(atPath: themesIndexPath)
|
||||||
|
for f in files {
|
||||||
|
let theme = f.deletingFileExtension
|
||||||
|
let ext = f.fileExtension
|
||||||
|
if ext == "plist" {
|
||||||
|
themes.append(theme)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
completion(themes)
|
||||||
|
} catch {
|
||||||
|
completion(themes)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the sha string only if the sha exist, and only if Themes directory exists.
|
||||||
|
func getSha() -> String? {
|
||||||
|
var sha : String? = nil
|
||||||
|
let themesPath = "\(self.themeManagerIndexDir)/Themes"
|
||||||
|
let shaPath = "\(self.themeManagerIndexDir)/sha"
|
||||||
|
|
||||||
|
if fm.fileExists(atPath: themesPath) && fm.fileExists(atPath: shaPath) {
|
||||||
|
if let data = try? Data(contentsOf: URL(fileURLWithPath: shaPath)) {
|
||||||
|
sha = String(data: data, encoding: .utf8)
|
||||||
|
if ((sha != nil) && (sha!.count < 40)) {
|
||||||
|
sha = nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sha
|
||||||
|
}
|
||||||
|
|
||||||
|
private func normalize(_ url: String) -> String {
|
||||||
|
if (url.range(of: " ") != nil) {
|
||||||
|
return url.replacingOccurrences(of: " ", with: "%20")
|
||||||
|
}
|
||||||
|
return url
|
||||||
|
}
|
||||||
|
|
||||||
|
private func downloadloadFile(at url: String, dst: String,
|
||||||
|
completion: @escaping (Bool) -> ()) {
|
||||||
|
if let validURL = URL(string: self.normalize(url)) {
|
||||||
|
let upperDir = dst.deletingLastPath
|
||||||
|
if !fm.fileExists(atPath: upperDir) {
|
||||||
|
do {
|
||||||
|
try fm.createDirectory(atPath: upperDir,
|
||||||
|
withIntermediateDirectories: true,
|
||||||
|
attributes: nil)
|
||||||
|
} catch {
|
||||||
|
print("DF1, \(error)")
|
||||||
|
completion(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var request = URLRequest(url: validURL)
|
||||||
|
request.httpMethod = "GET"
|
||||||
|
request.setValue(userAgent, forHTTPHeaderField: "User-Agent")
|
||||||
|
|
||||||
|
let config = URLSessionConfiguration.ephemeral
|
||||||
|
let session = URLSession(configuration: config)
|
||||||
|
|
||||||
|
let task = session.dataTask(with: request, completionHandler: {(d, r, e) in
|
||||||
|
if (e != nil) {
|
||||||
|
print("DF2, \(e!)")
|
||||||
|
completion(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
guard let data = d else {
|
||||||
|
print("DF3, Error: no datas.")
|
||||||
|
completion(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
do {
|
||||||
|
try data.write(to: URL(fileURLWithPath: dst))
|
||||||
|
completion(true)
|
||||||
|
} catch {
|
||||||
|
print("DF4, \(error)")
|
||||||
|
completion(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
task.resume()
|
||||||
|
|
||||||
|
} else {
|
||||||
|
print("DF5, Error: invalid url '\(url)'.")
|
||||||
|
completion(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private func getInfo(urlString: String, completion: @escaping (Bool) -> ()) {
|
||||||
|
if let url = URL(string: self.normalize(urlString)) {
|
||||||
|
var request = URLRequest(url: url)
|
||||||
|
request.httpMethod = "GET"
|
||||||
|
request.setValue("application/json; charset=utf-8", forHTTPHeaderField: "Content-Type")
|
||||||
|
request.setValue(userAgent, forHTTPHeaderField: "User-Agent")
|
||||||
|
let config = URLSessionConfiguration.ephemeral
|
||||||
|
let session = URLSession(configuration: config)
|
||||||
|
|
||||||
|
let task = session.dataTask(with: request, completionHandler: {(d, r, e) in
|
||||||
|
if (e != nil) {
|
||||||
|
print("GI1, \(e!)")
|
||||||
|
completion(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let data = d else {
|
||||||
|
print("GI2, no data.")
|
||||||
|
completion(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let utf8 = String(decoding: data, as: UTF8.self).data(using: .utf8) else {
|
||||||
|
print("GI3, data is not utf8.")
|
||||||
|
completion(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
let json = try JSONSerialization.jsonObject(with: utf8, options: .mutableContainers)
|
||||||
|
|
||||||
|
if let jdict = json as? [String: Any] {
|
||||||
|
guard let truncated = jdict["truncated"] as? Bool else {
|
||||||
|
print("GI4, Error: 'truncated' key not found")
|
||||||
|
completion(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if truncated == true {
|
||||||
|
print("GI4, Error: json has truncated list.")
|
||||||
|
completion(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let sha = jdict["sha"] as? String else {
|
||||||
|
print("GI4, Error: 'sha' key not found")
|
||||||
|
completion(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if sha == self.getSha() {
|
||||||
|
// we're done because we already have all the files needed
|
||||||
|
completion(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let tree = jdict["tree"] as? [[String: Any]] else {
|
||||||
|
print("GI4, Error: 'tree' key not found, or not an array.")
|
||||||
|
completion(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let shaPath = "\(self.themeManagerIndexDir)/\(sha)"
|
||||||
|
|
||||||
|
do {
|
||||||
|
if !fm.fileExists(atPath: shaPath) {
|
||||||
|
try fm.createDirectory(atPath: shaPath, withIntermediateDirectories: true, attributes: nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
print("GI5, Error: can't write sha commit.")
|
||||||
|
completion(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for obj in tree {
|
||||||
|
/*
|
||||||
|
"path": ".gitignore",
|
||||||
|
"mode": "100644",
|
||||||
|
"type": "blob",
|
||||||
|
"sha": "e43b0f988953ae3a84b00331d0ccf5f7d51cb3cf",
|
||||||
|
"size": 10,
|
||||||
|
"url": "https://api.github.com/repos/vectorsigma72/CloverThemes/git/blobs/e43b0f988953ae3a84b00331d0ccf5f7d51cb3cf"
|
||||||
|
*/
|
||||||
|
|
||||||
|
guard let type = obj["type"] as? String else {
|
||||||
|
print("GI6, Error: 'type' key not found")
|
||||||
|
completion(false)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if let path = obj["path"] as? String {
|
||||||
|
|
||||||
|
if !path.hasPrefix(".") && type == "blob" { // .gitignore, .DS_Store
|
||||||
|
let themeName = path.components(separatedBy: "/")[0]
|
||||||
|
let plistPath = "\(self.themeManagerIndexDir)/\(sha)/\(themeName).plist"
|
||||||
|
let theme = NSMutableArray(contentsOfFile: plistPath) ?? NSMutableArray()
|
||||||
|
if !theme.contains(path) {
|
||||||
|
theme.add(path)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if !theme.write(toFile: plistPath, atomically: false) {
|
||||||
|
print("GI7, Error: 'path' key not found.")
|
||||||
|
completion(false)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
print("GI8, Error: 'path' key not found.")
|
||||||
|
completion(false)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// move temp files in standard position
|
||||||
|
do {
|
||||||
|
try sha.write(toFile: "\(self.themeManagerIndexDir)/sha", atomically: true, encoding: .utf8)
|
||||||
|
if fm.fileExists(atPath: "\(self.themeManagerIndexDir)/Themes") {
|
||||||
|
try fm.removeItem(atPath: "\(self.themeManagerIndexDir)/Themes")
|
||||||
|
}
|
||||||
|
try fm.moveItem(atPath: shaPath, toPath: "\(self.themeManagerIndexDir)/Themes")
|
||||||
|
self.removeOld(new: sha)
|
||||||
|
completion(true)
|
||||||
|
} catch {
|
||||||
|
print("GI9, \(error)")
|
||||||
|
completion(false)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
//remove old themes (old sha)
|
||||||
|
} else {
|
||||||
|
print("GI10, json is not a dictionary (API change?).")
|
||||||
|
completion(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch {
|
||||||
|
print("GI11, \(error)")
|
||||||
|
completion(false)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
task.resume()
|
||||||
|
} else {
|
||||||
|
print("GI12, \(urlString) is invalid.")
|
||||||
|
completion(false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove old thumbnails from old sha commits
|
||||||
|
private func removeOld(new sha: String) {
|
||||||
|
do {
|
||||||
|
let contents : [String] = try fm.contentsOfDirectory(atPath: self.themeManagerIndexDir)
|
||||||
|
for c in contents {
|
||||||
|
if c != "sha" && c != "Themes" && c != sha {
|
||||||
|
try fm.removeItem(atPath: "\(self.themeManagerIndexDir)/\(c)")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch { }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the path for a given theme, if the download succeded
|
||||||
|
public func download(theme: String, down: ThemeDownload, completion: @escaping (String?) -> ()) {
|
||||||
|
if let sha = getSha() {
|
||||||
|
let shaPath = self.basePath.addPath(sha)
|
||||||
|
let themeDest = (down == .complete)
|
||||||
|
? self.themeManagerIndexDir.addPath("Downloads").addPath(theme)
|
||||||
|
: shaPath.addPath(theme)
|
||||||
|
|
||||||
|
if (down != .complete) && fm.fileExists(atPath: themeDest) {
|
||||||
|
completion(themeDest)
|
||||||
|
} else {
|
||||||
|
if !fm.fileExists(atPath: themeDest) {
|
||||||
|
do {
|
||||||
|
try fm.createDirectory(atPath: themeDest,
|
||||||
|
withIntermediateDirectories: true,
|
||||||
|
attributes: nil)
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
|
||||||
|
let plistPath = "\(themeManagerIndexDir)/Themes/\(theme).plist"
|
||||||
|
|
||||||
|
if let files = NSArray(contentsOfFile: plistPath) as? [String] {
|
||||||
|
let fc = files.count
|
||||||
|
if fc > 0 {
|
||||||
|
var broken = false
|
||||||
|
let dg = DispatchGroup()
|
||||||
|
for i in 0..<fc {
|
||||||
|
dg.enter()
|
||||||
|
if broken {
|
||||||
|
dg.leave()
|
||||||
|
break
|
||||||
|
} else {
|
||||||
|
let file = files[i]
|
||||||
|
// build the url
|
||||||
|
let furl = "https://github.com/\(self.user)/\(self.repo)/raw/master/\(file)"
|
||||||
|
|
||||||
|
if down == .thumbnail {
|
||||||
|
if file != theme.addPath("screenshot.png")
|
||||||
|
&& file != theme.addPath("theme.svg")
|
||||||
|
&& file != theme.addPath("theme.plist") {
|
||||||
|
dg.leave()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let filedest = (down == .complete)
|
||||||
|
? themeDest.deletingLastPath.addPath(file)
|
||||||
|
: shaPath.addPath(file)
|
||||||
|
|
||||||
|
if !fm.fileExists(atPath: filedest) {
|
||||||
|
self.downloadloadFile(at: self.normalize(furl), dst: filedest) { (success) in
|
||||||
|
broken = (success == false)
|
||||||
|
dg.leave()
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dg.leave()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dg.notify(queue: .main) {
|
||||||
|
if broken {
|
||||||
|
completion(nil)
|
||||||
|
} else {
|
||||||
|
completion(themeDest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
completion(nil)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
completion(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
completion(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public func getImageUrl(for theme: String, completion: @escaping (String?) -> ()) {
|
||||||
|
/*
|
||||||
|
We are going to load an image in a web view,
|
||||||
|
so no matter if the url will be a file on the local
|
||||||
|
filesystem (downloaded theme) or just on the online repository.
|
||||||
|
*/
|
||||||
|
if let sha = self.getSha() {
|
||||||
|
let localTheme = "\(basePath)/\(sha)/\(theme)"
|
||||||
|
let png = "\(localTheme)/screenshot.png"
|
||||||
|
let svg = "\(localTheme)/theme.svg"
|
||||||
|
if fm.fileExists(atPath: png) {
|
||||||
|
completion(png)
|
||||||
|
return
|
||||||
|
} else if fm.fileExists(atPath: svg) {
|
||||||
|
completion(svg)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// theme not found?? Downloading...
|
||||||
|
self.download(theme: theme, down: .thumbnail) { (path) in
|
||||||
|
if let localTheme = path {
|
||||||
|
let png = "\(localTheme)/screenshot.png"
|
||||||
|
let svg = "\(localTheme)/theme.svg"
|
||||||
|
if fm.fileExists(atPath: png) {
|
||||||
|
completion(png)
|
||||||
|
} else if fm.fileExists(atPath: svg) {
|
||||||
|
completion(svg)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
completion(nil)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func signTheme(at path: String) {
|
||||||
|
if let sha = getSha() {
|
||||||
|
let fileURL = URL(fileURLWithPath: path)
|
||||||
|
let data = sha.data(using: .utf8)
|
||||||
|
|
||||||
|
// remove all attributes
|
||||||
|
do {
|
||||||
|
let list = try fileURL.listExtendedAttributes()
|
||||||
|
for attr in list {
|
||||||
|
try fileURL.removeExtendedAttribute(forName: attr)
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
print(error.localizedDescription)
|
||||||
|
}
|
||||||
|
|
||||||
|
// set attribute
|
||||||
|
do {
|
||||||
|
try fileURL.setExtendedAttribute(data: data!, forName: kCloverThemeAttributeKey)
|
||||||
|
/* nine test
|
||||||
|
let adata = try fileURL.extendedAttribute(forName: attr)
|
||||||
|
print(String(data: adata, encoding: .utf8)!)
|
||||||
|
*/
|
||||||
|
} catch let error {
|
||||||
|
print(error.localizedDescription)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public func exist(theme: String) -> Bool {
|
||||||
|
return fm.fileExists(atPath: "\(self.themeManagerIndexDir)/Themes/\(theme).plist")
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
217
CloverApp/Clover/ThemeManager/ThemeManager.xib
Normal file
217
CloverApp/Clover/ThemeManager/ThemeManager.xib
Normal file
@ -0,0 +1,217 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="15702" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES" customObjectInstantitationMethod="direct">
|
||||||
|
<dependencies>
|
||||||
|
<deployment identifier="macosx"/>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="15702"/>
|
||||||
|
<plugIn identifier="com.apple.WebKitIBPlugin" version="15702"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<objects>
|
||||||
|
<customObject id="-2" userLabel="File's Owner"/>
|
||||||
|
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||||
|
<customObject id="-3" userLabel="Application" customClass="NSObject"/>
|
||||||
|
<window title="Themes" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" animationBehavior="default" id="QvC-M9-y7g">
|
||||||
|
<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="196" y="240" width="751" height="486"/>
|
||||||
|
<rect key="screenRect" x="0.0" y="0.0" width="1600" height="877"/>
|
||||||
|
<value key="minSize" type="size" width="751" height="486"/>
|
||||||
|
<value key="maxSize" type="size" width="751" height="486"/>
|
||||||
|
<view key="contentView" wantsLayer="YES" id="EiT-Mj-1SZ" customClass="GradientView" customModule="Clover" customModuleProvider="target">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="751" height="486"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<subviews>
|
||||||
|
<scrollView fixedFrame="YES" autohidesScrollers="YES" horizontalLineScroll="76" horizontalPageScroll="10" verticalLineScroll="76" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="r0K-Ss-e4a">
|
||||||
|
<rect key="frame" x="5" y="20" width="151" height="461"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<clipView key="contentView" ambiguous="YES" drawsBackground="NO" copiesOnScroll="NO" id="YEz-5q-kQJ">
|
||||||
|
<rect key="frame" x="1" y="1" width="149" height="459"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<tableView verticalHuggingPriority="750" ambiguous="YES" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" columnReordering="NO" columnSelection="YES" columnResizing="NO" multipleSelection="NO" autosaveColumns="NO" rowHeight="73" viewBased="YES" id="ydq-wg-aj2">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="149" height="459"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<size key="intercellSpacing" width="2" height="3"/>
|
||||||
|
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<tableColumns>
|
||||||
|
<tableColumn identifier="column1" width="147" minWidth="40" maxWidth="1000" id="SqG-sb-peF">
|
||||||
|
<tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border">
|
||||||
|
<font key="font" metaFont="controlContent" size="11"/>
|
||||||
|
<color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</tableHeaderCell>
|
||||||
|
<textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" title="Text Cell" id="XIw-Cc-NAw">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
<tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/>
|
||||||
|
<prototypeCellViews>
|
||||||
|
<tableCellView id="IDM-eI-bga">
|
||||||
|
<rect key="frame" x="1" y="1" width="147" height="17"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="vOd-E8-08W">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="147" height="17"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" lineBreakMode="truncatingTail" sendsActionOnEndEditing="YES" title="Table View Cell" id="zkl-n1-vr4">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
</textField>
|
||||||
|
</subviews>
|
||||||
|
<connections>
|
||||||
|
<outlet property="textField" destination="vOd-E8-08W" id="AAe-gI-75c"/>
|
||||||
|
</connections>
|
||||||
|
</tableCellView>
|
||||||
|
</prototypeCellViews>
|
||||||
|
</tableColumn>
|
||||||
|
</tableColumns>
|
||||||
|
</tableView>
|
||||||
|
</subviews>
|
||||||
|
<nil key="backgroundColor"/>
|
||||||
|
</clipView>
|
||||||
|
<scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" controlSize="mini" horizontal="YES" id="Hkt-fv-NXX">
|
||||||
|
<rect key="frame" x="1" y="119" width="223" height="11"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
</scroller>
|
||||||
|
<scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" controlSize="mini" horizontal="NO" id="3dn-D5-Whz">
|
||||||
|
<rect key="frame" x="224" y="17" width="11" height="102"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
</scroller>
|
||||||
|
</scrollView>
|
||||||
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="Q5A-Np-Gc4">
|
||||||
|
<rect key="frame" x="162" y="74" width="579" height="14"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" controlSize="small" lineBreakMode="truncatingTail" title="Description:" id="VVK-qM-R76">
|
||||||
|
<font key="font" metaFont="controlContent" size="11"/>
|
||||||
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
<connections>
|
||||||
|
<outlet property="delegate" destination="ClZ-60-myJ" id="zuI-fa-6ch"/>
|
||||||
|
</connections>
|
||||||
|
</textField>
|
||||||
|
<textField horizontalHuggingPriority="251" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="BMd-hN-0ay">
|
||||||
|
<rect key="frame" x="162" y="51" width="579" height="15"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<textFieldCell key="cell" controlSize="small" lineBreakMode="truncatingTail" title="Author:" id="nVY-gj-ELR">
|
||||||
|
<font key="font" metaFont="controlContent" size="11"/>
|
||||||
|
<color key="textColor" name="labelColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
</textFieldCell>
|
||||||
|
<connections>
|
||||||
|
<outlet property="delegate" destination="ClZ-60-myJ" id="Jzj-85-Zvh"/>
|
||||||
|
</connections>
|
||||||
|
</textField>
|
||||||
|
<comboBox focusRingType="none" verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="1Be-Yl-lqT">
|
||||||
|
<rect key="frame" x="164" y="97" width="201" height="25"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<comboBoxCell key="cell" scrollable="YES" lineBreakMode="clipping" selectable="YES" editable="YES" sendsActionOnEndEditing="YES" borderStyle="bezel" focusRingType="none" placeholderString="Theme" drawsBackground="YES" completes="NO" numberOfVisibleItems="5" id="ZdF-kp-eIO">
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/>
|
||||||
|
<objectValues>
|
||||||
|
<string>Item 1</string>
|
||||||
|
<string>Item 2</string>
|
||||||
|
<string>Item 3</string>
|
||||||
|
</objectValues>
|
||||||
|
</comboBoxCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="nameBoxSelected:" target="ClZ-60-myJ" id="rPH-oQ-4RO"/>
|
||||||
|
<outlet property="delegate" destination="ClZ-60-myJ" id="nX1-Jt-4WY"/>
|
||||||
|
</connections>
|
||||||
|
</comboBox>
|
||||||
|
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="11W-vh-mqt">
|
||||||
|
<rect key="frame" x="576" y="13" width="169" height="32"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="push" title="Install" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="hSu-fW-idj">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="InstallPressed:" target="ClZ-60-myJ" id="Phd-pp-aYa"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="bLz-we-3A0" customClass="FWPopUpButton" customModule="Clover" customModuleProvider="target">
|
||||||
|
<rect key="frame" x="162" y="123" width="580" height="25"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<popUpButtonCell key="cell" type="push" title="Item 1" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="cP4-wD-4Ph" id="MEO-zC-Iak">
|
||||||
|
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
<menu key="menu" id="fEx-Zt-ngB">
|
||||||
|
<items>
|
||||||
|
<menuItem title="Item 1" state="on" id="cP4-wD-4Ph"/>
|
||||||
|
<menuItem title="Item 2" id="4tT-M5-qZS"/>
|
||||||
|
<menuItem title="Item 3" id="5hd-qb-ZN5"/>
|
||||||
|
</items>
|
||||||
|
</menu>
|
||||||
|
</popUpButtonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="targetPopPressed:" target="ClZ-60-myJ" id="cA6-3I-hDI"/>
|
||||||
|
</connections>
|
||||||
|
</popUpButton>
|
||||||
|
<progressIndicator wantsLayer="YES" fixedFrame="YES" maxValue="100" displayedWhenStopped="NO" indeterminate="YES" controlSize="small" style="spinning" translatesAutoresizingMaskIntoConstraints="NO" id="tiZ-sK-mNx">
|
||||||
|
<rect key="frame" x="558" y="23" width="16" height="16"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
</progressIndicator>
|
||||||
|
<webView fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="7R3-UE-Q3H">
|
||||||
|
<rect key="frame" x="164" y="155" width="575" height="326"/>
|
||||||
|
<autoresizingMask key="autoresizingMask"/>
|
||||||
|
<webPreferences key="preferences" defaultFontSize="16" defaultFixedFontSize="13" minimumFontSize="0" javaEnabled="NO" javaScriptCanOpenWindowsAutomatically="NO">
|
||||||
|
<nil key="identifier"/>
|
||||||
|
</webPreferences>
|
||||||
|
</webView>
|
||||||
|
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="qNn-1b-hdX">
|
||||||
|
<rect key="frame" x="396" y="102" width="345" height="18"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="check" title="Show installed" bezelStyle="regularSquare" imagePosition="left" inset="2" id="PPl-2s-7pe">
|
||||||
|
<behavior key="behavior" changeContents="YES" doesNotDimImage="YES" lightByContents="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="showInstalledThemes:" target="ClZ-60-myJ" id="mYF-2e-FAu"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
<button verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="KDK-ig-T4V">
|
||||||
|
<rect key="frame" x="387" y="13" width="169" height="32"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
|
||||||
|
<buttonCell key="cell" type="push" title="Uninstall" bezelStyle="rounded" alignment="center" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="Nxb-Kj-kDi">
|
||||||
|
<behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/>
|
||||||
|
<font key="font" metaFont="system"/>
|
||||||
|
</buttonCell>
|
||||||
|
<connections>
|
||||||
|
<action selector="unInstallPressed:" target="ClZ-60-myJ" id="tVl-6l-eul"/>
|
||||||
|
</connections>
|
||||||
|
</button>
|
||||||
|
</subviews>
|
||||||
|
</view>
|
||||||
|
<connections>
|
||||||
|
<outlet property="delegate" destination="Rhe-Oy-I6J" id="Zlh-Ne-N7V"/>
|
||||||
|
</connections>
|
||||||
|
<point key="canvasLocation" x="171.5" y="236"/>
|
||||||
|
</window>
|
||||||
|
<customObject id="Rhe-Oy-I6J" customClass="ThemeManagerWC" customModule="Clover" customModuleProvider="target">
|
||||||
|
<connections>
|
||||||
|
<outlet property="window" destination="QvC-M9-y7g" id="lZL-g6-Xhg"/>
|
||||||
|
</connections>
|
||||||
|
</customObject>
|
||||||
|
<viewController id="ClZ-60-myJ" customClass="ThemeManagerVC" customModule="Clover" customModuleProvider="target">
|
||||||
|
<connections>
|
||||||
|
<outlet property="authorField" destination="BMd-hN-0ay" id="hW8-ad-MeQ"/>
|
||||||
|
<outlet property="infoField" destination="Q5A-Np-Gc4" id="A6G-u3-jDk"/>
|
||||||
|
<outlet property="installButton" destination="11W-vh-mqt" id="uVA-cy-LtI"/>
|
||||||
|
<outlet property="installedThemesCheckBox" destination="qNn-1b-hdX" id="7cy-kq-gen"/>
|
||||||
|
<outlet property="nameBox" destination="1Be-Yl-lqT" id="STE-Aj-xum"/>
|
||||||
|
<outlet property="sidebar" destination="ydq-wg-aj2" id="dMd-2Y-AFt"/>
|
||||||
|
<outlet property="spinner" destination="tiZ-sK-mNx" id="jY2-rJ-ECs"/>
|
||||||
|
<outlet property="targetPop" destination="bLz-we-3A0" id="EcP-hC-Wbm"/>
|
||||||
|
<outlet property="unistallButton" destination="KDK-ig-T4V" id="XVD-ko-iT8"/>
|
||||||
|
<outlet property="view" destination="EiT-Mj-1SZ" id="rmo-5n-mHh"/>
|
||||||
|
<outlet property="webView" destination="7R3-UE-Q3H" id="nTk-DN-ARl"/>
|
||||||
|
</connections>
|
||||||
|
</viewController>
|
||||||
|
</objects>
|
||||||
|
</document>
|
738
CloverApp/Clover/ThemeManager/ThemeManagerVC.swift
Normal file
738
CloverApp/Clover/ThemeManager/ThemeManagerVC.swift
Normal file
@ -0,0 +1,738 @@
|
|||||||
|
//
|
||||||
|
// ThemeManagerVC.swift
|
||||||
|
// ThemeManager
|
||||||
|
//
|
||||||
|
// Created by vector sigma on 07/01/2020.
|
||||||
|
// Copyright © 2020 vectorsigma. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
import WebKit
|
||||||
|
|
||||||
|
class GradientView : NSView {
|
||||||
|
override func draw(_ dirtyRect: NSRect) {
|
||||||
|
super.draw(dirtyRect)
|
||||||
|
/*
|
||||||
|
let up = NSColor(red: 48 / 255, green: 35 / 255, blue: 255 / 255, alpha: 0.5)
|
||||||
|
let down = NSColor(red: 150 / 255, green: 158 / 255, blue: 215 / 255, alpha: 0.5)
|
||||||
|
let grad = NSGradient(colors: [down, up])
|
||||||
|
grad?.draw(in: dirtyRect, angle: 45)*/
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ThemeManagerVC: NSViewController,
|
||||||
|
NSTableViewDelegate, NSTableViewDataSource, WebFrameLoadDelegate, WebUIDelegate {
|
||||||
|
var targetVolume : String? = nil
|
||||||
|
|
||||||
|
var manager : ThemeManager?
|
||||||
|
@IBOutlet var installedThemesCheckBox : NSButton!
|
||||||
|
|
||||||
|
@IBOutlet var webView : WebView!
|
||||||
|
@IBOutlet var sidebar : NSTableView!
|
||||||
|
@IBOutlet var nameBox : NSComboBox!
|
||||||
|
@IBOutlet var authorField : NSTextField!
|
||||||
|
@IBOutlet var infoField : NSTextField!
|
||||||
|
|
||||||
|
@IBOutlet var targetPop : FWPopUpButton!
|
||||||
|
@IBOutlet var spinner : NSProgressIndicator!
|
||||||
|
@IBOutlet var installButton : NSButton!
|
||||||
|
@IBOutlet var unistallButton : NSButton!
|
||||||
|
|
||||||
|
var loaded : Bool = false
|
||||||
|
var showInstalled : Bool = false
|
||||||
|
|
||||||
|
override func awakeFromNib() {
|
||||||
|
super.awakeFromNib()
|
||||||
|
if !self.loaded {
|
||||||
|
if #available(OSX 10.10, *) {} else {
|
||||||
|
self.viewDidLoad()
|
||||||
|
}
|
||||||
|
self.loaded = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func viewDidLoad() {
|
||||||
|
|
||||||
|
if #available(OSX 10.10, *) {
|
||||||
|
super.viewDidLoad()
|
||||||
|
}
|
||||||
|
self.loaded = true
|
||||||
|
|
||||||
|
/*
|
||||||
|
let winImagePath = "/Library/Desktop Pictures/Ink Cloud.jpg"
|
||||||
|
|
||||||
|
if fm.fileExists(atPath: winImagePath) {
|
||||||
|
let winImage = NSImage(byReferencingFile: winImagePath)
|
||||||
|
let winImageSize = NSMakeSize(self.view.frame.width, self.view.frame.height)
|
||||||
|
winImage?.size = winImageSize
|
||||||
|
self.view.window?.backgroundColor = NSColor.init(patternImage: winImage!)
|
||||||
|
}*/
|
||||||
|
|
||||||
|
self.view.window?.title = self.view.window!.title.locale
|
||||||
|
let settingVC = AppSD.settingsWC?.contentViewController as? SettingsViewController
|
||||||
|
settingVC?.themeUserField.isEnabled = false
|
||||||
|
settingVC?.themeRepoField.isEnabled = false
|
||||||
|
self.webView.drawsBackground = false
|
||||||
|
self.webView.uiDelegate = self
|
||||||
|
|
||||||
|
self.webView.frameLoadDelegate = self
|
||||||
|
self.webView.mainFrame.frameView.allowsScrolling = false
|
||||||
|
|
||||||
|
|
||||||
|
localize(view: self.view)
|
||||||
|
AppSD.isInstallerOpen = true
|
||||||
|
settingVC?.disksPopUp.isEnabled = false
|
||||||
|
settingVC?.updateCloverButton.isEnabled = false
|
||||||
|
settingVC?.unmountButton.isEnabled = false
|
||||||
|
|
||||||
|
AppSD.themes.removeAll()
|
||||||
|
self.nameBox.completes = true
|
||||||
|
|
||||||
|
self.nameBox.removeAllItems()
|
||||||
|
self.sidebar.delegate = self
|
||||||
|
self.sidebar.dataSource = self
|
||||||
|
self.sidebar.backgroundColor = NSColor.clear
|
||||||
|
self.sidebar.enclosingScrollView?.contentView.drawsBackground = false
|
||||||
|
|
||||||
|
if #available(OSX 10.10, *) {
|
||||||
|
self.sidebar.usesStaticContents = true
|
||||||
|
}
|
||||||
|
|
||||||
|
self.targetPop.removeAllItems()
|
||||||
|
self.populateTargets()
|
||||||
|
|
||||||
|
if let bootDevice = findBootPartitionDevice() {
|
||||||
|
if let mountPoint = getMountPoint(from: bootDevice) {
|
||||||
|
for i in self.targetPop.itemArray {
|
||||||
|
if let target = i.representedObject as? String {
|
||||||
|
if bootDevice == target {
|
||||||
|
self.targetPop.select(i)
|
||||||
|
self.targetVolume = mountPoint
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.showIndexing()
|
||||||
|
//return
|
||||||
|
let themeManagerIndexDir = NSHomeDirectory().addPath("Library/Application Support/CloverApp/Themeindex/\(AppSD.themeUser)_\(AppSD.themeRepo)")
|
||||||
|
|
||||||
|
self.manager = ThemeManager(user: AppSD.themeUser,
|
||||||
|
repo: AppSD.themeRepo,
|
||||||
|
basePath: themeManagerIndexDir,
|
||||||
|
indexDir: themeManagerIndexDir,
|
||||||
|
delegate: self)
|
||||||
|
|
||||||
|
/*
|
||||||
|
1) immediately load indexed themes (if any).
|
||||||
|
Fast if thumbnails already exists.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for t in self.manager!.getIndexedThemes() {
|
||||||
|
self.add(theme: t)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
2) download thumbnails.
|
||||||
|
Slower if thumbnails didn't exist or themes never indexed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
self.manager?.getThemes { (t) in
|
||||||
|
let sorted = t.sorted()
|
||||||
|
for t in sorted {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.add(theme: t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func dataSource() -> [String] {
|
||||||
|
if showInstalled {
|
||||||
|
return AppSD.installedThemes
|
||||||
|
}
|
||||||
|
return AppSD.themes
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func showInstalledThemes(_ sender: NSButton!) {
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 0.01) {
|
||||||
|
let copy = self.manager!.getIndexedThemes().sorted() // in cases of low downloads
|
||||||
|
self.nameBox.removeAllItems()
|
||||||
|
self.sidebar.noteNumberOfRowsChanged()
|
||||||
|
AppSD.installedThemes.removeAll()
|
||||||
|
AppSD.themes.removeAll()
|
||||||
|
|
||||||
|
if sender.state == .on {
|
||||||
|
if (self.targetVolume != nil && fm.fileExists(atPath: self.targetVolume!)) {
|
||||||
|
let themeDir = self.targetVolume!.addPath("EFI/CLOVER/themes")
|
||||||
|
var installed = [String]()
|
||||||
|
for theme in copy {
|
||||||
|
if fm.fileExists(atPath: themeDir.addPath(theme)) {
|
||||||
|
installed.append(theme)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if fm.fileExists(atPath: themeDir) {
|
||||||
|
do {
|
||||||
|
let userTheme = try fm.contentsOfDirectory(atPath: themeDir)
|
||||||
|
for theme in userTheme {
|
||||||
|
if (fm.fileExists(atPath: themeDir.addPath(theme).addPath("theme.plist"))
|
||||||
|
&& fm.fileExists(atPath: themeDir.addPath(theme).addPath("screenshot.png"))) {
|
||||||
|
if !installed.contains(theme) {
|
||||||
|
installed.append(theme)
|
||||||
|
}
|
||||||
|
} else if fm.fileExists(atPath: themeDir.addPath(theme).addPath("theme.svg")) {
|
||||||
|
if !installed.contains(theme) {
|
||||||
|
installed.append(theme)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch { }
|
||||||
|
}
|
||||||
|
AppSD.installedThemes = installed.sorted()
|
||||||
|
self.nameBox.addItems(withObjectValues: installed.sorted())
|
||||||
|
if installed.count == 0 {
|
||||||
|
self.showNoThemes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.showInstalled = true
|
||||||
|
} else {
|
||||||
|
AppSD.themes = copy
|
||||||
|
self.nameBox.addItems(withObjectValues: copy.sorted())
|
||||||
|
self.showInstalled = false
|
||||||
|
if copy.count == 0 {
|
||||||
|
self.showNoThemes()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
self.sidebar.reloadData()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func showNoThemes() {
|
||||||
|
self.webView.mainFrame.loadHTMLString(
|
||||||
|
"""
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<style>
|
||||||
|
.center {
|
||||||
|
height: 100%;
|
||||||
|
position: relative;
|
||||||
|
border: 3px solid gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center p {
|
||||||
|
margin: 0;
|
||||||
|
position: absolute;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
-ms-transform: translate(-50%, -50%);
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="center">
|
||||||
|
<p>\("No themes found".locale)</p>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
""",
|
||||||
|
baseURL: Bundle.main.bundleURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
func showIndexing() {
|
||||||
|
// https://www.w3schools.com/howto/howto_css_loader.asp
|
||||||
|
self.webView.mainFrame.loadHTMLString("""
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta name="viewport" content="width=device-width, initial- scale=1">
|
||||||
|
<style>
|
||||||
|
.loader {
|
||||||
|
position: absolute;
|
||||||
|
left: 30%;
|
||||||
|
top: 25%;
|
||||||
|
border: 20px solid #f3f3f3;
|
||||||
|
border-radius: 50%;
|
||||||
|
border-top: 16px solid white;
|
||||||
|
border-right: 16px solid gray;
|
||||||
|
border-bottom: 16px solid white;
|
||||||
|
border-left: 16px solid gray;
|
||||||
|
width: 160px;
|
||||||
|
height: 160px;
|
||||||
|
-webkit-animation: spin 2s linear infinite;
|
||||||
|
animation: spin 2s linear infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.blinking{
|
||||||
|
animation:blinkingText 1.2s infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes blinkingText{
|
||||||
|
0%{ color: gray; }
|
||||||
|
49%{ color: gray; }
|
||||||
|
60%{ color: transparent; }
|
||||||
|
99%{ color:transparent; }
|
||||||
|
100%{ color: gray; }
|
||||||
|
}
|
||||||
|
|
||||||
|
@-webkit-keyframes spin {
|
||||||
|
0% { -webkit-transform: rotate(0deg); }
|
||||||
|
100% { -webkit-transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes spin {
|
||||||
|
0% { transform: rotate(0deg); }
|
||||||
|
100% { transform: rotate(360deg); }
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h2><span class="blinking">Indexing..</span></h2>
|
||||||
|
|
||||||
|
<div class="loader"></div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
""", baseURL: Bundle.main.bundleURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func unInstallPressed(_ sender: NSButton!) {
|
||||||
|
if AppSD.isInstalling {
|
||||||
|
NSSound.beep()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if self.targetPop.indexOfSelectedItem == 0
|
||||||
|
|| self.targetVolume == nil
|
||||||
|
|| (self.targetVolume != nil && !fm.fileExists(atPath: self.targetVolume!)) {
|
||||||
|
NSSound.beep()
|
||||||
|
return // this should not happen
|
||||||
|
}
|
||||||
|
|
||||||
|
let theme = self.nameBox.stringValue
|
||||||
|
let themePath = self.targetVolume!.addPath("EFI/CLOVER/themes").addPath(theme)
|
||||||
|
|
||||||
|
let sr = self.sidebar.selectedRow
|
||||||
|
if sr >= 0 && sr < self.dataSource().count {
|
||||||
|
self.spinner.startAnimation(nil)
|
||||||
|
do {
|
||||||
|
if fm.fileExists(atPath: themePath) {
|
||||||
|
try fm.removeItem(atPath: themePath)
|
||||||
|
self.unistallButton.isEnabled = false
|
||||||
|
self.unistallButton.animator().isHidden = true
|
||||||
|
NSSound(contentsOfFile: "/System/Library/Components/CoreAudio.component/Contents/SharedSupport/SystemSounds/finder/empty trash.aif", byReference: false)?.play()
|
||||||
|
}
|
||||||
|
self.spinner.stopAnimation(nil)
|
||||||
|
self.showInstalledThemes(self.installedThemesCheckBox)
|
||||||
|
} catch {
|
||||||
|
NSSound(named: "Basso")?.play()
|
||||||
|
let alert = NSAlert()
|
||||||
|
alert.messageText = "Can't remove the theme".locale
|
||||||
|
alert.informativeText = "\(error.localizedDescription)"
|
||||||
|
alert.addButton(withTitle: "OK")
|
||||||
|
alert.runModal()
|
||||||
|
self.spinner.stopAnimation(nil)
|
||||||
|
self.showInstalledThemes(self.installedThemesCheckBox)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func InstallPressed(_ sender: NSButton!) {
|
||||||
|
if AppSD.isInstalling {
|
||||||
|
NSSound.beep()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if self.targetPop.indexOfSelectedItem == 0
|
||||||
|
|| self.targetVolume == nil
|
||||||
|
|| (self.targetVolume != nil && !fm.fileExists(atPath: self.targetVolume!)) {
|
||||||
|
NSSound.beep()
|
||||||
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
|
||||||
|
self.targetPop.performClick(self.targetPop)
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
let theme = self.nameBox.stringValue
|
||||||
|
let themeDest = self.targetVolume!.addPath("EFI/CLOVER/themes").addPath(theme)
|
||||||
|
self.spinner.startAnimation(nil)
|
||||||
|
let sr = self.sidebar.selectedRow
|
||||||
|
if sr >= 0 && sr < self.dataSource().count {
|
||||||
|
self.manager?.download(theme: theme,
|
||||||
|
down: .complete,
|
||||||
|
completion: { (path) in
|
||||||
|
|
||||||
|
if let themePath = path {
|
||||||
|
try? fm.removeItem(atPath: themeDest)
|
||||||
|
do {
|
||||||
|
try fm.moveItem(atPath: themePath, toPath: themeDest)
|
||||||
|
NSSound(named: "Glass")?.play()
|
||||||
|
} catch {
|
||||||
|
NSSound(named: "Basso")?.play()
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
let alert = NSAlert()
|
||||||
|
alert.messageText = "Installation failed".locale
|
||||||
|
alert.informativeText = "\(error.localizedDescription)"
|
||||||
|
alert.addButton(withTitle: "OK")
|
||||||
|
alert.runModal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
NSSound(named: "Basso")?.play()
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
let alert = NSAlert()
|
||||||
|
alert.messageText = "Installation failed".locale
|
||||||
|
alert.informativeText = "Theme \"\(theme)\" not found."
|
||||||
|
alert.addButton(withTitle: "OK")
|
||||||
|
alert.runModal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
AppSD.isInstalling = false
|
||||||
|
self.spinner.stopAnimation(nil)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
func addRow(for theme: String) {
|
||||||
|
let index = AppSD.themes.count
|
||||||
|
AppSD.themes.append(theme)
|
||||||
|
//if self.installedThemesCheckBox.state == .off {
|
||||||
|
self.sidebar.beginUpdates()
|
||||||
|
self.sidebar.insertRows(at: IndexSet(integer: index), withAnimation: .slideUp)
|
||||||
|
self.sidebar.endUpdates()
|
||||||
|
//}
|
||||||
|
self.nameBox.addItem(withObjectValue: theme)
|
||||||
|
}
|
||||||
|
|
||||||
|
func add(theme: String) {
|
||||||
|
if AppSD.themes.contains(theme) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if let sha = self.manager?.getSha() {
|
||||||
|
let themePath = self.manager!.basePath.addPath(sha).addPath(theme)
|
||||||
|
if fm.fileExists(atPath: themePath.addPath("theme.svg")) {
|
||||||
|
self.addRow(for: theme)
|
||||||
|
} else if (fm.fileExists(atPath: themePath.addPath("screenshot.png"))
|
||||||
|
&& fm.fileExists(atPath: themePath.addPath("theme.plist"))) {
|
||||||
|
self.addRow(for: theme)
|
||||||
|
} else {
|
||||||
|
self.manager?.download(theme: theme, down: .thumbnail, completion: { (path) in
|
||||||
|
if path != nil {
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.addRow(for: theme)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func nameBoxSelected(_ sender: NSComboBox!) {
|
||||||
|
let theme = sender.stringValue
|
||||||
|
if theme.count > 0 && self.dataSource().contains(theme) {
|
||||||
|
let index = self.dataSource().firstIndex(of: theme)
|
||||||
|
self.sidebar.selectRowIndexes(IndexSet(integer: index!), byExtendingSelection: false)
|
||||||
|
self.sidebar.scrollRowToVisible(index!)
|
||||||
|
} else {
|
||||||
|
NSSound.beep()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: NSTableView, didAdd rowView: NSTableRowView, forRow row: Int) {
|
||||||
|
if self.sidebar.selectedRow < 0 {
|
||||||
|
self.sidebar.selectRowIndexes(IndexSet(integer: 0), byExtendingSelection: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func numberOfRows(in tableView: NSTableView) -> Int {
|
||||||
|
return self.dataSource().count
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: NSTableView, heightOfRow row: Int) -> CGFloat {
|
||||||
|
return 82
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableViewSelectionDidChange(_ notification: Notification) {
|
||||||
|
let sr = self.sidebar.selectedRow
|
||||||
|
if sr >= 0 {
|
||||||
|
if let v = self.sidebar.view(atColumn: 0, row: sr, makeIfNecessary: false) as? ThemeView {
|
||||||
|
if v.isInstalled {
|
||||||
|
self.unistallButton.animator().isHidden = false
|
||||||
|
self.unistallButton.isEnabled = true
|
||||||
|
} else {
|
||||||
|
self.unistallButton.animator().isHidden = true
|
||||||
|
self.unistallButton.isEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (self.manager?.exist(theme: v.name))! {
|
||||||
|
self.installButton.isEnabled = true
|
||||||
|
} else {
|
||||||
|
self.installButton.isEnabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
guard let path = v.imagePath else {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
self.nameBox.stringValue = v.name
|
||||||
|
self.authorField.stringValue = v.author ?? ""
|
||||||
|
self.infoField.stringValue = v.info ?? ""
|
||||||
|
|
||||||
|
self.webView.mainFrame.loadHTMLString("""
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<div align="center" style="position:relative; height: 100%; width: 100%; top:0;left 0;">
|
||||||
|
<img src="\(URL(fileURLWithPath: path))" style="width: 100% ; max-width: 575px;top:0;"/>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
""", baseURL: Bundle.main.bundleURL)
|
||||||
|
|
||||||
|
if path.hasSuffix(".svg") {
|
||||||
|
let svgStr = try? String(contentsOfFile: path)
|
||||||
|
var author : String? = nil
|
||||||
|
var version : String? = nil
|
||||||
|
var description : String? = nil
|
||||||
|
if let lines = svgStr?.components(separatedBy: .newlines) {
|
||||||
|
/*
|
||||||
|
Version="0.87"
|
||||||
|
Year="2018-2019"
|
||||||
|
Author="Blackosx"
|
||||||
|
Description="Vector version of BGM (Based on Clovy theme file structure)"
|
||||||
|
*/
|
||||||
|
|
||||||
|
for line in lines {
|
||||||
|
if (line.range(of: "Version=\"") != nil) {
|
||||||
|
version = line.components(separatedBy: "Version=\"")[1].components(separatedBy: "\"")[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for line in lines {
|
||||||
|
if (line.range(of: "Author=\"") != nil) {
|
||||||
|
author = line.components(separatedBy: "Author=\"")[1].components(separatedBy: "\"")[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for line in lines {
|
||||||
|
if (line.range(of: "Description=\"") != nil) {
|
||||||
|
description = line.components(separatedBy: "Description=\"")[1].components(separatedBy: "\"")[0]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.authorField.stringValue = author ?? ""
|
||||||
|
self.infoField.stringValue = "\(description ?? "?"), v\(version ?? "?")"
|
||||||
|
} else {
|
||||||
|
// get theme.plist
|
||||||
|
let plistPath = "\((path as NSString).deletingLastPathComponent)/theme.plist"
|
||||||
|
let plist = NSDictionary(contentsOfFile: plistPath)
|
||||||
|
self.authorField.stringValue = (plist?.object(forKey: "Author") as? String) ?? ""
|
||||||
|
self.infoField.stringValue = (plist?.object(forKey: "Description") as? String) ?? ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: NSTableView, viewFor tableColumn: NSTableColumn?, row: Int) -> NSView? {
|
||||||
|
if let identifier = tableColumn?.identifier {
|
||||||
|
if identifier.rawValue == "column1" {
|
||||||
|
let tv = ThemeView(manager: self.manager!,
|
||||||
|
name: self.dataSource()[row],
|
||||||
|
row: row)
|
||||||
|
tv.manager.delegate = self
|
||||||
|
return tv
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func tableView(_ tableView: NSTableView, rowViewForRow row: Int) -> NSTableRowView? {
|
||||||
|
return ThemeTableRowView()
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: find suitable disks
|
||||||
|
func populateTargets() {
|
||||||
|
if AppSD.isInstalling {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let selected : String? = self.targetPop.selectedItem?.representedObject as? String
|
||||||
|
self.targetPop.removeAllItems()
|
||||||
|
self.targetPop.addItem(withTitle: "Select a disk..".locale)
|
||||||
|
let disks : NSDictionary = getAlldisks()
|
||||||
|
let bootPartition = findBootPartitionDevice()
|
||||||
|
let diskSorted : [String] = (disks.allKeys as! [String]).sorted()
|
||||||
|
for d in diskSorted {
|
||||||
|
let disk : String = d
|
||||||
|
if isWritable(diskOrMtp: disk) && !kBannedMedia.contains(getVolumeName(from: disk) ?? "") {
|
||||||
|
let fs : String = getFS(from: disk)?.lowercased() ?? kNotAvailable.locale
|
||||||
|
let psm : String = getPartitionSchemeMap(from: disk) ?? kNotAvailable.locale
|
||||||
|
let name : String = getVolumeName(from: disk) ?? kNotAvailable.locale
|
||||||
|
let mp : String = getMountPoint(from: disk) ?? kNotAvailable.locale
|
||||||
|
let parentDiskName : String = getMediaName(from: getBSDParent(of: disk) ?? "") ?? kNotAvailable.locale
|
||||||
|
|
||||||
|
let supportedFS = ["msdos", "fat32", "exfat", "hfs"]
|
||||||
|
|
||||||
|
if supportedFS.contains(fs) {
|
||||||
|
self.targetPop.addItem(withTitle: "\(disk)\t\(name), \("mount point".locale): \(mp), \(fs.uppercased()), \(psm): (\(parentDiskName))")
|
||||||
|
self.targetPop.invalidateIntrinsicContentSize()
|
||||||
|
// get the image
|
||||||
|
if disk == bootPartition {
|
||||||
|
let image : NSImage = NSImage(named: "NSApplicationIcon")!.copy() as! NSImage
|
||||||
|
image.size = NSMakeSize(16, 16)
|
||||||
|
self.targetPop.lastItem?.image = image
|
||||||
|
} else if let image : NSImage = getIconFor(volume: disk) {
|
||||||
|
image.size = NSMakeSize(16, 16)
|
||||||
|
self.targetPop.lastItem?.image = image
|
||||||
|
}
|
||||||
|
self.targetPop.lastItem?.representedObject = disk
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (selected != nil) {
|
||||||
|
for item in self.targetPop.itemArray {
|
||||||
|
if let d = item.representedObject as? String {
|
||||||
|
if selected == d {
|
||||||
|
self.targetPop.select(item)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@IBAction func targetPopPressed(_ sender: FWPopUpButton!) {
|
||||||
|
if let disk = sender?.selectedItem?.representedObject as? String {
|
||||||
|
if !isMountPoint(path: disk) {
|
||||||
|
//DispatchQueue.global(qos: .background).async {
|
||||||
|
let cmd = "diskutil mount \(disk)"
|
||||||
|
let msg = String(format: "Clover wants to mount %@", disk)
|
||||||
|
let script = "do shell script \"\(cmd)\" with prompt \"\(msg)\" with administrator privileges"
|
||||||
|
|
||||||
|
let task = Process()
|
||||||
|
|
||||||
|
if #available(OSX 10.12, *) {
|
||||||
|
task.launchPath = "/usr/bin/osascript"
|
||||||
|
task.arguments = ["-e", script]
|
||||||
|
} else {
|
||||||
|
task.launchPath = "/usr/sbin/diskutil"
|
||||||
|
task.arguments = ["mount", disk]
|
||||||
|
}
|
||||||
|
|
||||||
|
task.terminationHandler = { t in
|
||||||
|
if t.terminationStatus == 0 {
|
||||||
|
if isMountPoint(path: disk) {
|
||||||
|
self.targetVolume = getMountPoint(from: disk)
|
||||||
|
DispatchQueue.main.async {
|
||||||
|
self.populateTargets()
|
||||||
|
self.showInstalledThemes(self.installedThemesCheckBox)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
DispatchQueue.main.async { self.view.window?.makeKeyAndOrderFront(nil) }
|
||||||
|
} else {
|
||||||
|
NSSound.beep()
|
||||||
|
self.showInstalledThemes(self.installedThemesCheckBox)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
task.launch()
|
||||||
|
//}
|
||||||
|
} else {
|
||||||
|
self.targetVolume = getMountPoint(from: disk)
|
||||||
|
self.populateTargets()
|
||||||
|
self.showInstalledThemes(self.installedThemesCheckBox)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.targetVolume = nil
|
||||||
|
self.unistallButton.isEnabled = false
|
||||||
|
self.unistallButton.isHidden = true
|
||||||
|
self.showInstalledThemes(self.installedThemesCheckBox)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: ThemeManager Window controller
|
||||||
|
class ThemeManagerWC: NSWindowController, NSWindowDelegate {
|
||||||
|
var viewController : NSViewController? = nil
|
||||||
|
override var contentViewController: NSViewController? {
|
||||||
|
get {
|
||||||
|
self.viewController
|
||||||
|
}
|
||||||
|
set {
|
||||||
|
self.viewController = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class func loadFromNib() -> ThemeManagerWC? {
|
||||||
|
var topLevel: NSArray? = nil
|
||||||
|
Bundle.main.loadNibNamed("ThemeManager", owner: self, topLevelObjects: &topLevel)
|
||||||
|
if (topLevel != nil) {
|
||||||
|
var wc : ThemeManagerWC? = nil
|
||||||
|
for o in topLevel! {
|
||||||
|
if o is ThemeManagerWC {
|
||||||
|
wc = o as? ThemeManagerWC
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for o in topLevel! {
|
||||||
|
if o is ThemeManagerVC {
|
||||||
|
wc?.contentViewController = o as! ThemeManagerVC
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wc
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func windowShouldClose(_ sender: NSWindow) -> Bool {
|
||||||
|
if AppSD.isInstalling {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
let settingVC = AppSD.settingsWC?.contentViewController as? SettingsViewController
|
||||||
|
settingVC?.disksPopUp.isEnabled = true
|
||||||
|
settingVC?.updateCloverButton.isEnabled = true
|
||||||
|
settingVC?.searchESPDisks()
|
||||||
|
AppSD.isInstallerOpen = false
|
||||||
|
settingVC?.themeUserField.isEnabled = true
|
||||||
|
settingVC?.themeRepoField.isEnabled = true
|
||||||
|
self.window = nil
|
||||||
|
self.close()
|
||||||
|
AppSD.themeManagerWC = nil // remove a strong reference
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class ThemeTableRowView: NSTableRowView {
|
||||||
|
override func draw(_ dirtyRect: NSRect) {
|
||||||
|
super.draw(dirtyRect)
|
||||||
|
self.wantsLayer = true
|
||||||
|
self.layer?.backgroundColor = NSColor.clear.cgColor
|
||||||
|
}
|
||||||
|
|
||||||
|
override var isEmphasized: Bool {
|
||||||
|
set {}
|
||||||
|
get {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override var selectionHighlightStyle: NSTableView.SelectionHighlightStyle {
|
||||||
|
set {}
|
||||||
|
get {
|
||||||
|
return .regular
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func drawSelection(in dirtyRect: NSRect) {
|
||||||
|
if self.selectionHighlightStyle != .none {
|
||||||
|
let selectionRect = NSInsetRect(self.bounds, 2.5, 2.5)
|
||||||
|
NSColor.green.setFill()
|
||||||
|
//NSColor(calibratedWhite: 0.85, alpha: 0.6).setFill()
|
||||||
|
let selectionPath = NSBezierPath.init(rect: selectionRect)
|
||||||
|
selectionPath.fill()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
150
CloverApp/Clover/ThemeManager/ThemeView.swift
Normal file
150
CloverApp/Clover/ThemeManager/ThemeView.swift
Normal file
@ -0,0 +1,150 @@
|
|||||||
|
//
|
||||||
|
// ThemeView.swift
|
||||||
|
// ThemeManager
|
||||||
|
//
|
||||||
|
// Created by vector sigma on 07/01/2020.
|
||||||
|
// Copyright © 2020 vectorsigma. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import Cocoa
|
||||||
|
import WebKit
|
||||||
|
|
||||||
|
class ThemeView: NSView, WebFrameLoadDelegate, WebUIDelegate {
|
||||||
|
var manager : ThemeManager
|
||||||
|
var imagePath : String?
|
||||||
|
var name : String
|
||||||
|
var author : String?
|
||||||
|
var info : String?
|
||||||
|
var row : Int
|
||||||
|
var isInstalled = false
|
||||||
|
|
||||||
|
public let webView: WebView = {
|
||||||
|
let wv = WebView(frame: NSMakeRect(0, 0, 147, 82))
|
||||||
|
wv.mainFrame.frameView.allowsScrolling = false
|
||||||
|
wv.drawsBackground = false
|
||||||
|
return wv
|
||||||
|
} ()
|
||||||
|
|
||||||
|
deinit {
|
||||||
|
self.webView.stopLoading(nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
func webView(_ sender: WebView!, makeFirstResponder responder: NSResponder!) {
|
||||||
|
if self.row >= 0 {
|
||||||
|
self.manager.delegate?.sidebar.selectRowIndexes(IndexSet(integer: self.row),
|
||||||
|
byExtendingSelection: false)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// MARK: - designated initializer
|
||||||
|
init(manager: ThemeManager, name: String, row: Int) {
|
||||||
|
self.manager = manager
|
||||||
|
self.name = name
|
||||||
|
self.row = row
|
||||||
|
super.init(frame: NSMakeRect(0, 0, 147, 82))
|
||||||
|
self.setup()
|
||||||
|
self.load()
|
||||||
|
}
|
||||||
|
|
||||||
|
required init?(coder: NSCoder) {
|
||||||
|
fatalError("init(coder:) has not been implemented")
|
||||||
|
}
|
||||||
|
|
||||||
|
private func setup() {
|
||||||
|
self.addSubview(self.webView)
|
||||||
|
|
||||||
|
self.webView.translatesAutoresizingMaskIntoConstraints = false
|
||||||
|
let left = NSLayoutConstraint(item: self.webView,
|
||||||
|
attribute: .left,
|
||||||
|
relatedBy: .equal,
|
||||||
|
toItem: self,
|
||||||
|
attribute: .left,
|
||||||
|
multiplier: 1.0,
|
||||||
|
constant: 0.0)
|
||||||
|
let bottom = NSLayoutConstraint(item: self.webView,
|
||||||
|
attribute: .bottom,
|
||||||
|
relatedBy: .equal,
|
||||||
|
toItem: self,
|
||||||
|
attribute: .bottom,
|
||||||
|
multiplier: 1.0,
|
||||||
|
constant: 0.0)
|
||||||
|
let width = NSLayoutConstraint(item: self.webView,
|
||||||
|
attribute: .width,
|
||||||
|
relatedBy: .equal,
|
||||||
|
toItem: self,
|
||||||
|
attribute: .width,
|
||||||
|
multiplier: 1.0,
|
||||||
|
constant: 0.0)
|
||||||
|
let height = NSLayoutConstraint(item: self.webView,
|
||||||
|
attribute: .height,
|
||||||
|
relatedBy: .equal,
|
||||||
|
toItem: self,
|
||||||
|
attribute: .height,
|
||||||
|
multiplier: 1.0,
|
||||||
|
constant: 0.0)
|
||||||
|
self.addConstraints([left, bottom, height, width])
|
||||||
|
|
||||||
|
|
||||||
|
self.webView.uiDelegate = self
|
||||||
|
self.webView.frameLoadDelegate = self
|
||||||
|
}
|
||||||
|
|
||||||
|
private func load() {
|
||||||
|
if self.manager.exist(theme: self.name) {
|
||||||
|
self.manager.getImageUrl(for: self.name, completion: { (ipath) in
|
||||||
|
if let path = ipath {
|
||||||
|
self.imagePath = path
|
||||||
|
}
|
||||||
|
self.setInstalledStatus()
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
self.setInstalledStatus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@objc func targetVolumeDidChange() {
|
||||||
|
self.setInstalledStatus()
|
||||||
|
}
|
||||||
|
|
||||||
|
func setInstalledStatus() {
|
||||||
|
if let vol = self.manager.delegate?.targetVolume {
|
||||||
|
self.isInstalled = fm.fileExists(atPath: vol.addPath("EFI/CLOVER/themes").addPath(self.name))
|
||||||
|
if (self.imagePath == nil) {
|
||||||
|
if fm.fileExists(atPath: vol.addPath("EFI/CLOVER/themes").addPath(self.name).addPath("theme.svg")) {
|
||||||
|
self.imagePath = vol.addPath("EFI/CLOVER/themes").addPath(self.name).addPath("theme.svg")
|
||||||
|
self.setInstalledStatus()
|
||||||
|
} else if fm.fileExists(atPath: vol.addPath("EFI/CLOVER/themes").addPath(self.name).addPath("screenshot.png")) {
|
||||||
|
self.imagePath = vol.addPath("EFI/CLOVER/themes").addPath(self.name).addPath("screenshot.png")
|
||||||
|
self.setInstalledStatus()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let path = self.imagePath {
|
||||||
|
if self.isInstalled {
|
||||||
|
let icon = Bundle.main.path(forResource: "check", ofType: "png")
|
||||||
|
self.webView.mainFrame.loadHTMLString("""
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<div align="center" style="position:relative; height: 100%; width: 100%; top:0;left 0;">
|
||||||
|
<img src="\(URL(fileURLWithPath: path))" style="width: 100% ; max-width: 128px;"/>
|
||||||
|
<img src="\(URL(fileURLWithPath: icon!))" style="position:absolute; top:8; left:8;"/>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
""", baseURL: Bundle.main.bundleURL)
|
||||||
|
} else {
|
||||||
|
self.webView.mainFrame.loadHTMLString("""
|
||||||
|
<html>
|
||||||
|
<body>
|
||||||
|
<div align="center" style="position:relative; height: 100%; width: 100%; top:0;left 0;">
|
||||||
|
<img src="\(URL(fileURLWithPath: path))" style="width: 100% ; max-width: 128px;top:0;"/>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
""", baseURL: Bundle.main.bundleURL)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
BIN
CloverApp/Clover/check.png
Normal file
BIN
CloverApp/Clover/check.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.5 KiB |
@ -77,6 +77,33 @@ class Installer: NSObject {
|
|||||||
Darwin.exit(EXIT_FAILURE)
|
Darwin.exit(EXIT_FAILURE)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func disableInsexing(for volume: String) {
|
||||||
|
if fm.fileExists(atPath: volume) {
|
||||||
|
var file = volume.addPath(".metadata_never_index")
|
||||||
|
if !fm.fileExists(atPath: file) {
|
||||||
|
try? "".write(toFile: file, atomically: false, encoding: .utf8)
|
||||||
|
}
|
||||||
|
|
||||||
|
file = volume.addPath(".Spotlight-V100")
|
||||||
|
if fm.fileExists(atPath: file) {
|
||||||
|
try? fm.removeItem(atPath: file)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Clean everythings that starts with "._"
|
||||||
|
This of course only for ESPs
|
||||||
|
*/
|
||||||
|
|
||||||
|
let enumerator = fm.enumerator(atPath: volume)
|
||||||
|
while let file = enumerator?.nextObject() as? String {
|
||||||
|
let fullPath = volume.addPath(file)
|
||||||
|
if file.hasPrefix("._") {
|
||||||
|
try? fm.removeItem(atPath: fullPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private func copyReplace(src: String, dst: String, attr: [FileAttributeKey: Any]?, log: Bool) -> Bool {
|
private func copyReplace(src: String, dst: String, attr: [FileAttributeKey: Any]?, log: Bool) -> Bool {
|
||||||
var attributes : [FileAttributeKey: Any]? = attr
|
var attributes : [FileAttributeKey: Any]? = attr
|
||||||
let upperDir = dst.deletingLastPath
|
let upperDir = dst.deletingLastPath
|
||||||
@ -265,6 +292,10 @@ class Installer: NSObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isESP {
|
||||||
|
self.disableInsexing(for: targetVol)
|
||||||
|
}
|
||||||
|
|
||||||
// MARK: Check paths
|
// MARK: Check paths
|
||||||
var boot0Path: String? = nil
|
var boot0Path: String? = nil
|
||||||
var boot1Path: String? = nil
|
var boot1Path: String? = nil
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
let daemonVersion = "1.1.1"
|
let daemonVersion = "1.1.2"
|
||||||
|
|
||||||
let fm = FileManager.default
|
let fm = FileManager.default
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
|
|
||||||
import Foundation
|
import Foundation
|
||||||
|
|
||||||
let cmdVersion = "1.0.4"
|
let cmdVersion = "1.0.5"
|
||||||
let savedNVRAMPath = "/tmp/NVRAM_saved"
|
let savedNVRAMPath = "/tmp/NVRAM_saved"
|
||||||
let NVRAMSavedToRoot = "/tmp/NVRAM_savedToRoot"
|
let NVRAMSavedToRoot = "/tmp/NVRAM_savedToRoot"
|
||||||
|
|
||||||
@ -82,7 +82,7 @@ func disableInsexing(for volume: String) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
file = volume.addPath(".Spotlight-V100")
|
file = volume.addPath(".Spotlight-V100")
|
||||||
if fm.fileExists(atPath: volume.addPath("")) {
|
if fm.fileExists(atPath: file) {
|
||||||
try? fm.removeItem(atPath: file)
|
try? fm.removeItem(atPath: file)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "Falsch";
|
"false" = "Falsch";
|
||||||
|
|
||||||
"Theme:" = "Thema:";
|
"Theme:" = "Thema:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Sound:";
|
"Sound:" = "Sound:";
|
||||||
"*Make filesystem read-write" = "*Filesystem schreib-/lesbar machen";
|
"*Make filesystem read-write" = "*Filesystem schreib-/lesbar machen";
|
||||||
"*Disable Sleep Proxy Client" = "*Sleep Proxy Client deaktivieren";
|
"*Disable Sleep Proxy Client" = "*Sleep Proxy Client deaktivieren";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "false";
|
"false" = "false";
|
||||||
|
|
||||||
"Theme:" = "Theme:";
|
"Theme:" = "Theme:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Sound:";
|
"Sound:" = "Sound:";
|
||||||
"*Make filesystem read-write" = "*Make filesystem read-write";
|
"*Make filesystem read-write" = "*Make filesystem read-write";
|
||||||
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "false";
|
"false" = "false";
|
||||||
|
|
||||||
"Theme:" = "Theme:";
|
"Theme:" = "Theme:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Sound:";
|
"Sound:" = "Sound:";
|
||||||
"*Make filesystem read-write" = "*Make filesystem read-write";
|
"*Make filesystem read-write" = "*Make filesystem read-write";
|
||||||
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "faux";
|
"false" = "faux";
|
||||||
|
|
||||||
"Theme:" = "Thème:";
|
"Theme:" = "Thème:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Son:";
|
"Sound:" = "Son:";
|
||||||
"*Make filesystem read-write" = "*Changer système fichiers en lecture-écriture";
|
"*Make filesystem read-write" = "*Changer système fichiers en lecture-écriture";
|
||||||
"*Disable Sleep Proxy Client" = "*Désactiver Mise en veille du Proxy Client";
|
"*Disable Sleep Proxy Client" = "*Désactiver Mise en veille du Proxy Client";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "false";
|
"false" = "false";
|
||||||
|
|
||||||
"Theme:" = "Theme:";
|
"Theme:" = "Theme:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Sound:";
|
"Sound:" = "Sound:";
|
||||||
"*Make filesystem read-write" = "*Make filesystem read-write";
|
"*Make filesystem read-write" = "*Make filesystem read-write";
|
||||||
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "false";
|
"false" = "false";
|
||||||
|
|
||||||
"Theme:" = "Theme:";
|
"Theme:" = "Theme:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Sound:";
|
"Sound:" = "Sound:";
|
||||||
"*Make filesystem read-write" = "*Jadikan FileSystem Read-Write";
|
"*Make filesystem read-write" = "*Jadikan FileSystem Read-Write";
|
||||||
"*Disable Sleep Proxy Client" = "*Tiadakan Sleep Proxy Client";
|
"*Disable Sleep Proxy Client" = "*Tiadakan Sleep Proxy Client";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "falso";
|
"false" = "falso";
|
||||||
|
|
||||||
"Theme:" = "Tema:";
|
"Theme:" = "Tema:";
|
||||||
|
"Themes" = "Temi"; // window title
|
||||||
|
"No themes found" = "Nessun tema trovato";
|
||||||
|
"Manager" = "Gestore"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Non posso rimuovere il tema";
|
||||||
|
"Show installed" = "Mostra installati";
|
||||||
"Sound:" = "Suono:";
|
"Sound:" = "Suono:";
|
||||||
"*Make filesystem read-write" = "*Rendi il filesystem scrivibile";
|
"*Make filesystem read-write" = "*Rendi il filesystem scrivibile";
|
||||||
"*Disable Sleep Proxy Client" = "*Disabilita Sleep Proxy Client";
|
"*Disable Sleep Proxy Client" = "*Disabilita Sleep Proxy Client";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "false";
|
"false" = "false";
|
||||||
|
|
||||||
"Theme:" = "Theme:";
|
"Theme:" = "Theme:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Sound:";
|
"Sound:" = "Sound:";
|
||||||
"*Make filesystem read-write" = "*Make filesystem read-write";
|
"*Make filesystem read-write" = "*Make filesystem read-write";
|
||||||
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "아니오";
|
"false" = "아니오";
|
||||||
|
|
||||||
"Theme:" = "테마:";
|
"Theme:" = "테마:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "사운드:";
|
"Sound:" = "사운드:";
|
||||||
"*Make filesystem read-write" = "*파일시스템을 읽기-쓰기로 변경";
|
"*Make filesystem read-write" = "*파일시스템을 읽기-쓰기로 변경";
|
||||||
"*Disable Sleep Proxy Client" = "*잠자기 프록시 클라이언트 비활성화";
|
"*Disable Sleep Proxy Client" = "*잠자기 프록시 클라이언트 비활성화";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "false";
|
"false" = "false";
|
||||||
|
|
||||||
"Theme:" = "Theme:";
|
"Theme:" = "Theme:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Sound:";
|
"Sound:" = "Sound:";
|
||||||
"*Make filesystem read-write" = "*Make filesystem read-write";
|
"*Make filesystem read-write" = "*Make filesystem read-write";
|
||||||
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "false";
|
"false" = "false";
|
||||||
|
|
||||||
"Theme:" = "Theme:";
|
"Theme:" = "Theme:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Sound:";
|
"Sound:" = "Sound:";
|
||||||
"*Make filesystem read-write" = "*Make filesystem read-write";
|
"*Make filesystem read-write" = "*Make filesystem read-write";
|
||||||
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "false";
|
"false" = "false";
|
||||||
|
|
||||||
"Theme:" = "Theme:";
|
"Theme:" = "Theme:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Sound:";
|
"Sound:" = "Sound:";
|
||||||
"*Make filesystem read-write" = "*Make filesystem read-write";
|
"*Make filesystem read-write" = "*Make filesystem read-write";
|
||||||
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "false";
|
"false" = "false";
|
||||||
|
|
||||||
"Theme:" = "Theme:";
|
"Theme:" = "Theme:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Sound:";
|
"Sound:" = "Sound:";
|
||||||
"*Make filesystem read-write" = "*Make filesystem read-write";
|
"*Make filesystem read-write" = "*Make filesystem read-write";
|
||||||
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "falso";
|
"false" = "falso";
|
||||||
|
|
||||||
"Theme:" = "Tema:";
|
"Theme:" = "Tema:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Som:";
|
"Sound:" = "Som:";
|
||||||
"*Make filesystem read-write" = "*Fazer filesystem leitura-escrita";
|
"*Make filesystem read-write" = "*Fazer filesystem leitura-escrita";
|
||||||
"*Disable Sleep Proxy Client" = "*Disabilitar Sleep Proxy Client";
|
"*Disable Sleep Proxy Client" = "*Disabilitar Sleep Proxy Client";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "false";
|
"false" = "false";
|
||||||
|
|
||||||
"Theme:" = "Theme:";
|
"Theme:" = "Theme:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Sound:";
|
"Sound:" = "Sound:";
|
||||||
"*Make filesystem read-write" = "*Make filesystem read-write";
|
"*Make filesystem read-write" = "*Make filesystem read-write";
|
||||||
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "ложь";
|
"false" = "ложь";
|
||||||
|
|
||||||
"Theme:" = "Тема:";
|
"Theme:" = "Тема:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Звук:";
|
"Sound:" = "Звук:";
|
||||||
"*Make filesystem read-write" = "*Открыть файловую систему на запись";
|
"*Make filesystem read-write" = "*Открыть файловую систему на запись";
|
||||||
"*Disable Sleep Proxy Client" = "*Отключение Sleep Proxy Client";
|
"*Disable Sleep Proxy Client" = "*Отключение Sleep Proxy Client";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "Lažno";
|
"false" = "Lažno";
|
||||||
|
|
||||||
"Theme:" = "Tema:";
|
"Theme:" = "Tema:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Zvuk:";
|
"Sound:" = "Zvuk:";
|
||||||
"*Make filesystem read-write" = "*Filesystem čine čitanje-Pisanje";
|
"*Make filesystem read-write" = "*Filesystem čine čitanje-Pisanje";
|
||||||
"*Disable Sleep Proxy Client" = "*Sleep Proxy Client deaktiviran";
|
"*Disable Sleep Proxy Client" = "*Sleep Proxy Client deaktiviran";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "false";
|
"false" = "false";
|
||||||
|
|
||||||
"Theme:" = "Theme:";
|
"Theme:" = "Theme:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Sound:";
|
"Sound:" = "Sound:";
|
||||||
"*Make filesystem read-write" = "*Make filesystem read-write";
|
"*Make filesystem read-write" = "*Make filesystem read-write";
|
||||||
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "false";
|
"false" = "false";
|
||||||
|
|
||||||
"Theme:" = "Theme:";
|
"Theme:" = "Theme:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Sound:";
|
"Sound:" = "Sound:";
|
||||||
"*Make filesystem read-write" = "*Make filesystem read-write";
|
"*Make filesystem read-write" = "*Make filesystem read-write";
|
||||||
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "false";
|
"false" = "false";
|
||||||
|
|
||||||
"Theme:" = "Theme:";
|
"Theme:" = "Theme:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Sound:";
|
"Sound:" = "Sound:";
|
||||||
"*Make filesystem read-write" = "*Make filesystem read-write";
|
"*Make filesystem read-write" = "*Make filesystem read-write";
|
||||||
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "否";
|
"false" = "否";
|
||||||
|
|
||||||
"Theme:" = "主题:";
|
"Theme:" = "主题:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "声音:";
|
"Sound:" = "声音:";
|
||||||
"*Make filesystem read-write" = "*让文件系统可读写";
|
"*Make filesystem read-write" = "*让文件系统可读写";
|
||||||
"*Disable Sleep Proxy Client" = "*禁用 Sleep Proxy Client";
|
"*Disable Sleep Proxy Client" = "*禁用 Sleep Proxy Client";
|
||||||
|
@ -50,6 +50,11 @@
|
|||||||
"false" = "false";
|
"false" = "false";
|
||||||
|
|
||||||
"Theme:" = "Theme:";
|
"Theme:" = "Theme:";
|
||||||
|
"Themes" = "Themes"; // window title
|
||||||
|
"No themes found" = "No themes found";
|
||||||
|
"Manager" = "Manager"; // Theme manager
|
||||||
|
"Can't remove the theme" = "Can't remove the theme";
|
||||||
|
"Show installed" = "Show installed";
|
||||||
"Sound:" = "Sound:";
|
"Sound:" = "Sound:";
|
||||||
"*Make filesystem read-write" = "*Make filesystem read-write";
|
"*Make filesystem read-write" = "*Make filesystem read-write";
|
||||||
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
"*Disable Sleep Proxy Client" = "*Disable Sleep Proxy Client";
|
||||||
|
Loading…
Reference in New Issue
Block a user