From 3a71519926e59cddd715bbe5c588bd0221df22b3 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Wed, 17 Jan 2018 18:16:23 +0000 Subject: [PATCH 01/43] Use BoostBLEKit --- BoostRemote.xcodeproj/project.pbxproj | 42 ++++------------- BoostRemote/Action.swift | 3 +- BoostRemote/Command.swift | 29 ------------ BoostRemote/ControllerViewController.swift | 14 ++---- BoostRemote/DeviceType.swift | 30 ------------ BoostRemote/Motor.swift | 18 -------- BoostRemote/MoveHubManager.swift | 1 + BoostRemote/MoveHubService.swift | 5 +- BoostRemote/Notification.swift | 54 ---------------------- BoostRemote/Port.swift | 36 --------------- BoostRemote/State.swift | 3 +- BoostRemote/StickView.swift | 3 +- Cartfile | 1 + Cartfile.resolved | 1 + 14 files changed, 27 insertions(+), 213 deletions(-) delete mode 100644 BoostRemote/Command.swift delete mode 100644 BoostRemote/DeviceType.swift delete mode 100644 BoostRemote/Motor.swift delete mode 100644 BoostRemote/Notification.swift delete mode 100644 BoostRemote/Port.swift diff --git a/BoostRemote.xcodeproj/project.pbxproj b/BoostRemote.xcodeproj/project.pbxproj index 317b730..8948453 100644 --- a/BoostRemote.xcodeproj/project.pbxproj +++ b/BoostRemote.xcodeproj/project.pbxproj @@ -15,6 +15,7 @@ CB3BE8B61F2FF2F4000561F7 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CB3BE8B41F2FF2F4000561F7 /* Main.storyboard */; }; CB3BE8B81F2FF2F4000561F7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = CB3BE8B71F2FF2F4000561F7 /* Assets.xcassets */; }; CB3BE8BB1F2FF2F4000561F7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CB3BE8B91F2FF2F4000561F7 /* LaunchScreen.storyboard */; }; + CB4345A8200FC0D200D82D7D /* BoostBLEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CB4345A7200FC0D100D82D7D /* BoostBLEKit.framework */; }; CB44B8531F73C11400D0D250 /* Store.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB44B8521F73C11400D0D250 /* Store.swift */; }; CB5891F1200D2C8700E15F92 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = CB5891F3200D2C8700E15F92 /* Localizable.strings */; }; CB5891F9200D2DF300E15F92 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = CB5891FB200D2DF300E15F92 /* InfoPlist.strings */; }; @@ -25,13 +26,8 @@ CBD94E841F391B3F0037ED71 /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD94E831F391B3F0037ED71 /* State.swift */; }; CBD94E861F391D7F0037ED71 /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD94E851F391D7F0037ED71 /* Action.swift */; }; CBD94E881F391E2E0037ED71 /* Reducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD94E871F391E2E0037ED71 /* Reducer.swift */; }; - CBD94E8A1F392C310037ED71 /* Motor.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD94E891F392C310037ED71 /* Motor.swift */; }; - CBD94E8C1F3936A60037ED71 /* Command.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD94E8B1F3936A60037ED71 /* Command.swift */; }; CBF9D2B91F3CACA800B97E11 /* MoveHubManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF9D2B81F3CACA800B97E11 /* MoveHubManager.swift */; }; CBF9D2D61F3CB52800B97E11 /* MoveHubService.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF9D2D51F3CB52800B97E11 /* MoveHubService.swift */; }; - CBF9D2F01F3CCA6E00B97E11 /* Port.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF9D2EF1F3CCA6E00B97E11 /* Port.swift */; }; - CBF9D2F21F3CCA8900B97E11 /* DeviceType.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF9D2F11F3CCA8900B97E11 /* DeviceType.swift */; }; - CBF9D2F41F3CCB0900B97E11 /* Notification.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF9D2F31F3CCB0900B97E11 /* Notification.swift */; }; CBF9D2F61F3CDAC700B97E11 /* Data+HexString.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBF9D2F51F3CDAC700B97E11 /* Data+HexString.swift */; }; /* End PBXBuildFile section */ @@ -59,6 +55,7 @@ CB3BE8B71F2FF2F4000561F7 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; CB3BE8BA1F2FF2F4000561F7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; CB3BE8BC1F2FF2F4000561F7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + CB4345A7200FC0D100D82D7D /* BoostBLEKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BoostBLEKit.framework; path = Carthage/Build/iOS/BoostBLEKit.framework; sourceTree = ""; }; CB44B8521F73C11400D0D250 /* Store.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Store.swift; sourceTree = ""; }; CB5891F4200D2CEA00E15F92 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; CB5891FA200D2DF300E15F92 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -69,13 +66,8 @@ CBD94E831F391B3F0037ED71 /* State.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = State.swift; sourceTree = ""; }; CBD94E851F391D7F0037ED71 /* Action.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Action.swift; sourceTree = ""; }; CBD94E871F391E2E0037ED71 /* Reducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Reducer.swift; sourceTree = ""; }; - CBD94E891F392C310037ED71 /* Motor.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Motor.swift; sourceTree = ""; }; - CBD94E8B1F3936A60037ED71 /* Command.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Command.swift; sourceTree = ""; }; CBF9D2B81F3CACA800B97E11 /* MoveHubManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoveHubManager.swift; sourceTree = ""; }; CBF9D2D51F3CB52800B97E11 /* MoveHubService.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MoveHubService.swift; sourceTree = ""; }; - CBF9D2EF1F3CCA6E00B97E11 /* Port.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Port.swift; sourceTree = ""; }; - CBF9D2F11F3CCA8900B97E11 /* DeviceType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DeviceType.swift; sourceTree = ""; }; - CBF9D2F31F3CCB0900B97E11 /* Notification.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Notification.swift; sourceTree = ""; }; CBF9D2F51F3CDAC700B97E11 /* Data+HexString.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Data+HexString.swift"; sourceTree = ""; }; /* End PBXFileReference section */ @@ -84,6 +76,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + CB4345A8200FC0D200D82D7D /* BoostBLEKit.framework in Frameworks */, CBA46E7A1F882F0F0017E5C2 /* Result.framework in Frameworks */, CBA46E781F882F0C0017E5C2 /* ReactiveSwift.framework in Frameworks */, CBA46E7E1F882F800017E5C2 /* ReactiveCocoa.framework in Frameworks */, @@ -117,12 +110,12 @@ CB3BE8B01F2FF2F4000561F7 /* AppDelegate.swift */, CB3BE8B41F2FF2F4000561F7 /* Main.storyboard */, CB3BE8B21F2FF2F4000561F7 /* ControllerViewController.swift */, - CBF9D2B81F3CACA800B97E11 /* MoveHubManager.swift */, CB0BF7E41F8BD873004CCD4F /* VerticalSlider.swift */, CB0BF7E61F8BDD30004CCD4F /* StickView.swift */, + CBF9D2B81F3CACA800B97E11 /* MoveHubManager.swift */, + CBF9D2D51F3CB52800B97E11 /* MoveHubService.swift */, CBF9D2F51F3CDAC700B97E11 /* Data+HexString.swift */, CBF9D2D81F3CB63300B97E11 /* Redux */, - CBF9D2D71F3CB62700B97E11 /* MoveHub */, CB3BE8B71F2FF2F4000561F7 /* Assets.xcassets */, CB3BE8B91F2FF2F4000561F7 /* LaunchScreen.storyboard */, CB5891F3200D2C8700E15F92 /* Localizable.strings */, @@ -136,27 +129,15 @@ CBA46E761F882F0B0017E5C2 /* Frameworks */ = { isa = PBXGroup; children = ( + CB4345A7200FC0D100D82D7D /* BoostBLEKit.framework */, CBA46E7C1F882F800017E5C2 /* ReactiveCocoa.framework */, - CBA46E7B1F882F800017E5C2 /* ReSwift.framework */, - CBA46E791F882F0F0017E5C2 /* Result.framework */, CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */, + CBA46E791F882F0F0017E5C2 /* Result.framework */, + CBA46E7B1F882F800017E5C2 /* ReSwift.framework */, ); name = Frameworks; sourceTree = ""; }; - CBF9D2D71F3CB62700B97E11 /* MoveHub */ = { - isa = PBXGroup; - children = ( - CBD94E8B1F3936A60037ED71 /* Command.swift */, - CBF9D2F11F3CCA8900B97E11 /* DeviceType.swift */, - CBD94E891F392C310037ED71 /* Motor.swift */, - CBF9D2D51F3CB52800B97E11 /* MoveHubService.swift */, - CBF9D2F31F3CCB0900B97E11 /* Notification.swift */, - CBF9D2EF1F3CCA6E00B97E11 /* Port.swift */, - ); - name = MoveHub; - sourceTree = ""; - }; CBF9D2D81F3CB63300B97E11 /* Redux */ = { isa = PBXGroup; children = ( @@ -254,12 +235,14 @@ "$(SRCROOT)/Carthage/Build/iOS/ReactiveSwift.framework", "$(SRCROOT)/Carthage/Build/iOS/ReactiveCocoa.framework", "$(SRCROOT)/Carthage/Build/iOS/ReSwift.framework", + "$(SRCROOT)/Carthage/Build/iOS/BoostBLEKit.framework", ); outputPaths = ( "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Result.framework", "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/ReactiveSwift.framework", "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/ReactiveCocoa.framework", "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/ReSwift.framework", + "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/BoostBLEKit.framework", ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; @@ -276,17 +259,12 @@ CB3BE8B31F2FF2F4000561F7 /* ControllerViewController.swift in Sources */, CB0BF7E51F8BD873004CCD4F /* VerticalSlider.swift in Sources */, CB0BF7E71F8BDD30004CCD4F /* StickView.swift in Sources */, - CBD94E8A1F392C310037ED71 /* Motor.swift in Sources */, CBD94E861F391D7F0037ED71 /* Action.swift in Sources */, CB3BE8B11F2FF2F4000561F7 /* AppDelegate.swift in Sources */, - CBD94E8C1F3936A60037ED71 /* Command.swift in Sources */, CBF9D2F61F3CDAC700B97E11 /* Data+HexString.swift in Sources */, CB44B8531F73C11400D0D250 /* Store.swift in Sources */, - CBF9D2F21F3CCA8900B97E11 /* DeviceType.swift in Sources */, - CBF9D2F41F3CCB0900B97E11 /* Notification.swift in Sources */, CBD94E881F391E2E0037ED71 /* Reducer.swift in Sources */, CBD94E841F391B3F0037ED71 /* State.swift in Sources */, - CBF9D2F01F3CCA6E00B97E11 /* Port.swift in Sources */, CBF9D2D61F3CB52800B97E11 /* MoveHubService.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/BoostRemote/Action.swift b/BoostRemote/Action.swift index fb4ba0d..a081738 100644 --- a/BoostRemote/Action.swift +++ b/BoostRemote/Action.swift @@ -8,6 +8,7 @@ import Foundation import ReSwift +import BoostBLEKit enum ConnectAction: Action { @@ -20,7 +21,7 @@ enum ConnectAction: Action { struct NotificationAction: Action { - let notification: Notification + let notification: BoostBLEKit.Notification } struct ActionCenter { diff --git a/BoostRemote/Command.swift b/BoostRemote/Command.swift deleted file mode 100644 index 548ce50..0000000 --- a/BoostRemote/Command.swift +++ /dev/null @@ -1,29 +0,0 @@ -// -// Command.swift -// BoostRemote -// -// Created by Shinichiro Oba on 2017/08/08. -// Copyright © 2017 bricklife.com. All rights reserved. -// - -import Foundation - -protocol Command: CustomStringConvertible { - - var data: Data { get } -} - -struct MotorPowerCommand: Command { - - let port: Port - let power: Int8 - - var data: Data { - let power = UInt8(bitPattern: self.power) - return Data(bytes: [0x09, 0x00, 0x81, port.rawValue, 0x11, 0x07, power, 0x64, 0x03]) - } - - var description: String { - return "MotorPowerCommand " - } -} diff --git a/BoostRemote/ControllerViewController.swift b/BoostRemote/ControllerViewController.swift index 8aa0678..7980544 100644 --- a/BoostRemote/ControllerViewController.swift +++ b/BoostRemote/ControllerViewController.swift @@ -11,6 +11,7 @@ import ReactiveCocoa import ReactiveSwift import Result import ReSwift +import BoostBLEKit class ControllerViewController: UIViewController { @@ -23,7 +24,7 @@ class ControllerViewController: UIViewController { private let connectionState = MutableProperty(ConnectionState.disconnected) - private var motors: [Port: Motor] = [:] { + private var motors: [BoostBLEKit.Port: Motor] = [:] { didSet { stickC?.isHidden = !motors.keys.contains(.C) stickD?.isHidden = !motors.keys.contains(.D) @@ -106,7 +107,7 @@ class ControllerViewController: UIViewController { return Signal.merge(valueSignal, touchUpSignal).skipRepeats() } - private func sendCommand(port: Port, power: Int8) { + private func sendCommand(port: BoostBLEKit.Port, power: Int8) { if let command = motors[port]?.powerCommand(power: power) { ActionCenter.send(command: command) } @@ -139,16 +140,11 @@ extension ControllerViewController: StoreSubscriber { func newState(state: State) { connectionState.value = state.connectionState - let ports: [Port] = [.A, .B, .C, .D] + let ports: [BoostBLEKit.Port] = [.A, .B, .C, .D] for port in ports { motors[port] = state.portState[port].flatMap { type -> Motor? in guard state.connectionState == .connected else { return nil } - switch type { - case .builtInMotor, .interactiveMotor: - return Motor(port: port) - default: - return nil - } + return Motor(port: port, deviceType: type) } } } diff --git a/BoostRemote/DeviceType.swift b/BoostRemote/DeviceType.swift deleted file mode 100644 index 342ea98..0000000 --- a/BoostRemote/DeviceType.swift +++ /dev/null @@ -1,30 +0,0 @@ -// -// DeviceType.swift -// BoostRemote -// -// Created by ooba on 10/08/2017. -// Copyright © 2017 bricklife.com. All rights reserved. -// - -import Foundation - -enum DeviceType: UInt8 { - - case colorDistanceSensor = 0x25 - case interactiveMotor = 0x26 - case builtInMotor = 0x27 -} - -extension DeviceType: CustomStringConvertible { - - var description: String { - switch self { - case .colorDistanceSensor: - return "Color & Distance Sensor" - case .interactiveMotor: - return "Interactive Motor" - case .builtInMotor: - return "Built-in Motor" - } - } -} diff --git a/BoostRemote/Motor.swift b/BoostRemote/Motor.swift deleted file mode 100644 index a04d35f..0000000 --- a/BoostRemote/Motor.swift +++ /dev/null @@ -1,18 +0,0 @@ -// -// Motor.swift -// BoostRemote -// -// Created by Shinichiro Oba on 2017/08/08. -// Copyright © 2017 bricklife.com. All rights reserved. -// - -import Foundation - -struct Motor { - - let port: Port - - func powerCommand(power: Int8) -> MotorPowerCommand { - return MotorPowerCommand(port: port, power: power) - } -} diff --git a/BoostRemote/MoveHubManager.swift b/BoostRemote/MoveHubManager.swift index b95b67a..e46fa4a 100644 --- a/BoostRemote/MoveHubManager.swift +++ b/BoostRemote/MoveHubManager.swift @@ -9,6 +9,7 @@ import Foundation import CoreBluetooth import ReSwift +import BoostBLEKit class MoveHubManager: NSObject { diff --git a/BoostRemote/MoveHubService.swift b/BoostRemote/MoveHubService.swift index 7e50ca8..5c06e69 100644 --- a/BoostRemote/MoveHubService.swift +++ b/BoostRemote/MoveHubService.swift @@ -8,9 +8,10 @@ import Foundation import CoreBluetooth +import BoostBLEKit struct MoveHubService { - static let serviceUuid = CBUUID(string: "00001623-1212-EFDE-1623-785FEABCD123") - static let characteristicUuid = CBUUID(string: "00001624-1212-EFDE-1623-785FEABCD123") + static let serviceUuid = CBUUID(string: GATT.serviceUuid) + static let characteristicUuid = CBUUID(string: GATT.serviceUuid) } diff --git a/BoostRemote/Notification.swift b/BoostRemote/Notification.swift deleted file mode 100644 index 48a385e..0000000 --- a/BoostRemote/Notification.swift +++ /dev/null @@ -1,54 +0,0 @@ -// -// Notification.swift -// BoostRemote -// -// Created by ooba on 10/08/2017. -// Copyright © 2017 bricklife.com. All rights reserved. -// - -import Foundation - -enum Notification { - - case connected(Port, DeviceType) - case disconnected(Port) -} - -extension Notification { - - init?(data: Data) { - guard data.count >= 3 else { return nil } - - switch data[2] { - case 0x04: - guard data.count >= 5 else { return nil } - guard let port = Port(rawValue: data[3]) else { return nil } - - switch data[4] { - case 0x00: - self = .disconnected(port) - case 0x01, 0x02: - guard data.count >= 6 else { return nil } - guard let deviceType = DeviceType(rawValue: data[5]) else { return nil } - self = .connected(port, deviceType) - default: - return nil - } - - default: - return nil - } - } -} - -extension Notification: CustomStringConvertible { - - var description: String { - switch self { - case .connected(let port, let deviceType): - return "Connected \(deviceType) into \(port)" - case .disconnected(let port): - return "Disconnected a device from \(port)" - } - } -} diff --git a/BoostRemote/Port.swift b/BoostRemote/Port.swift deleted file mode 100644 index 7c56e9c..0000000 --- a/BoostRemote/Port.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// Port.swift -// BoostRemote -// -// Created by ooba on 10/08/2017. -// Copyright © 2017 bricklife.com. All rights reserved. -// - -import Foundation - -enum Port: UInt8 { - - case A = 0x37 - case B = 0x38 - case C = 0x01 - case D = 0x02 - case AB = 0x39 -} - -extension Port: CustomStringConvertible { - - var description: String { - switch self { - case .A: - return "A" - case .B: - return "B" - case .C: - return "C" - case .D: - return "D" - case .AB: - return "A and B" - } - } -} diff --git a/BoostRemote/State.swift b/BoostRemote/State.swift index 51bca7d..b1da1e7 100644 --- a/BoostRemote/State.swift +++ b/BoostRemote/State.swift @@ -8,6 +8,7 @@ import Foundation import ReSwift +import BoostBLEKit struct State: StateType { @@ -24,4 +25,4 @@ enum ConnectionState { case unsupported } -typealias PortState = [Port: DeviceType] +typealias PortState = [BoostBLEKit.Port: DeviceType] diff --git a/BoostRemote/StickView.swift b/BoostRemote/StickView.swift index f8b68d4..3cfcbc4 100644 --- a/BoostRemote/StickView.swift +++ b/BoostRemote/StickView.swift @@ -7,6 +7,7 @@ // import UIKit +import BoostBLEKit @IBDesignable class StickView: UIView { @@ -15,7 +16,7 @@ class StickView: UIView { return verticalSlider.slider } - var port: Port? { + var port: BoostBLEKit.Port? { didSet { imageView.image = port.flatMap { UIImage(named: "port\($0)") } } diff --git a/Cartfile b/Cartfile index f709d4e..9b348f6 100644 --- a/Cartfile +++ b/Cartfile @@ -1,2 +1,3 @@ +github "bricklife/BoostBLEKit" github "ReactiveCocoa/ReactiveCocoa" github "ReSwift/ReSwift" diff --git a/Cartfile.resolved b/Cartfile.resolved index 18025f0..ea12315 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -2,3 +2,4 @@ github "ReSwift/ReSwift" "4.0.1" github "ReactiveCocoa/ReactiveCocoa" "7.1.0" github "ReactiveCocoa/ReactiveSwift" "3.1.0" github "antitypical/Result" "3.2.4" +github "bricklife/BoostBLEKit" "1.0.0" From 3a56fbbd61eff71c198f3e7166761e655fffc28a Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Wed, 24 Jan 2018 00:08:14 +0000 Subject: [PATCH 02/43] Normalization --- BoostRemote/ControllerViewController.swift | 2 +- BoostRemote/StickView.swift | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/BoostRemote/ControllerViewController.swift b/BoostRemote/ControllerViewController.swift index 7980544..b746890 100644 --- a/BoostRemote/ControllerViewController.swift +++ b/BoostRemote/ControllerViewController.swift @@ -96,7 +96,7 @@ class ControllerViewController: UIViewController { } private func signal(for slider: UISlider) -> Signal { - let valueSignal = slider.reactive.values.map { Int8($0) * 10 } + let valueSignal = slider.reactive.values.map { Int8($0 * 10) * 10 } let touchUpSignal = Signal .merge(slider.reactive.controlEvents(.touchUpInside), diff --git a/BoostRemote/StickView.swift b/BoostRemote/StickView.swift index 3cfcbc4..f95d924 100644 --- a/BoostRemote/StickView.swift +++ b/BoostRemote/StickView.swift @@ -60,8 +60,8 @@ class StickView: UIView { verticalSlider.slider.setMinimumTrackImage(UIImage(named: "left"), for: .normal) verticalSlider.slider.setMaximumTrackImage(UIImage(named: "right"), for: .normal) - verticalSlider.slider.maximumValue = 10 - verticalSlider.slider.minimumValue = -10 + verticalSlider.slider.maximumValue = 1 + verticalSlider.slider.minimumValue = -1 verticalSlider.slider.value = 0 return verticalSlider From fbe8e0747acfcad5b65c2ddf931ea0cbb4620060 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Wed, 24 Jan 2018 00:31:50 +0000 Subject: [PATCH 03/43] Refactoring --- BoostRemote/ControllerViewController.swift | 47 ++++++++-------------- BoostRemote/StickView.swift | 15 +++++++ 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/BoostRemote/ControllerViewController.swift b/BoostRemote/ControllerViewController.swift index b746890..e60e84c 100644 --- a/BoostRemote/ControllerViewController.swift +++ b/BoostRemote/ControllerViewController.swift @@ -7,9 +7,7 @@ // import UIKit -import ReactiveCocoa import ReactiveSwift -import Result import ReSwift import BoostBLEKit @@ -35,27 +33,7 @@ class ControllerViewController: UIViewController { super.viewDidLoad() setupConnectButtonImageView() - - stickA.port = .A - stickB.port = .B - stickC.port = .C - stickD.port = .D - - stickC.isHidden = true - stickD.isHidden = true - - signal(for: stickA.slider).observeValues { [weak self] (value) in - self?.sendCommand(port: .A, power: value) - } - signal(for: stickB.slider).observeValues { [weak self] (value) in - self?.sendCommand(port: .B, power: value) - } - signal(for: stickC.slider).observeValues { [weak self] (value) in - self?.sendCommand(port: .C, power: value) - } - signal(for: stickD.slider).observeValues { [weak self] (value) in - self?.sendCommand(port: .D, power: value) - } + setupSticks() } override func viewWillAppear(_ animated: Bool) { @@ -95,16 +73,23 @@ class ControllerViewController: UIViewController { } } - private func signal(for slider: UISlider) -> Signal { - let valueSignal = slider.reactive.values.map { Int8($0 * 10) * 10 } + private func setupSticks() { + stickA.port = .A + stickB.port = .B + stickC.port = .C + stickD.port = .D - let touchUpSignal = Signal - .merge(slider.reactive.controlEvents(.touchUpInside), - slider.reactive.controlEvents(.touchUpOutside)) - .on(value: { $0.value = 0 }) - .map { _ in Int8(0) } + stickC.isHidden = true + stickD.isHidden = true - return Signal.merge(valueSignal, touchUpSignal).skipRepeats() + [stickA, stickB, stickC, stickD].forEach { (stick) in + guard let port = stick?.port else { return } + stick?.signal.map { Int8($0 * 10) * 10 } + .skipRepeats() + .observeValues { [weak self] (value) in + self?.sendCommand(port: port, power: value) + } + } } private func sendCommand(port: BoostBLEKit.Port, power: Int8) { diff --git a/BoostRemote/StickView.swift b/BoostRemote/StickView.swift index f95d924..dd33eff 100644 --- a/BoostRemote/StickView.swift +++ b/BoostRemote/StickView.swift @@ -7,6 +7,9 @@ // import UIKit +import ReactiveCocoa +import ReactiveSwift +import Result import BoostBLEKit @IBDesignable @@ -22,6 +25,18 @@ class StickView: UIView { } } + lazy var signal: Signal = { + let valueSignal = self.slider.reactive.values + + let touchUpSignal = Signal + .merge(self.slider.reactive.controlEvents(.touchUpInside), + self.slider.reactive.controlEvents(.touchUpOutside)) + .on(value: { $0.value = 0 }) + .map { _ in Float(0) } + + return Signal.merge(valueSignal, touchUpSignal) + }() + required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) From 3c82040b9c6e7521719744de1dc89a8e768d2b36 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Wed, 24 Jan 2018 00:34:20 +0000 Subject: [PATCH 04/43] Refactoring --- BoostRemote/StickView.swift | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/BoostRemote/StickView.swift b/BoostRemote/StickView.swift index dd33eff..417f600 100644 --- a/BoostRemote/StickView.swift +++ b/BoostRemote/StickView.swift @@ -15,10 +15,6 @@ import BoostBLEKit @IBDesignable class StickView: UIView { - var slider: UISlider { - return verticalSlider.slider - } - var port: BoostBLEKit.Port? { didSet { imageView.image = port.flatMap { UIImage(named: "port\($0)") } @@ -26,11 +22,11 @@ class StickView: UIView { } lazy var signal: Signal = { - let valueSignal = self.slider.reactive.values + let valueSignal = self.verticalSlider.slider.reactive.values let touchUpSignal = Signal - .merge(self.slider.reactive.controlEvents(.touchUpInside), - self.slider.reactive.controlEvents(.touchUpOutside)) + .merge(self.verticalSlider.slider.reactive.controlEvents(.touchUpInside), + self.verticalSlider.slider.reactive.controlEvents(.touchUpOutside)) .on(value: { $0.value = 0 }) .map { _ in Float(0) } From 3b6adaefec3349487479ea2a53de287d25377984 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Wed, 24 Jan 2018 01:16:46 +0000 Subject: [PATCH 05/43] Add base.pdf --- .../Assets.xcassets/base.imageset/Contents.json | 12 ++++++++++++ .../Assets.xcassets/base.imageset/base.pdf | Bin 0 -> 3987 bytes 2 files changed, 12 insertions(+) create mode 100644 BoostRemote/Assets.xcassets/base.imageset/Contents.json create mode 100644 BoostRemote/Assets.xcassets/base.imageset/base.pdf diff --git a/BoostRemote/Assets.xcassets/base.imageset/Contents.json b/BoostRemote/Assets.xcassets/base.imageset/Contents.json new file mode 100644 index 0000000..8ae6865 --- /dev/null +++ b/BoostRemote/Assets.xcassets/base.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "base.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/BoostRemote/Assets.xcassets/base.imageset/base.pdf b/BoostRemote/Assets.xcassets/base.imageset/base.pdf new file mode 100644 index 0000000000000000000000000000000000000000..21f5bd06e04f778bb525db1c8824eab54ceaaf9f GIT binary patch literal 3987 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 literal 0 HcmV?d00001 From f5060d99ea9228be0c9e4848db0f023a4e286f0f Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Wed, 24 Jan 2018 02:02:03 +0000 Subject: [PATCH 06/43] Implement original vertical slider --- .../base.imageset/Contents.json | 16 +++- BoostRemote/StickView.swift | 28 ++----- BoostRemote/VerticalSlider.swift | 77 ++++++++++++++++--- 3 files changed, 89 insertions(+), 32 deletions(-) diff --git a/BoostRemote/Assets.xcassets/base.imageset/Contents.json b/BoostRemote/Assets.xcassets/base.imageset/Contents.json index 8ae6865..abe5d3a 100644 --- a/BoostRemote/Assets.xcassets/base.imageset/Contents.json +++ b/BoostRemote/Assets.xcassets/base.imageset/Contents.json @@ -2,7 +2,21 @@ "images" : [ { "idiom" : "universal", - "filename" : "base.pdf" + "filename" : "base.pdf", + "resizing" : { + "mode" : "9-part", + "center" : { + "mode" : "tile", + "width" : 1, + "height" : 1 + }, + "cap-insets" : { + "bottom" : 15, + "top" : 15, + "right" : 15, + "left" : 15 + } + } } ], "info" : { diff --git a/BoostRemote/StickView.swift b/BoostRemote/StickView.swift index 417f600..92f05dd 100644 --- a/BoostRemote/StickView.swift +++ b/BoostRemote/StickView.swift @@ -7,7 +7,6 @@ // import UIKit -import ReactiveCocoa import ReactiveSwift import Result import BoostBLEKit @@ -15,24 +14,14 @@ import BoostBLEKit @IBDesignable class StickView: UIView { + let (signal, observer) = Signal.pipe() + var port: BoostBLEKit.Port? { didSet { imageView.image = port.flatMap { UIImage(named: "port\($0)") } } } - lazy var signal: Signal = { - let valueSignal = self.verticalSlider.slider.reactive.values - - let touchUpSignal = Signal - .merge(self.verticalSlider.slider.reactive.controlEvents(.touchUpInside), - self.verticalSlider.slider.reactive.controlEvents(.touchUpOutside)) - .on(value: { $0.value = 0 }) - .map { _ in Float(0) } - - return Signal.merge(valueSignal, touchUpSignal) - }() - required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) @@ -61,20 +50,16 @@ class StickView: UIView { imageView.centerXAnchor.constraint(equalTo: centerXAnchor), imageView.heightAnchor.constraint(equalToConstant: 32), ]) + + verticalSlider.update = { [weak self] (value) in + self?.observer.send(value: -value) + } } private let verticalSlider: VerticalSlider = { let verticalSlider = VerticalSlider() verticalSlider.translatesAutoresizingMaskIntoConstraints = false - verticalSlider.slider.setThumbImage(UIImage(named: "thumb"), for: .normal) - verticalSlider.slider.setMinimumTrackImage(UIImage(named: "left"), for: .normal) - verticalSlider.slider.setMaximumTrackImage(UIImage(named: "right"), for: .normal) - - verticalSlider.slider.maximumValue = 1 - verticalSlider.slider.minimumValue = -1 - verticalSlider.slider.value = 0 - return verticalSlider }() @@ -83,6 +68,7 @@ class StickView: UIView { imageView.translatesAutoresizingMaskIntoConstraints = false imageView.contentMode = .center + return imageView }() } diff --git a/BoostRemote/VerticalSlider.swift b/BoostRemote/VerticalSlider.swift index 7bd9f99..858e6a5 100644 --- a/BoostRemote/VerticalSlider.swift +++ b/BoostRemote/VerticalSlider.swift @@ -11,7 +11,9 @@ import UIKit @IBDesignable class VerticalSlider: UIView { - let slider = UISlider() + var update: ((CGFloat) -> Void)? + + private var thumbCenterYConstraint: NSLayoutConstraint! required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) @@ -26,19 +28,74 @@ class VerticalSlider: UIView { } private func initialize() { - addSubview(slider) - slider.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi * -0.5)) + addSubview(baseView) + addSubview(thumbView) + + NSLayoutConstraint.activate([ + baseView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.5), + baseView.heightAnchor.constraint(equalTo: heightAnchor), + baseView.centerXAnchor.constraint(equalTo: centerXAnchor), + baseView.centerYAnchor.constraint(equalTo: centerYAnchor), + ]) + + thumbCenterYConstraint = thumbView.centerYAnchor.constraint(equalTo: centerYAnchor) + + NSLayoutConstraint.activate([ + thumbView.centerXAnchor.constraint(equalTo: centerXAnchor), + thumbCenterYConstraint, + ]) } - override func layoutSubviews() { - super.layoutSubviews() + private let baseView: UIView = { + let view = UIImageView(image: #imageLiteral(resourceName: "base")) + view.translatesAutoresizingMaskIntoConstraints = false + + return view + }() + + private let thumbView: UIView = { + let view = UIImageView(image: #imageLiteral(resourceName: "thumb")) + view.translatesAutoresizingMaskIntoConstraints = false + + return view + }() + + private func move(location: CGPoint) { + let size = thumbView.bounds.height + let base = (bounds.height - size) / 2 + + var value = (location.y - bounds.midY) / base + if value < -1 { + value = -1 + } else if value > 1 { + value = 1 + } - slider.bounds.size.width = bounds.height - slider.center.x = bounds.midX - slider.center.y = bounds.midY + thumbCenterYConstraint.constant = base * value + update?(value) + } + + private func reset() { + move(location: CGPoint(x: bounds.midX, y: bounds.midY)) + } + + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + guard let touch = touches.first else { return } + let location = touch.location(in: self) + move(location: location) + } + + override func touchesMoved(_ touches: Set, with event: UIEvent?) { + guard let touch = touches.first else { return } + let location = touch.location(in: self) + move(location: location) + } + + override func touchesEnded(_ touches: Set, with event: UIEvent?) { + reset() } - override var intrinsicContentSize: CGSize { - return CGSize(width: slider.intrinsicContentSize.height, height: slider.intrinsicContentSize.width) + override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + reset() } } From 12812aec1c7f69f3d8ca0e47d5e87308f82b609a Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Wed, 24 Jan 2018 02:08:13 +0000 Subject: [PATCH 07/43] Fix the characteristic UUID --- BoostRemote/MoveHubService.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/BoostRemote/MoveHubService.swift b/BoostRemote/MoveHubService.swift index 5c06e69..e927e98 100644 --- a/BoostRemote/MoveHubService.swift +++ b/BoostRemote/MoveHubService.swift @@ -13,5 +13,5 @@ import BoostBLEKit struct MoveHubService { static let serviceUuid = CBUUID(string: GATT.serviceUuid) - static let characteristicUuid = CBUUID(string: GATT.serviceUuid) + static let characteristicUuid = CBUUID(string: GATT.characteristicUuid) } From 95ea0031f59aff811f4047ca03f3accefc5624e1 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Wed, 24 Jan 2018 02:23:25 +0000 Subject: [PATCH 08/43] Enable Haptic Feedback --- BoostRemote/ControllerViewController.swift | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/BoostRemote/ControllerViewController.swift b/BoostRemote/ControllerViewController.swift index e60e84c..818eb37 100644 --- a/BoostRemote/ControllerViewController.swift +++ b/BoostRemote/ControllerViewController.swift @@ -29,6 +29,16 @@ class ControllerViewController: UIViewController { } } + private let feedbackGenerator: Any? = { + if #available(iOS 10.0, *) { + let generator = UISelectionFeedbackGenerator() + generator.prepare() + return generator + } else { + return nil + } + }() + override func viewDidLoad() { super.viewDidLoad() @@ -93,11 +103,21 @@ class ControllerViewController: UIViewController { } private func sendCommand(port: BoostBLEKit.Port, power: Int8) { + if power == 100 || power == -100 { + feedback() + } + if let command = motors[port]?.powerCommand(power: power) { ActionCenter.send(command: command) } } + private func feedback() { + if #available(iOS 10.0, *), let generator = feedbackGenerator as? UISelectionFeedbackGenerator { + generator.selectionChanged() + } + } + private func alert(message: String) { let alert = UIAlertController(title: NSLocalizedString("CAUTION", comment: "CAUTION"), message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) From c302ac82bada03da6d37a36ae43f35ed9b3d70e4 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Wed, 24 Jan 2018 02:26:58 +0000 Subject: [PATCH 09/43] Remove unnecessary PDFs --- BoostRemote.xcodeproj/project.pbxproj | 4 --- .../left.imageset/Contents.json | 23 ------------------ .../Assets.xcassets/left.imageset/left.pdf | Bin 4000 -> 0 bytes .../right.imageset/Contents.json | 23 ------------------ .../Assets.xcassets/right.imageset/right.pdf | Bin 4019 -> 0 bytes 5 files changed, 50 deletions(-) delete mode 100644 BoostRemote/Assets.xcassets/left.imageset/Contents.json delete mode 100644 BoostRemote/Assets.xcassets/left.imageset/left.pdf delete mode 100644 BoostRemote/Assets.xcassets/right.imageset/Contents.json delete mode 100644 BoostRemote/Assets.xcassets/right.imageset/right.pdf diff --git a/BoostRemote.xcodeproj/project.pbxproj b/BoostRemote.xcodeproj/project.pbxproj index 8948453..915fe53 100644 --- a/BoostRemote.xcodeproj/project.pbxproj +++ b/BoostRemote.xcodeproj/project.pbxproj @@ -22,7 +22,6 @@ CBA46E781F882F0C0017E5C2 /* ReactiveSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */; }; CBA46E7A1F882F0F0017E5C2 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E791F882F0F0017E5C2 /* Result.framework */; }; CBA46E7D1F882F800017E5C2 /* ReSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E7B1F882F800017E5C2 /* ReSwift.framework */; }; - CBA46E7E1F882F800017E5C2 /* ReactiveCocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E7C1F882F800017E5C2 /* ReactiveCocoa.framework */; }; CBD94E841F391B3F0037ED71 /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD94E831F391B3F0037ED71 /* State.swift */; }; CBD94E861F391D7F0037ED71 /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD94E851F391D7F0037ED71 /* Action.swift */; }; CBD94E881F391E2E0037ED71 /* Reducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD94E871F391E2E0037ED71 /* Reducer.swift */; }; @@ -62,7 +61,6 @@ CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReactiveSwift.framework; path = Carthage/Build/iOS/ReactiveSwift.framework; sourceTree = ""; }; CBA46E791F882F0F0017E5C2 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/iOS/Result.framework; sourceTree = ""; }; CBA46E7B1F882F800017E5C2 /* ReSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReSwift.framework; path = Carthage/Build/iOS/ReSwift.framework; sourceTree = ""; }; - CBA46E7C1F882F800017E5C2 /* ReactiveCocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReactiveCocoa.framework; path = Carthage/Build/iOS/ReactiveCocoa.framework; sourceTree = ""; }; CBD94E831F391B3F0037ED71 /* State.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = State.swift; sourceTree = ""; }; CBD94E851F391D7F0037ED71 /* Action.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Action.swift; sourceTree = ""; }; CBD94E871F391E2E0037ED71 /* Reducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Reducer.swift; sourceTree = ""; }; @@ -79,7 +77,6 @@ CB4345A8200FC0D200D82D7D /* BoostBLEKit.framework in Frameworks */, CBA46E7A1F882F0F0017E5C2 /* Result.framework in Frameworks */, CBA46E781F882F0C0017E5C2 /* ReactiveSwift.framework in Frameworks */, - CBA46E7E1F882F800017E5C2 /* ReactiveCocoa.framework in Frameworks */, CBA46E7D1F882F800017E5C2 /* ReSwift.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; @@ -130,7 +127,6 @@ isa = PBXGroup; children = ( CB4345A7200FC0D100D82D7D /* BoostBLEKit.framework */, - CBA46E7C1F882F800017E5C2 /* ReactiveCocoa.framework */, CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */, CBA46E791F882F0F0017E5C2 /* Result.framework */, CBA46E7B1F882F800017E5C2 /* ReSwift.framework */, diff --git a/BoostRemote/Assets.xcassets/left.imageset/Contents.json b/BoostRemote/Assets.xcassets/left.imageset/Contents.json deleted file mode 100644 index 17a173e..0000000 --- a/BoostRemote/Assets.xcassets/left.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "left.pdf", - "resizing" : { - "mode" : "3-part-horizontal", - "center" : { - "mode" : "tile", - "width" : 1 - }, - "cap-insets" : { - "right" : 32, - "left" : 31 - } - } - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/BoostRemote/Assets.xcassets/left.imageset/left.pdf b/BoostRemote/Assets.xcassets/left.imageset/left.pdf deleted file mode 100644 index a5838b4b14c6d3f6b6b9129653d2a2b2f7b7c4b9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4000 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 diff --git a/BoostRemote/Assets.xcassets/right.imageset/Contents.json b/BoostRemote/Assets.xcassets/right.imageset/Contents.json deleted file mode 100644 index 97038bf..0000000 --- a/BoostRemote/Assets.xcassets/right.imageset/Contents.json +++ /dev/null @@ -1,23 +0,0 @@ -{ - "images" : [ - { - "idiom" : "universal", - "filename" : "right.pdf", - "resizing" : { - "mode" : "3-part-horizontal", - "center" : { - "mode" : "tile", - "width" : 1 - }, - "cap-insets" : { - "right" : 32, - "left" : 31 - } - } - } - ], - "info" : { - "version" : 1, - "author" : "xcode" - } -} \ No newline at end of file diff --git a/BoostRemote/Assets.xcassets/right.imageset/right.pdf b/BoostRemote/Assets.xcassets/right.imageset/right.pdf deleted file mode 100644 index 6d845eaa9cb336a9a5e5fe93827ade253980f38d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4019 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 F{C^|x$R_{* From f8219d7fc33437f885f6254808f17424681169c2 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Wed, 24 Jan 2018 02:28:06 +0000 Subject: [PATCH 10/43] Remove ReactiveCocoa --- .../com.mono0926.LicensePlist.plist | 4 +-- .../BoostBLEKit.plist | 36 +++++++++++++++++++ .../ReactiveCocoa.plist | 34 ------------------ Cartfile | 2 +- Cartfile.resolved | 1 - 5 files changed, 39 insertions(+), 38 deletions(-) create mode 100644 BoostRemote/Settings.bundle/com.mono0926.LicensePlist/BoostBLEKit.plist delete mode 100644 BoostRemote/Settings.bundle/com.mono0926.LicensePlist/ReactiveCocoa.plist diff --git a/BoostRemote/Settings.bundle/com.mono0926.LicensePlist.plist b/BoostRemote/Settings.bundle/com.mono0926.LicensePlist.plist index 6d97e81..c1e696f 100644 --- a/BoostRemote/Settings.bundle/com.mono0926.LicensePlist.plist +++ b/BoostRemote/Settings.bundle/com.mono0926.LicensePlist.plist @@ -6,9 +6,9 @@ File - com.mono0926.LicensePlist/ReactiveCocoa + com.mono0926.LicensePlist/BoostBLEKit Title - ReactiveCocoa + BoostBLEKit Type PSChildPaneSpecifier diff --git a/BoostRemote/Settings.bundle/com.mono0926.LicensePlist/BoostBLEKit.plist b/BoostRemote/Settings.bundle/com.mono0926.LicensePlist/BoostBLEKit.plist new file mode 100644 index 0000000..b9919dc --- /dev/null +++ b/BoostRemote/Settings.bundle/com.mono0926.LicensePlist/BoostBLEKit.plist @@ -0,0 +1,36 @@ + + + + + PreferenceSpecifiers + + + FooterText + MIT License + +Copyright (c) 2018 Shinichiro Oba + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + + Type + PSGroupSpecifier + + + + diff --git a/BoostRemote/Settings.bundle/com.mono0926.LicensePlist/ReactiveCocoa.plist b/BoostRemote/Settings.bundle/com.mono0926.LicensePlist/ReactiveCocoa.plist deleted file mode 100644 index 6b2e8fc..0000000 --- a/BoostRemote/Settings.bundle/com.mono0926.LicensePlist/ReactiveCocoa.plist +++ /dev/null @@ -1,34 +0,0 @@ - - - - - PreferenceSpecifiers - - - FooterText - **Copyright (c) 2012 - 2016, GitHub, Inc.** -**All rights reserved.** - -Permission is hereby granted, free of charge, to any person obtaining a copy of -this software and associated documentation files (the "Software"), to deal in -the Software without restriction, including without limitation the rights to -use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -the Software, and to permit persons to whom the Software is furnished to do so, -subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - - Type - PSGroupSpecifier - - - - diff --git a/Cartfile b/Cartfile index 9b348f6..9b2b6ba 100644 --- a/Cartfile +++ b/Cartfile @@ -1,3 +1,3 @@ github "bricklife/BoostBLEKit" -github "ReactiveCocoa/ReactiveCocoa" +github "ReactiveCocoa/ReactiveSwift" github "ReSwift/ReSwift" diff --git a/Cartfile.resolved b/Cartfile.resolved index ea12315..e896c7e 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,5 +1,4 @@ github "ReSwift/ReSwift" "4.0.1" -github "ReactiveCocoa/ReactiveCocoa" "7.1.0" github "ReactiveCocoa/ReactiveSwift" "3.1.0" github "antitypical/Result" "3.2.4" github "bricklife/BoostBLEKit" "1.0.0" From f7c1592fb75d9a68154a4860ad8a98e92d29446e Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Thu, 25 Jan 2018 18:51:21 +0000 Subject: [PATCH 11/43] Remove @IBDesignable --- BoostRemote/StickView.swift | 1 - BoostRemote/VerticalSlider.swift | 1 - 2 files changed, 2 deletions(-) diff --git a/BoostRemote/StickView.swift b/BoostRemote/StickView.swift index 92f05dd..ed74bea 100644 --- a/BoostRemote/StickView.swift +++ b/BoostRemote/StickView.swift @@ -11,7 +11,6 @@ import ReactiveSwift import Result import BoostBLEKit -@IBDesignable class StickView: UIView { let (signal, observer) = Signal.pipe() diff --git a/BoostRemote/VerticalSlider.swift b/BoostRemote/VerticalSlider.swift index 858e6a5..ee60e28 100644 --- a/BoostRemote/VerticalSlider.swift +++ b/BoostRemote/VerticalSlider.swift @@ -8,7 +8,6 @@ import UIKit -@IBDesignable class VerticalSlider: UIView { var update: ((CGFloat) -> Void)? From 7f1b7ba02191e58411a8ed8e1ad96045bc6e8ad7 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Thu, 25 Jan 2018 19:43:49 +0000 Subject: [PATCH 12/43] Add FourSticksViewController --- BoostRemote.xcodeproj/project.pbxproj | 4 ++ BoostRemote/Base.lproj/Main.storyboard | 64 +++++++++++++++++++++- BoostRemote/FourSticksViewController.swift | 60 ++++++++++++++++++++ 3 files changed, 127 insertions(+), 1 deletion(-) create mode 100644 BoostRemote/FourSticksViewController.swift diff --git a/BoostRemote.xcodeproj/project.pbxproj b/BoostRemote.xcodeproj/project.pbxproj index 915fe53..3cd131b 100644 --- a/BoostRemote.xcodeproj/project.pbxproj +++ b/BoostRemote.xcodeproj/project.pbxproj @@ -17,6 +17,7 @@ CB3BE8BB1F2FF2F4000561F7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CB3BE8B91F2FF2F4000561F7 /* LaunchScreen.storyboard */; }; CB4345A8200FC0D200D82D7D /* BoostBLEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CB4345A7200FC0D100D82D7D /* BoostBLEKit.framework */; }; CB44B8531F73C11400D0D250 /* Store.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB44B8521F73C11400D0D250 /* Store.swift */; }; + CB547EBB201A62A400B00D8C /* FourSticksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB547EBA201A62A400B00D8C /* FourSticksViewController.swift */; }; CB5891F1200D2C8700E15F92 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = CB5891F3200D2C8700E15F92 /* Localizable.strings */; }; CB5891F9200D2DF300E15F92 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = CB5891FB200D2DF300E15F92 /* InfoPlist.strings */; }; CBA46E781F882F0C0017E5C2 /* ReactiveSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */; }; @@ -56,6 +57,7 @@ CB3BE8BC1F2FF2F4000561F7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; CB4345A7200FC0D100D82D7D /* BoostBLEKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BoostBLEKit.framework; path = Carthage/Build/iOS/BoostBLEKit.framework; sourceTree = ""; }; CB44B8521F73C11400D0D250 /* Store.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Store.swift; sourceTree = ""; }; + CB547EBA201A62A400B00D8C /* FourSticksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FourSticksViewController.swift; sourceTree = ""; }; CB5891F4200D2CEA00E15F92 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; CB5891FA200D2DF300E15F92 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = ""; }; CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReactiveSwift.framework; path = Carthage/Build/iOS/ReactiveSwift.framework; sourceTree = ""; }; @@ -107,6 +109,7 @@ CB3BE8B01F2FF2F4000561F7 /* AppDelegate.swift */, CB3BE8B41F2FF2F4000561F7 /* Main.storyboard */, CB3BE8B21F2FF2F4000561F7 /* ControllerViewController.swift */, + CB547EBA201A62A400B00D8C /* FourSticksViewController.swift */, CB0BF7E41F8BD873004CCD4F /* VerticalSlider.swift */, CB0BF7E61F8BDD30004CCD4F /* StickView.swift */, CBF9D2B81F3CACA800B97E11 /* MoveHubManager.swift */, @@ -256,6 +259,7 @@ CB0BF7E51F8BD873004CCD4F /* VerticalSlider.swift in Sources */, CB0BF7E71F8BDD30004CCD4F /* StickView.swift in Sources */, CBD94E861F391D7F0037ED71 /* Action.swift in Sources */, + CB547EBB201A62A400B00D8C /* FourSticksViewController.swift in Sources */, CB3BE8B11F2FF2F4000561F7 /* AppDelegate.swift in Sources */, CBF9D2F61F3CDAC700B97E11 /* Data+HexString.swift in Sources */, CB44B8531F73C11400D0D250 /* Store.swift in Sources */, diff --git a/BoostRemote/Base.lproj/Main.storyboard b/BoostRemote/Base.lproj/Main.storyboard index 010f330..5800882 100644 --- a/BoostRemote/Base.lproj/Main.storyboard +++ b/BoostRemote/Base.lproj/Main.storyboard @@ -132,7 +132,69 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BoostRemote/FourSticksViewController.swift b/BoostRemote/FourSticksViewController.swift new file mode 100644 index 0000000..4739dd4 --- /dev/null +++ b/BoostRemote/FourSticksViewController.swift @@ -0,0 +1,60 @@ +// +// FourSticksViewController.swift +// BoostRemote +// +// Created by ooba on 25/01/2018. +// Copyright © 2018 bricklife.com. All rights reserved. +// + +import UIKit +import ReactiveSwift +import Result +import BoostBLEKit + +class FourSticksViewController: UIViewController { + + @IBOutlet private weak var stickA: StickView! + @IBOutlet private weak var stickB: StickView! + @IBOutlet private weak var stickC: StickView! + @IBOutlet private weak var stickD: StickView! + + var motors: [BoostBLEKit.Port: Motor] = [:] { + didSet { + stickC?.isHidden = !motors.keys.contains(.C) + stickD?.isHidden = !motors.keys.contains(.D) + } + } + + private let (signalA, observerA) = Signal.pipe() + private let (signalB, observerB) = Signal.pipe() + private let (signalC, observerC) = Signal.pipe() + private let (signalD, observerD) = Signal.pipe() + + lazy var signal: [BoostBLEKit.Port: Signal] = [ + .A: self.signalA, + .B: self.signalB, + .C: self.signalC, + .D: self.signalD, + ] + + override func viewDidLoad() { + super.viewDidLoad() + + setupSticks() + } + + private func setupSticks() { + stickA.port = .A + stickB.port = .B + stickC.port = .C + stickD.port = .D + + stickA.signal.observe(observerA) + stickB.signal.observe(observerB) + stickC.signal.observe(observerC) + stickD.signal.observe(observerD) + + stickC.isHidden = true + stickD.isHidden = true + } +} From 1f4becc09617f3a92436d547e66e0a0cb77f8ee6 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Thu, 25 Jan 2018 21:23:23 +0000 Subject: [PATCH 13/43] Use FourSticksViewController --- BoostRemote/Base.lproj/Main.storyboard | 71 ++++++---------------- BoostRemote/ControllerViewController.swift | 26 +++----- BoostRemote/FourSticksViewController.swift | 20 +++--- 3 files changed, 40 insertions(+), 77 deletions(-) diff --git a/BoostRemote/Base.lproj/Main.storyboard b/BoostRemote/Base.lproj/Main.storyboard index 5800882..b4dea4a 100644 --- a/BoostRemote/Base.lproj/Main.storyboard +++ b/BoostRemote/Base.lproj/Main.storyboard @@ -23,11 +23,8 @@ - - - - + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + - + - - - + + + @@ -124,50 +97,46 @@ - - - - - + - + - + - + - + - + - + diff --git a/BoostRemote/ControllerViewController.swift b/BoostRemote/ControllerViewController.swift index 818eb37..de6906e 100644 --- a/BoostRemote/ControllerViewController.swift +++ b/BoostRemote/ControllerViewController.swift @@ -13,19 +13,18 @@ import BoostBLEKit class ControllerViewController: UIViewController { - @IBOutlet private weak var stickA: StickView! - @IBOutlet private weak var stickB: StickView! - @IBOutlet private weak var stickC: StickView! - @IBOutlet private weak var stickD: StickView! - @IBOutlet private weak var connectButtonImageView: UIImageView! + private var stickViewController: FourSticksViewController? { + return childViewControllers.first as? FourSticksViewController + } + private let connectionState = MutableProperty(ConnectionState.disconnected) private var motors: [BoostBLEKit.Port: Motor] = [:] { didSet { - stickC?.isHidden = !motors.keys.contains(.C) - stickD?.isHidden = !motors.keys.contains(.D) + stickViewController?.setEnable(motors.keys.contains(.C), port: .C) + stickViewController?.setEnable(motors.keys.contains(.D), port: .D) } } @@ -84,17 +83,8 @@ class ControllerViewController: UIViewController { } private func setupSticks() { - stickA.port = .A - stickB.port = .B - stickC.port = .C - stickD.port = .D - - stickC.isHidden = true - stickD.isHidden = true - - [stickA, stickB, stickC, stickD].forEach { (stick) in - guard let port = stick?.port else { return } - stick?.signal.map { Int8($0 * 10) * 10 } + stickViewController?.signals.forEach { (port, signal) in + signal.map { Int8($0 * 10) * 10 } .skipRepeats() .observeValues { [weak self] (value) in self?.sendCommand(port: port, power: value) diff --git a/BoostRemote/FourSticksViewController.swift b/BoostRemote/FourSticksViewController.swift index 4739dd4..7d46e1b 100644 --- a/BoostRemote/FourSticksViewController.swift +++ b/BoostRemote/FourSticksViewController.swift @@ -18,19 +18,12 @@ class FourSticksViewController: UIViewController { @IBOutlet private weak var stickC: StickView! @IBOutlet private weak var stickD: StickView! - var motors: [BoostBLEKit.Port: Motor] = [:] { - didSet { - stickC?.isHidden = !motors.keys.contains(.C) - stickD?.isHidden = !motors.keys.contains(.D) - } - } - private let (signalA, observerA) = Signal.pipe() private let (signalB, observerB) = Signal.pipe() private let (signalC, observerC) = Signal.pipe() private let (signalD, observerD) = Signal.pipe() - lazy var signal: [BoostBLEKit.Port: Signal] = [ + lazy var signals: [BoostBLEKit.Port: Signal] = [ .A: self.signalA, .B: self.signalB, .C: self.signalC, @@ -57,4 +50,15 @@ class FourSticksViewController: UIViewController { stickC.isHidden = true stickD.isHidden = true } + + func setEnable(_ enable: Bool, port: BoostBLEKit.Port) { + switch port { + case .B: + stickB.isHidden = !enable + case .C: + stickC.isHidden = !enable + default: + break + } + } } From 4e459f12f2892db3b0e6c0e8dc670751bc5b5c64 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Thu, 25 Jan 2018 21:29:17 +0000 Subject: [PATCH 14/43] Introduce FeedbackGenerator --- BoostRemote.xcodeproj/project.pbxproj | 4 ++++ BoostRemote/ControllerViewController.swift | 18 +------------- BoostRemote/FeedbackGenerator.swift | 28 ++++++++++++++++++++++ 3 files changed, 33 insertions(+), 17 deletions(-) create mode 100644 BoostRemote/FeedbackGenerator.swift diff --git a/BoostRemote.xcodeproj/project.pbxproj b/BoostRemote.xcodeproj/project.pbxproj index 3cd131b..d80320a 100644 --- a/BoostRemote.xcodeproj/project.pbxproj +++ b/BoostRemote.xcodeproj/project.pbxproj @@ -20,6 +20,7 @@ CB547EBB201A62A400B00D8C /* FourSticksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB547EBA201A62A400B00D8C /* FourSticksViewController.swift */; }; CB5891F1200D2C8700E15F92 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = CB5891F3200D2C8700E15F92 /* Localizable.strings */; }; CB5891F9200D2DF300E15F92 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = CB5891FB200D2DF300E15F92 /* InfoPlist.strings */; }; + CB70D813201A82D500EAB1D6 /* FeedbackGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB70D812201A82D500EAB1D6 /* FeedbackGenerator.swift */; }; CBA46E781F882F0C0017E5C2 /* ReactiveSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */; }; CBA46E7A1F882F0F0017E5C2 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E791F882F0F0017E5C2 /* Result.framework */; }; CBA46E7D1F882F800017E5C2 /* ReSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E7B1F882F800017E5C2 /* ReSwift.framework */; }; @@ -60,6 +61,7 @@ CB547EBA201A62A400B00D8C /* FourSticksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FourSticksViewController.swift; sourceTree = ""; }; CB5891F4200D2CEA00E15F92 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; CB5891FA200D2DF300E15F92 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = ""; }; + CB70D812201A82D500EAB1D6 /* FeedbackGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackGenerator.swift; sourceTree = ""; }; CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReactiveSwift.framework; path = Carthage/Build/iOS/ReactiveSwift.framework; sourceTree = ""; }; CBA46E791F882F0F0017E5C2 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/iOS/Result.framework; sourceTree = ""; }; CBA46E7B1F882F800017E5C2 /* ReSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReSwift.framework; path = Carthage/Build/iOS/ReSwift.framework; sourceTree = ""; }; @@ -112,6 +114,7 @@ CB547EBA201A62A400B00D8C /* FourSticksViewController.swift */, CB0BF7E41F8BD873004CCD4F /* VerticalSlider.swift */, CB0BF7E61F8BDD30004CCD4F /* StickView.swift */, + CB70D812201A82D500EAB1D6 /* FeedbackGenerator.swift */, CBF9D2B81F3CACA800B97E11 /* MoveHubManager.swift */, CBF9D2D51F3CB52800B97E11 /* MoveHubService.swift */, CBF9D2F51F3CDAC700B97E11 /* Data+HexString.swift */, @@ -261,6 +264,7 @@ CBD94E861F391D7F0037ED71 /* Action.swift in Sources */, CB547EBB201A62A400B00D8C /* FourSticksViewController.swift in Sources */, CB3BE8B11F2FF2F4000561F7 /* AppDelegate.swift in Sources */, + CB70D813201A82D500EAB1D6 /* FeedbackGenerator.swift in Sources */, CBF9D2F61F3CDAC700B97E11 /* Data+HexString.swift in Sources */, CB44B8531F73C11400D0D250 /* Store.swift in Sources */, CBD94E881F391E2E0037ED71 /* Reducer.swift in Sources */, diff --git a/BoostRemote/ControllerViewController.swift b/BoostRemote/ControllerViewController.swift index de6906e..b1bd177 100644 --- a/BoostRemote/ControllerViewController.swift +++ b/BoostRemote/ControllerViewController.swift @@ -28,16 +28,6 @@ class ControllerViewController: UIViewController { } } - private let feedbackGenerator: Any? = { - if #available(iOS 10.0, *) { - let generator = UISelectionFeedbackGenerator() - generator.prepare() - return generator - } else { - return nil - } - }() - override func viewDidLoad() { super.viewDidLoad() @@ -94,7 +84,7 @@ class ControllerViewController: UIViewController { private func sendCommand(port: BoostBLEKit.Port, power: Int8) { if power == 100 || power == -100 { - feedback() + FeedbackGenerator.feedback() } if let command = motors[port]?.powerCommand(power: power) { @@ -102,12 +92,6 @@ class ControllerViewController: UIViewController { } } - private func feedback() { - if #available(iOS 10.0, *), let generator = feedbackGenerator as? UISelectionFeedbackGenerator { - generator.selectionChanged() - } - } - private func alert(message: String) { let alert = UIAlertController(title: NSLocalizedString("CAUTION", comment: "CAUTION"), message: message, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil)) diff --git a/BoostRemote/FeedbackGenerator.swift b/BoostRemote/FeedbackGenerator.swift new file mode 100644 index 0000000..7a96c27 --- /dev/null +++ b/BoostRemote/FeedbackGenerator.swift @@ -0,0 +1,28 @@ +// +// FeedbackGenerator.swift +// BoostRemote +// +// Created by Shinichiro Oba on 2018/01/25. +// Copyright © 2018 bricklife.com. All rights reserved. +// + +import UIKit + +final class FeedbackGenerator { + + private static let feedbackGenerator: Any? = { + if #available(iOS 10.0, *) { + let generator = UISelectionFeedbackGenerator() + generator.prepare() + return generator + } else { + return nil + } + }() + + static func feedback() { + if #available(iOS 10.0, *) { + (feedbackGenerator as? UISelectionFeedbackGenerator)?.selectionChanged() + } + } +} From 189bb8329043316a09b1340e5f3e70757a0a2ab9 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Fri, 26 Jan 2018 01:29:09 +0000 Subject: [PATCH 15/43] Add an extension of UIImage --- BoostRemote.xcodeproj/project.pbxproj | 4 +++ BoostRemote/ControllerViewController.swift | 16 ++-------- BoostRemote/StickView.swift | 2 +- BoostRemote/UIImage+Extension.swift | 36 ++++++++++++++++++++++ 4 files changed, 43 insertions(+), 15 deletions(-) create mode 100644 BoostRemote/UIImage+Extension.swift diff --git a/BoostRemote.xcodeproj/project.pbxproj b/BoostRemote.xcodeproj/project.pbxproj index d80320a..d3da185 100644 --- a/BoostRemote.xcodeproj/project.pbxproj +++ b/BoostRemote.xcodeproj/project.pbxproj @@ -21,6 +21,7 @@ CB5891F1200D2C8700E15F92 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = CB5891F3200D2C8700E15F92 /* Localizable.strings */; }; CB5891F9200D2DF300E15F92 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = CB5891FB200D2DF300E15F92 /* InfoPlist.strings */; }; CB70D813201A82D500EAB1D6 /* FeedbackGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB70D812201A82D500EAB1D6 /* FeedbackGenerator.swift */; }; + CB7390C9201AB89900EAE3A7 /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB7390C8201AB89900EAE3A7 /* UIImage+Extension.swift */; }; CBA46E781F882F0C0017E5C2 /* ReactiveSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */; }; CBA46E7A1F882F0F0017E5C2 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E791F882F0F0017E5C2 /* Result.framework */; }; CBA46E7D1F882F800017E5C2 /* ReSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E7B1F882F800017E5C2 /* ReSwift.framework */; }; @@ -62,6 +63,7 @@ CB5891F4200D2CEA00E15F92 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; CB5891FA200D2DF300E15F92 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = ""; }; CB70D812201A82D500EAB1D6 /* FeedbackGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackGenerator.swift; sourceTree = ""; }; + CB7390C8201AB89900EAE3A7 /* UIImage+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Extension.swift"; sourceTree = ""; }; CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReactiveSwift.framework; path = Carthage/Build/iOS/ReactiveSwift.framework; sourceTree = ""; }; CBA46E791F882F0F0017E5C2 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/iOS/Result.framework; sourceTree = ""; }; CBA46E7B1F882F800017E5C2 /* ReSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReSwift.framework; path = Carthage/Build/iOS/ReSwift.framework; sourceTree = ""; }; @@ -114,6 +116,7 @@ CB547EBA201A62A400B00D8C /* FourSticksViewController.swift */, CB0BF7E41F8BD873004CCD4F /* VerticalSlider.swift */, CB0BF7E61F8BDD30004CCD4F /* StickView.swift */, + CB7390C8201AB89900EAE3A7 /* UIImage+Extension.swift */, CB70D812201A82D500EAB1D6 /* FeedbackGenerator.swift */, CBF9D2B81F3CACA800B97E11 /* MoveHubManager.swift */, CBF9D2D51F3CB52800B97E11 /* MoveHubService.swift */, @@ -258,6 +261,7 @@ buildActionMask = 2147483647; files = ( CBF9D2B91F3CACA800B97E11 /* MoveHubManager.swift in Sources */, + CB7390C9201AB89900EAE3A7 /* UIImage+Extension.swift in Sources */, CB3BE8B31F2FF2F4000561F7 /* ControllerViewController.swift in Sources */, CB0BF7E51F8BD873004CCD4F /* VerticalSlider.swift in Sources */, CB0BF7E71F8BDD30004CCD4F /* StickView.swift in Sources */, diff --git a/BoostRemote/ControllerViewController.swift b/BoostRemote/ControllerViewController.swift index b1bd177..72c0415 100644 --- a/BoostRemote/ControllerViewController.swift +++ b/BoostRemote/ControllerViewController.swift @@ -48,7 +48,7 @@ class ControllerViewController: UIViewController { private func setupConnectButtonImageView() { connectButtonImageView.animationDuration = 1 connectButtonImageView.animationRepeatCount = -1 - connectButtonImageView.animationImages = (1...4).map { "connecting\($0)" }.flatMap { UIImage(named: $0) } + connectButtonImageView.animationImages = UIImage.connectingImages() connectionState.producer.startWithValues { [weak self] (state) in if state == .connecting { @@ -56,19 +56,7 @@ class ControllerViewController: UIViewController { } else { self?.connectButtonImageView.stopAnimating() } - - let imageName: String - switch state { - case .disconnected: - imageName = "disconnected" - case .connecting: - imageName = "disconnected" - case .connected: - imageName = "connected" - case .offline, .unsupported: - imageName = "offline" - } - self?.connectButtonImageView.image = UIImage(named: imageName) + self?.connectButtonImageView.image = UIImage(connectionState: state) } } diff --git a/BoostRemote/StickView.swift b/BoostRemote/StickView.swift index ed74bea..f2c2dba 100644 --- a/BoostRemote/StickView.swift +++ b/BoostRemote/StickView.swift @@ -17,7 +17,7 @@ class StickView: UIView { var port: BoostBLEKit.Port? { didSet { - imageView.image = port.flatMap { UIImage(named: "port\($0)") } + imageView.image = port.flatMap(UIImage.init(port:)) } } diff --git a/BoostRemote/UIImage+Extension.swift b/BoostRemote/UIImage+Extension.swift new file mode 100644 index 0000000..82f7815 --- /dev/null +++ b/BoostRemote/UIImage+Extension.swift @@ -0,0 +1,36 @@ +// +// UIImage+Extension.swift +// BoostRemote +// +// Created by Shinichiro Oba on 2018/01/26. +// Copyright © 2018 bricklife.com. All rights reserved. +// + +import UIKit +import BoostBLEKit + +extension UIImage { + + convenience init?(port: BoostBLEKit.Port) { + self.init(named: "port\(port)") + } + + convenience init?(connectionState: ConnectionState) { + let imageName: String + switch connectionState { + case .disconnected: + imageName = "disconnected" + case .connecting: + imageName = "disconnected" + case .connected: + imageName = "connected" + case .offline, .unsupported: + imageName = "offline" + } + self.init(named: imageName) + } + + static func connectingImages() -> [UIImage] { + return (1...4).map { "connecting\($0)" }.flatMap(UIImage.init(named:)) + } +} From feb74a306c86d98cee9ad62661d0b55520dce94e Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Fri, 26 Jan 2018 01:59:27 +0000 Subject: [PATCH 16/43] Add an image for port A and B --- .../portAB.imageset/Contents.json | 12 ++++++++++++ .../Assets.xcassets/portAB.imageset/portAB.pdf | Bin 0 -> 6694 bytes 2 files changed, 12 insertions(+) create mode 100644 BoostRemote/Assets.xcassets/portAB.imageset/Contents.json create mode 100644 BoostRemote/Assets.xcassets/portAB.imageset/portAB.pdf diff --git a/BoostRemote/Assets.xcassets/portAB.imageset/Contents.json b/BoostRemote/Assets.xcassets/portAB.imageset/Contents.json new file mode 100644 index 0000000..090cb6a --- /dev/null +++ b/BoostRemote/Assets.xcassets/portAB.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "portAB.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/BoostRemote/Assets.xcassets/portAB.imageset/portAB.pdf b/BoostRemote/Assets.xcassets/portAB.imageset/portAB.pdf new file mode 100644 index 0000000000000000000000000000000000000000..a8f9bbb2123e15482566ff41371ed49deda938ef GIT binary patch literal 6694 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 literal 0 HcmV?d00001 From 124d8e8443bbd093a6907e6aa924f0b0f374100d Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Fri, 26 Jan 2018 02:07:27 +0000 Subject: [PATCH 17/43] Use Double instead of CGFloat --- BoostRemote/FourSticksViewController.swift | 10 +++++----- BoostRemote/StickView.swift | 2 +- BoostRemote/VerticalSlider.swift | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/BoostRemote/FourSticksViewController.swift b/BoostRemote/FourSticksViewController.swift index 7d46e1b..96a3866 100644 --- a/BoostRemote/FourSticksViewController.swift +++ b/BoostRemote/FourSticksViewController.swift @@ -18,12 +18,12 @@ class FourSticksViewController: UIViewController { @IBOutlet private weak var stickC: StickView! @IBOutlet private weak var stickD: StickView! - private let (signalA, observerA) = Signal.pipe() - private let (signalB, observerB) = Signal.pipe() - private let (signalC, observerC) = Signal.pipe() - private let (signalD, observerD) = Signal.pipe() + private let (signalA, observerA) = Signal.pipe() + private let (signalB, observerB) = Signal.pipe() + private let (signalC, observerC) = Signal.pipe() + private let (signalD, observerD) = Signal.pipe() - lazy var signals: [BoostBLEKit.Port: Signal] = [ + lazy var signals: [BoostBLEKit.Port: Signal] = [ .A: self.signalA, .B: self.signalB, .C: self.signalC, diff --git a/BoostRemote/StickView.swift b/BoostRemote/StickView.swift index f2c2dba..7b524e2 100644 --- a/BoostRemote/StickView.swift +++ b/BoostRemote/StickView.swift @@ -13,7 +13,7 @@ import BoostBLEKit class StickView: UIView { - let (signal, observer) = Signal.pipe() + let (signal, observer) = Signal.pipe() var port: BoostBLEKit.Port? { didSet { diff --git a/BoostRemote/VerticalSlider.swift b/BoostRemote/VerticalSlider.swift index ee60e28..8f76f7e 100644 --- a/BoostRemote/VerticalSlider.swift +++ b/BoostRemote/VerticalSlider.swift @@ -10,7 +10,7 @@ import UIKit class VerticalSlider: UIView { - var update: ((CGFloat) -> Void)? + var update: ((Double) -> Void)? private var thumbCenterYConstraint: NSLayoutConstraint! @@ -71,7 +71,7 @@ class VerticalSlider: UIView { } thumbCenterYConstraint.constant = base * value - update?(value) + update?(Double(value)) } private func reset() { From 9eb9c2be8a553cad74887bf86042b95ca48f2f3d Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Fri, 26 Jan 2018 02:14:15 +0000 Subject: [PATCH 18/43] Introduce Controller protocol --- BoostRemote.xcodeproj/project.pbxproj | 4 ++++ BoostRemote/Controller.swift | 19 +++++++++++++++++++ BoostRemote/ControllerViewController.swift | 22 +++++++++++++--------- BoostRemote/FourSticksViewController.swift | 2 +- 4 files changed, 37 insertions(+), 10 deletions(-) create mode 100644 BoostRemote/Controller.swift diff --git a/BoostRemote.xcodeproj/project.pbxproj b/BoostRemote.xcodeproj/project.pbxproj index d3da185..5a27b3e 100644 --- a/BoostRemote.xcodeproj/project.pbxproj +++ b/BoostRemote.xcodeproj/project.pbxproj @@ -25,6 +25,7 @@ CBA46E781F882F0C0017E5C2 /* ReactiveSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */; }; CBA46E7A1F882F0F0017E5C2 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E791F882F0F0017E5C2 /* Result.framework */; }; CBA46E7D1F882F800017E5C2 /* ReSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E7B1F882F800017E5C2 /* ReSwift.framework */; }; + CBC72DFA201AC35C00ABE096 /* Controller.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBC72DF9201AC35C00ABE096 /* Controller.swift */; }; CBD94E841F391B3F0037ED71 /* State.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD94E831F391B3F0037ED71 /* State.swift */; }; CBD94E861F391D7F0037ED71 /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD94E851F391D7F0037ED71 /* Action.swift */; }; CBD94E881F391E2E0037ED71 /* Reducer.swift in Sources */ = {isa = PBXBuildFile; fileRef = CBD94E871F391E2E0037ED71 /* Reducer.swift */; }; @@ -67,6 +68,7 @@ CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReactiveSwift.framework; path = Carthage/Build/iOS/ReactiveSwift.framework; sourceTree = ""; }; CBA46E791F882F0F0017E5C2 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/iOS/Result.framework; sourceTree = ""; }; CBA46E7B1F882F800017E5C2 /* ReSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReSwift.framework; path = Carthage/Build/iOS/ReSwift.framework; sourceTree = ""; }; + CBC72DF9201AC35C00ABE096 /* Controller.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Controller.swift; sourceTree = ""; }; CBD94E831F391B3F0037ED71 /* State.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = State.swift; sourceTree = ""; }; CBD94E851F391D7F0037ED71 /* Action.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Action.swift; sourceTree = ""; }; CBD94E871F391E2E0037ED71 /* Reducer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Reducer.swift; sourceTree = ""; }; @@ -113,6 +115,7 @@ CB3BE8B01F2FF2F4000561F7 /* AppDelegate.swift */, CB3BE8B41F2FF2F4000561F7 /* Main.storyboard */, CB3BE8B21F2FF2F4000561F7 /* ControllerViewController.swift */, + CBC72DF9201AC35C00ABE096 /* Controller.swift */, CB547EBA201A62A400B00D8C /* FourSticksViewController.swift */, CB0BF7E41F8BD873004CCD4F /* VerticalSlider.swift */, CB0BF7E61F8BDD30004CCD4F /* StickView.swift */, @@ -260,6 +263,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + CBC72DFA201AC35C00ABE096 /* Controller.swift in Sources */, CBF9D2B91F3CACA800B97E11 /* MoveHubManager.swift in Sources */, CB7390C9201AB89900EAE3A7 /* UIImage+Extension.swift in Sources */, CB3BE8B31F2FF2F4000561F7 /* ControllerViewController.swift in Sources */, diff --git a/BoostRemote/Controller.swift b/BoostRemote/Controller.swift new file mode 100644 index 0000000..3e9b2c3 --- /dev/null +++ b/BoostRemote/Controller.swift @@ -0,0 +1,19 @@ +// +// Controller.swift +// BoostRemote +// +// Created by Shinichiro Oba on 2018/01/26. +// Copyright © 2018 bricklife.com. All rights reserved. +// + +import Foundation +import ReactiveSwift +import Result +import BoostBLEKit + +protocol Controller { + + var signals: [BoostBLEKit.Port: Signal] { get } + + func setEnable(_ enable: Bool, port: BoostBLEKit.Port) +} diff --git a/BoostRemote/ControllerViewController.swift b/BoostRemote/ControllerViewController.swift index 72c0415..041492a 100644 --- a/BoostRemote/ControllerViewController.swift +++ b/BoostRemote/ControllerViewController.swift @@ -15,16 +15,18 @@ class ControllerViewController: UIViewController { @IBOutlet private weak var connectButtonImageView: UIImageView! - private var stickViewController: FourSticksViewController? { - return childViewControllers.first as? FourSticksViewController + private var controllers: [Controller] { + return childViewControllers.flatMap { $0 as? Controller } } private let connectionState = MutableProperty(ConnectionState.disconnected) private var motors: [BoostBLEKit.Port: Motor] = [:] { didSet { - stickViewController?.setEnable(motors.keys.contains(.C), port: .C) - stickViewController?.setEnable(motors.keys.contains(.D), port: .D) + controllers.forEach { + $0.setEnable(motors.keys.contains(.C), port: .C) + $0.setEnable(motors.keys.contains(.D), port: .D) + } } } @@ -61,11 +63,13 @@ class ControllerViewController: UIViewController { } private func setupSticks() { - stickViewController?.signals.forEach { (port, signal) in - signal.map { Int8($0 * 10) * 10 } - .skipRepeats() - .observeValues { [weak self] (value) in - self?.sendCommand(port: port, power: value) + controllers.forEach { + $0.signals.forEach { (port, signal) in + signal.map { Int8($0 * 10) * 10 } + .skipRepeats() + .observeValues { [weak self] (value) in + self?.sendCommand(port: port, power: value) + } } } } diff --git a/BoostRemote/FourSticksViewController.swift b/BoostRemote/FourSticksViewController.swift index 96a3866..3681c11 100644 --- a/BoostRemote/FourSticksViewController.swift +++ b/BoostRemote/FourSticksViewController.swift @@ -11,7 +11,7 @@ import ReactiveSwift import Result import BoostBLEKit -class FourSticksViewController: UIViewController { +class FourSticksViewController: UIViewController, Controller { @IBOutlet private weak var stickA: StickView! @IBOutlet private weak var stickB: StickView! From 0fcf02f6551c30599484d9e537bd0c50ad063c12 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Fri, 26 Jan 2018 12:55:27 +0000 Subject: [PATCH 19/43] Fix a bug --- BoostRemote/FourSticksViewController.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BoostRemote/FourSticksViewController.swift b/BoostRemote/FourSticksViewController.swift index 3681c11..bc8d877 100644 --- a/BoostRemote/FourSticksViewController.swift +++ b/BoostRemote/FourSticksViewController.swift @@ -53,10 +53,10 @@ class FourSticksViewController: UIViewController, Controller { func setEnable(_ enable: Bool, port: BoostBLEKit.Port) { switch port { - case .B: - stickB.isHidden = !enable case .C: stickC.isHidden = !enable + case .D: + stickD.isHidden = !enable default: break } From cbe5554f89f56317814d7bc2a6a95c8630e8c4b2 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Fri, 26 Jan 2018 13:14:36 +0000 Subject: [PATCH 20/43] Add JoystickViewController --- BoostRemote.xcodeproj/project.pbxproj | 4 + .../thumb.imageset/Contents.json | 16 ++- BoostRemote/Base.lproj/Main.storyboard | 111 ++++++++++++++++++ BoostRemote/FourSticksViewController.swift | 3 - BoostRemote/JoystickViewController.swift | 55 +++++++++ BoostRemote/StickView.swift | 3 +- BoostRemote/VerticalSlider.swift | 2 + 7 files changed, 189 insertions(+), 5 deletions(-) create mode 100644 BoostRemote/JoystickViewController.swift diff --git a/BoostRemote.xcodeproj/project.pbxproj b/BoostRemote.xcodeproj/project.pbxproj index 5a27b3e..3ce26d4 100644 --- a/BoostRemote.xcodeproj/project.pbxproj +++ b/BoostRemote.xcodeproj/project.pbxproj @@ -18,6 +18,7 @@ CB4345A8200FC0D200D82D7D /* BoostBLEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CB4345A7200FC0D100D82D7D /* BoostBLEKit.framework */; }; CB44B8531F73C11400D0D250 /* Store.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB44B8521F73C11400D0D250 /* Store.swift */; }; CB547EBB201A62A400B00D8C /* FourSticksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB547EBA201A62A400B00D8C /* FourSticksViewController.swift */; }; + CB547EBD201B5C3D00B00D8C /* JoystickViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB547EBC201B5C3D00B00D8C /* JoystickViewController.swift */; }; CB5891F1200D2C8700E15F92 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = CB5891F3200D2C8700E15F92 /* Localizable.strings */; }; CB5891F9200D2DF300E15F92 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = CB5891FB200D2DF300E15F92 /* InfoPlist.strings */; }; CB70D813201A82D500EAB1D6 /* FeedbackGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB70D812201A82D500EAB1D6 /* FeedbackGenerator.swift */; }; @@ -61,6 +62,7 @@ CB4345A7200FC0D100D82D7D /* BoostBLEKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BoostBLEKit.framework; path = Carthage/Build/iOS/BoostBLEKit.framework; sourceTree = ""; }; CB44B8521F73C11400D0D250 /* Store.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Store.swift; sourceTree = ""; }; CB547EBA201A62A400B00D8C /* FourSticksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FourSticksViewController.swift; sourceTree = ""; }; + CB547EBC201B5C3D00B00D8C /* JoystickViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoystickViewController.swift; sourceTree = ""; }; CB5891F4200D2CEA00E15F92 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; CB5891FA200D2DF300E15F92 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = ""; }; CB70D812201A82D500EAB1D6 /* FeedbackGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackGenerator.swift; sourceTree = ""; }; @@ -117,6 +119,7 @@ CB3BE8B21F2FF2F4000561F7 /* ControllerViewController.swift */, CBC72DF9201AC35C00ABE096 /* Controller.swift */, CB547EBA201A62A400B00D8C /* FourSticksViewController.swift */, + CB547EBC201B5C3D00B00D8C /* JoystickViewController.swift */, CB0BF7E41F8BD873004CCD4F /* VerticalSlider.swift */, CB0BF7E61F8BDD30004CCD4F /* StickView.swift */, CB7390C8201AB89900EAE3A7 /* UIImage+Extension.swift */, @@ -269,6 +272,7 @@ CB3BE8B31F2FF2F4000561F7 /* ControllerViewController.swift in Sources */, CB0BF7E51F8BD873004CCD4F /* VerticalSlider.swift in Sources */, CB0BF7E71F8BDD30004CCD4F /* StickView.swift in Sources */, + CB547EBD201B5C3D00B00D8C /* JoystickViewController.swift in Sources */, CBD94E861F391D7F0037ED71 /* Action.swift in Sources */, CB547EBB201A62A400B00D8C /* FourSticksViewController.swift in Sources */, CB3BE8B11F2FF2F4000561F7 /* AppDelegate.swift in Sources */, diff --git a/BoostRemote/Assets.xcassets/thumb.imageset/Contents.json b/BoostRemote/Assets.xcassets/thumb.imageset/Contents.json index 5275443..f6b862d 100644 --- a/BoostRemote/Assets.xcassets/thumb.imageset/Contents.json +++ b/BoostRemote/Assets.xcassets/thumb.imageset/Contents.json @@ -2,7 +2,21 @@ "images" : [ { "idiom" : "universal", - "filename" : "thumb.pdf" + "filename" : "thumb.pdf", + "resizing" : { + "mode" : "9-part", + "center" : { + "mode" : "tile", + "width" : 1, + "height" : 1 + }, + "cap-insets" : { + "bottom" : 15, + "top" : 15, + "right" : 15, + "left" : 15 + } + } } ], "info" : { diff --git a/BoostRemote/Base.lproj/Main.storyboard b/BoostRemote/Base.lproj/Main.storyboard index b4dea4a..e8cba0e 100644 --- a/BoostRemote/Base.lproj/Main.storyboard +++ b/BoostRemote/Base.lproj/Main.storyboard @@ -7,6 +7,7 @@ + @@ -42,6 +43,12 @@ + + + + + + @@ -49,9 +56,13 @@ + + + + @@ -165,5 +176,105 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/BoostRemote/FourSticksViewController.swift b/BoostRemote/FourSticksViewController.swift index bc8d877..7b67dea 100644 --- a/BoostRemote/FourSticksViewController.swift +++ b/BoostRemote/FourSticksViewController.swift @@ -46,9 +46,6 @@ class FourSticksViewController: UIViewController, Controller { stickB.signal.observe(observerB) stickC.signal.observe(observerC) stickD.signal.observe(observerD) - - stickC.isHidden = true - stickD.isHidden = true } func setEnable(_ enable: Bool, port: BoostBLEKit.Port) { diff --git a/BoostRemote/JoystickViewController.swift b/BoostRemote/JoystickViewController.swift new file mode 100644 index 0000000..e72b27a --- /dev/null +++ b/BoostRemote/JoystickViewController.swift @@ -0,0 +1,55 @@ +// +// JoystickViewController.swift +// BoostRemote +// +// Created by ooba on 26/01/2018. +// Copyright © 2018 bricklife.com. All rights reserved. +// + +import UIKit +import ReactiveSwift +import Result +import BoostBLEKit + +class JoystickViewController: UIViewController, Controller { + + @IBOutlet private weak var stickC: StickView! + @IBOutlet private weak var stickD: StickView! + + private let (signalA, observerA) = Signal.pipe() + private let (signalB, observerB) = Signal.pipe() + private let (signalC, observerC) = Signal.pipe() + private let (signalD, observerD) = Signal.pipe() + + lazy var signals: [BoostBLEKit.Port: Signal] = [ + .A: self.signalA, + .B: self.signalB, + .C: self.signalC, + .D: self.signalD, + ] + + override func viewDidLoad() { + super.viewDidLoad() + + setupSticks() + } + + private func setupSticks() { + stickC.port = .C + stickD.port = .D + + stickC.signal.observe(observerC) + stickD.signal.observe(observerD) + } + + func setEnable(_ enable: Bool, port: BoostBLEKit.Port) { + switch port { + case .C: + stickC.isHidden = !enable + case .D: + stickD.isHidden = !enable + default: + break + } + } +} diff --git a/BoostRemote/StickView.swift b/BoostRemote/StickView.swift index 7b524e2..11262c9 100644 --- a/BoostRemote/StickView.swift +++ b/BoostRemote/StickView.swift @@ -46,7 +46,8 @@ class StickView: UIView { NSLayoutConstraint.activate([ imageView.topAnchor.constraint(equalTo: verticalSlider.bottomAnchor, constant: 16), imageView.bottomAnchor.constraint(equalTo: bottomAnchor), - imageView.centerXAnchor.constraint(equalTo: centerXAnchor), + imageView.leftAnchor.constraint(equalTo: leftAnchor), + imageView.rightAnchor.constraint(equalTo: rightAnchor), imageView.heightAnchor.constraint(equalToConstant: 32), ]) diff --git a/BoostRemote/VerticalSlider.swift b/BoostRemote/VerticalSlider.swift index 8f76f7e..db6b37d 100644 --- a/BoostRemote/VerticalSlider.swift +++ b/BoostRemote/VerticalSlider.swift @@ -41,6 +41,8 @@ class VerticalSlider: UIView { NSLayoutConstraint.activate([ thumbView.centerXAnchor.constraint(equalTo: centerXAnchor), + thumbView.widthAnchor.constraint(equalTo: widthAnchor), + thumbView.heightAnchor.constraint(equalTo: widthAnchor), thumbCenterYConstraint, ]) } From e5f58e8ab27aa627fabb906d1885a43eba1d0ce2 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Fri, 26 Jan 2018 13:26:54 +0000 Subject: [PATCH 21/43] Disregard bottom safe area --- BoostRemote/Base.lproj/Main.storyboard | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/BoostRemote/Base.lproj/Main.storyboard b/BoostRemote/Base.lproj/Main.storyboard index e8cba0e..99e2a46 100644 --- a/BoostRemote/Base.lproj/Main.storyboard +++ b/BoostRemote/Base.lproj/Main.storyboard @@ -52,20 +52,20 @@ + - + + - - - + @@ -84,9 +84,9 @@ - + - + From 7ba558f54c1fb77512b59796305a7c37c98ddac6 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Fri, 26 Jan 2018 13:43:44 +0000 Subject: [PATCH 22/43] Tweak layout --- BoostRemote/Base.lproj/Main.storyboard | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/BoostRemote/Base.lproj/Main.storyboard b/BoostRemote/Base.lproj/Main.storyboard index 99e2a46..0c318ed 100644 --- a/BoostRemote/Base.lproj/Main.storyboard +++ b/BoostRemote/Base.lproj/Main.storyboard @@ -99,9 +99,9 @@ + - @@ -225,6 +225,7 @@ + @@ -232,18 +233,25 @@ - - + + + + + + + + + - + - + @@ -260,7 +268,9 @@ + + From ebbd3217280efd7997082d52cacf1274c71b173e Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Fri, 26 Jan 2018 18:36:20 +0000 Subject: [PATCH 23/43] Enable to control by JoystickView --- BoostRemote.xcodeproj/project.pbxproj | 4 + BoostRemote/Base.lproj/Main.storyboard | 26 +----- BoostRemote/JoystickView.swift | 113 +++++++++++++++++++++++ BoostRemote/JoystickViewController.swift | 23 ++++- 4 files changed, 141 insertions(+), 25 deletions(-) create mode 100644 BoostRemote/JoystickView.swift diff --git a/BoostRemote.xcodeproj/project.pbxproj b/BoostRemote.xcodeproj/project.pbxproj index 3ce26d4..e87efbb 100644 --- a/BoostRemote.xcodeproj/project.pbxproj +++ b/BoostRemote.xcodeproj/project.pbxproj @@ -23,6 +23,7 @@ CB5891F9200D2DF300E15F92 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = CB5891FB200D2DF300E15F92 /* InfoPlist.strings */; }; CB70D813201A82D500EAB1D6 /* FeedbackGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB70D812201A82D500EAB1D6 /* FeedbackGenerator.swift */; }; CB7390C9201AB89900EAE3A7 /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB7390C8201AB89900EAE3A7 /* UIImage+Extension.swift */; }; + CB84A382201BA3D300C02CD8 /* JoystickView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB84A381201BA3D300C02CD8 /* JoystickView.swift */; }; CBA46E781F882F0C0017E5C2 /* ReactiveSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */; }; CBA46E7A1F882F0F0017E5C2 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E791F882F0F0017E5C2 /* Result.framework */; }; CBA46E7D1F882F800017E5C2 /* ReSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E7B1F882F800017E5C2 /* ReSwift.framework */; }; @@ -67,6 +68,7 @@ CB5891FA200D2DF300E15F92 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = ""; }; CB70D812201A82D500EAB1D6 /* FeedbackGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackGenerator.swift; sourceTree = ""; }; CB7390C8201AB89900EAE3A7 /* UIImage+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Extension.swift"; sourceTree = ""; }; + CB84A381201BA3D300C02CD8 /* JoystickView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoystickView.swift; sourceTree = ""; }; CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReactiveSwift.framework; path = Carthage/Build/iOS/ReactiveSwift.framework; sourceTree = ""; }; CBA46E791F882F0F0017E5C2 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/iOS/Result.framework; sourceTree = ""; }; CBA46E7B1F882F800017E5C2 /* ReSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReSwift.framework; path = Carthage/Build/iOS/ReSwift.framework; sourceTree = ""; }; @@ -122,6 +124,7 @@ CB547EBC201B5C3D00B00D8C /* JoystickViewController.swift */, CB0BF7E41F8BD873004CCD4F /* VerticalSlider.swift */, CB0BF7E61F8BDD30004CCD4F /* StickView.swift */, + CB84A381201BA3D300C02CD8 /* JoystickView.swift */, CB7390C8201AB89900EAE3A7 /* UIImage+Extension.swift */, CB70D812201A82D500EAB1D6 /* FeedbackGenerator.swift */, CBF9D2B81F3CACA800B97E11 /* MoveHubManager.swift */, @@ -280,6 +283,7 @@ CBF9D2F61F3CDAC700B97E11 /* Data+HexString.swift in Sources */, CB44B8531F73C11400D0D250 /* Store.swift in Sources */, CBD94E881F391E2E0037ED71 /* Reducer.swift in Sources */, + CB84A382201BA3D300C02CD8 /* JoystickView.swift in Sources */, CBD94E841F391B3F0037ED71 /* State.swift in Sources */, CBF9D2D61F3CB52800B97E11 /* MoveHubService.swift in Sources */, ); diff --git a/BoostRemote/Base.lproj/Main.storyboard b/BoostRemote/Base.lproj/Main.storyboard index 0c318ed..eb2e013 100644 --- a/BoostRemote/Base.lproj/Main.storyboard +++ b/BoostRemote/Base.lproj/Main.storyboard @@ -187,31 +187,10 @@ - + - - - - - - - - - - - - - - - - - - - - - @@ -273,6 +252,7 @@ + @@ -283,8 +263,6 @@ - - diff --git a/BoostRemote/JoystickView.swift b/BoostRemote/JoystickView.swift new file mode 100644 index 0000000..90e3871 --- /dev/null +++ b/BoostRemote/JoystickView.swift @@ -0,0 +1,113 @@ +// +// JoystickView.swift +// BoostRemote +// +// Created by ooba on 26/01/2018. +// Copyright © 2018 bricklife.com. All rights reserved. +// + +import UIKit + +class JoystickView: UIView { + + var update: ((Double, Double) -> Void)? + + private var thumbCenterXConstraint: NSLayoutConstraint! + private var thumbCenterYConstraint: NSLayoutConstraint! + + required init?(coder aDecoder: NSCoder) { + super.init(coder: aDecoder) + + initialize() + } + + required override init(frame: CGRect) { + super.init(frame: frame) + + initialize() + } + + private func initialize() { + addSubview(baseView) + addSubview(thumbView) + + NSLayoutConstraint.activate([ + baseView.widthAnchor.constraint(equalTo: widthAnchor), + baseView.heightAnchor.constraint(equalTo: heightAnchor), + baseView.centerXAnchor.constraint(equalTo: centerXAnchor), + baseView.centerYAnchor.constraint(equalTo: centerYAnchor), + ]) + + thumbCenterXConstraint = thumbView.centerXAnchor.constraint(equalTo: centerXAnchor) + thumbCenterYConstraint = thumbView.centerYAnchor.constraint(equalTo: centerYAnchor) + + NSLayoutConstraint.activate([ + thumbView.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.4), + thumbView.heightAnchor.constraint(equalTo: widthAnchor, multiplier: 0.4), + thumbCenterXConstraint, + thumbCenterYConstraint, + ]) + } + + private let baseView: UIView = { + let view = UIImageView(image: #imageLiteral(resourceName: "base")) + view.translatesAutoresizingMaskIntoConstraints = false + + return view + }() + + private let thumbView: UIView = { + let view = UIImageView(image: #imageLiteral(resourceName: "thumb")) + view.translatesAutoresizingMaskIntoConstraints = false + + return view + }() + + private func move(location: CGPoint) { + let width = (bounds.width - thumbView.bounds.width) / 2 + let height = (bounds.height - thumbView.bounds.height) / 2 + + var x = (location.x - bounds.midX) / width + if x < -1 { + x = -1 + } else if x > 1 { + x = 1 + } + + var y = (location.y - bounds.midY) / height + if y < -1 { + y = -1 + } else if y > 1 { + y = 1 + } + + thumbCenterXConstraint.constant = x * width + thumbCenterYConstraint.constant = y * height + + update?(Double(x), Double(y)) + } + + private func reset() { + move(location: CGPoint(x: bounds.midX, y: bounds.midY)) + } + + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + guard let touch = touches.first else { return } + let location = touch.location(in: self) + move(location: location) + } + + override func touchesMoved(_ touches: Set, with event: UIEvent?) { + guard let touch = touches.first else { return } + let location = touch.location(in: self) + move(location: location) + } + + override func touchesEnded(_ touches: Set, with event: UIEvent?) { + reset() + } + + override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + reset() + } +} diff --git a/BoostRemote/JoystickViewController.swift b/BoostRemote/JoystickViewController.swift index e72b27a..2af8bbf 100644 --- a/BoostRemote/JoystickViewController.swift +++ b/BoostRemote/JoystickViewController.swift @@ -13,6 +13,7 @@ import BoostBLEKit class JoystickViewController: UIViewController, Controller { + @IBOutlet private weak var joystickView: JoystickView! @IBOutlet private weak var stickC: StickView! @IBOutlet private weak var stickD: StickView! @@ -30,10 +31,30 @@ class JoystickViewController: UIViewController, Controller { override func viewDidLoad() { super.viewDidLoad() - + + setupJoystick() setupSticks() } + private func setupJoystick() { + joystickView.update = { [weak self] (x, y) in + func calc(x: Double, y: Double) -> Double { + if x > 0, y > 0 { + return max(x, y) + } else if x < 0, y < 0 { + return min(x, y) + } else { + return x + y + } + } + let valueA = calc(x: x, y: -y) + let valueB = calc(x: -x, y: -y) + + self?.observerA.send(value: valueA) + self?.observerB.send(value: valueB) + } + } + private func setupSticks() { stickC.port = .C stickD.port = .D From d832215ef6e56b246caa12ccef4e9e48717f98eb Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Fri, 26 Jan 2018 19:04:40 +0000 Subject: [PATCH 24/43] Introduce Settings class and improve controllability --- BoostRemote.xcodeproj/project.pbxproj | 4 ++++ BoostRemote/ControllerViewController.swift | 2 +- BoostRemote/Settings.swift | 22 ++++++++++++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 BoostRemote/Settings.swift diff --git a/BoostRemote.xcodeproj/project.pbxproj b/BoostRemote.xcodeproj/project.pbxproj index e87efbb..b37fe94 100644 --- a/BoostRemote.xcodeproj/project.pbxproj +++ b/BoostRemote.xcodeproj/project.pbxproj @@ -24,6 +24,7 @@ CB70D813201A82D500EAB1D6 /* FeedbackGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB70D812201A82D500EAB1D6 /* FeedbackGenerator.swift */; }; CB7390C9201AB89900EAE3A7 /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB7390C8201AB89900EAE3A7 /* UIImage+Extension.swift */; }; CB84A382201BA3D300C02CD8 /* JoystickView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB84A381201BA3D300C02CD8 /* JoystickView.swift */; }; + CB84A384201BADEC00C02CD8 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB84A383201BADEC00C02CD8 /* Settings.swift */; }; CBA46E781F882F0C0017E5C2 /* ReactiveSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */; }; CBA46E7A1F882F0F0017E5C2 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E791F882F0F0017E5C2 /* Result.framework */; }; CBA46E7D1F882F800017E5C2 /* ReSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E7B1F882F800017E5C2 /* ReSwift.framework */; }; @@ -69,6 +70,7 @@ CB70D812201A82D500EAB1D6 /* FeedbackGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackGenerator.swift; sourceTree = ""; }; CB7390C8201AB89900EAE3A7 /* UIImage+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Extension.swift"; sourceTree = ""; }; CB84A381201BA3D300C02CD8 /* JoystickView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoystickView.swift; sourceTree = ""; }; + CB84A383201BADEC00C02CD8 /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = ""; }; CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReactiveSwift.framework; path = Carthage/Build/iOS/ReactiveSwift.framework; sourceTree = ""; }; CBA46E791F882F0F0017E5C2 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/iOS/Result.framework; sourceTree = ""; }; CBA46E7B1F882F800017E5C2 /* ReSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReSwift.framework; path = Carthage/Build/iOS/ReSwift.framework; sourceTree = ""; }; @@ -118,6 +120,7 @@ children = ( CB3BE8B01F2FF2F4000561F7 /* AppDelegate.swift */, CB3BE8B41F2FF2F4000561F7 /* Main.storyboard */, + CB84A383201BADEC00C02CD8 /* Settings.swift */, CB3BE8B21F2FF2F4000561F7 /* ControllerViewController.swift */, CBC72DF9201AC35C00ABE096 /* Controller.swift */, CB547EBA201A62A400B00D8C /* FourSticksViewController.swift */, @@ -275,6 +278,7 @@ CB3BE8B31F2FF2F4000561F7 /* ControllerViewController.swift in Sources */, CB0BF7E51F8BD873004CCD4F /* VerticalSlider.swift in Sources */, CB0BF7E71F8BDD30004CCD4F /* StickView.swift in Sources */, + CB84A384201BADEC00C02CD8 /* Settings.swift in Sources */, CB547EBD201B5C3D00B00D8C /* JoystickViewController.swift in Sources */, CBD94E861F391D7F0037ED71 /* Action.swift in Sources */, CB547EBB201A62A400B00D8C /* FourSticksViewController.swift in Sources */, diff --git a/BoostRemote/ControllerViewController.swift b/BoostRemote/ControllerViewController.swift index 041492a..1d5668e 100644 --- a/BoostRemote/ControllerViewController.swift +++ b/BoostRemote/ControllerViewController.swift @@ -65,7 +65,7 @@ class ControllerViewController: UIViewController { private func setupSticks() { controllers.forEach { $0.signals.forEach { (port, signal) in - signal.map { Int8($0 * 10) * 10 } + signal.map { Int8(round($0 * Settings.step) * 100 / Settings.step) } .skipRepeats() .observeValues { [weak self] (value) in self?.sendCommand(port: port, power: value) diff --git a/BoostRemote/Settings.swift b/BoostRemote/Settings.swift new file mode 100644 index 0000000..cbc8514 --- /dev/null +++ b/BoostRemote/Settings.swift @@ -0,0 +1,22 @@ +// +// Settings.swift +// BoostRemote +// +// Created by ooba on 26/01/2018. +// Copyright © 2018 bricklife.com. All rights reserved. +// + +import Foundation + +final class Settings { + + private static var userDefaults: UserDefaults = { + UserDefaults.standard.register(defaults: ["step": Double(5)]) + return UserDefaults.standard + }() + + static var step: Double { + get { return userDefaults.double(forKey: "step") } + set { userDefaults.set(newValue, forKey: "step") } + } +} From 3a8df6caf3822a05f53ad26c440dcc307e6b1997 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Tue, 30 Jan 2018 01:13:55 +0000 Subject: [PATCH 25/43] Add mode setting --- BoostRemote/Settings.swift | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/BoostRemote/Settings.swift b/BoostRemote/Settings.swift index cbc8514..4a1a773 100644 --- a/BoostRemote/Settings.swift +++ b/BoostRemote/Settings.swift @@ -19,4 +19,14 @@ final class Settings { get { return userDefaults.double(forKey: "step") } set { userDefaults.set(newValue, forKey: "step") } } + + enum Mode: String { + case joystick = "joystick" + case twinsticks = "twinsticks" + } + + static var mode: Mode { + get { return userDefaults.string(forKey: "mode").flatMap(Mode.init(rawValue:)) ?? .joystick } + set { userDefaults.set(newValue.rawValue, forKey: "mode") } + } } From 9cfd24a3e2c7e64997b366c35319078c983f5280 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Tue, 30 Jan 2018 01:28:31 +0000 Subject: [PATCH 26/43] Add Settings screen --- BoostRemote.xcodeproj/project.pbxproj | 4 + BoostRemote/Action.swift | 7 + BoostRemote/Base.lproj/Main.storyboard | 230 +++++++++++++++++---- BoostRemote/Controller.swift | 2 + BoostRemote/ControllerViewController.swift | 14 +- BoostRemote/FourSticksViewController.swift | 2 + BoostRemote/JoystickViewController.swift | 2 + BoostRemote/Reducer.swift | 28 ++- BoostRemote/Settings.swift | 11 +- BoostRemote/SettingsViewController.swift | 68 ++++++ BoostRemote/State.swift | 7 + BoostRemote/Store.swift | 7 +- 12 files changed, 336 insertions(+), 46 deletions(-) create mode 100644 BoostRemote/SettingsViewController.swift diff --git a/BoostRemote.xcodeproj/project.pbxproj b/BoostRemote.xcodeproj/project.pbxproj index b37fe94..2010118 100644 --- a/BoostRemote.xcodeproj/project.pbxproj +++ b/BoostRemote.xcodeproj/project.pbxproj @@ -25,6 +25,7 @@ CB7390C9201AB89900EAE3A7 /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB7390C8201AB89900EAE3A7 /* UIImage+Extension.swift */; }; CB84A382201BA3D300C02CD8 /* JoystickView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB84A381201BA3D300C02CD8 /* JoystickView.swift */; }; CB84A384201BADEC00C02CD8 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB84A383201BADEC00C02CD8 /* Settings.swift */; }; + CB8C7EB4201FEF6500274A09 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB8C7EB3201FEF6500274A09 /* SettingsViewController.swift */; }; CBA46E781F882F0C0017E5C2 /* ReactiveSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */; }; CBA46E7A1F882F0F0017E5C2 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E791F882F0F0017E5C2 /* Result.framework */; }; CBA46E7D1F882F800017E5C2 /* ReSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E7B1F882F800017E5C2 /* ReSwift.framework */; }; @@ -71,6 +72,7 @@ CB7390C8201AB89900EAE3A7 /* UIImage+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Extension.swift"; sourceTree = ""; }; CB84A381201BA3D300C02CD8 /* JoystickView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoystickView.swift; sourceTree = ""; }; CB84A383201BADEC00C02CD8 /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = ""; }; + CB8C7EB3201FEF6500274A09 /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReactiveSwift.framework; path = Carthage/Build/iOS/ReactiveSwift.framework; sourceTree = ""; }; CBA46E791F882F0F0017E5C2 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/iOS/Result.framework; sourceTree = ""; }; CBA46E7B1F882F800017E5C2 /* ReSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReSwift.framework; path = Carthage/Build/iOS/ReSwift.framework; sourceTree = ""; }; @@ -121,6 +123,7 @@ CB3BE8B01F2FF2F4000561F7 /* AppDelegate.swift */, CB3BE8B41F2FF2F4000561F7 /* Main.storyboard */, CB84A383201BADEC00C02CD8 /* Settings.swift */, + CB8C7EB3201FEF6500274A09 /* SettingsViewController.swift */, CB3BE8B21F2FF2F4000561F7 /* ControllerViewController.swift */, CBC72DF9201AC35C00ABE096 /* Controller.swift */, CB547EBA201A62A400B00D8C /* FourSticksViewController.swift */, @@ -277,6 +280,7 @@ CB7390C9201AB89900EAE3A7 /* UIImage+Extension.swift in Sources */, CB3BE8B31F2FF2F4000561F7 /* ControllerViewController.swift in Sources */, CB0BF7E51F8BD873004CCD4F /* VerticalSlider.swift in Sources */, + CB8C7EB4201FEF6500274A09 /* SettingsViewController.swift in Sources */, CB0BF7E71F8BDD30004CCD4F /* StickView.swift in Sources */, CB84A384201BADEC00C02CD8 /* Settings.swift in Sources */, CB547EBD201B5C3D00B00D8C /* JoystickViewController.swift in Sources */, diff --git a/BoostRemote/Action.swift b/BoostRemote/Action.swift index a081738..0177f70 100644 --- a/BoostRemote/Action.swift +++ b/BoostRemote/Action.swift @@ -24,6 +24,13 @@ struct NotificationAction: Action { let notification: BoostBLEKit.Notification } +enum SettingsAction: Action { + + case incrementStep + case decrementStep + case selectMode(Settings.Mode) +} + struct ActionCenter { static func startScan() { diff --git a/BoostRemote/Base.lproj/Main.storyboard b/BoostRemote/Base.lproj/Main.storyboard index eb2e013..1cc74da 100644 --- a/BoostRemote/Base.lproj/Main.storyboard +++ b/BoostRemote/Base.lproj/Main.storyboard @@ -37,36 +37,58 @@ - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + + - - - - - + + + + - - + @@ -114,16 +136,137 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + - + @@ -133,21 +276,21 @@ - + - + - + @@ -174,14 +317,14 @@ - + - + @@ -212,25 +355,18 @@ - - + + - - - - - - - - + - + @@ -247,7 +383,6 @@ - @@ -259,10 +394,29 @@ - + + + + + + + + + + + + + + + + + + + + diff --git a/BoostRemote/Controller.swift b/BoostRemote/Controller.swift index 3e9b2c3..1c3cd8a 100644 --- a/BoostRemote/Controller.swift +++ b/BoostRemote/Controller.swift @@ -13,6 +13,8 @@ import BoostBLEKit protocol Controller { + var mode: Settings.Mode { get } + var signals: [BoostBLEKit.Port: Signal] { get } func setEnable(_ enable: Bool, port: BoostBLEKit.Port) diff --git a/BoostRemote/ControllerViewController.swift b/BoostRemote/ControllerViewController.swift index 1d5668e..f885d65 100644 --- a/BoostRemote/ControllerViewController.swift +++ b/BoostRemote/ControllerViewController.swift @@ -15,11 +15,12 @@ class ControllerViewController: UIViewController { @IBOutlet private weak var connectButtonImageView: UIImageView! - private var controllers: [Controller] { - return childViewControllers.flatMap { $0 as? Controller } + private var controllers: [Controller & UIViewController] { + return childViewControllers.flatMap { $0 as? (Controller & UIViewController) } } private let connectionState = MutableProperty(ConnectionState.disconnected) + private let step = MutableProperty(Settings.defaultStep) private var motors: [BoostBLEKit.Port: Motor] = [:] { didSet { @@ -65,7 +66,9 @@ class ControllerViewController: UIViewController { private func setupSticks() { controllers.forEach { $0.signals.forEach { (port, signal) in - signal.map { Int8(round($0 * Settings.step) * 100 / Settings.step) } + signal + .withLatest(from: step.signal) + .map { (value, step) in Int8(round(value * step) * 100 / step) } .skipRepeats() .observeValues { [weak self] (value) in self?.sendCommand(port: port, power: value) @@ -90,6 +93,8 @@ class ControllerViewController: UIViewController { present(alert, animated: true, completion: nil) } + @IBAction func close(_ segue: UIStoryboardSegue) {} + @IBAction private func connectButtonPushed(_ sender: Any) { switch connectionState.value { case .disconnected: @@ -118,5 +123,8 @@ extension ControllerViewController: StoreSubscriber { return Motor(port: port, deviceType: type) } } + + controllers.forEach { $0.view.isHidden = ($0.mode != state.settingsState.mode) } + step.value = state.settingsState.step } } diff --git a/BoostRemote/FourSticksViewController.swift b/BoostRemote/FourSticksViewController.swift index 7b67dea..c815000 100644 --- a/BoostRemote/FourSticksViewController.swift +++ b/BoostRemote/FourSticksViewController.swift @@ -13,6 +13,8 @@ import BoostBLEKit class FourSticksViewController: UIViewController, Controller { + let mode = Settings.Mode.twinsticks + @IBOutlet private weak var stickA: StickView! @IBOutlet private weak var stickB: StickView! @IBOutlet private weak var stickC: StickView! diff --git a/BoostRemote/JoystickViewController.swift b/BoostRemote/JoystickViewController.swift index 2af8bbf..25a256a 100644 --- a/BoostRemote/JoystickViewController.swift +++ b/BoostRemote/JoystickViewController.swift @@ -13,6 +13,8 @@ import BoostBLEKit class JoystickViewController: UIViewController, Controller { + let mode = Settings.Mode.joystick + @IBOutlet private weak var joystickView: JoystickView! @IBOutlet private weak var stickC: StickView! @IBOutlet private weak var stickD: StickView! diff --git a/BoostRemote/Reducer.swift b/BoostRemote/Reducer.swift index a4389dc..9101165 100644 --- a/BoostRemote/Reducer.swift +++ b/BoostRemote/Reducer.swift @@ -14,7 +14,8 @@ struct Reducer { static func appReducer(action: Action, state: State?) -> State { return State( connectionState: connectionReducer(state: state?.connectionState, action: action), - portState: portReducer(state: state?.portState, action: action) + portState: portReducer(state: state?.portState, action: action), + settingsState: settingsReducer(state: state?.settingsState, action: action) ) } @@ -51,4 +52,29 @@ struct Reducer { return state } + + static func settingsReducer(state: SettingsState?, action: Action) -> SettingsState { + var state = state ?? SettingsState(mode: Settings.defaultMode, step: Settings.defaultStep) + + guard let action = action as? SettingsAction else { return state } + + switch action { + case .incrementStep: + if state.step < 100 { + state.step += 1 + } + case .decrementStep: + if state.step > 1 { + state.step -= 1 + } + case .selectMode(let mode): + state.mode = mode + } + + // ToDo: Avoid side-effect + Settings.mode = state.mode + Settings.step = state.step + + return state + } } diff --git a/BoostRemote/Settings.swift b/BoostRemote/Settings.swift index 4a1a773..66dbb37 100644 --- a/BoostRemote/Settings.swift +++ b/BoostRemote/Settings.swift @@ -10,12 +10,17 @@ import Foundation final class Settings { + typealias Step = Double + + static let defaultMode: Mode = .joystick + static let defaultStep: Step = 5 + private static var userDefaults: UserDefaults = { - UserDefaults.standard.register(defaults: ["step": Double(5)]) + UserDefaults.standard.register(defaults: ["step": Double(defaultStep)]) return UserDefaults.standard }() - static var step: Double { + static var step: Step { get { return userDefaults.double(forKey: "step") } set { userDefaults.set(newValue, forKey: "step") } } @@ -26,7 +31,7 @@ final class Settings { } static var mode: Mode { - get { return userDefaults.string(forKey: "mode").flatMap(Mode.init(rawValue:)) ?? .joystick } + get { return userDefaults.string(forKey: "mode").flatMap(Mode.init(rawValue:)) ?? defaultMode } set { userDefaults.set(newValue.rawValue, forKey: "mode") } } } diff --git a/BoostRemote/SettingsViewController.swift b/BoostRemote/SettingsViewController.swift new file mode 100644 index 0000000..d188289 --- /dev/null +++ b/BoostRemote/SettingsViewController.swift @@ -0,0 +1,68 @@ +// +// SettingsViewController.swift +// BoostRemote +// +// Created by Shinichiro Oba on 2018/01/30. +// Copyright © 2018 bricklife.com. All rights reserved. +// + +import UIKit +import ReSwift + +class SettingsViewController: UITableViewController { + + @IBOutlet private weak var joystickModeCell: UITableViewCell! + @IBOutlet private weak var twinsticksModeCell: UITableViewCell! + @IBOutlet private weak var stepStepper: UIStepper! + @IBOutlet private weak var stepLabel: UILabel! + + private var settingsState: SettingsState! + + override func viewDidLoad() { + super.viewDidLoad() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + StoreCenter.store.subscribe(self) + } + + override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + StoreCenter.store.unsubscribe(self) + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + switch indexPath.row { + case 0: + StoreCenter.store.dispatch(SettingsAction.selectMode(.joystick)) + case 1: + StoreCenter.store.dispatch(SettingsAction.selectMode(.twinsticks)) + default: + break + } + tableView.deselectRow(at: indexPath, animated: true) + } + + @IBAction func tappedStepper(_ sender: Any) { + if stepStepper.value > settingsState.step { + StoreCenter.store.dispatch(SettingsAction.incrementStep) + } else if stepStepper.value < settingsState.step { + StoreCenter.store.dispatch(SettingsAction.decrementStep) + } + } +} + +extension SettingsViewController: StoreSubscriber { + + func newState(state: State) { + let settings = state.settingsState + + joystickModeCell.accessoryType = (settings.mode == .joystick) ? .checkmark : .none + twinsticksModeCell.accessoryType = (settings.mode == .twinsticks) ? .checkmark : .none + stepStepper.value = settings.step + stepLabel.text = "\(settings.step)" + + settingsState = settings + } +} diff --git a/BoostRemote/State.swift b/BoostRemote/State.swift index b1da1e7..7443cc2 100644 --- a/BoostRemote/State.swift +++ b/BoostRemote/State.swift @@ -14,6 +14,7 @@ struct State: StateType { var connectionState: ConnectionState var portState: PortState + var settingsState: SettingsState } enum ConnectionState { @@ -26,3 +27,9 @@ enum ConnectionState { } typealias PortState = [BoostBLEKit.Port: DeviceType] + +struct SettingsState { + + var mode: Settings.Mode + var step: Settings.Step +} diff --git a/BoostRemote/Store.swift b/BoostRemote/Store.swift index 03cf8b2..a0793fa 100644 --- a/BoostRemote/Store.swift +++ b/BoostRemote/Store.swift @@ -11,5 +11,10 @@ import ReSwift struct StoreCenter { - static let store = Store(reducer: Reducer.appReducer, state: nil) + static let store: Store = { + let initialState = State(connectionState: .disconnected, + portState: [:], + settingsState: SettingsState(mode: Settings.mode, step: Settings.step)) + return Store(reducer: Reducer.appReducer, state: nil) + }() } From 946c2b530f2170cc8df60ddee7c21574f4a0cf73 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Tue, 30 Jan 2018 01:33:03 +0000 Subject: [PATCH 27/43] Rename --- BoostRemote.xcodeproj/project.pbxproj | 8 ++++---- BoostRemote/Base.lproj/Main.storyboard | 4 ++-- ...iewController.swift => TwinSticksViewController.swift} | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) rename BoostRemote/{FourSticksViewController.swift => TwinSticksViewController.swift} (94%) diff --git a/BoostRemote.xcodeproj/project.pbxproj b/BoostRemote.xcodeproj/project.pbxproj index 2010118..e012993 100644 --- a/BoostRemote.xcodeproj/project.pbxproj +++ b/BoostRemote.xcodeproj/project.pbxproj @@ -17,7 +17,7 @@ CB3BE8BB1F2FF2F4000561F7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = CB3BE8B91F2FF2F4000561F7 /* LaunchScreen.storyboard */; }; CB4345A8200FC0D200D82D7D /* BoostBLEKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CB4345A7200FC0D100D82D7D /* BoostBLEKit.framework */; }; CB44B8531F73C11400D0D250 /* Store.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB44B8521F73C11400D0D250 /* Store.swift */; }; - CB547EBB201A62A400B00D8C /* FourSticksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB547EBA201A62A400B00D8C /* FourSticksViewController.swift */; }; + CB547EBB201A62A400B00D8C /* TwinSticksViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB547EBA201A62A400B00D8C /* TwinSticksViewController.swift */; }; CB547EBD201B5C3D00B00D8C /* JoystickViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB547EBC201B5C3D00B00D8C /* JoystickViewController.swift */; }; CB5891F1200D2C8700E15F92 /* Localizable.strings in Resources */ = {isa = PBXBuildFile; fileRef = CB5891F3200D2C8700E15F92 /* Localizable.strings */; }; CB5891F9200D2DF300E15F92 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = CB5891FB200D2DF300E15F92 /* InfoPlist.strings */; }; @@ -64,7 +64,7 @@ CB3BE8BC1F2FF2F4000561F7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; CB4345A7200FC0D100D82D7D /* BoostBLEKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = BoostBLEKit.framework; path = Carthage/Build/iOS/BoostBLEKit.framework; sourceTree = ""; }; CB44B8521F73C11400D0D250 /* Store.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Store.swift; sourceTree = ""; }; - CB547EBA201A62A400B00D8C /* FourSticksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FourSticksViewController.swift; sourceTree = ""; }; + CB547EBA201A62A400B00D8C /* TwinSticksViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TwinSticksViewController.swift; sourceTree = ""; }; CB547EBC201B5C3D00B00D8C /* JoystickViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoystickViewController.swift; sourceTree = ""; }; CB5891F4200D2CEA00E15F92 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Localizable.strings; sourceTree = ""; }; CB5891FA200D2DF300E15F92 /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/InfoPlist.strings; sourceTree = ""; }; @@ -126,7 +126,7 @@ CB8C7EB3201FEF6500274A09 /* SettingsViewController.swift */, CB3BE8B21F2FF2F4000561F7 /* ControllerViewController.swift */, CBC72DF9201AC35C00ABE096 /* Controller.swift */, - CB547EBA201A62A400B00D8C /* FourSticksViewController.swift */, + CB547EBA201A62A400B00D8C /* TwinSticksViewController.swift */, CB547EBC201B5C3D00B00D8C /* JoystickViewController.swift */, CB0BF7E41F8BD873004CCD4F /* VerticalSlider.swift */, CB0BF7E61F8BDD30004CCD4F /* StickView.swift */, @@ -285,7 +285,7 @@ CB84A384201BADEC00C02CD8 /* Settings.swift in Sources */, CB547EBD201B5C3D00B00D8C /* JoystickViewController.swift in Sources */, CBD94E861F391D7F0037ED71 /* Action.swift in Sources */, - CB547EBB201A62A400B00D8C /* FourSticksViewController.swift in Sources */, + CB547EBB201A62A400B00D8C /* TwinSticksViewController.swift in Sources */, CB3BE8B11F2FF2F4000561F7 /* AppDelegate.swift in Sources */, CB70D813201A82D500EAB1D6 /* FeedbackGenerator.swift in Sources */, CBF9D2F61F3CDAC700B97E11 /* Data+HexString.swift in Sources */, diff --git a/BoostRemote/Base.lproj/Main.storyboard b/BoostRemote/Base.lproj/Main.storyboard index 1cc74da..891ee24 100644 --- a/BoostRemote/Base.lproj/Main.storyboard +++ b/BoostRemote/Base.lproj/Main.storyboard @@ -257,10 +257,10 @@ - + - + diff --git a/BoostRemote/FourSticksViewController.swift b/BoostRemote/TwinSticksViewController.swift similarity index 94% rename from BoostRemote/FourSticksViewController.swift rename to BoostRemote/TwinSticksViewController.swift index c815000..321b484 100644 --- a/BoostRemote/FourSticksViewController.swift +++ b/BoostRemote/TwinSticksViewController.swift @@ -1,5 +1,5 @@ // -// FourSticksViewController.swift +// TwinSticksViewController.swift // BoostRemote // // Created by ooba on 25/01/2018. @@ -11,7 +11,7 @@ import ReactiveSwift import Result import BoostBLEKit -class FourSticksViewController: UIViewController, Controller { +class TwinSticksViewController: UIViewController, Controller { let mode = Settings.Mode.twinsticks From a56339739496b7034bf1db69f34039b71ce2f52b Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Tue, 30 Jan 2018 01:35:43 +0000 Subject: [PATCH 28/43] Fix --- BoostRemote/Base.lproj/Main.storyboard | 2 ++ BoostRemote/ControllerViewController.swift | 11 +++++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/BoostRemote/Base.lproj/Main.storyboard b/BoostRemote/Base.lproj/Main.storyboard index 891ee24..0f869e6 100644 --- a/BoostRemote/Base.lproj/Main.storyboard +++ b/BoostRemote/Base.lproj/Main.storyboard @@ -130,6 +130,8 @@ + + diff --git a/BoostRemote/ControllerViewController.swift b/BoostRemote/ControllerViewController.swift index f885d65..4ded1b4 100644 --- a/BoostRemote/ControllerViewController.swift +++ b/BoostRemote/ControllerViewController.swift @@ -14,9 +14,11 @@ import BoostBLEKit class ControllerViewController: UIViewController { @IBOutlet private weak var connectButtonImageView: UIImageView! - - private var controllers: [Controller & UIViewController] { - return childViewControllers.flatMap { $0 as? (Controller & UIViewController) } + @IBOutlet private weak var joystickView: UIView! + @IBOutlet private weak var twinSticksView: UIView! + + private var controllers: [Controller] { + return childViewControllers.flatMap { $0 as? Controller } } private let connectionState = MutableProperty(ConnectionState.disconnected) @@ -124,7 +126,8 @@ extension ControllerViewController: StoreSubscriber { } } - controllers.forEach { $0.view.isHidden = ($0.mode != state.settingsState.mode) } + joystickView.isHidden = state.settingsState.mode != .joystick + twinSticksView.isHidden = state.settingsState.mode != .twinsticks step.value = state.settingsState.step } } From 4214af596cc247f949268b9a10318005fe12e8cc Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Wed, 31 Jan 2018 00:24:41 +0000 Subject: [PATCH 29/43] Refactoring --- BoostRemote.xcodeproj/project.pbxproj | 4 --- BoostRemote/Action.swift | 2 +- BoostRemote/Controller.swift | 2 -- BoostRemote/ControllerViewController.swift | 13 +++++--- BoostRemote/JoystickViewController.swift | 2 -- BoostRemote/Reducer.swift | 6 +--- BoostRemote/Settings.swift | 37 ---------------------- BoostRemote/SettingsViewController.swift | 2 +- BoostRemote/State.swift | 16 ++++++++-- BoostRemote/Store.swift | 37 +++++++++++++++++++--- BoostRemote/TwinSticksViewController.swift | 2 -- 11 files changed, 58 insertions(+), 65 deletions(-) delete mode 100644 BoostRemote/Settings.swift diff --git a/BoostRemote.xcodeproj/project.pbxproj b/BoostRemote.xcodeproj/project.pbxproj index e012993..ea7a2da 100644 --- a/BoostRemote.xcodeproj/project.pbxproj +++ b/BoostRemote.xcodeproj/project.pbxproj @@ -24,7 +24,6 @@ CB70D813201A82D500EAB1D6 /* FeedbackGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB70D812201A82D500EAB1D6 /* FeedbackGenerator.swift */; }; CB7390C9201AB89900EAE3A7 /* UIImage+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB7390C8201AB89900EAE3A7 /* UIImage+Extension.swift */; }; CB84A382201BA3D300C02CD8 /* JoystickView.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB84A381201BA3D300C02CD8 /* JoystickView.swift */; }; - CB84A384201BADEC00C02CD8 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB84A383201BADEC00C02CD8 /* Settings.swift */; }; CB8C7EB4201FEF6500274A09 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB8C7EB3201FEF6500274A09 /* SettingsViewController.swift */; }; CBA46E781F882F0C0017E5C2 /* ReactiveSwift.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */; }; CBA46E7A1F882F0F0017E5C2 /* Result.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = CBA46E791F882F0F0017E5C2 /* Result.framework */; }; @@ -71,7 +70,6 @@ CB70D812201A82D500EAB1D6 /* FeedbackGenerator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FeedbackGenerator.swift; sourceTree = ""; }; CB7390C8201AB89900EAE3A7 /* UIImage+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+Extension.swift"; sourceTree = ""; }; CB84A381201BA3D300C02CD8 /* JoystickView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = JoystickView.swift; sourceTree = ""; }; - CB84A383201BADEC00C02CD8 /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = ""; }; CB8C7EB3201FEF6500274A09 /* SettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; CBA46E771F882F0C0017E5C2 /* ReactiveSwift.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ReactiveSwift.framework; path = Carthage/Build/iOS/ReactiveSwift.framework; sourceTree = ""; }; CBA46E791F882F0F0017E5C2 /* Result.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Result.framework; path = Carthage/Build/iOS/Result.framework; sourceTree = ""; }; @@ -122,7 +120,6 @@ children = ( CB3BE8B01F2FF2F4000561F7 /* AppDelegate.swift */, CB3BE8B41F2FF2F4000561F7 /* Main.storyboard */, - CB84A383201BADEC00C02CD8 /* Settings.swift */, CB8C7EB3201FEF6500274A09 /* SettingsViewController.swift */, CB3BE8B21F2FF2F4000561F7 /* ControllerViewController.swift */, CBC72DF9201AC35C00ABE096 /* Controller.swift */, @@ -282,7 +279,6 @@ CB0BF7E51F8BD873004CCD4F /* VerticalSlider.swift in Sources */, CB8C7EB4201FEF6500274A09 /* SettingsViewController.swift in Sources */, CB0BF7E71F8BDD30004CCD4F /* StickView.swift in Sources */, - CB84A384201BADEC00C02CD8 /* Settings.swift in Sources */, CB547EBD201B5C3D00B00D8C /* JoystickViewController.swift in Sources */, CBD94E861F391D7F0037ED71 /* Action.swift in Sources */, CB547EBB201A62A400B00D8C /* TwinSticksViewController.swift in Sources */, diff --git a/BoostRemote/Action.swift b/BoostRemote/Action.swift index 0177f70..d096cfb 100644 --- a/BoostRemote/Action.swift +++ b/BoostRemote/Action.swift @@ -28,7 +28,7 @@ enum SettingsAction: Action { case incrementStep case decrementStep - case selectMode(Settings.Mode) + case selectMode(SettingsState.Mode) } struct ActionCenter { diff --git a/BoostRemote/Controller.swift b/BoostRemote/Controller.swift index 1c3cd8a..3e9b2c3 100644 --- a/BoostRemote/Controller.swift +++ b/BoostRemote/Controller.swift @@ -13,8 +13,6 @@ import BoostBLEKit protocol Controller { - var mode: Settings.Mode { get } - var signals: [BoostBLEKit.Port: Signal] { get } func setEnable(_ enable: Bool, port: BoostBLEKit.Port) diff --git a/BoostRemote/ControllerViewController.swift b/BoostRemote/ControllerViewController.swift index 4ded1b4..02dd077 100644 --- a/BoostRemote/ControllerViewController.swift +++ b/BoostRemote/ControllerViewController.swift @@ -22,7 +22,7 @@ class ControllerViewController: UIViewController { } private let connectionState = MutableProperty(ConnectionState.disconnected) - private let step = MutableProperty(Settings.defaultStep) + private let settingsState = MutableProperty(SettingsState()) private var motors: [BoostBLEKit.Port: Motor] = [:] { didSet { @@ -69,7 +69,7 @@ class ControllerViewController: UIViewController { controllers.forEach { $0.signals.forEach { (port, signal) in signal - .withLatest(from: step.signal) + .withLatest(from: settingsState.signal.map { $0.step }) .map { (value, step) in Int8(round(value * step) * 100 / step) } .skipRepeats() .observeValues { [weak self] (value) in @@ -77,6 +77,11 @@ class ControllerViewController: UIViewController { } } } + + settingsState.signal.observeValues { [weak self] (state) in + self?.joystickView.isHidden = state.mode != .joystick + self?.twinSticksView.isHidden = state.mode != .twinsticks + } } private func sendCommand(port: BoostBLEKit.Port, power: Int8) { @@ -126,8 +131,6 @@ extension ControllerViewController: StoreSubscriber { } } - joystickView.isHidden = state.settingsState.mode != .joystick - twinSticksView.isHidden = state.settingsState.mode != .twinsticks - step.value = state.settingsState.step + settingsState.value = state.settingsState } } diff --git a/BoostRemote/JoystickViewController.swift b/BoostRemote/JoystickViewController.swift index 25a256a..2af8bbf 100644 --- a/BoostRemote/JoystickViewController.swift +++ b/BoostRemote/JoystickViewController.swift @@ -13,8 +13,6 @@ import BoostBLEKit class JoystickViewController: UIViewController, Controller { - let mode = Settings.Mode.joystick - @IBOutlet private weak var joystickView: JoystickView! @IBOutlet private weak var stickC: StickView! @IBOutlet private weak var stickD: StickView! diff --git a/BoostRemote/Reducer.swift b/BoostRemote/Reducer.swift index 9101165..791ccc2 100644 --- a/BoostRemote/Reducer.swift +++ b/BoostRemote/Reducer.swift @@ -54,7 +54,7 @@ struct Reducer { } static func settingsReducer(state: SettingsState?, action: Action) -> SettingsState { - var state = state ?? SettingsState(mode: Settings.defaultMode, step: Settings.defaultStep) + var state = state ?? SettingsState() guard let action = action as? SettingsAction else { return state } @@ -71,10 +71,6 @@ struct Reducer { state.mode = mode } - // ToDo: Avoid side-effect - Settings.mode = state.mode - Settings.step = state.step - return state } } diff --git a/BoostRemote/Settings.swift b/BoostRemote/Settings.swift deleted file mode 100644 index 66dbb37..0000000 --- a/BoostRemote/Settings.swift +++ /dev/null @@ -1,37 +0,0 @@ -// -// Settings.swift -// BoostRemote -// -// Created by ooba on 26/01/2018. -// Copyright © 2018 bricklife.com. All rights reserved. -// - -import Foundation - -final class Settings { - - typealias Step = Double - - static let defaultMode: Mode = .joystick - static let defaultStep: Step = 5 - - private static var userDefaults: UserDefaults = { - UserDefaults.standard.register(defaults: ["step": Double(defaultStep)]) - return UserDefaults.standard - }() - - static var step: Step { - get { return userDefaults.double(forKey: "step") } - set { userDefaults.set(newValue, forKey: "step") } - } - - enum Mode: String { - case joystick = "joystick" - case twinsticks = "twinsticks" - } - - static var mode: Mode { - get { return userDefaults.string(forKey: "mode").flatMap(Mode.init(rawValue:)) ?? defaultMode } - set { userDefaults.set(newValue.rawValue, forKey: "mode") } - } -} diff --git a/BoostRemote/SettingsViewController.swift b/BoostRemote/SettingsViewController.swift index d188289..26982ba 100644 --- a/BoostRemote/SettingsViewController.swift +++ b/BoostRemote/SettingsViewController.swift @@ -61,7 +61,7 @@ extension SettingsViewController: StoreSubscriber { joystickModeCell.accessoryType = (settings.mode == .joystick) ? .checkmark : .none twinsticksModeCell.accessoryType = (settings.mode == .twinsticks) ? .checkmark : .none stepStepper.value = settings.step - stepLabel.text = "\(settings.step)" + stepLabel.text = "\(Int(settings.step))" settingsState = settings } diff --git a/BoostRemote/State.swift b/BoostRemote/State.swift index 7443cc2..2774b43 100644 --- a/BoostRemote/State.swift +++ b/BoostRemote/State.swift @@ -30,6 +30,18 @@ typealias PortState = [BoostBLEKit.Port: DeviceType] struct SettingsState { - var mode: Settings.Mode - var step: Settings.Step + enum Mode: String { + case joystick = "joystick" + case twinsticks = "twinsticks" + } + + typealias Step = Double + + var mode: Mode + var step: Step + + init(mode: Mode = .joystick, step: Step = 5) { + self.mode = mode + self.step = step + } } diff --git a/BoostRemote/Store.swift b/BoostRemote/Store.swift index a0793fa..4efc2da 100644 --- a/BoostRemote/Store.swift +++ b/BoostRemote/Store.swift @@ -12,9 +12,38 @@ import ReSwift struct StoreCenter { static let store: Store = { - let initialState = State(connectionState: .disconnected, - portState: [:], - settingsState: SettingsState(mode: Settings.mode, step: Settings.step)) - return Store(reducer: Reducer.appReducer, state: nil) + let state = PersistentManager.shared.load() + let store = Store(reducer: Reducer.appReducer, state: state) + store.subscribe(PersistentManager.shared) + + return store }() + + final class PersistentManager: StoreSubscriber { + + static let shared = PersistentManager() + + func newState(state: State) { + save(state: state) + } + + func load() -> State { + var settingsState = SettingsState() + if let step = UserDefaults.standard.object(forKey: "step") as? SettingsState.Step { + settingsState.step = step + } + if let rawValue = UserDefaults.standard.string(forKey: "mode"), let mode = SettingsState.Mode(rawValue: rawValue) { + settingsState.mode = mode + } + + return State(connectionState: .disconnected, + portState: [:], + settingsState: settingsState) + } + + func save(state: State) { + UserDefaults.standard.set(state.settingsState.step, forKey: "step") + UserDefaults.standard.set(state.settingsState.mode.rawValue, forKey: "mode") + } + } } diff --git a/BoostRemote/TwinSticksViewController.swift b/BoostRemote/TwinSticksViewController.swift index 321b484..f0d4078 100644 --- a/BoostRemote/TwinSticksViewController.swift +++ b/BoostRemote/TwinSticksViewController.swift @@ -13,8 +13,6 @@ import BoostBLEKit class TwinSticksViewController: UIViewController, Controller { - let mode = Settings.Mode.twinsticks - @IBOutlet private weak var stickA: StickView! @IBOutlet private weak var stickB: StickView! @IBOutlet private weak var stickC: StickView! From 7afe4ee756a5cc50119ce05ed7a6e53ba8895099 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Wed, 31 Jan 2018 00:35:23 +0000 Subject: [PATCH 30/43] Refactoring --- BoostRemote/Action.swift | 5 ++--- BoostRemote/Reducer.swift | 15 ++++++++------- BoostRemote/SettingsViewController.swift | 10 +++------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/BoostRemote/Action.swift b/BoostRemote/Action.swift index d096cfb..2a4114d 100644 --- a/BoostRemote/Action.swift +++ b/BoostRemote/Action.swift @@ -26,9 +26,8 @@ struct NotificationAction: Action { enum SettingsAction: Action { - case incrementStep - case decrementStep - case selectMode(SettingsState.Mode) + case step(SettingsState.Step) + case mode(SettingsState.Mode) } struct ActionCenter { diff --git a/BoostRemote/Reducer.swift b/BoostRemote/Reducer.swift index 791ccc2..ea4612c 100644 --- a/BoostRemote/Reducer.swift +++ b/BoostRemote/Reducer.swift @@ -59,15 +59,16 @@ struct Reducer { guard let action = action as? SettingsAction else { return state } switch action { - case .incrementStep: - if state.step < 100 { - state.step += 1 + case .step(let step): + state.step = step + if state.step < 1 { + state.step = 1 } - case .decrementStep: - if state.step > 1 { - state.step -= 1 + if state.step > 100 { + state.step = 100 } - case .selectMode(let mode): + + case .mode(let mode): state.mode = mode } diff --git a/BoostRemote/SettingsViewController.swift b/BoostRemote/SettingsViewController.swift index 26982ba..6dc0d91 100644 --- a/BoostRemote/SettingsViewController.swift +++ b/BoostRemote/SettingsViewController.swift @@ -35,9 +35,9 @@ class SettingsViewController: UITableViewController { override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { switch indexPath.row { case 0: - StoreCenter.store.dispatch(SettingsAction.selectMode(.joystick)) + StoreCenter.store.dispatch(SettingsAction.mode(.joystick)) case 1: - StoreCenter.store.dispatch(SettingsAction.selectMode(.twinsticks)) + StoreCenter.store.dispatch(SettingsAction.mode(.twinsticks)) default: break } @@ -45,11 +45,7 @@ class SettingsViewController: UITableViewController { } @IBAction func tappedStepper(_ sender: Any) { - if stepStepper.value > settingsState.step { - StoreCenter.store.dispatch(SettingsAction.incrementStep) - } else if stepStepper.value < settingsState.step { - StoreCenter.store.dispatch(SettingsAction.decrementStep) - } + StoreCenter.store.dispatch(SettingsAction.step(stepStepper.value)) } } From 6f309077552be4a54d5d4354d55812aa9d7c9e2d Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Wed, 31 Jan 2018 00:44:35 +0000 Subject: [PATCH 31/43] Refactoring --- BoostRemote/Reducer.swift | 7 ------- BoostRemote/State.swift | 17 +++++++++++++---- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/BoostRemote/Reducer.swift b/BoostRemote/Reducer.swift index ea4612c..9b4435c 100644 --- a/BoostRemote/Reducer.swift +++ b/BoostRemote/Reducer.swift @@ -61,13 +61,6 @@ struct Reducer { switch action { case .step(let step): state.step = step - if state.step < 1 { - state.step = 1 - } - if state.step > 100 { - state.step = 100 - } - case .mode(let mode): state.mode = mode } diff --git a/BoostRemote/State.swift b/BoostRemote/State.swift index 2774b43..34e71b8 100644 --- a/BoostRemote/State.swift +++ b/BoostRemote/State.swift @@ -38,10 +38,19 @@ struct SettingsState { typealias Step = Double var mode: Mode - var step: Step + var step: Step { + didSet { + if step < 1 { + step = 1 + } + if step > 100 { + step = 100 + } + } + } - init(mode: Mode = .joystick, step: Step = 5) { - self.mode = mode - self.step = step + init() { + self.mode = .joystick + self.step = 5 } } From 665f72909c79a3a0e31888bdad6cb79cb4ac95ae Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Tue, 17 Apr 2018 17:52:16 +0100 Subject: [PATCH 32/43] Use Xcode 9.3 --- BoostRemote.xcodeproj/project.pbxproj | 8 +++++--- .../xcshareddata/IDEWorkspaceChecks.plist | 8 ++++++++ BoostRemote/ControllerViewController.swift | 2 +- BoostRemote/Data+HexString.swift | 2 +- BoostRemote/UIImage+Extension.swift | 2 +- 5 files changed, 16 insertions(+), 6 deletions(-) create mode 100644 BoostRemote.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist diff --git a/BoostRemote.xcodeproj/project.pbxproj b/BoostRemote.xcodeproj/project.pbxproj index ea7a2da..8d62a25 100644 --- a/BoostRemote.xcodeproj/project.pbxproj +++ b/BoostRemote.xcodeproj/project.pbxproj @@ -195,7 +195,7 @@ isa = PBXProject; attributes = { LastSwiftUpdateCheck = 0830; - LastUpgradeCheck = 0900; + LastUpgradeCheck = 0930; ORGANIZATIONNAME = bricklife.com; TargetAttributes = { CB3BE8AC1F2FF2F4000561F7 = { @@ -250,14 +250,12 @@ inputPaths = ( "$(SRCROOT)/Carthage/Build/iOS/Result.framework", "$(SRCROOT)/Carthage/Build/iOS/ReactiveSwift.framework", - "$(SRCROOT)/Carthage/Build/iOS/ReactiveCocoa.framework", "$(SRCROOT)/Carthage/Build/iOS/ReSwift.framework", "$(SRCROOT)/Carthage/Build/iOS/BoostBLEKit.framework", ); outputPaths = ( "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/Result.framework", "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/ReactiveSwift.framework", - "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/ReactiveCocoa.framework", "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/ReSwift.framework", "$(BUILT_PRODUCTS_DIR)/$(FRAMEWORKS_FOLDER_PATH)/BoostBLEKit.framework", ); @@ -346,6 +344,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -353,6 +352,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; @@ -404,6 +404,7 @@ CLANG_WARN_BOOL_CONVERSION = YES; CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_DOCUMENTATION_COMMENTS = YES; CLANG_WARN_EMPTY_BODY = YES; @@ -411,6 +412,7 @@ CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; diff --git a/BoostRemote.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/BoostRemote.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/BoostRemote.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/BoostRemote/ControllerViewController.swift b/BoostRemote/ControllerViewController.swift index 02dd077..16b30aa 100644 --- a/BoostRemote/ControllerViewController.swift +++ b/BoostRemote/ControllerViewController.swift @@ -18,7 +18,7 @@ class ControllerViewController: UIViewController { @IBOutlet private weak var twinSticksView: UIView! private var controllers: [Controller] { - return childViewControllers.flatMap { $0 as? Controller } + return childViewControllers.compactMap { $0 as? Controller } } private let connectionState = MutableProperty(ConnectionState.disconnected) diff --git a/BoostRemote/Data+HexString.swift b/BoostRemote/Data+HexString.swift index b3bef1f..2709073 100644 --- a/BoostRemote/Data+HexString.swift +++ b/BoostRemote/Data+HexString.swift @@ -19,7 +19,7 @@ extension Data { let even = hexString.enumerated().filter { $0.offset % 2 == 0 }.map { $0.element } let odd = hexString.enumerated().filter { $0.offset % 2 == 1 }.map { $0.element } - let bytes = zip(even, odd).flatMap { UInt8(String([$0.0, $0.1]), radix: 16) } + let bytes = zip(even, odd).compactMap { UInt8(String([$0.0, $0.1]), radix: 16) } self.init(bytes: bytes) } diff --git a/BoostRemote/UIImage+Extension.swift b/BoostRemote/UIImage+Extension.swift index 82f7815..527f1ec 100644 --- a/BoostRemote/UIImage+Extension.swift +++ b/BoostRemote/UIImage+Extension.swift @@ -31,6 +31,6 @@ extension UIImage { } static func connectingImages() -> [UIImage] { - return (1...4).map { "connecting\($0)" }.flatMap(UIImage.init(named:)) + return (1...4).map { "connecting\($0)" }.compactMap(UIImage.init(named:)) } } From a97e4fadbc7531b55cf6ba6959a7a9ee044444fc Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Tue, 17 Apr 2018 17:53:28 +0100 Subject: [PATCH 33/43] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7adc0ab..a95e39b 100644 --- a/README.md +++ b/README.md @@ -13,8 +13,8 @@ Remote Control iOS app for LEGO® Boost - LEGO® Boost Move Hub ## Development Environment -- Xcode 9 -- Swift 4 +- Xcode 9.3 +- Swift 4.1 ## App Store https://itunes.apple.com/us/app/boost-remote/id1270503610?ls=1&mt=8 From d48b606cc74e346f10260be460595156f7c51a80 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Tue, 17 Apr 2018 18:03:18 +0100 Subject: [PATCH 34/43] Update .storyboard --- BoostRemote/Base.lproj/LaunchScreen.storyboard | 10 +++++++--- BoostRemote/Base.lproj/Main.storyboard | 4 ++-- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/BoostRemote/Base.lproj/LaunchScreen.storyboard b/BoostRemote/Base.lproj/LaunchScreen.storyboard index fdf3f97..fff6a9a 100644 --- a/BoostRemote/Base.lproj/LaunchScreen.storyboard +++ b/BoostRemote/Base.lproj/LaunchScreen.storyboard @@ -1,7 +1,11 @@ - - + + + + + - + + diff --git a/BoostRemote/Base.lproj/Main.storyboard b/BoostRemote/Base.lproj/Main.storyboard index 0f869e6..1c31942 100644 --- a/BoostRemote/Base.lproj/Main.storyboard +++ b/BoostRemote/Base.lproj/Main.storyboard @@ -1,11 +1,11 @@ - + - + From 8fc866f8f11f013d397e60220cd3b62d9edc0982 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Fri, 20 Apr 2018 12:33:47 +0100 Subject: [PATCH 35/43] Move Haptic Feedback into UI views --- BoostRemote/ControllerViewController.swift | 4 ---- BoostRemote/JoystickView.swift | 18 +++++++++++++++++- BoostRemote/VerticalSlider.swift | 13 ++++++++++++- 3 files changed, 29 insertions(+), 6 deletions(-) diff --git a/BoostRemote/ControllerViewController.swift b/BoostRemote/ControllerViewController.swift index 16b30aa..13d3a6e 100644 --- a/BoostRemote/ControllerViewController.swift +++ b/BoostRemote/ControllerViewController.swift @@ -85,10 +85,6 @@ class ControllerViewController: UIViewController { } private func sendCommand(port: BoostBLEKit.Port, power: Int8) { - if power == 100 || power == -100 { - FeedbackGenerator.feedback() - } - if let command = motors[port]?.powerCommand(power: power) { ActionCenter.send(command: command) } diff --git a/BoostRemote/JoystickView.swift b/BoostRemote/JoystickView.swift index 90e3871..c139e01 100644 --- a/BoostRemote/JoystickView.swift +++ b/BoostRemote/JoystickView.swift @@ -10,6 +10,9 @@ import UIKit class JoystickView: UIView { + private(set) var x: Double = 0 + private(set) var y: Double = 0 + var update: ((Double, Double) -> Void)? private var thumbCenterXConstraint: NSLayoutConstraint! @@ -84,7 +87,20 @@ class JoystickView: UIView { thumbCenterXConstraint.constant = x * width thumbCenterYConstraint.constant = y * height - update?(Double(x), Double(y)) + let newX = Double(x) + let newY = Double(y) + + if (newX == 1 || newX == -1) && self.x != newX { + FeedbackGenerator.feedback() + } + if (newY == 1 || newY == -1) && self.y != newY { + FeedbackGenerator.feedback() + } + + self.x = newX + self.y = newY + + update?(newX, newY) } private func reset() { diff --git a/BoostRemote/VerticalSlider.swift b/BoostRemote/VerticalSlider.swift index db6b37d..fdd9b7f 100644 --- a/BoostRemote/VerticalSlider.swift +++ b/BoostRemote/VerticalSlider.swift @@ -10,6 +10,8 @@ import UIKit class VerticalSlider: UIView { + private(set) var value: Double = 0 + var update: ((Double) -> Void)? private var thumbCenterYConstraint: NSLayoutConstraint! @@ -73,7 +75,16 @@ class VerticalSlider: UIView { } thumbCenterYConstraint.constant = base * value - update?(Double(value)) + + let newValue = Double(value) + + if (newValue == 1 || newValue == -1) && self.value != newValue { + FeedbackGenerator.feedback() + } + + self.value = newValue + + update?(newValue) } private func reset() { From 2c63d1525e51da65b01e9e093edb5553b4c60b42 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Fri, 20 Apr 2018 12:36:47 +0100 Subject: [PATCH 36/43] Use UIImpactFeedbackGenerator --- BoostRemote/FeedbackGenerator.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/BoostRemote/FeedbackGenerator.swift b/BoostRemote/FeedbackGenerator.swift index 7a96c27..471862e 100644 --- a/BoostRemote/FeedbackGenerator.swift +++ b/BoostRemote/FeedbackGenerator.swift @@ -12,7 +12,7 @@ final class FeedbackGenerator { private static let feedbackGenerator: Any? = { if #available(iOS 10.0, *) { - let generator = UISelectionFeedbackGenerator() + let generator = UIImpactFeedbackGenerator(style: .light) generator.prepare() return generator } else { @@ -22,7 +22,7 @@ final class FeedbackGenerator { static func feedback() { if #available(iOS 10.0, *) { - (feedbackGenerator as? UISelectionFeedbackGenerator)?.selectionChanged() + (feedbackGenerator as? UIImpactFeedbackGenerator)?.impactOccurred() } } } From 5bb864759d5e936bc4932d12f55c0600fdfff7e4 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Fri, 20 Apr 2018 13:26:42 +0100 Subject: [PATCH 37/43] Fix the controller sizes --- BoostRemote/Base.lproj/Main.storyboard | 144 ++++++++----------------- 1 file changed, 47 insertions(+), 97 deletions(-) diff --git a/BoostRemote/Base.lproj/Main.storyboard b/BoostRemote/Base.lproj/Main.storyboard index 1c31942..3025c70 100644 --- a/BoostRemote/Base.lproj/Main.storyboard +++ b/BoostRemote/Base.lproj/Main.storyboard @@ -8,7 +8,6 @@ - @@ -21,111 +20,62 @@ - - + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - - - - - + + + + + + + + + - - - - - - - - - - - - - @@ -136,7 +86,7 @@ - + @@ -257,7 +207,7 @@ - + @@ -319,7 +269,7 @@ - + @@ -396,12 +346,12 @@ - + - + @@ -414,7 +364,7 @@ - + From 00de6e6fa073632ecdfeddefae0e9ac0fa5d075d Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Fri, 20 Apr 2018 13:49:52 +0100 Subject: [PATCH 38/43] Add settings icon --- .../settings.imageset/Contents.json | 12 ++++++++++++ .../settings.imageset/settings.pdf | Bin 0 -> 4805 bytes BoostRemote/Base.lproj/Main.storyboard | 14 ++++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 BoostRemote/Assets.xcassets/settings.imageset/Contents.json create mode 100644 BoostRemote/Assets.xcassets/settings.imageset/settings.pdf diff --git a/BoostRemote/Assets.xcassets/settings.imageset/Contents.json b/BoostRemote/Assets.xcassets/settings.imageset/Contents.json new file mode 100644 index 0000000..228b81a --- /dev/null +++ b/BoostRemote/Assets.xcassets/settings.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "settings.pdf" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/BoostRemote/Assets.xcassets/settings.imageset/settings.pdf b/BoostRemote/Assets.xcassets/settings.imageset/settings.pdf new file mode 100644 index 0000000000000000000000000000000000000000..38dbbb5f9b64b584f6407f605319f382bd9b3955 GIT binary patch literal 4805 zcmai&2UHVV*M=d0KtMr7kfKB+6hTNx0z`TjDWOY;0HGHJq)L?{5TtkM9i%8INK<;1 zh%^xi9i)RI9r=P+|Lgtkzt%Tv*38K}`|O-^X0LZWbHHk{@;9M;Fd(>X{_Ffo;kT^! zZ5=>32m*34vjvKZg7}p&j#jSLAOu0u0P)M)*t=q!33q$6D@GP$?qq=hiHieWT%9p! z2cQRWS(1t)Gn86>_ZHbG*~}C8iCreBi;WzjpC_pSdY3c0amZ!Up~_-qPX|@DkyU4J z_p~%#!yA`PSEw8u?W3c1#$%6PS_*ySKWy@gc;#oBn0kNtQ<3^pat@~aS11=NnnMte zyE>~qB2iwXA(`VqHBM}t#A>OUPoLEjixq83E1g=Z5(^eq%5>;@!Wp|(zS05Jd+O$s zsjGU^+=rFdE%u8xxa?(bM%H~!vAm;udVSBlHvuA5+m#|pPRIzve*7-o$+;bi?(5$7 zksBet$zJeYe=T&F(=KgTd$pY+x}q?qQ4V1(sz|eR{(9;1i_q4&?D1Ban!C8z>nj;q z&)E{S+E6=tDm6VXxt_<~k{4Jjc)fA^V?%_>Xq4y{DZ9G}#HFSxcI3mr)s76^JWhJO zcT;Y7nVVB?bqb~rfc;lnVoVH* ztT>0v?@od1t}zAg^D%wt%QeW^x{b=2HqwHVxz%u{*Bmsa^(;6z8mDYiVW}3Gvot$Y ze7_sg7{2Zke(^HqzONWh_0*h5M{`;vcKpNl;Il@Piti7?kW@%c+wqcVZz%hf%*#UM zBs$xv;pF)JYf7xuaO>yAYYgvzoRqE&x&Wh%rzF9B+uD_#YP6C? zu8L*u)Yn27r5$C=JH|1Ejg&h$2H0wwPUGjmD=g}26M+y~?C>X+o-QdA9cRufZ*3DX zbaO#YLb0yu{mv(^x~@C5Ml00j=663Sh>k1fS?d!G8r_pI$|}Z&Z>(Ar<^M>fM=TMwBpu`dk=@Dj(AjRQ0u_lz;A z)gnNEiuXJjA+QX5ve%36&4b@d$`yS;c$}tRfcJs>#<7I&G}(pRQUFGx+g&+{8Pfyzdf0&P!=RFLF zUkz>b^XiOobOpiwG9nF(i_-&VbBqf}@Gn8e$}xLUYVZguBACfABt-fYJ7iz4Fuk1@}dNN5V?JcR6R`5Ukwlv z#Nj4OCQo;sTgO7{EwMrB0>T##uofNKRjEPZhfWM@WRF3wq3wwTH7l8jGXwzunEbqpCJOu4GW6;axlyT;x((<83j&Ad$tp}1wx<# z^x2d-&)8<$D(rU(7kKKslan~+vYGVy85`gk*m^a5DtI~&4rVODVi0W zA5FHI|I%f7uvMkGZwBRwZ&jIo?4gX?uBLthVeqeTN|Yl8>p7%Y$E=mHtgY#dELiWq z8JoQ7t9dNe<#njN#j%RZkiur@P1>(M<8P!V+F{pEyHeGZpiNZma7J=|`Wb2iMD&%6 zs2czD+tm}qPTE{myfi4ySo zv3S5rWf<-_tt`c+xv)bWW#J6Y;bqL746<(qT!u#$_#gmY)3Yr8uzMtU5K)l- zZCa8<629928%fd^QsN(pfKt$p#BPsl?-30Jc)cf84HUe0#*p;x+q3tmsQncrfg#OG z5Mq3Q4MpH4?WG*4l4$xoniS~~T4sF;PZ=pSVLFm_nXqWuSjqkO97UIJJSxeSQ4`y~ z?#fh0Vf5%Ai~KzZe&(3iC+K`KU=V%wBhf4Wu}TpZ3Wb*5DOrz8PsthHj!)mIr58U} z)50*#yh+3xY|;`(A=yPiG9a%@!Mr6a9j(hweEynU3|k(cSS~gCTpsi5$lEdZ=Sa?k zW}}lY(|0h=hU#Ib&2-QsW_KXN$>zyA$_xvFmb9>d{lI*);pYXqoX;fOCS~Ph60X=a?%=_QEa{cO6%EajxCRd8+f{nK$>Qk zO|ysBnt*;Repe@>SUcWuMpNpO+6B^FO9Zjovun{ZQ7lp%2c2($s|OUJT-icsJ=+Y; zxSv1yDAl0I!l4>Rrx?P{pux_aQXQbBXv=2AA;!^oEw1~Pg@W^CJxOC!IeR9^1WXev zp%%}@L5I4-A}2kjioEk$(o@n?CST)hk>ikVNpfAfKB`gH=Z+7*LL4mVTheTISzKw1 zUBXI|Hy9N^n&h5j!k5Wua?S6~kAkCGfO@lJvt~eUrB1f|bajhZu%cXQPJ-EEvsAM% zvqv+Cc6D$=Y(Q+y1yr%*QsoD5{xv4)!FR^Gx$qJsM|PAf|gT4aR(I9JU@C^$ou88aIm@7p$-`K55`i*uUX;<6#0@ zf@K16LR5*ew$m`(aC(VD32F#p%VCSQ9kV?g<|~cF72@18aOo!SleweN<;uD+ui69K z@2$&X%W+JpOifITOxjFI@D2oHs$*(*>U`=VytCR`pXw#4{=EL;OJhhv%6gxcCAcaA znO#=CR(NwjJa3{@tjxTqO4lk^wW|N3Q7oTYqWN(MuVq??tHx2=Em(8FOA+;*IhCLF^q$F&WFcEcyB_9xrtR}kiACr}q|;B( zoA9pjYTjJoW!2->Bhz)LUamZ7{nVCfXJqcv8DcwYUe#YPvGB62_~xYBn>8PiRHMoX z`g+xR+|IcjwnL6XD7jduM`+`@-H)zrT=hXd!{=ANOxN~rVQ0xXy*Zx`Di%(r>-BT@ zpY6}3qGs4+7`l1cdEowZEsJvup9LS*#N%G}koI`Otp3VDpUPX3_52~b`jdqCRSOx#=_$jbl0gxzq69w2=r;}$GR ziJ&&Rbl`HCj~D)oW7V@(+r!txo%E)eoUBY+{q3l(4_yiok@QOR?(*FV?Q+8kDstX( zNpea_y1aT-bMjbyET}+?o|XBMH@lm2@$QESrO?^c8Q|b>egX)rpxlE(-p#@Wc<3eSbe z)b-d5uWMh-ksOFo=5o=qtWSROL;3q{EPERGksei*?F+n>0w%LZz3=?O_FU?mWAByj zZ{3H!2up-roT6>L^*&QZjWvD%J)WMm?s^> z@k8oa>Xl8V)>Rt|9n!C*)u$V8_8XkDZ@0f>zcyi6Rc1S$#AZD3-K=*edl#to%&;WY=zQ#o!cz74kbA!MQBJJeiHg+c^wW`NT2^Z6U>1i4=)7|&0bVu-3L>NQpt-G$`b=7kp z(#tE$@x1{_6~oXEfR()-jUT!!vF5Rm- zPMj@!(nRL7cwltMkKd{DnSXMU&P)<<=3t$#$@|3kv)Gak{&;}An8sM5&rA5&`q+GR zHir|4x{*;LQFc7MH)>hjxV@S+YKp6RY!ww!E5m=1uwQ{{CBqftc;u_)mletsaM*q9 zgxB-!_RU^w(%@|H8}1*kb`u6lGkx6;8?DT`+cxb6R#GJH;ES4&2O~QUixywz2HkBo z3JSyVrA-n$0ms>g=G&byORK0oR6=H?g!@Cvqpuzu4weg(yFuR${|(Tm6#5gI1)&1J zf%lYOPc;JMD$2-6qg^l-pi_X=02%!bIfdxoO#C-vyMXvrFcvmwX(tbm0fZ0&6Cj*F zA^8D;yrCd|B^wJD0z980Iw9L1fDAni|7S)Sv@6=)$?7kBclpKbe`7fm`l|<*3fdfm z(gf*(pb$PNj1LY{e}Hy&^#TzH{U_9WxN`p|@vw|HPq*tYojpM+fu8NzObtBsSR>?yMU%t;VcoGkwQ{r5;coH3R_2nY%T zLjLan2_g_M1jrKfOM}Cpgf%@qK#spPC{&0r$A4;Yh%n*x{8NKK1PIgmrv`;0{?!*M z@NW$cLHxTf3`!`Af98Wj2=DU0HK-t=EdDD_0Q&!Ef6l|z8Es>aasIhCq-o$pilbU%g(R literal 0 HcmV?d00001 diff --git a/BoostRemote/Base.lproj/Main.storyboard b/BoostRemote/Base.lproj/Main.storyboard index 3025c70..cd5fcaa 100644 --- a/BoostRemote/Base.lproj/Main.storyboard +++ b/BoostRemote/Base.lproj/Main.storyboard @@ -62,15 +62,28 @@ + + + @@ -369,6 +382,7 @@ + From 793a41a1dd5acfbc4b14cfb72bcd9a4f184a9346 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Fri, 20 Apr 2018 15:07:08 +0100 Subject: [PATCH 39/43] Add four options for motor power step --- BoostRemote/Base.lproj/Main.storyboard | 133 ++++++++++++++++------- BoostRemote/SettingsViewController.swift | 37 +++++-- 2 files changed, 119 insertions(+), 51 deletions(-) diff --git a/BoostRemote/Base.lproj/Main.storyboard b/BoostRemote/Base.lproj/Main.storyboard index cd5fcaa..b4d3c55 100644 --- a/BoostRemote/Base.lproj/Main.storyboard +++ b/BoostRemote/Base.lproj/Main.storyboard @@ -112,87 +112,138 @@ - + - - - - - - - + - - - - - - - + - + - + - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - @@ -212,8 +263,10 @@ - - + + + + diff --git a/BoostRemote/SettingsViewController.swift b/BoostRemote/SettingsViewController.swift index 6dc0d91..0ab421b 100644 --- a/BoostRemote/SettingsViewController.swift +++ b/BoostRemote/SettingsViewController.swift @@ -13,8 +13,11 @@ class SettingsViewController: UITableViewController { @IBOutlet private weak var joystickModeCell: UITableViewCell! @IBOutlet private weak var twinsticksModeCell: UITableViewCell! - @IBOutlet private weak var stepStepper: UIStepper! - @IBOutlet private weak var stepLabel: UILabel! + + @IBOutlet private weak var step1Cell: UITableViewCell! + @IBOutlet private weak var step2Cell: UITableViewCell! + @IBOutlet private weak var step5Cell: UITableViewCell! + @IBOutlet private weak var step10Cell: UITableViewCell! private var settingsState: SettingsState! @@ -33,20 +36,29 @@ class SettingsViewController: UITableViewController { } override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - switch indexPath.row { - case 0: + let cell = tableView.cellForRow(at: indexPath) + + switch cell { + case joystickModeCell: StoreCenter.store.dispatch(SettingsAction.mode(.joystick)) - case 1: + case twinsticksModeCell: StoreCenter.store.dispatch(SettingsAction.mode(.twinsticks)) + + case step1Cell: + StoreCenter.store.dispatch(SettingsAction.step(1)) + case step2Cell: + StoreCenter.store.dispatch(SettingsAction.step(2)) + case step5Cell: + StoreCenter.store.dispatch(SettingsAction.step(5)) + case step10Cell: + StoreCenter.store.dispatch(SettingsAction.step(10)) + default: break } + tableView.deselectRow(at: indexPath, animated: true) } - - @IBAction func tappedStepper(_ sender: Any) { - StoreCenter.store.dispatch(SettingsAction.step(stepStepper.value)) - } } extension SettingsViewController: StoreSubscriber { @@ -56,8 +68,11 @@ extension SettingsViewController: StoreSubscriber { joystickModeCell.accessoryType = (settings.mode == .joystick) ? .checkmark : .none twinsticksModeCell.accessoryType = (settings.mode == .twinsticks) ? .checkmark : .none - stepStepper.value = settings.step - stepLabel.text = "\(Int(settings.step))" + + step1Cell.accessoryType = (settings.step == 1) ? .checkmark : .none + step2Cell.accessoryType = (settings.step == 2) ? .checkmark : .none + step5Cell.accessoryType = (settings.step == 5) ? .checkmark : .none + step10Cell.accessoryType = (settings.step == 10) ? .checkmark : .none settingsState = settings } From 70126447a829bcdc84d4113487da2167e436dbf0 Mon Sep 17 00:00:00 2001 From: Shinichiro Oba Date: Fri, 20 Apr 2018 15:17:10 +0100 Subject: [PATCH 40/43] Update texts in Settings screen --- BoostRemote.xcodeproj/project.pbxproj | 2 ++ BoostRemote/Base.lproj/Main.storyboard | 8 +++--- BoostRemote/ja.lproj/Main.strings | 39 ++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 BoostRemote/ja.lproj/Main.strings diff --git a/BoostRemote.xcodeproj/project.pbxproj b/BoostRemote.xcodeproj/project.pbxproj index 8d62a25..fa22316 100644 --- a/BoostRemote.xcodeproj/project.pbxproj +++ b/BoostRemote.xcodeproj/project.pbxproj @@ -53,6 +53,7 @@ /* Begin PBXFileReference section */ CB0BF7E41F8BD873004CCD4F /* VerticalSlider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VerticalSlider.swift; sourceTree = ""; }; CB0BF7E61F8BDD30004CCD4F /* StickView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = StickView.swift; sourceTree = ""; }; + CB28BF14208A2C9700F5C15B /* ja */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ja; path = ja.lproj/Main.strings; sourceTree = ""; }; CB385A491F4E35210061EBE4 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = Settings.bundle; sourceTree = ""; }; CB3BE8AD1F2FF2F4000561F7 /* BoostRemote.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BoostRemote.app; sourceTree = BUILT_PRODUCTS_DIR; }; CB3BE8B01F2FF2F4000561F7 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; @@ -298,6 +299,7 @@ isa = PBXVariantGroup; children = ( CB3BE8B51F2FF2F4000561F7 /* Base */, + CB28BF14208A2C9700F5C15B /* ja */, ); name = Main.storyboard; sourceTree = ""; diff --git a/BoostRemote/Base.lproj/Main.storyboard b/BoostRemote/Base.lproj/Main.storyboard index b4d3c55..fb7fb1e 100644 --- a/BoostRemote/Base.lproj/Main.storyboard +++ b/BoostRemote/Base.lproj/Main.storyboard @@ -110,7 +110,7 @@ - + @@ -148,7 +148,7 @@ - + @@ -230,14 +230,14 @@