Path: blob/a-new-beginning/Folium-iOS/Controllers/SettingsControllers/FoliumSettingsController.swift
2 views
//
// FoliumSettingsController.swift
// Folium-iOS
//
// Created by Jarrod Norwell on 29/10/2024.
// Copyright © 2024 Jarrod Norwell. All rights reserved.
//
import Foundation
import SettingsKit
import UIKit
enum FoliumSettingsHeaders : String, CaseIterable {
case emulation = "Emulation"
var header: SettingHeader {
switch self {
case .emulation:
SettingHeader(text: rawValue,
secondaryText: "Emulation Controller Settings")
}
}
static var allHeaders: [SettingHeader] { allCases.map { $0.header } }
}
enum FoliumSettingsItems : String, CaseIterable {
// Emulation
case buttonTransparency = "folium.v1.38.buttonTransparency"
case expandButtonsBy = "folium.v1.38.expandButtonsBy"
var title: String {
switch self {
case .buttonTransparency:
"Button Transparency"
case .expandButtonsBy:
"Expand Buttons By"
}
}
var details: String? {
switch self {
case .buttonTransparency:
"Changes the opacity of the on-screen emulation controller buttons improving gameplay visibility on smaller screens"
case .expandButtonsBy:
"Expands the on-screen emulation controller buttons improving user interaction"
}
}
func setting(_ delegate: SettingDelegate? = nil) -> BaseSetting {
switch self {
case .buttonTransparency:
StepperSetting(key: rawValue,
title: title,
details: details,
min: 0,
max: 1,
value: UserDefaults.standard.double(forKey: rawValue),
delegate: delegate)
case .expandButtonsBy:
StepperSetting(key: rawValue,
title: title,
details: details,
min: 0,
max: 10,
value: UserDefaults.standard.double(forKey: rawValue),
delegate: delegate)
}
}
static func settings(_ header: FoliumSettingsHeaders) -> [FoliumSettingsItems] {
switch header {
case .emulation:
[.buttonTransparency, .expandButtonsBy]
}
}
}
class FoliumSettingsController : UIViewController, UICollectionViewDelegate {
var dataSource: UICollectionViewDiffableDataSource<FoliumSettingsHeaders, AnyHashableSendable>! = nil
var snapshot: NSDiffableDataSourceSnapshot<FoliumSettingsHeaders, AnyHashableSendable>! = nil
let settingsKit: SettingsKit = SettingsKit()
override func viewDidLoad() {
super.viewDidLoad()
if let navigationController {
navigationController.navigationBar.prefersLargeTitles = true
}
navigationItem.leftBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "xmark"), primaryAction: UIAction { _ in
self.dismiss(animated: true)
})
if #available(iOS 26, *) {
navigationItem.title = "Folium"
navigationItem.largeTitle = navigationItem.title
navigationItem.subtitle = "Settings"
navigationItem.largeSubtitle = navigationItem.subtitle
} else {
title = "Folium"
}
navigationItem.style = .browser
var configuration: UICollectionLayoutListConfiguration = UICollectionLayoutListConfiguration(appearance: .insetGrouped)
configuration.backgroundColor = .clear
configuration.headerMode = .supplementary
configuration.trailingSwipeActionsConfigurationProvider = { indexPath in
guard let dataSource = self.dataSource, let item: BaseSetting = dataSource.itemIdentifier(for: indexPath) as? BaseSetting else {
return UISwipeActionsConfiguration()
}
let informationContextualAction: UIContextualAction = UIContextualAction(style: .normal, title: nil, handler: { action, view, performed in
let alertController: UIAlertController = UIAlertController(title: item.title, message: item.details, preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "Dismiss", style: .default) { _ in
performed(true)
})
// alertController.preferredAction = alertController.actions.first
self.present(alertController, animated: true)
})
informationContextualAction.image = UIImage(systemName: "info")
return UISwipeActionsConfiguration(actions: [
informationContextualAction
])
}
let collectionView: UICollectionView = UICollectionView(frame: .zero,
collectionViewLayout: UICollectionViewCompositionalLayout.list(using: configuration))
collectionView.translatesAutoresizingMaskIntoConstraints = false
collectionView.delegate = self
view.addSubview(collectionView)
collectionView.topAnchor.constraint(equalTo: view.topAnchor).isActive = true
collectionView.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
collectionView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
collectionView.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
if #available(iOS 26, *) {
let backgroundView: UIVisualEffectView = UIVisualEffectView(effect: UIGlassEffect(style: .regular))
backgroundView.cornerConfiguration = .corners(radius: .containerConcentric())
collectionView.backgroundColor = .clear
collectionView.backgroundView = backgroundView
view.backgroundColor = .clear
} else {
view.backgroundColor = .systemBackground
}
let headerCellRegistration = UICollectionView.SupplementaryRegistration<UICollectionViewListCell>(elementKind: UICollectionView.elementKindSectionHeader) { supplementaryView, elementKind, indexPath in
var contentConfiguration = UIListContentConfiguration.extraProminentInsetGroupedHeader()
contentConfiguration.text = self.snapshot.sectionIdentifiers[indexPath.section].header.text
contentConfiguration.secondaryText = self.snapshot.sectionIdentifiers[indexPath.section].header.secondaryText
contentConfiguration.secondaryTextProperties.color = .secondaryLabel
supplementaryView.contentConfiguration = contentConfiguration
}
let stepperCell: UICollectionView.CellRegistration<UICollectionViewListCell, StepperSetting> = CellManager.Settings.stepperCell
dataSource = .init(collectionView: collectionView) { collectionView, indexPath, itemIdentifier in
switch itemIdentifier {
case let stepperSetting as StepperSetting:
collectionView.dequeueConfiguredReusableCell(using: stepperCell, for: indexPath, item: stepperSetting)
default:
nil
}
}
dataSource.supplementaryViewProvider = { collectionView, elementKind, indexPath in
collectionView.dequeueConfiguredReusableSupplementary(using: headerCellRegistration, for: indexPath)
}
snapshot = .init()
snapshot.appendSections(FoliumSettingsHeaders.allCases)
snapshot.sectionIdentifiers.forEach { header in
snapshot.appendItems(FoliumSettingsItems.settings(header).map { $0.setting(self) }, toSection: header)
}
Task {
await dataSource.apply(snapshot)
}
}
func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
collectionView.deselectItem(at: indexPath, animated: true)
}
}
extension FoliumSettingsController : SettingDelegate {
func didChangeSetting(at indexPath: IndexPath) {
guard let sectionIdentifier = dataSource.sectionIdentifier(for: indexPath.section) else {
return
}
var snapshot = dataSource.snapshot()
let item = snapshot.itemIdentifiers(inSection: sectionIdentifier)[indexPath.item]
switch item {
case let stepperSetting as StepperSetting:
stepperSetting.value = UserDefaults.standard.double(forKey: stepperSetting.key)
default:
break
}
snapshot.reloadItems([item])
Task {
await dataSource.apply(snapshot, animatingDifferences: false)
}
}
}