GBA001/Delta/Settings/SettingsViewController.swift
2018-11-12 12:43:30 -08:00

335 lines
11 KiB
Swift

//
// SettingsViewController.swift
// Delta
//
// Created by Riley Testut on 9/4/15.
// Copyright © 2015 Riley Testut. All rights reserved.
//
import UIKit
import DeltaCore
import Roxas
private extension SettingsViewController
{
enum Section: Int
{
case controllers
case controllerSkins
case controllerOpacity
case syncing
case threeDTouch
}
enum Segue: String
{
case controllers = "controllersSegue"
case controllerSkins = "controllerSkinsSegue"
}
enum ControllerSkinsRow: Int
{
case snes
case gba
case gbc
}
enum SyncingRow: Int
{
case service
}
}
class SettingsViewController: UITableViewController
{
@IBOutlet private var controllerOpacityLabel: UILabel!
@IBOutlet private var controllerOpacitySlider: UISlider!
@IBOutlet private var versionLabel: UILabel!
private var selectionFeedbackGenerator: UISelectionFeedbackGenerator?
private var previousSelectedRowIndexPath: IndexPath?
required init?(coder aDecoder: NSCoder)
{
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)
}
override func viewDidLoad()
{
super.viewDidLoad()
self.controllerOpacitySlider.value = Float(Settings.translucentControllerSkinOpacity)
self.updateControllerOpacityLabel()
if let version = Bundle.main.object(forInfoDictionaryKey: "CFBundleShortVersionString") as? String
{
self.versionLabel.text = NSLocalizedString(String(format: "Delta %@", version), comment: "Delta Version")
}
else
{
self.versionLabel.text = NSLocalizedString("Delta", comment: "")
}
}
override func viewWillAppear(_ animated: Bool)
{
super.viewWillAppear(animated)
if let indexPath = self.previousSelectedRowIndexPath
{
if indexPath.section == Section.controllers.rawValue
{
// Update and temporarily re-select selected row.
self.tableView.reloadSections(IndexSet(integer: Section.controllers.rawValue), with: .none)
self.tableView.selectRow(at: indexPath, animated: false, scrollPosition: UITableView.ScrollPosition.none)
}
self.tableView.deselectRow(at: indexPath, animated: true)
}
}
override func didReceiveMemoryWarning()
{
super.didReceiveMemoryWarning()
}
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
{
guard
let identifier = segue.identifier,
let segueType = Segue(rawValue: identifier),
let cell = sender as? UITableViewCell,
let indexPath = self.tableView.indexPath(for: cell)
else { return }
self.previousSelectedRowIndexPath = indexPath
switch segueType
{
case Segue.controllers:
let controllersSettingsViewController = segue.destination as! ControllersSettingsViewController
controllersSettingsViewController.playerIndex = indexPath.row
case Segue.controllerSkins:
let systemControllerSkinsViewController = segue.destination as! SystemControllerSkinsViewController
let row = ControllerSkinsRow(rawValue: indexPath.row)!
switch row
{
case .snes: systemControllerSkinsViewController.system = .snes
case .gba: systemControllerSkinsViewController.system = .gba
case .gbc: systemControllerSkinsViewController.system = .gbc
}
}
}
}
private extension SettingsViewController
{
func updateControllerOpacityLabel()
{
let percentage = String(format: "%.f", Settings.translucentControllerSkinOpacity * 100) + "%"
self.controllerOpacityLabel.text = percentage
}
func isSectionHidden(_ section: Section) -> Bool
{
switch section
{
case .threeDTouch: return self.view.traitCollection.forceTouchCapability != .available
default: return false
}
}
}
private extension SettingsViewController
{
@IBAction func beginChangingControllerOpacity(with sender: UISlider)
{
self.selectionFeedbackGenerator = UISelectionFeedbackGenerator()
self.selectionFeedbackGenerator?.prepare()
}
@IBAction func changeControllerOpacity(with sender: UISlider)
{
let roundedValue = CGFloat((sender.value / 0.05).rounded() * 0.05)
if roundedValue != Settings.translucentControllerSkinOpacity
{
self.selectionFeedbackGenerator?.selectionChanged()
}
Settings.translucentControllerSkinOpacity = CGFloat(roundedValue)
self.updateControllerOpacityLabel()
}
@IBAction func didFinishChangingControllerOpacity(with sender: UISlider)
{
sender.value = Float(Settings.translucentControllerSkinOpacity)
self.selectionFeedbackGenerator = nil
}
}
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)
}
@objc func externalGameControllerDidDisconnect(_ notification: Notification)
{
self.tableView.reloadSections(IndexSet(integer: Section.controllers.rawValue), with: .none)
}
}
extension SettingsViewController
{
override func tableView(_ tableView: UITableView, numberOfRowsInSection sectionIndex: Int) -> Int
{
let section = Section(rawValue: sectionIndex)!
switch section
{
case .controllers: return 1 // Temporarily hide other controller indexes until controller logic is finalized
case .controllerSkins: return System.supportedSystems.count
default:
if isSectionHidden(section)
{
return 0
}
else
{
return super.tableView(tableView, numberOfRowsInSection: sectionIndex)
}
}
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = super.tableView(tableView, cellForRowAt: indexPath)
let section = Section(rawValue: indexPath.section)!
switch section
{
case .controllers:
if indexPath.row == Settings.localControllerPlayerIndex
{
cell.detailTextLabel?.text = UIDevice.current.name
}
else if let index = ExternalGameControllerManager.shared.connectedControllers.index(where: { $0.playerIndex == indexPath.row })
{
let controller = ExternalGameControllerManager.shared.connectedControllers[index]
cell.detailTextLabel?.text = controller.name
}
else
{
cell.detailTextLabel?.text = nil
}
case .controllerSkins: cell.textLabel?.text = System.supportedSystems[indexPath.row].localizedName
case .syncing: cell.detailTextLabel?.text = Settings.syncingService.localizedName
case .controllerOpacity, .threeDTouch: break
}
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let cell = tableView.cellForRow(at: indexPath)
let section = Section(rawValue: indexPath.section)!
switch section
{
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
}
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
{
let section = Section(rawValue: section)!
if isSectionHidden(section)
{
return nil
}
else
{
return super.tableView(tableView, titleForHeaderInSection: section.rawValue)
}
}
override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String?
{
let section = Section(rawValue: section)!
if isSectionHidden(section)
{
return nil
}
else
{
return super.tableView(tableView, titleForFooterInSection: section.rawValue)
}
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
{
let section = Section(rawValue: section)!
if isSectionHidden(section)
{
return 1
}
else
{
return super.tableView(tableView, heightForHeaderInSection: section.rawValue)
}
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat
{
let section = Section(rawValue: section)!
if isSectionHidden(section)
{
return 1
}
else
{
return super.tableView(tableView, heightForFooterInSection: section.rawValue)
}
}
}