diff --git a/Delta.xcodeproj/project.pbxproj b/Delta.xcodeproj/project.pbxproj index 4e2fd38..d45313d 100644 --- a/Delta.xcodeproj/project.pbxproj +++ b/Delta.xcodeproj/project.pbxproj @@ -49,6 +49,7 @@ BF4828841F9027B600028B97 /* Delta.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = BF4828811F9027B600028B97 /* Delta.xcdatamodeld */; }; BF4828861F9028F500028B97 /* System.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF4828851F9028F500028B97 /* System.swift */; }; BF4828881F90290F00028B97 /* Action.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF4828871F90290F00028B97 /* Action.swift */; }; + BF48F74E219A16DA00BC2FC1 /* SyncingServicesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF48F74D219A16DA00BC2FC1 /* SyncingServicesViewController.swift */; }; BF525EE81FF5F370004AA849 /* DeepLinkController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF525EE71FF5F370004AA849 /* DeepLinkController.swift */; }; BF525EEA1FF6CD12004AA849 /* DeepLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF525EE91FF6CD12004AA849 /* DeepLink.swift */; }; BF5942641E09BBB10051894B /* LoadControllerSkinImageOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5942611E09BBB10051894B /* LoadControllerSkinImageOperation.swift */; }; @@ -180,6 +181,7 @@ BF4828831F9027B600028B97 /* Delta.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Delta.xcdatamodel; sourceTree = ""; }; BF4828851F9028F500028B97 /* System.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = System.swift; sourceTree = ""; }; BF4828871F90290F00028B97 /* Action.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Action.swift; sourceTree = ""; }; + BF48F74D219A16DA00BC2FC1 /* SyncingServicesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SyncingServicesViewController.swift; sourceTree = ""; }; BF525EE71FF5F370004AA849 /* DeepLinkController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLinkController.swift; sourceTree = ""; }; BF525EE91FF6CD12004AA849 /* DeepLink.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeepLink.swift; sourceTree = ""; }; BF5942611E09BBB10051894B /* LoadControllerSkinImageOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LoadControllerSkinImageOperation.swift; sourceTree = ""; }; @@ -345,6 +347,14 @@ path = "Game Selection"; sourceTree = ""; }; + BF48F74C219A16C100BC2FC1 /* Syncing */ = { + isa = PBXGroup; + children = ( + BF48F74D219A16DA00BC2FC1 /* SyncingServicesViewController.swift */, + ); + path = Syncing; + sourceTree = ""; + }; BF525EE61FF5F355004AA849 /* Deep Linking */ = { isa = PBXGroup; children = ( @@ -564,6 +574,7 @@ BF71CF851FE8FFF1001F1613 /* App Icon Shortcuts */, BF11734E1DA32CEC00047DF8 /* Controllers */, BF1DAD5B1D9F574900E752A7 /* Controller Skins */, + BF48F74C219A16C100BC2FC1 /* Syncing */, ); path = Settings; sourceTree = ""; @@ -893,6 +904,7 @@ BF5942801E09BC830051894B /* SaveState.swift in Sources */, BF59428E1E09BCFB0051894B /* ImportController.swift in Sources */, BF13A7581D5D2FD9000BB055 /* EmulatorCore+Cheats.swift in Sources */, + BF48F74E219A16DA00BC2FC1 /* SyncingServicesViewController.swift in Sources */, BF6424831F5B8F3F00D6AB44 /* ListMenuViewController.swift in Sources */, BF1020E31F95B05B00313182 /* DeltaToDelta2.xcmappingmodel in Sources */, BF6BF3131EB7E47F008E83CD /* ImportOption.swift in Sources */, diff --git a/Delta/Base.lproj/Settings.storyboard b/Delta/Base.lproj/Settings.storyboard index ed24fe3..b900c2c 100644 --- a/Delta/Base.lproj/Settings.storyboard +++ b/Delta/Base.lproj/Settings.storyboard @@ -1,12 +1,11 @@ - + - - + @@ -19,7 +18,7 @@ diff --git a/Delta/Emulation/GameViewController.swift b/Delta/Emulation/GameViewController.swift index f7e7d2c..a2a0cac 100644 --- a/Delta/Emulation/GameViewController.swift +++ b/Delta/Emulation/GameViewController.swift @@ -906,6 +906,8 @@ private extension GameViewController } case .translucentControllerSkinOpacity: self.controllerView.translucentControllerSkinOpacity = Settings.translucentControllerSkinOpacity + + case .syncingService: break } } diff --git a/Delta/Settings/Settings.swift b/Delta/Settings/Settings.swift index 8460403..048ba2d 100644 --- a/Delta/Settings/Settings.swift +++ b/Delta/Settings/Settings.swift @@ -32,6 +32,7 @@ extension Settings case localControllerPlayerIndex case translucentControllerSkinOpacity case preferredControllerSkin + case syncingService } } @@ -45,6 +46,15 @@ extension Settings } struct Settings +{ + static func registerDefaults() + { + let defaults = [#keyPath(UserDefaults.translucentControllerSkinOpacity): 0.7, #keyPath(UserDefaults.gameShortcutsMode): GameShortcutsMode.recent.rawValue] as [String : Any] + UserDefaults.standard.register(defaults: defaults) + } +} + +extension Settings { /// Controllers static var localControllerPlayerIndex: Int? = 0 { @@ -120,10 +130,12 @@ struct Settings } } - static func registerDefaults() - { - let defaults = [#keyPath(UserDefaults.translucentControllerSkinOpacity): 0.7, #keyPath(UserDefaults.gameShortcutsMode): GameShortcutsMode.recent.rawValue] as [String : Any] - UserDefaults.standard.register(defaults: defaults) + static var syncingService: SyncingService { + get { return SyncingService(rawValue: UserDefaults.standard.syncingService) ?? .none } + set { + UserDefaults.standard.syncingService = newValue.rawValue + NotificationCenter.default.post(name: .settingsDidChange, object: nil, userInfo: [NotificationUserInfoKey.name: Name.syncingService]) + } } static func preferredControllerSkin(for system: System, traits: DeltaCore.ControllerSkin.Traits) -> ControllerSkin? @@ -220,4 +232,6 @@ private extension UserDefaults @NSManaged var gameShortcutsMode: String @NSManaged var gameShortcutIdentifiers: [String] + + @NSManaged var syncingService: String } diff --git a/Delta/Settings/SettingsViewController.swift b/Delta/Settings/SettingsViewController.swift index 34c3a36..46b9bce 100644 --- a/Delta/Settings/SettingsViewController.swift +++ b/Delta/Settings/SettingsViewController.swift @@ -19,6 +19,7 @@ private extension SettingsViewController case controllers case controllerSkins case controllerOpacity + case syncing case threeDTouch } @@ -34,6 +35,11 @@ private extension SettingsViewController case gba case gbc } + + enum SyncingRow: Int + { + case service + } } class SettingsViewController: UITableViewController @@ -50,6 +56,7 @@ class SettingsViewController: UITableViewController { super.init(coder: aDecoder) + NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.settingsDidChange(with:)), name: .settingsDidChange, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.externalGameControllerDidConnect(_:)), name: .externalGameControllerDidConnect, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(SettingsViewController.externalGameControllerDidDisconnect(_:)), name: .externalGameControllerDidDisconnect, object: nil) } @@ -173,6 +180,26 @@ private extension SettingsViewController private extension SettingsViewController { + @objc func settingsDidChange(with notification: Notification) + { + guard let settingsName = notification.userInfo?[Settings.NotificationUserInfoKey.name] as? Settings.Name else { return } + + switch settingsName + { + case .localControllerPlayerIndex, .preferredControllerSkin, .translucentControllerSkinOpacity: break + case .syncingService: + let selectedIndexPath = self.tableView.indexPathForSelectedRow + + let indexPath = IndexPath(row: SyncingRow.service.rawValue, section: Section.syncing.rawValue) + self.tableView.reloadRows(at: [indexPath], with: .none) + + if indexPath == selectedIndexPath + { + self.tableView.selectRow(at: selectedIndexPath, animated: true, scrollPosition: .none) + } + } + } + @objc func externalGameControllerDidConnect(_ notification: Notification) { self.tableView.reloadSections(IndexSet(integer: Section.controllers.rawValue), with: .none) @@ -228,7 +255,8 @@ extension SettingsViewController } case .controllerSkins: cell.textLabel?.text = System.supportedSystems[indexPath.row].localizedName - default: break + case .syncing: cell.detailTextLabel?.text = Settings.syncingService.localizedName + case .controllerOpacity, .threeDTouch: break } return cell @@ -241,10 +269,9 @@ extension SettingsViewController switch section { - case Section.controllers: self.performSegue(withIdentifier: Segue.controllers.rawValue, sender: cell) - case Section.controllerSkins: self.performSegue(withIdentifier: Segue.controllerSkins.rawValue, sender: cell) - case Section.controllerOpacity: break - case Section.threeDTouch: break + case .controllers: self.performSegue(withIdentifier: Segue.controllers.rawValue, sender: cell) + case .controllerSkins: self.performSegue(withIdentifier: Segue.controllerSkins.rawValue, sender: cell) + case .controllerOpacity, .threeDTouch, .syncing: break } } diff --git a/Delta/Settings/Syncing/SyncingServicesViewController.swift b/Delta/Settings/Syncing/SyncingServicesViewController.swift new file mode 100644 index 0000000..34917e1 --- /dev/null +++ b/Delta/Settings/Syncing/SyncingServicesViewController.swift @@ -0,0 +1,90 @@ +// +// SyncingServicesViewController.swift +// Delta +// +// Created by Riley Testut on 6/27/17. +// Copyright © 2017 Riley Testut. All rights reserved. +// + +import UIKit + +enum SyncingService: String, CaseIterable +{ + case none + case googleDrive + + var localizedName: String { + switch self + { + case .none: return NSLocalizedString("None", comment: "") + case .googleDrive: return NSLocalizedString("Google Drive", comment: "") + } + } +} + +extension SyncingServicesViewController +{ + enum Section: Int, CaseIterable + { + case service + case account + case signOut + } +} + +class SyncingServicesViewController: UITableViewController +{ + override func numberOfSections(in tableView: UITableView) -> Int + { + guard Settings.syncingService != .none else { return 1 } + + return super.numberOfSections(in: tableView) + } + + override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell + { + let cell = super.tableView(tableView, cellForRowAt: indexPath) + + switch Section.allCases[indexPath.section] + { + case .service: + let service = SyncingService.allCases[indexPath.row] + cell.accessoryType = (service == Settings.syncingService) ? .checkmark : .none + + case .account, .signOut: break + } + + return cell + } + + override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) + { + switch Section.allCases[indexPath.section] + { + case .service: + Settings.syncingService = SyncingService.allCases[indexPath.row] + + if Settings.syncingService == .none && self.tableView.numberOfSections > 1 + { + self.tableView.deleteSections(IndexSet(integersIn: Section.account.rawValue ... Section.signOut.rawValue), with: .fade) + } + else if Settings.syncingService != .none && self.tableView.numberOfSections == 1 + { + self.tableView.insertSections(IndexSet(integersIn: Section.account.rawValue ... Section.signOut.rawValue), with: .fade) + } + + self.tableView.reloadSections(IndexSet(integer: Section.service.rawValue), with: .none) + + case .account, .signOut: break + } + } + + override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat + { + switch Section.allCases[indexPath.section] + { + case .service: return super.tableView(tableView, heightForRowAt: indexPath) + case .account, .signOut: return (Settings.syncingService == .none) ? 0 : super.tableView(tableView, heightForRowAt: indexPath) + } + } +}