Adds FAQ links underneath Controller Skins and BIOS settings

This commit is contained in:
Riley Testut 2023-11-16 16:06:06 -06:00
parent 47b96d1cf6
commit c5333ad118
4 changed files with 181 additions and 10 deletions

View File

@ -191,6 +191,7 @@
D55C468F29E761C000EA6DE9 /* AnyFeature.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55C468E29E761C000EA6DE9 /* AnyFeature.swift */; };
D55C469129E7631000EA6DE9 /* AnyOption.swift in Sources */ = {isa = PBXBuildFile; fileRef = D55C469029E7631000EA6DE9 /* AnyOption.swift */; };
D560BD8629EDC45600289847 /* ExternalDisplaySceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D560BD8529EDC45600289847 /* ExternalDisplaySceneDelegate.swift */; };
D56F7ABC2B05988700490ACB /* AttributedHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D56F7ABB2B05988700490ACB /* AttributedHeaderFooterView.swift */; };
D57D795629F300E100BB2CF8 /* CustomTintColor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A817AF29DF4E6E00904AFE /* CustomTintColor.swift */; };
D57D795F29F315F700BB2CF8 /* FeatureDetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D54A4BB229E4D27E004C7D57 /* FeatureDetailView.swift */; };
D57D796029F315F700BB2CF8 /* ExperimentalFeaturesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A9C00229DDED6D00A8D610 /* ExperimentalFeaturesView.swift */; };
@ -464,6 +465,7 @@
D55C468E29E761C000EA6DE9 /* AnyFeature.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyFeature.swift; sourceTree = "<group>"; };
D55C469029E7631000EA6DE9 /* AnyOption.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AnyOption.swift; sourceTree = "<group>"; };
D560BD8529EDC45600289847 /* ExternalDisplaySceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ExternalDisplaySceneDelegate.swift; sourceTree = "<group>"; };
D56F7ABB2B05988700490ACB /* AttributedHeaderFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AttributedHeaderFooterView.swift; sourceTree = "<group>"; };
D586496F297734280081477E /* CheatMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheatMetadata.swift; sourceTree = "<group>"; };
D586497129774ABD0081477E /* CheatBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheatBase.swift; sourceTree = "<group>"; };
D5864977297756CE0081477E /* CheatBaseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheatBaseView.swift; sourceTree = "<group>"; };
@ -787,6 +789,7 @@
BFFA4C081E8A24D600D87934 /* GameTableViewCell.swift */,
BF71CF891FE904B1001F1613 /* GameTableViewCell.xib */,
BF8A333321A484A000A42FD4 /* BadgedTableViewCell.swift */,
D56F7ABB2B05988700490ACB /* AttributedHeaderFooterView.swift */,
);
path = "Table View";
sourceTree = "<group>";
@ -1663,6 +1666,7 @@
BF6866171DCAC8B900BF2D06 /* ControllerSkin+Configuring.swift in Sources */,
BF713C0822499ED4004A1A2B /* PreviousHarmony.xcdatamodeld in Sources */,
BF59427D1E09BC830051894B /* ControllerSkin.swift in Sources */,
D56F7ABC2B05988700490ACB /* AttributedHeaderFooterView.swift in Sources */,
BFAB9F7D219A43380080EC7D /* SyncManager.swift in Sources */,
BFCEA67E1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift in Sources */,
BF1173501DA32CF600047DF8 /* ControllersSettingsViewController.swift in Sources */,

View File

@ -0,0 +1,75 @@
//
// AttributedHeaderFooterView.swift
// Delta
//
// Created by Riley Testut on 11/15/23.
// Copyright © 2023 Riley Testut. All rights reserved.
//
import UIKit
@available(iOS 15, *)
final class AttributedHeaderFooterView: UITableViewHeaderFooterView
{
static let reuseIdentifier: String = "TextViewHeaderFooterView"
var attributedText: AttributedString? {
get {
guard let attributedText = self.textView.attributedText else { return nil }
return AttributedString(attributedText)
}
set {
guard var attributedText = newValue else {
self.textView.attributedText = nil
return
}
var attributes = AttributeContainer()
attributes.foregroundColor = UIColor.secondaryLabel
attributes.font = self.textLabel?.font ?? UIFont.preferredFont(forTextStyle: .footnote)
attributedText.mergeAttributes(attributes, mergePolicy: .keepCurrent)
self.textView.attributedText = NSAttributedString(attributedText)
}
}
private let textView: UITextView
override init(reuseIdentifier: String?)
{
self.textView = UITextView(frame: .zero)
self.textView.translatesAutoresizingMaskIntoConstraints = false
self.textView.textContainer.lineFragmentPadding = 0
self.textView.textContainerInset = .zero
self.textView.isSelectable = true // Must be true to open links
self.textView.isEditable = false
self.textView.isScrollEnabled = false
self.textView.backgroundColor = nil
self.textView.textContainer.lineBreakMode = .byWordWrapping
super.init(reuseIdentifier: reuseIdentifier)
self.textView.delegate = self
self.contentView.addSubview(self.textView)
NSLayoutConstraint.activate([
self.textView.topAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.topAnchor),
self.textView.bottomAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.bottomAnchor),
self.textView.leadingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.leadingAnchor),
self.textView.trailingAnchor.constraint(equalTo: self.contentView.layoutMarginsGuide.trailingAnchor),
])
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
@available(iOS 15, *)
extension AttributedHeaderFooterView: UITextViewDelegate
{
func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool
{
return true
}
}

View File

@ -120,6 +120,11 @@ class MelonDSCoreSettingsViewController: UITableViewController
self.navigationItem.rightBarButtonItem = nil
}
if #available(iOS 15, *)
{
self.tableView.register(AttributedHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: AttributedHeaderFooterView.reuseIdentifier)
}
NotificationCenter.default.addObserver(self, selector: #selector(MelonDSCoreSettingsViewController.willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
}
@ -460,8 +465,43 @@ extension MelonDSCoreSettingsViewController
case (false, .horizontal): return NSLocalizedString("When AirPlaying DS games, both screens will be placed side-by-side on the external display.", comment: "")
}
default: return super.tableView(tableView, titleForFooterInSection: section.rawValue)
case .dsBIOS, .dsiBIOS:
guard #available(iOS 15, *) else { break }
return nil
default: break
}
return super.tableView(tableView, titleForFooterInSection: section.rawValue)
}
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView?
{
let section = Section(rawValue: section)!
guard !isSectionHidden(section) else { return nil }
switch section
{
case .dsBIOS, .dsiBIOS:
guard #available(iOS 15, *), let footerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: AttributedHeaderFooterView.reuseIdentifier) as? AttributedHeaderFooterView else { break }
let systemName = (section == .dsiBIOS) ? String(localized: "DSi") : String(localized: "DS")
var attributedText = AttributedString(localized: "Delta requires these BIOS files in order to play Nintendo \(systemName) games.")
attributedText += " "
var learnMore = AttributedString(localized: "Learn more…")
learnMore.link = URL(string: "https://faq.deltaemulator.com/getting-started/nintendo-ds-bios-files")
attributedText += learnMore
footerView.attributedText = attributedText
return footerView
default: break
}
return super.tableView(tableView, viewForFooterInSection: section.rawValue)
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
@ -481,14 +521,24 @@ extension MelonDSCoreSettingsViewController
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat
{
let section = Section(rawValue: section)!
guard !isSectionHidden(section) else { return 1 }
if isSectionHidden(section)
switch section
{
return 1
case .dsBIOS, .dsiBIOS: return UITableView.automaticDimension
default: return super.tableView(tableView, heightForFooterInSection: section.rawValue)
}
else
}
override func tableView(_ tableView: UITableView, estimatedHeightForFooterInSection section: Int) -> CGFloat
{
let section = Section(rawValue: section)!
guard !isSectionHidden(section) else { return 1 }
switch section
{
return super.tableView(tableView, heightForFooterInSection: section.rawValue)
case .dsBIOS, .dsiBIOS: return 30
default: return UITableView.automaticDimension
}
}
}

View File

@ -115,6 +115,11 @@ class SettingsViewController: UITableViewController
self.versionLabel.text = NSLocalizedString("Delta", comment: "")
#endif
}
if #available(iOS 15, *)
{
self.tableView.register(AttributedHeaderFooterView.self, forHeaderFooterViewReuseIdentifier: AttributedHeaderFooterView.reuseIdentifier)
}
}
override func viewWillAppear(_ animated: Bool)
@ -584,6 +589,33 @@ extension SettingsViewController
}
}
override func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView?
{
let section = Section(rawValue: section)!
guard !isSectionHidden(section) else { return nil }
switch section
{
case .controllerSkins:
guard #available(iOS 15, *), let footerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: AttributedHeaderFooterView.reuseIdentifier) as? AttributedHeaderFooterView else { break }
var attributedText = AttributedString(localized: "Customize the appearance of each system.")
attributedText += " "
var learnMore = AttributedString(localized: "Learn more…")
learnMore.link = URL(string: "https://faq.deltaemulator.com/using-delta/controller-skins")
attributedText += learnMore
footerView.attributedText = attributedText
return footerView
default: break
}
return super.tableView(tableView, viewForFooterInSection: section.rawValue)
}
override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String?
{
let section = Section(rawValue: section)!
@ -594,7 +626,7 @@ extension SettingsViewController
#if !BETA
case .advanced: return nil
#endif
case .controllerSkins: return nil
default: return super.tableView(tableView, titleForFooterInSection: section.rawValue)
}
}
@ -616,14 +648,24 @@ extension SettingsViewController
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat
{
let section = Section(rawValue: section)!
guard !isSectionHidden(section) else { return 1 }
if isSectionHidden(section)
switch section
{
return 1
case .controllerSkins: return UITableView.automaticDimension
default: return super.tableView(tableView, heightForFooterInSection: section.rawValue)
}
else
}
override func tableView(_ tableView: UITableView, estimatedHeightForFooterInSection section: Int) -> CGFloat
{
let section = Section(rawValue: section)!
guard !isSectionHidden(section) else { return 1 }
switch section
{
return super.tableView(tableView, heightForFooterInSection: section.rawValue)
case .controllerSkins: return 30
default: return UITableView.automaticDimension
}
}
}