mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-11-24 11:45:27 +01:00
b06c4d4d41
Clver.app: Corrected a bug that was causing the installer to fail on unknown drivers. CloverDaemonNew : Now is registered with the Power notifications (sleep and wake), so that can clean up nvram.plist files created by third partu kexts. At shut down it now delete the following nvram keys: efi-backup-boot-device efi-backup-boot-device-data install-product-url previous-system-uuid Clover.app promoted to Beta.
664 lines
22 KiB
Swift
664 lines
22 KiB
Swift
//
|
|
// SettingsView.swift
|
|
// Clover
|
|
//
|
|
// Created by vector sigma on 30/10/2019.
|
|
// Copyright © 2019 CloverHackyColor. All rights reserved.
|
|
//
|
|
|
|
import Cocoa
|
|
|
|
class SettingsViewController: NSViewController, NSTextFieldDelegate, URLSessionDownloadDelegate {
|
|
// MARK: Variables
|
|
@IBOutlet var currentRevField : NSTextField!
|
|
@IBOutlet var bootDeviceField : NSTextField!
|
|
@IBOutlet var configPathField : FWTextField!
|
|
@IBOutlet var disksPopUp : NSPopUpButton!
|
|
@IBOutlet var unmountButton : NSButton!
|
|
@IBOutlet var themeField : FWTextField!
|
|
@IBOutlet var soundField : FWTextField!
|
|
@IBOutlet var disbaleSleepProxyButton : NSButton!
|
|
@IBOutlet var makeRootRWButton : NSButton!
|
|
@IBOutlet var installDaemonButton : NSButton!
|
|
@IBOutlet var unInstallDaemonButton : NSButton!
|
|
@IBOutlet var timeIntervalPopUp : NSPopUpButton!
|
|
@IBOutlet var checkNowButton : NSButton!
|
|
@IBOutlet var lastUpdateCheckField : NSTextField!
|
|
@IBOutlet var runAtLoginButton : NSButton!
|
|
|
|
@IBOutlet var updateCloverButton : NSButton!
|
|
@IBOutlet var installCloverButton : NSButton!
|
|
|
|
@IBOutlet var progressBar : NSProgressIndicator!
|
|
|
|
@IBOutlet var appVersionField : NSTextField!
|
|
|
|
var lastReleaseRev : String? = nil
|
|
var lastReleaseLink : String? = nil
|
|
var currentRev : String = findCloverRevision() ?? kNotAvailable.locale
|
|
var bootDevice : String? = findBootPartitionDevice()
|
|
|
|
var timerUpdate : Timer? = nil
|
|
var timeUpdateInterval : TimeInterval = UpdateInterval.never.rawValue
|
|
|
|
var downloadTask : URLSessionDownloadTask? = nil
|
|
|
|
// MARK: View customization
|
|
override func viewDidLoad() {
|
|
super.viewDidLoad()
|
|
let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as! String + " Beta"
|
|
self.appVersionField.stringValue = "v\(appVersion)"
|
|
localize(view: self.view)
|
|
self.view.wantsLayer = true
|
|
self.view.layer?.backgroundColor = NSColor.clear.cgColor
|
|
|
|
self.themeField.delegate = self
|
|
self.soundField.delegate = self
|
|
|
|
self.progressBar.isHidden = true
|
|
|
|
self.runAtLoginButton.state = UDs.bool(forKey: kRunAtLogin) ? .on : .off
|
|
self.unmountButton.isEnabled = false
|
|
|
|
self.setUpdateInformations()
|
|
|
|
let nvram = getNVRAM()
|
|
var nvdata = nvram?.object(forKey: "Clover.Theme") as? Data
|
|
|
|
self.themeField.placeholderString = kNotAvailable.locale
|
|
self.themeField.stringValue = (nvdata != nil) ? String(decoding: nvdata!, as: UTF8.self) : ""
|
|
self.themeField.cell?.representedObject = self.themeField.stringValue
|
|
|
|
nvdata = nvram?.object(forKey: "Clover.Sound") as? Data
|
|
self.soundField.placeholderString = kNotAvailable.locale
|
|
self.soundField.stringValue = (nvdata != nil) ? String(decoding: nvdata!, as: UTF8.self) : ""
|
|
self.soundField.cell?.representedObject = self.soundField.stringValue
|
|
|
|
nvdata = nvram?.object(forKey: "Clover.RootRW") as? Data
|
|
var value : String = String(decoding: nvdata ?? Data(), as: UTF8.self)
|
|
self.makeRootRWButton.state = (value == "true") ? .on : .off
|
|
|
|
nvdata = nvram?.object(forKey: "Clover.DisableSleepProxyClient") as? Data
|
|
value = String(decoding: nvdata ?? Data(), as: UTF8.self)
|
|
self.disbaleSleepProxyButton.state = (value == "true") ? .on : .off
|
|
|
|
|
|
let daemonExist = fm.fileExists(atPath: kDaemonPath) && fm.fileExists(atPath: kLaunchPlistPath)
|
|
self.unInstallDaemonButton.isEnabled = daemonExist
|
|
|
|
self.setUpdateButton()
|
|
self.searchESPDisks()
|
|
|
|
let itervals = ["never", "daily", "weekly", "monthly"]
|
|
self.timeIntervalPopUp.removeAllItems()
|
|
for i in itervals {
|
|
self.timeIntervalPopUp.addItem(withTitle: i.locale)
|
|
self.timeIntervalPopUp.lastItem?.representedObject = i
|
|
}
|
|
|
|
if (UDs.object(forKey: kUpdateSearchInterval) == nil) {
|
|
// search update the first time..
|
|
UDs.set("monthly", forKey: kUpdateSearchInterval)
|
|
UDs.synchronize()
|
|
}
|
|
|
|
let def = UDs.string(forKey: kUpdateSearchInterval)!
|
|
for i in self.timeIntervalPopUp.itemArray {
|
|
let c = i.representedObject as! String
|
|
if def == c {
|
|
self.timeIntervalPopUp.select(i)
|
|
break
|
|
}
|
|
}
|
|
|
|
if let date : Date = UDs.object(forKey: kLastSearchUpdateDateKey) as? Date {
|
|
let now = DateFormatter.localizedString(from: date, dateStyle: .short, timeStyle: .short)
|
|
self.lastUpdateCheckField.stringValue = "\("last checked:".locale) \(now)"
|
|
} else {
|
|
self.lastUpdateCheckField.stringValue = "\("last checked:".locale) \("never".locale)"
|
|
}
|
|
|
|
self.timerUpdate = Timer.scheduledTimer(timeInterval: 60 * 60,
|
|
target: self,
|
|
selector: #selector(self.setUpdateTimer),
|
|
userInfo: nil,
|
|
repeats: true)
|
|
}
|
|
|
|
func setUpdateInformations() {
|
|
let rev = findCloverRevision(at: Bundle.main.sharedSupportPath!.addPath("CloverV2/EFI")) ?? "0000"
|
|
var title = "\("Install Clover".locale) \(rev)"
|
|
self.installCloverButton.title = title
|
|
|
|
self.bootDevice = findBootPartitionDevice()
|
|
title = "\("Boot device".locale): \(self.bootDevice ?? kNotAvailable.locale)"
|
|
self.bootDeviceField.stringValue = title
|
|
|
|
self.configPathField.stringValue = findConfigPath() ?? kNotAvailable.locale
|
|
title = "\("Current Clover revision".locale): \(self.currentRev)"
|
|
self.currentRevField.stringValue = title
|
|
|
|
let last : String = (self.lastReleaseRev == nil) ? kNotAvailable.locale : "r\(self.lastReleaseRev!)"
|
|
title = "\("Update Clover available".locale): \(last)"
|
|
|
|
self.installCloverButton.isEnabled = true
|
|
}
|
|
|
|
override var representedObject: Any? {
|
|
didSet {
|
|
// Update the view, if already loaded.
|
|
}
|
|
}
|
|
|
|
// MARK: Disks
|
|
func searchESPDisks() {
|
|
self.unmountButton.isEnabled = false
|
|
let selected = self.disksPopUp.selectedItem?.representedObject as? String
|
|
|
|
self.disksPopUp.removeAllItems()
|
|
self.disksPopUp.addItem(withTitle: "Select a disk..".locale)
|
|
for e in getAllESPs() {
|
|
if isWritable(diskOrMtp: e) {
|
|
let fs = getFS(from: e) ?? kNotAvailable.locale
|
|
let mp = getMountPoint(from: e) ?? kNotAvailable.locale
|
|
let title : String = "\(e), \(fs), \("mount point".locale): \(mp)"
|
|
self.disksPopUp.addItem(withTitle: title)
|
|
self.disksPopUp.lastItem?.representedObject = e
|
|
if e == self.bootDevice {
|
|
let image : NSImage = NSImage(named: "NSApplicationIcon")!.copy() as! NSImage
|
|
image.size = NSMakeSize(16, 16)
|
|
self.disksPopUp.lastItem?.image = image
|
|
} else if let image : NSImage = getIconFor(volume: e) {
|
|
image.size = NSMakeSize(16, 16)
|
|
self.disksPopUp.lastItem?.image = image
|
|
}
|
|
}
|
|
}
|
|
|
|
if (selected != nil) {
|
|
for item in self.disksPopUp.itemArray {
|
|
if let d = item.representedObject as? String {
|
|
if d == selected {
|
|
self.disksPopUp.select(item)
|
|
if isMountPoint(path: d) {
|
|
self.unmountButton.isEnabled = true
|
|
}
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// MARK: Mount ESPs
|
|
@IBAction func mountESP(_ sender: NSPopUpButton!) {
|
|
self.unmountButton.isEnabled = false
|
|
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()
|
|
task.launchPath = "/usr/bin/osascript"
|
|
task.arguments = ["-e", script]
|
|
|
|
task.terminationHandler = { t in
|
|
if t.terminationStatus == 0 {
|
|
DispatchQueue.main.async {
|
|
self.unmountButton.isEnabled = true
|
|
}
|
|
NSWorkspace.shared.openFile(getMountPoint(from: disk) ?? "")
|
|
} else {
|
|
NSSound.beep()
|
|
}
|
|
}
|
|
task.launch()
|
|
}
|
|
} else {
|
|
self.unmountButton.isEnabled = true
|
|
NSWorkspace.shared.openFile(getMountPoint(from: disk) ?? "")
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: Umount
|
|
@IBAction func umount(_ sender: NSButton!) {
|
|
if let disk = self.disksPopUp.selectedItem?.representedObject as? String {
|
|
if isMountPoint(path: disk) {
|
|
DispatchQueue.global(qos: .background).async {
|
|
let cmd = "diskutil umount \(disk)"
|
|
let msg = String(format: "Clover wants to umount %@", disk)
|
|
let script = "do shell script \"\(cmd)\" with prompt \"\(msg)\" with administrator privileges"
|
|
|
|
let task = Process()
|
|
task.launchPath = "/usr/bin/osascript"
|
|
task.arguments = ["-e", script]
|
|
|
|
task.terminationHandler = { t in
|
|
if t.terminationStatus != 0 {
|
|
NSSound.beep()
|
|
}
|
|
DispatchQueue.main.async {
|
|
self.searchESPDisks()
|
|
}
|
|
}
|
|
task.launch()
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: Controls actions
|
|
@IBAction func installClover(_ sender: NSButton!) {
|
|
if (AppSD.installerWC == nil) {
|
|
AppSD.installerWC = InstallerWindowController.loadFromNib()
|
|
}
|
|
|
|
AppSD.installerWC?.showWindow(self)
|
|
NSApp.activate(ignoringOtherApps: true)
|
|
}
|
|
|
|
@IBAction func installDaemon(_ sender: NSButton!) {
|
|
let daemonPath = Bundle.main.executablePath!.deletingLastPath.addPath("CloverDaemonNew")
|
|
|
|
DispatchQueue.global(qos: .background).async {
|
|
let task = Process()
|
|
let msg = "Install CloverDaemonNew".locale
|
|
|
|
let script = "do shell script \"\" & quoted form of \"\(daemonPath)\" & \" --install\" with prompt \"\(msg)\" with administrator privileges"
|
|
|
|
task.launchPath = "/usr/bin/osascript"
|
|
task.arguments = ["-e", script]
|
|
|
|
task.terminationHandler = { t in
|
|
if t.terminationStatus != 0 {
|
|
print(t.terminationReason)
|
|
NSSound.beep()
|
|
}
|
|
|
|
DispatchQueue.main.async {
|
|
let daemonExist = fm.fileExists(atPath: kDaemonPath) && fm.fileExists(atPath: kLaunchPlistPath)
|
|
self.unInstallDaemonButton.isEnabled = daemonExist
|
|
}
|
|
}
|
|
task.launch()
|
|
}
|
|
}
|
|
|
|
@IBAction func unInstallDaemon(_ sender: NSButton!) {
|
|
let daemonPath = Bundle.main.executablePath!.deletingLastPath.addPath("CloverDaemonNew")
|
|
|
|
DispatchQueue.global(qos: .background).async {
|
|
let task = Process()
|
|
let msg = "Install CloverDaemonNew".locale
|
|
|
|
let script = "do shell script \"\" & quoted form of \"\(daemonPath)\" & \" --uninstall\" with prompt \"\(msg)\" with administrator privileges"
|
|
|
|
task.launchPath = "/usr/bin/osascript"
|
|
task.arguments = ["-e", script]
|
|
|
|
task.terminationHandler = { t in
|
|
if t.terminationStatus != 0 {
|
|
print(t.terminationReason)
|
|
NSSound.beep()
|
|
}
|
|
|
|
DispatchQueue.main.async {
|
|
let daemonExist = fm.fileExists(atPath: kDaemonPath) && fm.fileExists(atPath: kLaunchPlistPath)
|
|
self.unInstallDaemonButton.isEnabled = daemonExist
|
|
}
|
|
}
|
|
task.launch()
|
|
}
|
|
}
|
|
|
|
@IBAction func setUpdateInterval(_ sender: NSPopUpButton!) {
|
|
if let selected = sender.selectedItem?.representedObject as? String {
|
|
UDs.set(selected, forKey: kUpdateSearchInterval)
|
|
self.setUpdateTimer()
|
|
}
|
|
}
|
|
|
|
@IBAction func checkNow(_ sender: NSButton!) {
|
|
self.searchUpdate()
|
|
}
|
|
|
|
// MARK: Run At Login
|
|
@IBAction func runAtLogin(_ sender: NSButton!) {
|
|
if sender.state == .on {
|
|
AppSD.setLaunchAtStartup()
|
|
} else {
|
|
AppSD.removeLaunchAtStartup()
|
|
}
|
|
|
|
// check the result
|
|
sender.state = UDs.bool(forKey: kRunAtLogin) ? .on : .off
|
|
}
|
|
|
|
// MARK: NVRAM editing
|
|
func controlTextDidEndEditing(_ obj: Notification) {
|
|
if let field = obj.object as? NSTextField {
|
|
let delete : Bool = field.stringValue.count == 0
|
|
if field == self.themeField || field == soundField {
|
|
if let old = field.cell?.representedObject as? String {
|
|
let key = (field == self.themeField) ? "Clover.Theme" : "Clover.Sound"
|
|
if old != field.stringValue {
|
|
if delete {
|
|
deleteNVRAM(key: key)
|
|
} 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
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
@IBAction func disableSleepProxy(_ sender: NSButton!) {
|
|
let key = "Clover.DisableSleepProxyClient"
|
|
if sender.state == .on {
|
|
setNVRAM(key: key, stringValue: "true"/*, error: &error*/)
|
|
} else {
|
|
deleteNVRAM(key: key)
|
|
}
|
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
|
|
var value = ""
|
|
if let nvram = getNVRAM() {
|
|
let nvdata = nvram.object(forKey: "Clover.DisableSleepProxyClient") as? Data
|
|
value = String(decoding: nvdata ?? Data(), as: UTF8.self)
|
|
}
|
|
self.disbaleSleepProxyButton.state = (value == "true") ? .on : .off
|
|
}
|
|
}
|
|
|
|
@IBAction func makeRootRW(_ sender: NSButton!) {
|
|
let key = "Clover.RootRW"
|
|
if sender.state == .on {
|
|
setNVRAM(key: key, stringValue: "true"/*, error: &error*/)
|
|
} else {
|
|
deleteNVRAM(key: key)
|
|
}
|
|
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + 1.0) {
|
|
var value = ""
|
|
if let nvram = getNVRAM() {
|
|
let nvdata = nvram.object(forKey: "Clover.RootRW") as? Data
|
|
value = String(decoding: nvdata ?? Data(), as: UTF8.self)
|
|
}
|
|
self.disbaleSleepProxyButton.state = (value == "true") ? .on : .off
|
|
}
|
|
}
|
|
|
|
@IBAction func readDaemonLog(_ sender: NSButton!) {
|
|
DispatchQueue.global(qos: .background).async {
|
|
let cmd = "cat /Library/Logs/CloverEFI/clover.daemon.log > /tmp/clover.daemon.log && open /tmp/clover.daemon.log"
|
|
let msg = "CloverDaemon log"
|
|
let script = "do shell script \"\(cmd)\" with prompt \"\(msg)\" with administrator privileges"
|
|
|
|
let task = Process()
|
|
task.launchPath = "/usr/bin/osascript"
|
|
task.arguments = ["-e", script]
|
|
|
|
task.terminationHandler = { t in
|
|
if t.terminationStatus == 0 {
|
|
DispatchQueue.main.async {
|
|
self.unmountButton.isEnabled = true
|
|
}
|
|
NSWorkspace.shared.openFile("/tmp/clover.daemon.log")
|
|
} else {
|
|
NSSound.beep()
|
|
}
|
|
}
|
|
task.launch()
|
|
}
|
|
}
|
|
|
|
@IBAction func readbdmesg(_ sender: NSButton!) {
|
|
if let bdmesg = dumpBootlog() {
|
|
do {
|
|
try bdmesg.write(toFile: "/tmp/bdmesg.log", atomically: true, encoding: .utf8)
|
|
NSWorkspace.shared.openFile("/tmp/bdmesg.log")
|
|
} catch {
|
|
NSSound.beep()
|
|
}
|
|
} else {
|
|
NSSound.beep()
|
|
}
|
|
}
|
|
|
|
|
|
// MARK: Search update
|
|
@objc func setUpdateTimer() {
|
|
// check last date update was checked
|
|
var ti : TimeInterval = UpdateInterval.never.rawValue
|
|
let def = (UDs.value(forKey: kUpdateSearchInterval) as? String) ?? "never"
|
|
switch def {
|
|
case "never":
|
|
ti = UpdateInterval.never.rawValue
|
|
case "daily":
|
|
ti = UpdateInterval.daily.rawValue
|
|
case "weekly":
|
|
ti = UpdateInterval.weekly.rawValue
|
|
case "monthly":
|
|
ti = UpdateInterval.monthly.rawValue
|
|
default:
|
|
break
|
|
}
|
|
|
|
|
|
|
|
// Time interval is what user defines less time elapsed
|
|
if ti > 0 {
|
|
let lastCheckDate : Date = (UDs.object(forKey: kLastSearchUpdateDateKey) as? Date) ?? Date()
|
|
let secElapsed = Date().timeIntervalSinceReferenceDate - lastCheckDate.timeIntervalSinceReferenceDate
|
|
|
|
if secElapsed >= ti {
|
|
print(secElapsed)
|
|
self.searchUpdate()
|
|
}
|
|
}
|
|
}
|
|
|
|
func setUpdateButton() {
|
|
if (self.lastReleaseRev != nil && self.lastReleaseLink != nil) {
|
|
AppSD.statusItem.title = self.lastReleaseRev
|
|
self.updateCloverButton.title = String(format: "Update to %@".locale, self.lastReleaseRev!)
|
|
self.updateCloverButton.isEnabled = true
|
|
} else {
|
|
AppSD.statusItem.title = ""
|
|
self.updateCloverButton.title = kNotAvailable.locale
|
|
self.updateCloverButton.isEnabled = false
|
|
}
|
|
}
|
|
|
|
@objc func searchUpdate() {
|
|
getLatestRelease { (l, v) in
|
|
self.lastReleaseLink = l
|
|
self.lastReleaseRev = v
|
|
let currRevNum : Int = Int(self.currentRev) ?? 0
|
|
let lastRevNum : Int = Int(self.lastReleaseRev ?? "0") ?? 0
|
|
|
|
if (self.lastReleaseLink != nil && self.lastReleaseRev != nil)
|
|
&& lastRevNum > 0
|
|
&& (lastRevNum > currRevNum) {
|
|
UDs.set(self.lastReleaseLink!, forKey: kLastUpdateLink)
|
|
UDs.set(self.lastReleaseRev!, forKey: kLastUpdateRevision)
|
|
DispatchQueue.main.async {
|
|
AppSD.statusItem.button?.title = "\(lastRevNum)"
|
|
AppSD.statusItem.button?.imagePosition = .imageLeft
|
|
self.updateCloverButton.isEnabled = true
|
|
self.updateCloverButton.title = String(format: "Update to r%d".locale, lastRevNum)
|
|
}
|
|
} else {
|
|
DispatchQueue.main.async {
|
|
let ll = UDs.string(forKey: kLastUpdateLink)
|
|
let lr = UDs.string(forKey: kLastUpdateRevision)
|
|
if (ll != nil && lr != nil) {
|
|
self.lastReleaseLink = ll
|
|
self.lastReleaseRev = lr
|
|
AppSD.statusItem.button?.title = "\(lastRevNum)"
|
|
AppSD.statusItem.button?.imagePosition = .imageLeft
|
|
self.updateCloverButton.isEnabled = true
|
|
self.updateCloverButton.title = String(format: "Update to r%d".locale, lastRevNum)
|
|
} else {
|
|
AppSD.statusItem.button?.title = ""
|
|
AppSD.statusItem.button?.imagePosition = .imageOnly
|
|
self.updateCloverButton.isEnabled = false
|
|
self.updateCloverButton.title = kNotAvailable.locale
|
|
}
|
|
}
|
|
}
|
|
|
|
let date = Date()
|
|
let now = DateFormatter.localizedString(from: date, dateStyle: .short, timeStyle: .short)
|
|
DispatchQueue.main.async {
|
|
self.lastUpdateCheckField.stringValue = "\("last checked:".locale) \(now)"
|
|
}
|
|
UDs.set(date, forKey: kLastSearchUpdateDateKey)
|
|
UDs.synchronize()
|
|
}
|
|
}
|
|
|
|
// MARK: Download
|
|
@IBAction func updateClover(_ sender: NSButton!) {
|
|
if AppSD.isInstalling ||
|
|
AppSD.isInstallerOpen ||
|
|
self.lastReleaseLink == nil ||
|
|
self.lastReleaseRev == nil {
|
|
NSSound.beep()
|
|
return
|
|
}
|
|
self.progressBar.isHidden = false
|
|
self.progressBar.doubleValue = 0.0
|
|
let url = URL(string: self.lastReleaseLink!)
|
|
|
|
let b = URLSessionConfiguration.default
|
|
let session = Foundation.URLSession(configuration: b, delegate: self, delegateQueue: nil)
|
|
|
|
//let session = URLSession(configuration: .default)
|
|
|
|
if (url != nil) {
|
|
self.installCloverButton.isEnabled = false
|
|
self.downloadTask = session.downloadTask(with: url!)
|
|
self.downloadTask?.resume()
|
|
}
|
|
}
|
|
|
|
func urlSession(_ session: URLSession,
|
|
downloadTask: URLSessionDownloadTask,
|
|
didFinishDownloadingTo location: URL) {
|
|
|
|
DispatchQueue.main.async {
|
|
self.progressBar.doubleValue = 100
|
|
self.progressBar.isHidden = true
|
|
}
|
|
|
|
do {
|
|
|
|
let lastPath = downloadTask.originalRequest!.url!.lastPathComponent
|
|
let data = try Data(contentsOf: location)
|
|
|
|
if lastPath.fileExtension == "zip" && lastPath.hasPrefix("CloverV2") {
|
|
// ok, We have the download completed: replace CloverV2 inside SharedSupport directory!
|
|
|
|
// Decompress the zip archive
|
|
let tempDir = NSTemporaryDirectory().addPath("CloverXXXXX")
|
|
if fm.fileExists(atPath: tempDir) {
|
|
try fm.removeItem(atPath: tempDir)
|
|
try fm.createDirectory(atPath: tempDir, withIntermediateDirectories: true, attributes: nil)
|
|
}
|
|
let file = tempDir.addPath(lastPath)
|
|
try data.write(to: URL(fileURLWithPath: file))
|
|
unzip(file: file, destination: tempDir) { (success) in
|
|
if success {
|
|
self.replaceCloverV2(with: tempDir.addPath("CloverV2"))
|
|
}
|
|
}
|
|
} else {
|
|
try data.write(to: URL(fileURLWithPath: NSHomeDirectory().addPath("Downloads/\(lastPath)")))
|
|
replaceCloverV2(with: "/Users/vectorsigma/src/CloverBootloader/CloverPackage/CloverV2")
|
|
}
|
|
|
|
} catch {
|
|
print(error)
|
|
}
|
|
}
|
|
|
|
func urlSession(_ session: URLSession,
|
|
task: URLSessionTask,
|
|
didCompleteWithError error: Error?) {
|
|
|
|
DispatchQueue.main.async {
|
|
self.installCloverButton.isEnabled = true
|
|
}
|
|
if (error != nil) {
|
|
print(error!.localizedDescription)
|
|
}
|
|
}
|
|
|
|
func urlSession(_ session: URLSession,
|
|
downloadTask: URLSessionDownloadTask,
|
|
didWriteData bytesWritten: Int64,
|
|
totalBytesWritten: Int64,
|
|
totalBytesExpectedToWrite: Int64) {
|
|
|
|
if totalBytesExpectedToWrite == NSURLSessionTransferSizeUnknown {
|
|
DispatchQueue.main.async {
|
|
self.progressBar.isIndeterminate = true
|
|
self.progressBar.startAnimation(nil)
|
|
}
|
|
} else {
|
|
let percentage : Double = Double(totalBytesWritten) / Double(totalBytesExpectedToWrite) * 100
|
|
|
|
DispatchQueue.main.async {
|
|
self.progressBar?.isIndeterminate = false
|
|
self.progressBar?.doubleValue = percentage
|
|
}
|
|
}
|
|
}
|
|
|
|
private func replaceCloverV2(with newOne: String) {
|
|
var isDir : ObjCBool = false
|
|
if fm.fileExists(atPath: newOne, isDirectory: &isDir) {
|
|
if isDir.boolValue {
|
|
do {
|
|
try fm.removeItem(atPath: Cloverv2Path)
|
|
try fm.copyItem(atPath: newOne, toPath: Cloverv2Path)
|
|
print("CloverV2 Replaced!")
|
|
DispatchQueue.main.async {
|
|
self.lastReleaseRev = nil
|
|
self.lastReleaseLink = nil
|
|
self.setUpdateInformations()
|
|
self.setUpdateButton()
|
|
}
|
|
} catch {
|
|
print(error)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: Close
|
|
@IBAction func close(_ sender: NSButton!) {
|
|
NSApp.terminate(nil)
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// MARK: Settings Window controller
|
|
class SettingsWindowController: NSWindowController, NSWindowDelegate {
|
|
class func loadFromNib() -> SettingsWindowController {
|
|
let wc = NSStoryboard(name: "Settings",
|
|
bundle: nil).instantiateController(withIdentifier: "SettingsWindowController") as! SettingsWindowController
|
|
return wc
|
|
}
|
|
}
|