ux: use UITableView for dropdowns in reader to be consistent with settings

This commit was merged in pull request #31.
This commit is contained in:
2026-07-30 01:38:05 +02:00
parent aeeca62daa
commit 2718792c67
+109 -187
View File
@@ -91,10 +91,8 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
let bottomBarView = UIView()
let info = UILabel()
let pageTurnDropdownView = UIView()
let pageTurnDropdownButton = UIButton()
let backgroundColorDropdownView = UIView()
let backgroundColorDropdownButton = UIButton()
let homeButton = UIButton()
@@ -347,12 +345,12 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
func convertStringToColor(_ str: String) -> UIColor {
let r: UIColor!
switch str {
case "White": r = .white
case "Gray": r = .gray
case "Black": r = .black
case "Red": r = .red
case "Blue": r = .blue
switch str.lowercased() {
case "white": r = .white
case "gray": r = .gray
case "black": r = .black
case "red": r = .red
case "blue": r = .blue
default: r = .black
}
return r
@@ -1094,44 +1092,15 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
}
func setupBackgroundColorDropdown() {
backgroundColorDropdownButton.setTitle("Background color", for: .normal)
backgroundColorDropdownButton.setTitle("Background Color", for: .normal)
backgroundColorDropdownButton.setTitleColor(.white, for: .normal)
backgroundColorDropdownButton.translatesAutoresizingMaskIntoConstraints = false
topBarView.addSubview(backgroundColorDropdownButton)
backgroundColorDropdownButton.addTarget(
self, action: #selector(toggleBackgroundColorDropdown), for: .touchDown
self, action: #selector(backgroundColorTapped), for: .touchDown
)
backgroundColorDropdownView.backgroundColor = UIColor.darkGray
backgroundColorDropdownView.translatesAutoresizingMaskIntoConstraints = false
backgroundColorDropdownView.isHidden = true
readerView.addSubview(backgroundColorDropdownView)
let stackView = UIStackView()
stackView.axis = .vertical
stackView.spacing = 8
stackView.distribution = .fillEqually
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.isLayoutMarginsRelativeArrangement = true
stackView.layoutMargins = UIEdgeInsets(top: 8, left: 0, bottom: 8, right: 0)
backgroundColorDropdownView.addSubview(stackView)
let colorOptions = ["White", "Gray", "Black", "Red", "Blue", "Default"]
for title in colorOptions {
let button = UIButton(type: .system)
button.setTitle(title, for: .normal)
button.setTitleColor(.white, for: .normal)
button.contentHorizontalAlignment = .left
button.contentEdgeInsets = UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 0)
button.backgroundColor = .clear
button.translatesAutoresizingMaskIntoConstraints = false
button.addTarget(
self, action: #selector(handleBackgroundColorOption), for: .touchDown
)
stackView.addArrangedSubview(button)
}
NSLayoutConstraint.activate([
backgroundColorDropdownButton.trailingAnchor.constraint(
equalTo: topBarView.trailingAnchor, constant: -32
@@ -1145,67 +1114,19 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
backgroundColorDropdownButton.bottomAnchor.constraint(
equalTo: topBarView.bottomAnchor
),
backgroundColorDropdownView.topAnchor.constraint(
equalTo: backgroundColorDropdownButton.bottomAnchor
),
backgroundColorDropdownView.leadingAnchor.constraint(
equalTo: backgroundColorDropdownButton.leadingAnchor
),
backgroundColorDropdownView.trailingAnchor.constraint(
equalTo: backgroundColorDropdownButton.trailingAnchor
),
stackView.topAnchor.constraint(
equalTo: backgroundColorDropdownView.topAnchor
),
stackView.bottomAnchor.constraint(equalTo: backgroundColorDropdownView.bottomAnchor),
stackView.leadingAnchor.constraint(equalTo: backgroundColorDropdownView.leadingAnchor),
stackView.trailingAnchor.constraint(
equalTo: backgroundColorDropdownView.trailingAnchor
),
])
}
func setupPageTurnDropdown() {
pageTurnDropdownButton.setTitle("Page Turn Mode", for: .normal)
pageTurnDropdownButton.setTitle("Page Turn Mode", for: .normal)
pageTurnDropdownButton.setTitleColor(.white, for: .normal)
pageTurnDropdownButton.translatesAutoresizingMaskIntoConstraints = false
topBarView.addSubview(pageTurnDropdownButton)
pageTurnDropdownButton.addTarget(
self, action: #selector(togglePageTurnDropdown), for: .touchDown
self, action: #selector(pageTurnTapped), for: .touchDown
)
pageTurnDropdownView.backgroundColor = UIColor.darkGray
pageTurnDropdownView.translatesAutoresizingMaskIntoConstraints = false
pageTurnDropdownView.isHidden = true
readerView.addSubview(pageTurnDropdownView)
let stackView = UIStackView()
stackView.axis = .vertical
stackView.spacing = 8
stackView.distribution = .fillEqually
stackView.translatesAutoresizingMaskIntoConstraints = false
stackView.isLayoutMarginsRelativeArrangement = true
stackView.layoutMargins = UIEdgeInsets(top: 8, left: 0, bottom: 8, right: 0)
pageTurnDropdownView.addSubview(stackView)
let pageTurnOptions = ["Left to right", "Right to left", "Scroll", "Default"]
for title in pageTurnOptions {
let button = UIButton(type: .system)
button.setTitle(title, for: .normal)
button.setTitleColor(.white, for: .normal)
button.contentHorizontalAlignment = .left
button.backgroundColor = .clear
button.translatesAutoresizingMaskIntoConstraints = false
button.contentEdgeInsets = UIEdgeInsets(top: 0, left: 8, bottom: 0, right: 0)
button.addTarget(
self, action: #selector(handlePageTurnOption), for: .touchDown
)
stackView.addArrangedSubview(button)
}
NSLayoutConstraint.activate([
pageTurnDropdownButton.trailingAnchor.constraint(
equalTo: backgroundColorDropdownButton.leadingAnchor, constant: -32
@@ -1219,88 +1140,9 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
pageTurnDropdownButton.bottomAnchor.constraint(
equalTo: topBarView.bottomAnchor
),
pageTurnDropdownView.topAnchor.constraint(
equalTo: pageTurnDropdownButton.bottomAnchor
),
pageTurnDropdownView.leadingAnchor.constraint(
equalTo: pageTurnDropdownButton.leadingAnchor
),
pageTurnDropdownView.trailingAnchor.constraint(
equalTo: pageTurnDropdownButton.trailingAnchor
),
stackView.topAnchor.constraint(
equalTo: pageTurnDropdownView.topAnchor
),
stackView.bottomAnchor.constraint(equalTo: pageTurnDropdownView.bottomAnchor),
stackView.leadingAnchor.constraint(equalTo: pageTurnDropdownView.leadingAnchor),
stackView.trailingAnchor.constraint(
equalTo: pageTurnDropdownView.trailingAnchor
),
])
}
@objc func handlePageTurnOption(_ sender: UIButton) {
if let title = sender.currentTitle {
let prev = mode
switch title.lowercased() {
case "left to right": mode = .leftToRight
case "right to left": mode = .rightToLeft
case "scroll": mode = .scroll
case "default": mode = settings.defaultPageTurnMode
default: break
}
if prev == mode { return }
if mode != .scroll {
let archiveURL = getArchiveURL(progress.v)
imageLoader.loadImage(
archiveURL: archiveURL,
filename: getImagePath(progress),
scaling: .scaleAspectFit,
screenSize: UIScreen.main.bounds.size
) { [weak self] image in
self?.imageView.image = image
}
}
}
scrollingCollectionView.isHidden = mode != .scroll
leftView.isHidden = mode == .scroll
rightView.isHidden = mode == .scroll
imageView.isHidden = mode == .scroll
// This does not optmize for the case where you switch between scrolling and non-scrolling in the same comic.
// However this is badly supported because of the lack of state conversion.
if mode == .scroll {
scrollingCollectionView.reloadData()
}
togglePageTurnDropdown()
saveLocalState()
}
@objc func handleBackgroundColorOption(_ sender: UIButton) {
if let title = sender.currentTitle {
switch title.lowercased() {
case "white": readerView.backgroundColor = .white
case "gray": readerView.backgroundColor = .gray
case "black": readerView.backgroundColor = .black
case "red": readerView.backgroundColor = .red
case "blue": readerView.backgroundColor = .blue
case "default": readerView.backgroundColor = convertStringToColor(settings.defaultReadingBackgroundColor)
default: break
}
}
toggleBackgroundColorDropdown()
saveLocalState()
}
@objc func togglePageTurnDropdown() {
pageTurnDropdownView.isHidden.toggle()
}
@objc func toggleBackgroundColorDropdown() {
backgroundColorDropdownView.isHidden.toggle()
}
func gestureRecognizer(
_: UIGestureRecognizer,
shouldRecognizeSimultaneouslyWith _: UIGestureRecognizer
@@ -1311,11 +1153,6 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
func toggleBar() {
topBarView.isHidden.toggle()
bottomBarView.isHidden.toggle()
if topBarView.isHidden {
pageTurnDropdownView.isHidden = true
backgroundColorDropdownView.isHidden = true
}
}
func scrollViewDidEndDecelerating(_: UIScrollView) {
@@ -1335,8 +1172,6 @@ final class ViewController: UIViewController, UIGestureRecognizerDelegate {
func hideBar() {
topBarView.isHidden = true
bottomBarView.isHidden = true
pageTurnDropdownView.isHidden = true
backgroundColorDropdownView.isHidden = true
}
@objc func handleLongPress(_ gesture: UILongPressGestureRecognizer) {
@@ -2230,7 +2065,7 @@ class SettingsMenuViewController: UITableViewController {
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
preferredContentSize = CGSize(width: 440, height: items.count * 44)
preferredContentSize = CGSize(width: 220, height: items.count * 44)
}
override func tableView(_: UITableView, numberOfRowsInSection _: Int) -> Int {
@@ -2259,11 +2094,9 @@ class SettingsMenuViewController: UITableViewController {
}
extension ViewController {
private func colorLeafItems(applyTo colorHandler: @escaping (UIColor) -> Void) -> [SettingsMenuItem] {
let palette: [(String, UIColor)] = [
("Black", .black), ("White", .white), ("Red", .red), ("Blue", .blue),
]
return palette.map { name, color in
private func colorItems(applyTo colorHandler: @escaping (UIColor) -> Void) -> [SettingsMenuItem] {
let items: [(String, UIColor)] = [("Black", .black), ("White", .white), ("Red", .red), ("Blue", .blue)]
return items.map { name, color in
SettingsMenuItem(title: name, children: nil, action: { [weak self] in
colorHandler(color)
self?.dismiss(animated: false)
@@ -2271,11 +2104,37 @@ extension ViewController {
}
}
private func pageTurnLeafItems(applyTo pageTurnHandler: @escaping (PageTurnMode) -> Void) -> [SettingsMenuItem] {
let palette: [(String, PageTurnMode)] = [
private func colorDefaultItems(applyTo colorHandler: @escaping (UIColor) -> Void) -> [SettingsMenuItem] {
let items: [(String, UIColor)] = [
("Black", .black), ("White", .white), ("Red", .red), ("Blue", .blue),
("Default", convertStringToColor(settings.defaultReadingBackgroundColor)),
]
return items.map { name, color in
SettingsMenuItem(title: name, children: nil, action: { [weak self] in
colorHandler(color)
self?.dismiss(animated: false)
})
}
}
private func pageTurnItems(applyTo pageTurnHandler: @escaping (PageTurnMode) -> Void) -> [SettingsMenuItem] {
let items: [(String, PageTurnMode)] = [
("Left to right", .leftToRight), ("Right to left", .rightToLeft), ("Scroll", .scroll),
]
return palette.map { name, pageTurnMode in
return items.map { name, pageTurnMode in
SettingsMenuItem(title: name, children: nil, action: { [weak self] in
pageTurnHandler(pageTurnMode)
self?.dismiss(animated: false)
})
}
}
private func pageTurnDefaultItems(applyTo pageTurnHandler: @escaping (PageTurnMode) -> Void) -> [SettingsMenuItem] {
let items: [(String, PageTurnMode)] = [
("Left to right", .leftToRight), ("Right to left", .rightToLeft), ("Scroll", .scroll),
("Default", settings.defaultPageTurnMode),
]
return items.map { name, pageTurnMode in
SettingsMenuItem(title: name, children: nil, action: { [weak self] in
pageTurnHandler(pageTurnMode)
self?.dismiss(animated: false)
@@ -2284,16 +2143,16 @@ extension ViewController {
}
private func makeSettingsTree() -> [SettingsMenuItem] {
let backgroundColors = colorLeafItems { [weak self] color in
let backgroundColors = colorItems { [weak self] color in
self?.homeView.backgroundColor = color
self?.settings.homeBackgroundColor = self?.convertColorToString(color) ?? "White"
self?.saveSettings()
}
let defaultReadingBackgroundColor = colorLeafItems { [weak self] color in
let defaultReadingBackgroundColor = colorItems { [weak self] color in
self?.settings.defaultReadingBackgroundColor = self?.convertColorToString(color) ?? "Black"
self?.saveSettings()
}
let defaultPageTurnMode = pageTurnLeafItems { [weak self] pageTurnMode in
let defaultPageTurnMode = pageTurnItems { [weak self] pageTurnMode in
self?.settings.defaultPageTurnMode = pageTurnMode
self?.saveSettings()
}
@@ -2311,6 +2170,39 @@ extension ViewController {
return [colorsMenu, pageTurnMenu]
}
private func makePageTurnTree() -> [SettingsMenuItem] {
return pageTurnDefaultItems { [self] pageTurnMode in
if self.mode == pageTurnMode { return }
if self.mode != .scroll {
let archiveURL = getArchiveURL(progress.v)
imageLoader.loadImage(
archiveURL: archiveURL,
filename: getImagePath(self.progress),
scaling: .scaleAspectFit,
screenSize: UIScreen.main.bounds.size
) { [weak self] image in
self?.imageView.image = image
}
}
scrollingCollectionView.isHidden = mode != .scroll
leftView.isHidden = mode == .scroll
rightView.isHidden = mode == .scroll
imageView.isHidden = mode == .scroll
if mode == .scroll {
scrollingCollectionView.reloadData()
}
self.mode = pageTurnMode
saveLocalState()
}
}
private func makeBackgroundColorTree() -> [SettingsMenuItem] {
return colorDefaultItems { [weak self] color in
self?.readerView.backgroundColor = color
}
}
}
extension ViewController: UIPopoverPresentationControllerDelegate {
@@ -2329,6 +2221,36 @@ extension ViewController: UIPopoverPresentationControllerDelegate {
present(nav, animated: false)
}
@objc private func pageTurnTapped() {
let root = SettingsMenuViewController(title: "Modes", items: makePageTurnTree())
let nav = UINavigationController(rootViewController: root)
nav.modalPresentationStyle = .popover
if let popover = nav.popoverPresentationController {
popover.sourceView = pageTurnDropdownButton
popover.sourceRect = pageTurnDropdownButton.bounds
popover.permittedArrowDirections = .up
popover.delegate = self
}
present(nav, animated: false)
}
@objc private func backgroundColorTapped() {
let root = SettingsMenuViewController(title: "Colors", items: makeBackgroundColorTree())
let nav = UINavigationController(rootViewController: root)
nav.modalPresentationStyle = .popover
if let popover = nav.popoverPresentationController {
popover.sourceView = backgroundColorDropdownButton
popover.sourceRect = backgroundColorDropdownButton.bounds
popover.permittedArrowDirections = .up
popover.delegate = self
}
present(nav, animated: false)
}
func adaptivePresentationStyle(for _: UIPresentationController) -> UIModalPresentationStyle {
return .none // keeps it a real popover on iPhone instead of a full-screen sheet
}