From 6846612b83a386257c719596c2d3d0a610f8dbc2 Mon Sep 17 00:00:00 2001 From: David Sinclair Date: Tue, 28 Apr 2020 17:56:52 -0700 Subject: [PATCH] #12 (widget) - Adding Turn Touch code, WIP. --- Turn Touch iOS.xcodeproj/project.pbxproj | 8 + .../Base.lproj/MainInterface.storyboard | 17 +- Widget Extension/WidgetDelegate.swift | 88 +++++++ .../WidgetExtensionViewController.swift | 217 +++++++++++++++++- 4 files changed, 314 insertions(+), 16 deletions(-) create mode 100644 Widget Extension/WidgetDelegate.swift diff --git a/Turn Touch iOS.xcodeproj/project.pbxproj b/Turn Touch iOS.xcodeproj/project.pbxproj index d9f13ce..81551d4 100644 --- a/Turn Touch iOS.xcodeproj/project.pbxproj +++ b/Turn Touch iOS.xcodeproj/project.pbxproj @@ -7,6 +7,9 @@ objects = { /* Begin PBXBuildFile section */ + 170C8DC6245906150089B2C0 /* WidgetDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 170C8DC5245906150089B2C0 /* WidgetDelegate.swift */; }; + 170C8DC7245907A70089B2C0 /* TTModeDirection.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB41B7A1CEEA9E300CD5F09 /* TTModeDirection.swift */; }; + 170C8DC8245907B40089B2C0 /* TTModeMap.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFB41B831CF5342100CD5F09 /* TTModeMap.swift */; }; 17AE44062458FF9C00D06762 /* NotificationCenter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17AE44052458FF9C00D06762 /* NotificationCenter.framework */; }; 17AE44092458FF9C00D06762 /* WidgetExtensionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 17AE44082458FF9C00D06762 /* WidgetExtensionViewController.swift */; }; 17AE440C2458FF9C00D06762 /* MainInterface.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 17AE440A2458FF9C00D06762 /* MainInterface.storyboard */; }; @@ -909,6 +912,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 170C8DC5245906150089B2C0 /* WidgetDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetDelegate.swift; sourceTree = ""; }; 17AE44042458FF9C00D06762 /* Turn Touch Widget.appex */ = {isa = PBXFileReference; explicitFileType = "wrapper.app-extension"; includeInIndex = 0; path = "Turn Touch Widget.appex"; sourceTree = BUILT_PRODUCTS_DIR; }; 17AE44052458FF9C00D06762 /* NotificationCenter.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NotificationCenter.framework; path = System/Library/Frameworks/NotificationCenter.framework; sourceTree = SDKROOT; }; 17AE44082458FF9C00D06762 /* WidgetExtensionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WidgetExtensionViewController.swift; sourceTree = ""; }; @@ -1420,6 +1424,7 @@ isa = PBXGroup; children = ( 17AE44082458FF9C00D06762 /* WidgetExtensionViewController.swift */, + 170C8DC5245906150089B2C0 /* WidgetDelegate.swift */, 17AE440A2458FF9C00D06762 /* MainInterface.storyboard */, 17AE440D2458FF9C00D06762 /* Info.plist */, ); @@ -3083,6 +3088,9 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 170C8DC6245906150089B2C0 /* WidgetDelegate.swift in Sources */, + 170C8DC8245907B40089B2C0 /* TTModeMap.swift in Sources */, + 170C8DC7245907A70089B2C0 /* TTModeDirection.swift in Sources */, 17AE44092458FF9C00D06762 /* WidgetExtensionViewController.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/Widget Extension/Base.lproj/MainInterface.storyboard b/Widget Extension/Base.lproj/MainInterface.storyboard index 34b7fdf..19d50af 100644 --- a/Widget Extension/Base.lproj/MainInterface.storyboard +++ b/Widget Extension/Base.lproj/MainInterface.storyboard @@ -1,5 +1,6 @@ + @@ -9,23 +10,10 @@ - + - - - - - - - - - @@ -34,6 +22,7 @@ + diff --git a/Widget Extension/WidgetDelegate.swift b/Widget Extension/WidgetDelegate.swift new file mode 100644 index 0000000..c668a07 --- /dev/null +++ b/Widget Extension/WidgetDelegate.swift @@ -0,0 +1,88 @@ +// +// WidgetDelegate.swift +// Widget Extension +// +// Created by David Sinclair on 2020-04-28. +// Copyright © 2020 Turn Touch. All rights reserved. +// + +import UIKit + +class WidgetDelegate: UIResponder { + /// Singleton shared instance. + static let shared = WidgetDelegate() + + var window: UIWindow? +// var modeMap: TTModeMap! +// @IBOutlet var mainViewController: WidgetExtensionViewController! + + override init() { + super.init() + + // self.erasePreferences() + self.loadPreferences() + +// modeMap = TTModeMap() +// modeMap.setupModes() +// modeMap.activateModes() + } + + func redrawMainLayout() { +// modeMap.setupModes() +// mainViewController.layoutStackview() +// modeMap.activateModes() + } + + func loadPreferences() { + let prefs = UserDefaults.standard + let defaultPrefsFile = Bundle.main.path(forResource: "Preferences", ofType: "plist") + let defaultPrefs = NSDictionary(contentsOfFile: defaultPrefsFile!) as! [String: AnyObject] + prefs.register(defaults: defaultPrefs) + + self.processDefaultSettings() + + prefs.set(Bundle.main.infoDictionary!["CFBundleShortVersionString"], forKey: "version") + prefs.set(Bundle.main.infoDictionary!["CFBundleVersion"], forKey: "build_number") + + prefs.synchronize() + } + + func processDefaultSettings() { + let defaults = UserDefaults.standard + defaults.synchronize() + + guard let settingsBundle = Bundle.main.path(forResource: "Settings", ofType: "bundle") as NSString? else { + NSLog("Could not find Settings.bundle"); + return; + } + + if let settings = NSDictionary(contentsOfFile: settingsBundle.appendingPathComponent("Root.plist")) { + // print(" ---> Settings: \(settings)") + if let preferences = settings.object(forKey: "PreferenceSpecifiers") as? [[String: Any]] { + + var defaultsToRegister = [String: Any](minimumCapacity: preferences.count) + + for prefSpecification in preferences { + if let key = prefSpecification["Key"] as? String { + if !key.contains("") { + let currentObject = defaults.object(forKey: key) + if currentObject == nil { + let objectToSet = prefSpecification["DefaultValue"] + defaultsToRegister[key] = objectToSet! + + NSLog("Setting object \(String(describing: objectToSet)) for key \(key)") + } + } + } + } + + defaults.register(defaults: defaultsToRegister) + defaults.synchronize() + } + } + } +} + +func appDelegate() -> WidgetDelegate { + return WidgetDelegate.shared +} diff --git a/Widget Extension/WidgetExtensionViewController.swift b/Widget Extension/WidgetExtensionViewController.swift index 1a42c61..aa458d1 100644 --- a/Widget Extension/WidgetExtensionViewController.swift +++ b/Widget Extension/WidgetExtensionViewController.swift @@ -10,12 +10,18 @@ import UIKit import NotificationCenter class WidgetExtensionViewController: UIViewController, NCWidgetProviding { - + var stackView = UIStackView() + var modeTabsView = UIStackView() +// var modeTabs: [TTModeTab] = [] +// var modeTabsConstraint: NSLayoutConstraint! +// var actionDiamondView = TTActionDiamondView(diamondType: .interactive) +// var actionDiamondConstraint: NSLayoutConstraint! + override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } - + func widgetPerformUpdate(completionHandler: (@escaping (NCUpdateResult) -> Void)) { // Perform any setup necessary in order to update the view. @@ -26,4 +32,211 @@ class WidgetExtensionViewController: UIViewController, NCWidgetProviding { completionHandler(NCUpdateResult.newData) } + override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { + super.init(nibName: nibNameOrNil, bundle: nibBundleOrNil) + + self.view.backgroundColor = UIColor.white + + self.layoutStackview() + + self.registerAsObserver() + } + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + } + + func layoutStackview() { +// modeTabsView.arrangedSubviews.forEach { $0.removeFromSuperview() } +// stackView.arrangedSubviews.forEach { $0.removeFromSuperview() } +// stackView.constraints.forEach { stackView.removeConstraint($0) } +// +// stackView.translatesAutoresizingMaskIntoConstraints = false +// stackView.axis = .vertical +// stackView.distribution = .fill +// stackView.alignment = .fill +// stackView.spacing = 0 +// // stackView.contentMode = .ScaleToFill +// let guide = self.view.safeAreaLayoutGuide +// self.view.addSubview(stackView) +// self.view.addConstraint(NSLayoutConstraint(item: stackView, attribute: .width, +// relatedBy: .equal, toItem: self.view, attribute: .width, multiplier: 1.0, constant: 0.0)) +// self.view.addConstraint(stackView.topAnchor.constraint(equalToSystemSpacingBelow: guide.topAnchor, multiplier: 1.0)) +// self.view.addConstraint(NSLayoutConstraint(item: stackView, attribute: .bottom, +// relatedBy: .equal, toItem: self.view, attribute: .bottom, multiplier: 1.0, constant: 0.0)) +// self.view.addConstraint(NSLayoutConstraint(item: stackView, attribute: .left, +// relatedBy: .equal, toItem: self.view, attribute: .left, multiplier: 1.0, constant: 0.0)) +// self.view.addConstraint(NSLayoutConstraint(item: stackView, attribute: .right, +// relatedBy: .equal, toItem: self.view, attribute: .right, multiplier: 1.0, constant: 0.0)) +// +// if appDelegate().modeMap.buttonAppMode() == .SixteenButtons { +// modeTabs = [ +// TTModeTab(modeDirection:.north), +// TTModeTab(modeDirection:.east), +// TTModeTab(modeDirection:.west), +// TTModeTab(modeDirection:.south), +// ] +// } else { +// modeTabs = [ +// TTModeTab(modeDirection: .single), +// TTModeTab(modeDirection: .double), +// TTModeTab(modeDirection: .hold) +// ] +// } +// for view in modeTabs { +// modeTabsView.addArrangedSubview(view) +// } +// modeTabsView.axis = .horizontal +// modeTabsView.distribution = .fillEqually +// modeTabsView.alignment = .fill +// modeTabsView.spacing = 0 +// modeTabsView.contentMode = .scaleToFill +// stackView.addArrangedSubview(modeTabsView); +// +// modeTabsConstraint = NSLayoutConstraint(item: modeTabsView, attribute: .height, relatedBy: .equal, +// toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 92.0) +// stackView.addConstraint(modeTabsConstraint) +// +// actionDiamondConstraint = NSLayoutConstraint(item: actionDiamondView, attribute: .height, relatedBy: .equal, +// toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 420) +// stackView.addConstraint(actionDiamondConstraint) +// stackView.addArrangedSubview(actionDiamondView) + + // if appDelegate().modeMap.buttonAppMode() == .TwelveButtons, let modeTitleView = modeTitleView { + // modeTitleView.alpha = 0 + // scrollStackView.addArrangedSubview(modeTitleView) + // modeTitleConstraint = NSLayoutConstraint(item: modeTitleView, attribute: .height, relatedBy: .equal, + // toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 0) + // scrollStackView.addConstraint(modeTitleConstraint) + // + // scrollStackView.addArrangedSubview(modeMenuView) + // modeMenuConstaint = NSLayoutConstraint(item: modeMenuView, attribute: .height, relatedBy: .equal, + // toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 1.0) + // scrollStackView.addConstraint(modeMenuConstaint) + // } + // + // scrollStackView.addArrangedSubview(actionMenuView) + // actionMenuConstaint = NSLayoutConstraint(item: actionMenuView, attribute: .height, relatedBy: .equal, + // toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 1.0) + // scrollStackView.addConstraint(actionMenuConstaint) + // + // actionTitleView.alpha = 0 + // scrollStackView.addArrangedSubview(actionTitleView) + // actionTitleConstraint = NSLayoutConstraint(item: actionTitleView, attribute: .height, relatedBy: .equal, + // toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 0) + // scrollStackView.addConstraint(actionTitleConstraint) + // + // optionsView.setContentCompressionResistancePriority(UILayoutPriority.defaultHigh, for: .vertical) + // scrollStackView.addArrangedSubview(optionsView) + // optionsConstraint = NSLayoutConstraint(item: optionsView, attribute: .height, relatedBy: .equal, + // toItem: nil, attribute: .notAnAttribute, + // multiplier: 1.0, constant: 0) + // // scrollStackView.addConstraint(optionsConstraint) + // + // batchActionsStackView.setContentCompressionResistancePriority(UILayoutPriority.defaultHigh, for: .vertical) + // scrollStackView.addArrangedSubview(batchActionsStackView) + // + // addActionMenuConstraint = NSLayoutConstraint(item: addActionMenu, attribute: .height, relatedBy: .equal, + // toItem: nil, attribute: .notAnAttribute, + // multiplier: 1.0, constant: 0) + // scrollStackView.addArrangedSubview(addActionMenu) + // scrollStackView.addConstraint(addActionMenuConstraint) + // + // addActionButtonConstraint = NSLayoutConstraint(item: addActionButtonView, attribute: .height, relatedBy: .equal, + // toItem: nil, attribute: .notAnAttribute, + // multiplier: 1.0, constant: 0) + // scrollStackView.addArrangedSubview(addActionButtonView) + // scrollStackView.addConstraint(addActionButtonConstraint) + // + // scrollView.setContentHuggingPriority(UILayoutPriority(rawValue: 100), for: NSLayoutConstraint.Axis.vertical) + // scrollView.alwaysBounceVertical = true + // scrollView.insertSubview(scrollStackView, at: 0) + // scrollView.backgroundColor = UIColor(hex: 0xF5F6F8) + // scrollView.addConstraint(NSLayoutConstraint(item: scrollStackView, attribute: .top, + // relatedBy: .equal, toItem: scrollView, attribute: .top, + // multiplier: 1.0, constant: 0.0)) + // scrollView.addConstraint(NSLayoutConstraint(item: scrollStackView, attribute: .leading, + // relatedBy: .equal, toItem: scrollView, attribute: .leading, + // multiplier: 1.0, constant: 0.0)) + // scrollView.addConstraint(NSLayoutConstraint(item: scrollStackView, attribute: .trailing, + // relatedBy: .equal, toItem: scrollView, attribute: .trailing, + // multiplier: 1.0, constant: 0.0)) + // scrollView.addConstraint(NSLayoutConstraint(item: scrollStackView, attribute: .width, + // relatedBy: .equal, toItem: scrollView, attribute: .width, + // multiplier: 1.0, constant: 0.0)) + // scrollView.addConstraint(NSLayoutConstraint(item: scrollStackView, attribute: .bottom, + // relatedBy: .equal, toItem: scrollView, attribute: .bottom, + // multiplier: 1.0, constant: 0.0)) + // stackView.addArrangedSubview(scrollView) + // stackView.addConstraint(NSLayoutConstraint(item: scrollView, attribute: .leading, + // relatedBy: .equal, toItem: stackView, attribute: .leading, + // multiplier: 1.0, constant: 0.0)) + // stackView.addConstraint(NSLayoutConstraint(item: scrollView, attribute: .trailing, + // relatedBy: .equal, toItem: stackView, attribute: .trailing, + // multiplier: 1.0, constant: 0.0)) + // scrollView.setNeedsLayout() + // scrollView.layoutIfNeeded() + + self.applyConstraints() + } + + override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { + super.traitCollectionDidChange(previousTraitCollection) + + self.applyConstraints() + } + + func applyConstraints() { +// let buttonAppMode = appDelegate().modeMap.buttonAppMode() +// +// if self.traitCollection.verticalSizeClass == UIUserInterfaceSizeClass.compact { +// titleBarConstraint.constant = 28 +// modeTabsConstraint.constant = 70 +// switch buttonAppMode { +// case .SixteenButtons: +// modeTitleConstraint.constant = 48 +// case .TwelveButtons: +// modeTitleConstraint.constant = 0 +// } +// } else { +// titleBarConstraint.constant = 44 +// modeTabsConstraint.constant = 92 +// switch buttonAppMode { +// case .SixteenButtons: +// modeTitleConstraint.constant = 64 +// case .TwelveButtons: +// modeTitleConstraint.constant = 0 +// } +// } +// +// if self.traitCollection.horizontalSizeClass == .compact { +// actionDiamondConstraint.constant = 270 +// } else { +// actionDiamondConstraint.constant = 420 +// } + } + + // MARK: KVO + + func registerAsObserver() { + // appDelegate().modeMap.addObserver(self, forKeyPath: "openedModeChangeMenu", options: [], context: nil) + // appDelegate().modeMap.addObserver(self, forKeyPath: "openedActionChangeMenu", options: [], context: nil) + // appDelegate().modeMap.addObserver(self, forKeyPath: "openedAddActionChangeMenu", options: [], context: nil) + // appDelegate().modeMap.addObserver(self, forKeyPath: "selectedModeDirection", options: [], context: nil) + // appDelegate().modeMap.addObserver(self, forKeyPath: "inspectingModeDirection", options: [], context: nil) + // appDelegate().modeMap.addObserver(self, forKeyPath: "tempMode", options: [], context: nil) + // appDelegate().bluetoothMonitor.addObserver(self, forKeyPath: "nicknamedConnectedCount", options: [], context: nil) + // appDelegate().bluetoothMonitor.addObserver(self, forKeyPath: "pairedDevicesCount", options: [], context: nil) + } + + deinit { +// appDelegate().modeMap.removeObserver(self, forKeyPath: "openedModeChangeMenu") + // appDelegate().modeMap.removeObserver(self, forKeyPath: "openedActionChangeMenu") + // appDelegate().modeMap.removeObserver(self, forKeyPath: "openedAddActionChangeMenu") + // appDelegate().modeMap.removeObserver(self, forKeyPath: "selectedModeDirection") + // appDelegate().modeMap.removeObserver(self, forKeyPath: "inspectingModeDirection") + // appDelegate().modeMap.removeObserver(self, forKeyPath: "tempMode") + // appDelegate().bluetoothMonitor.removeObserver(self, forKeyPath: "nicknamedConnectedCount") + // appDelegate().bluetoothMonitor.removeObserver(self, forKeyPath: "pairedDevicesCount") + } }