-
-
Notifications
You must be signed in to change notification settings - Fork 273
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add full settings menu for beta features
Fixes IOS-354
- Loading branch information
1 parent
1e6ae17
commit 4dd856f
Showing
6 changed files
with
206 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
11 changes: 11 additions & 0 deletions
11
...on/Scene/Settings/Beta Testing Settings/BetaTestSettingsDiffableTableViewDataSource.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
// Copyright © 2025 Mastodon gGmbH. All rights reserved. | ||
|
||
import UIKit | ||
|
||
class BetaTestSettingsDiffableTableViewDataSource: UITableViewDiffableDataSource<BetaTestSettingsSectionType, BetaTestSetting> { | ||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { | ||
guard let settingsSectionType = sectionIdentifier(for: section) else { return nil } | ||
|
||
return settingsSectionType.sectionTitle.uppercased() | ||
} | ||
} |
170 changes: 170 additions & 0 deletions
170
Mastodon/Scene/Settings/Beta Testing Settings/BetaTestSettingsViewController.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
// Copyright © 2025 Mastodon gGmbH. All rights reserved. | ||
|
||
import UIKit | ||
import MastodonSDK | ||
|
||
struct BetaTestSettingsViewModel { | ||
let useStagingForDonations: Bool | ||
let testGroupedNotifications: Bool | ||
|
||
init() { | ||
useStagingForDonations = Mastodon.API.isTestingDonations | ||
testGroupedNotifications = UserDefaults.standard.bool(forKey: BetaTestSetting.useGroupedNotifications.userDefaultsKey) | ||
} | ||
|
||
func byToggling(_ setting: BetaTestSetting) -> BetaTestSettingsViewModel { | ||
switch setting { | ||
case .useStagingForDonations: | ||
Mastodon.API.toggleTestingDonations() | ||
case .useGroupedNotifications: | ||
UserDefaults.standard.set(!testGroupedNotifications, forKey: setting.userDefaultsKey) | ||
case .clearPreviousDonationCampaigns: | ||
assertionFailure("this is an action, not a setting") | ||
break | ||
} | ||
return BetaTestSettingsViewModel() | ||
} | ||
} | ||
|
||
enum BetaTestSettingsSectionType: Hashable { | ||
case donations | ||
case notifications | ||
|
||
var sectionTitle: String { | ||
switch self { | ||
case .donations: | ||
return "Donations" | ||
case .notifications: | ||
return "Notifications" | ||
} | ||
} | ||
} | ||
|
||
enum BetaTestSetting: Hashable { | ||
case useStagingForDonations | ||
case clearPreviousDonationCampaigns | ||
case useGroupedNotifications | ||
|
||
var labelText: String { | ||
switch self { | ||
case .useStagingForDonations: | ||
return "Donations use test endpoint" | ||
case .clearPreviousDonationCampaigns: | ||
return "Clear donation history" | ||
case .useGroupedNotifications: | ||
return "Test grouped notifications" | ||
} | ||
} | ||
|
||
var userDefaultsKey: String { | ||
switch self { | ||
case .useGroupedNotifications: | ||
return "use_grouped_notifications" | ||
case .useStagingForDonations, .clearPreviousDonationCampaigns: | ||
return "UNEXPECTED_KEY" | ||
} | ||
} | ||
} | ||
|
||
fileprivate typealias BasicCell = UITableViewCell | ||
fileprivate let basicCellReuseIdentifier = "basic_cell" | ||
|
||
class BetaTestSettingsViewController: UIViewController { | ||
|
||
let tableView: UITableView | ||
|
||
var tableViewDataSource: BetaTestSettingsDiffableTableViewDataSource? | ||
|
||
private var viewModel: BetaTestSettingsViewModel { | ||
didSet { | ||
loadFromViewModel(animated: true) | ||
} | ||
} | ||
|
||
init() { | ||
tableView = UITableView(frame: .zero, style: .insetGrouped) | ||
tableView.translatesAutoresizingMaskIntoConstraints = false | ||
tableView.register(BasicCell.self, forCellReuseIdentifier: basicCellReuseIdentifier) | ||
tableView.register(ToggleTableViewCell.self, forCellReuseIdentifier: ToggleTableViewCell.reuseIdentifier) | ||
|
||
viewModel = BetaTestSettingsViewModel() | ||
|
||
super.init(nibName: nil, bundle: nil) | ||
|
||
tableView.delegate = self | ||
|
||
let tableViewDataSource = BetaTestSettingsDiffableTableViewDataSource(tableView: tableView, cellProvider: { [weak self] tableView, indexPath, itemIdentifier in | ||
guard let self else { return nil } | ||
switch itemIdentifier { | ||
case .useStagingForDonations: | ||
guard let selectionCell = tableView.dequeueReusableCell(withIdentifier: ToggleTableViewCell.reuseIdentifier, for: indexPath) as? ToggleTableViewCell else { assertionFailure("unexpected cell type"); return nil } | ||
selectionCell.label.text = itemIdentifier.labelText | ||
selectionCell.toggle.isOn = self.viewModel.useStagingForDonations | ||
selectionCell.toggle.removeTarget(self, action: nil, for: .valueChanged) | ||
selectionCell.toggle.addTarget(self, action: #selector(didToggleDonationsStaging), for: .valueChanged) | ||
return selectionCell | ||
case .clearPreviousDonationCampaigns: | ||
let cell = tableView.dequeueReusableCell(withIdentifier: basicCellReuseIdentifier, for: indexPath) | ||
cell.textLabel?.text = itemIdentifier.labelText | ||
cell.textLabel?.textColor = .red | ||
return cell | ||
case .useGroupedNotifications: | ||
guard let selectionCell = tableView.dequeueReusableCell(withIdentifier: ToggleTableViewCell.reuseIdentifier, for: indexPath) as? ToggleTableViewCell else { assertionFailure("unexpected cell type"); return nil } | ||
selectionCell.label.text = itemIdentifier.labelText | ||
selectionCell.toggle.isOn = self.viewModel.testGroupedNotifications | ||
selectionCell.toggle.removeTarget(self, action: nil, for: .valueChanged) | ||
selectionCell.toggle.addTarget(self, action: #selector(didToggleGroupedNotifications), for: .valueChanged) | ||
return selectionCell | ||
} | ||
}) | ||
|
||
tableView.dataSource = tableViewDataSource | ||
self.tableViewDataSource = tableViewDataSource | ||
|
||
view.backgroundColor = .systemGroupedBackground | ||
view.addSubview(tableView) | ||
tableView.pinTo(to: view) | ||
|
||
title = "Beta Test Settings" | ||
} | ||
|
||
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } | ||
|
||
override func viewDidLoad() { | ||
super.viewDidLoad() | ||
loadFromViewModel(animated: false) | ||
} | ||
|
||
@objc func didToggleDonationsStaging(_ sender: UISwitch) { | ||
viewModel = viewModel.byToggling(.useStagingForDonations) | ||
} | ||
@objc func didToggleGroupedNotifications(_ sender: UISwitch) { | ||
viewModel = viewModel.byToggling(.useGroupedNotifications) | ||
} | ||
|
||
func loadFromViewModel(animated: Bool = true) { | ||
var snapshot = NSDiffableDataSourceSnapshot<BetaTestSettingsSectionType, BetaTestSetting>() | ||
snapshot.appendSections([.donations, .notifications]) | ||
snapshot.appendItems([.useStagingForDonations], toSection: .donations) | ||
if viewModel.useStagingForDonations { | ||
snapshot.appendItems([.useStagingForDonations, .clearPreviousDonationCampaigns], toSection: .donations) | ||
} | ||
snapshot.appendItems([.useGroupedNotifications], toSection: .notifications) | ||
tableViewDataSource?.apply(snapshot, animatingDifferences: animated) | ||
} | ||
} | ||
|
||
extension BetaTestSettingsViewController: UITableViewDelegate { | ||
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { | ||
guard let identifier = tableViewDataSource?.itemIdentifier(for: indexPath) else { return } | ||
switch identifier { | ||
case .useStagingForDonations, .useGroupedNotifications: | ||
break | ||
case .clearPreviousDonationCampaigns: | ||
Mastodon.Entity.DonationCampaign.forgetPreviousCampaigns() | ||
DispatchQueue.main.async { | ||
self.tableView.deselectRow(at: indexPath, animated: true) | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters