Implement basic UI for notification-settings-screen (IOS-14)

No functionality (yet), but all relevant classes and protocols are there.
This commit is contained in:
Nathan Mattes 2023-06-30 11:45:58 +02:00
parent 24724b9943
commit a1d0c74617
9 changed files with 293 additions and 6 deletions

View File

@ -136,6 +136,7 @@
D81A22782AB4782400905D71 /* SearchResultOverviewSection.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81A22772AB4782400905D71 /* SearchResultOverviewSection.swift */; };
D81A227B2AB47B9A00905D71 /* SearchResultDefaultSectionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81A227A2AB47B9A00905D71 /* SearchResultDefaultSectionTableViewCell.swift */; };
D82BD7532ABC44C2009A374A /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8F9170E2A4B47EF008A5370 /* Coordinator.swift */; };
D81D12462A4E1861005009D4 /* PolicySelectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81D12452A4E1861005009D4 /* PolicySelectionViewController.swift */; };
D81D124B2A4E1914005009D4 /* ToggleTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D81D124A2A4E1914005009D4 /* ToggleTableViewCell.swift */; };
D8318A802A4466D300C0FB73 /* SettingsCoordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8318A7F2A4466D300C0FB73 /* SettingsCoordinator.swift */; };
D8318A862A4468C700C0FB73 /* SettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8318A852A4468C700C0FB73 /* SettingsViewController.swift */; };
@ -149,6 +150,10 @@
D886FBD329DF710F00272017 /* WelcomeSeparatorView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D886FBD229DF710F00272017 /* WelcomeSeparatorView.swift */; };
D8916DC029211BE500124085 /* ContentSizedTableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8916DBF29211BE500124085 /* ContentSizedTableView.swift */; };
D8A6AB6C291C5136003AB663 /* MastodonLoginViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8A6AB6B291C5136003AB663 /* MastodonLoginViewController.swift */; };
D8B5E4EE2A4EB8930008970C /* NotificationSettingTableViewToggleCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8B5E4ED2A4EB8920008970C /* NotificationSettingTableViewToggleCell.swift */; };
D8B5E4F02A4EB8A00008970C /* NotificationSettingTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8B5E4EF2A4EB8A00008970C /* NotificationSettingTableViewCell.swift */; };
D8B5E4F22A4EBCF90008970C /* NotificationSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8B5E4F12A4EBCF90008970C /* NotificationSettings.swift */; };
D8B5E4F42A4ED0240008970C /* NotificationSettingsViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8B5E4F32A4ED0240008970C /* NotificationSettingsViewModel.swift */; };
D8BE30B32A179E26006B8270 /* SuggestionAccountTableViewFooter.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8BE30B22A179E26006B8270 /* SuggestionAccountTableViewFooter.swift */; };
D8BEBCB62A1B7FFD0004F475 /* SuggestionAccountTableViewCell+ViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8BEBCB52A1B7FFD0004F475 /* SuggestionAccountTableViewCell+ViewModel.swift */; };
D8D688F62AB869CB000F651A /* SearchResultsProfileTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8D688F52AB869CB000F651A /* SearchResultsProfileTableViewCell.swift */; };
@ -787,6 +792,7 @@
D82463542A52B47B00A3DBDD /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = be; path = be.lproj/InfoPlist.strings; sourceTree = "<group>"; };
D82463552A52B47B00A3DBDD /* be */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; name = be; path = be.lproj/Intents.stringsdict; sourceTree = "<group>"; };
D82BD7512ABC42D6009A374A /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = "<group>"; };
D81D12452A4E1861005009D4 /* PolicySelectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolicySelectionViewController.swift; sourceTree = "<group>"; };
D81D124A2A4E1914005009D4 /* ToggleTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ToggleTableViewCell.swift; sourceTree = "<group>"; };
D8318A7F2A4466D300C0FB73 /* SettingsCoordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsCoordinator.swift; sourceTree = "<group>"; };
D8318A832A4468A800C0FB73 /* GeneralSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GeneralSettingsViewController.swift; sourceTree = "<group>"; };
@ -811,6 +817,10 @@
D8A6FE6429325F5900666A47 /* StringsConvertor */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = StringsConvertor; sourceTree = "<group>"; };
D8A6FE6529325F5900666A47 /* ios-infoPlist.json */ = {isa = PBXFileReference; lastKnownFileType = text.json; path = "ios-infoPlist.json"; sourceTree = "<group>"; };
D8A6FE6629325F5900666A47 /* Localizable.stringsdict */ = {isa = PBXFileReference; lastKnownFileType = text.plist.stringsdict; path = Localizable.stringsdict; sourceTree = "<group>"; };
D8B5E4ED2A4EB8920008970C /* NotificationSettingTableViewToggleCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NotificationSettingTableViewToggleCell.swift; sourceTree = "<group>"; };
D8B5E4EF2A4EB8A00008970C /* NotificationSettingTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingTableViewCell.swift; sourceTree = "<group>"; };
D8B5E4F12A4EBCF90008970C /* NotificationSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettings.swift; sourceTree = "<group>"; };
D8B5E4F32A4ED0240008970C /* NotificationSettingsViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationSettingsViewModel.swift; sourceTree = "<group>"; };
D8BE30B22A179E26006B8270 /* SuggestionAccountTableViewFooter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SuggestionAccountTableViewFooter.swift; sourceTree = "<group>"; };
D8BEBCB52A1B7FFD0004F475 /* SuggestionAccountTableViewCell+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SuggestionAccountTableViewCell+ViewModel.swift"; sourceTree = "<group>"; };
D8D688F52AB869CB000F651A /* SearchResultsProfileTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchResultsProfileTableViewCell.swift; sourceTree = "<group>"; };
@ -1755,10 +1765,10 @@
D81D12492A4E190A005009D4 /* Shared */,
D8F916FF2A4AD898008A5370 /* Settings Overview */,
D8F917042A4B0657008A5370 /* General Settings */,
D81D12432A4E181C005009D4 /* Notification Settings */,
D8F917092A4B2AFF008A5370 /* About Mastodon */,
D8318A7E2A4466C900C0FB73 /* Legacy */,
D8318A7F2A4466D300C0FB73 /* SettingsCoordinator.swift */,
D8318A872A4468D300C0FB73 /* NotificationSettingsViewController.swift */,
D8318A8B2A4468E600C0FB73 /* SupportMastodonViewController.swift */,
);
path = Settings;
@ -1835,6 +1845,19 @@
path = Cells;
sourceTree = "<group>";
};
D81D12432A4E181C005009D4 /* Notification Settings */ = {
isa = PBXGroup;
children = (
D8318A872A4468D300C0FB73 /* NotificationSettingsViewController.swift */,
D8B5E4ED2A4EB8920008970C /* NotificationSettingTableViewToggleCell.swift */,
D8B5E4EF2A4EB8A00008970C /* NotificationSettingTableViewCell.swift */,
D8B5E4F12A4EBCF90008970C /* NotificationSettings.swift */,
D8B5E4F32A4ED0240008970C /* NotificationSettingsViewModel.swift */,
D81D12452A4E1861005009D4 /* PolicySelectionViewController.swift */,
);
path = "Notification Settings";
sourceTree = "<group>";
};
D81D12492A4E190A005009D4 /* Shared */ = {
isa = PBXGroup;
children = (
@ -3658,6 +3681,7 @@
DB63F767279A5EB300455B82 /* NotificationTimelineViewModel.swift in Sources */,
2D607AD826242FC500B70763 /* NotificationViewModel.swift in Sources */,
DB5B54AB2833C12A00DEF8B2 /* RebloggedByViewController.swift in Sources */,
D81D12462A4E1861005009D4 /* PolicySelectionViewController.swift in Sources */,
DB848E33282B62A800A302CC /* ReportResultView.swift in Sources */,
DBABE3EC25ECAC4B00879EE5 /* WelcomeIllustrationView.swift in Sources */,
DB0FCB9C27980AB6006C02E2 /* HashtagTimelineViewController+DataSourceProvider.swift in Sources */,
@ -3708,6 +3732,7 @@
DB6180F426391D110018D199 /* MediaPreviewImageView.swift in Sources */,
DBF9814A265E24F500E4BA07 /* ProfileFieldCollectionViewHeaderFooterView.swift in Sources */,
2D939AB525EDD8A90076FA61 /* String.swift in Sources */,
D8B5E4F22A4EBCF90008970C /* NotificationSettings.swift in Sources */,
DB4481B925EE289600BEFB67 /* UITableView.swift in Sources */,
DB5B54B02833C24200DEF8B2 /* FavoritedByViewController+DataSourceProvider.swift in Sources */,
DBE3CDBB261C427900430CC6 /* TimelineHeaderTableViewCell.swift in Sources */,
@ -3739,6 +3764,7 @@
DB5B549D2833A67400DEF8B2 /* FamiliarFollowersViewModel.swift in Sources */,
DBB9759C262462E1004620BD /* ThreadMetaView.swift in Sources */,
DB5B729E273113F300081888 /* FollowingListViewModel+State.swift in Sources */,
D8B5E4F02A4EB8A00008970C /* NotificationSettingTableViewCell.swift in Sources */,
DBF9814C265E339500E4BA07 /* ProfileFieldAddEntryCollectionViewCell.swift in Sources */,
DB63F76227996B6600455B82 /* SearchHistoryViewController+DataSourceProvider.swift in Sources */,
DBA5E7AB263BD3F5004598BB /* TimelineTableViewCellContextMenuConfiguration.swift in Sources */,
@ -3921,6 +3947,7 @@
DB0FCB862796BDA1006C02E2 /* SearchSection.swift in Sources */,
DB1D61CF26F1B33600DA8662 /* WelcomeViewModel.swift in Sources */,
D8BEBCB62A1B7FFD0004F475 /* SuggestionAccountTableViewCell+ViewModel.swift in Sources */,
D8B5E4F42A4ED0240008970C /* NotificationSettingsViewModel.swift in Sources */,
DBD376B2269302A4007FEC24 /* UITableViewCell.swift in Sources */,
DB4F0966269ED52200D62E92 /* SearchResultViewModel.swift in Sources */,
D8F917142A4D74C3008A5370 /* GeneralSettingsDiffableTableViewDataSource.swift in Sources */,
@ -3960,6 +3987,7 @@
DBDFF19A28055A1400557A48 /* DiscoveryViewController.swift in Sources */,
DB9D6BFF25E4F5940051B173 /* ProfileViewController.swift in Sources */,
D8F917112A4C6B40008A5370 /* GeneralSettingToggleTableViewCell.swift in Sources */,
D8B5E4EE2A4EB8930008970C /* NotificationSettingTableViewToggleCell.swift in Sources */,
DB3EA8F1281B9EF600598866 /* DiscoveryCommunityViewModel+Diffable.swift in Sources */,
D8318A8A2A4468DC00C0FB73 /* AboutViewController.swift in Sources */,
85BC11B32932414900E191CD /* AltTextViewController.swift in Sources */,

View File

@ -0,0 +1,24 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
class NotificationSettingTableViewCell: UITableViewCell {
static let reuseIdentifier = "NotificationSettingTableViewCell"
func configure(with entry: NotificationSettingEntry, viewModel: NotificationSettingsViewModel) {
switch entry {
case.alert(_):
// we use toggle cells for these
break
case .policy:
var content = UIListContentConfiguration.valueCell()
//TODO: @zeitschlag Localization
content.text = "Get Notifications from"
content.secondaryText = viewModel.selectedPolicy.title
contentConfiguration = content
}
}
}

View File

@ -0,0 +1,37 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
protocol NotificationSettingToggleCellDelegate: AnyObject {
}
class NotificationSettingTableViewToggleCell: ToggleTableViewCell {
override class var reuseIdentifier: String {
return "NotificationSettingToggleCell"
}
var alert: NotificationAlert?
weak var delegate: NotificationSettingToggleCellDelegate?
override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
toggle.addTarget(self, action: #selector(NotificationSettingTableViewToggleCell.toggleValueChanged(_:)), for: .valueChanged)
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
func configure(with alert: NotificationAlert, viewModel: NotificationSettingsViewModel) {
self.alert = alert
label.text = alert.title
}
@objc
func toggleValueChanged(_ sender: UISwitch) {
}
}

View File

@ -0,0 +1,53 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import Foundation
struct NotificationSettingsSection: Hashable {
let entries: [NotificationSettingEntry]
}
enum NotificationSettingEntry: Hashable {
case policy
case alert(NotificationAlert)
}
enum NotificationPolicy: Hashable {
case anyone
case followers
case follow
case noone
var title: String {
switch self {
case .anyone:
return "Anyone"
case .followers:
return "People who follow you"
case .follow:
return "People you follow"
case .noone:
return "No one"
}
}
}
enum NotificationAlert: Hashable, CaseIterable {
case mentionsAndReplies
case boosts
case favorites
case newFollowers
var title: String {
switch self {
case .mentionsAndReplies:
return "Mentions & Replies"
case .boosts:
return "Boosts"
case .favorites:
return "Favorites"
case .newFollowers:
return "New Followers"
}
}
}

View File

@ -0,0 +1,103 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
protocol NotificationSettingsViewControllerDelegate: AnyObject {
func showPolicyList(_ viewController: UIViewController, viewModel: NotificationSettingsViewModel)
}
class NotificationSettingsViewController: UIViewController {
weak var delegate: NotificationSettingsViewControllerDelegate?
let tableView: UITableView
var tableViewDataSource: UITableViewDiffableDataSource<NotificationSettingsSection, NotificationSettingEntry>?
let sections: [NotificationSettingsSection]
var viewModel: NotificationSettingsViewModel
init() {
//TODO: @zeitschlag Read Settings
viewModel = NotificationSettingsViewModel(selectedPolicy: .follow)
sections = [
NotificationSettingsSection(entries: [
.policy
]),
NotificationSettingsSection(entries: NotificationAlert.allCases.map { NotificationSettingEntry.alert($0) } )
]
tableView = UITableView(frame: .zero, style: .insetGrouped)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.register(NotificationSettingTableViewCell.self, forCellReuseIdentifier: NotificationSettingTableViewCell.reuseIdentifier)
tableView.register(NotificationSettingTableViewToggleCell.self, forCellReuseIdentifier: NotificationSettingTableViewToggleCell.reuseIdentifier)
super.init(nibName: nil, bundle: nil)
let tableViewDataSource = UITableViewDiffableDataSource<NotificationSettingsSection, NotificationSettingEntry>(tableView: tableView) { [ weak self] tableView, indexPath, itemIdentifier in
let cell: UITableViewCell
switch itemIdentifier {
case .policy:
guard let self,
let notificationCell = tableView.dequeueReusableCell(withIdentifier: NotificationSettingTableViewCell.reuseIdentifier, for: indexPath) as? NotificationSettingTableViewCell else { fatalError("WTF Wrong cell!?") }
notificationCell.configure(with: .policy, viewModel: viewModel)
cell = notificationCell
case .alert(let alert):
guard let self,
let toggleCell = tableView.dequeueReusableCell(withIdentifier: NotificationSettingTableViewToggleCell.reuseIdentifier, for: indexPath) as? NotificationSettingTableViewToggleCell else { fatalError("WTF Wrong cell!?") }
toggleCell.configure(with: alert, viewModel: self.viewModel)
toggleCell.delegate = self
cell = toggleCell
}
return cell
}
tableView.dataSource = tableViewDataSource
tableView.delegate = self
self.tableViewDataSource = tableViewDataSource
view.backgroundColor = .systemGroupedBackground
view.addSubview(tableView)
tableView.pinToParent()
title = "Notifications"
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
override func viewDidLoad() {
super.viewDidLoad()
var snapshot = NSDiffableDataSourceSnapshot<NotificationSettingsSection, NotificationSettingEntry>()
for section in sections {
snapshot.appendSections([section])
snapshot.appendItems(section.entries)
}
tableViewDataSource?.apply(snapshot, animatingDifferences: false)
}
}
extension NotificationSettingsViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let entry = sections[indexPath.section].entries[indexPath.row]
if case let .policy = entry {
delegate?.showPolicyList(self, viewModel: viewModel)
}
tableView.deselectRow(at: indexPath, animated: true)
}
}
extension NotificationSettingsViewController: NotificationSettingToggleCellDelegate {
}

View File

@ -0,0 +1,7 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import Foundation
struct NotificationSettingsViewModel {
var selectedPolicy: NotificationPolicy
}

View File

@ -0,0 +1,21 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
protocol PolicySelectionViewControllerDelegate: AnyObject {
}
class PolicySelectionViewController: UIViewController {
weak var delegate: PolicySelectionViewControllerDelegate?
//TODO: TableView with SubscriptionAlerts/NotificationAlert
init(viewModel: NotificationSettingsViewModel) {
super.init(nibName: nil, bundle: nil)
view.backgroundColor = .systemGroupedBackground
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
}

View File

@ -1,3 +0,0 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import Foundation

View File

@ -52,8 +52,10 @@ extension SettingsCoordinator: SettingsViewControllerDelegate {
navigationController.pushViewController(generalSettingsViewController, animated: true)
case .notifications:
break
// show notifications
let notificationViewController = NotificationSettingsViewController()
notificationViewController.delegate = self
navigationController.pushViewController(notificationViewController, animated: true)
case .aboutMastodon:
let aboutViewController = AboutViewController()
aboutViewController.delegate = self
@ -111,3 +113,18 @@ extension SettingsCoordinator: GeneralSettingsViewControllerDelegate {
setting.update(preferredUsingDefaultBrowser: viewModel.selectedOpenLinks == .browser)
}
}
//MARK: - NotificationSettingsViewControllerDelegate
extension SettingsCoordinator: NotificationSettingsViewControllerDelegate {
func showPolicyList(_ viewController: UIViewController, viewModel: NotificationSettingsViewModel) {
let policyListViewController = PolicySelectionViewController(viewModel: viewModel)
policyListViewController.delegate = self
navigationController.pushViewController(policyListViewController, animated: true)
}
}
//MARK: - PolicySelectionViewControllerDelegate
extension SettingsCoordinator: PolicySelectionViewControllerDelegate {
}