From b0886979e5a63c6d65d0271e818a5f0ed6918788 Mon Sep 17 00:00:00 2001 From: Nathan Mattes Date: Wed, 27 Sep 2023 18:02:59 +0200 Subject: [PATCH] Remove old settings --- Mastodon.xcodeproj/project.pbxproj | 45 -- ...ngsAppearanceTableViewCell+ViewModel.swift | 59 -- .../SettingsAppearanceTableViewCell.swift | 135 ----- .../Cell/SettingsLinkTableViewCell.swift | 35 -- .../Cell/SettingsToggleTableViewCell.swift | 75 --- .../Scene/Settings/Legacy/SettingsItem.swift | 112 ---- .../Settings/Legacy/SettingsSection.swift | 137 ----- .../Legacy/SettingsViewController.swift | 515 ------------------ .../Settings/Legacy/SettingsViewModel.swift | 159 ------ .../Settings/Legacy/View/AppearanceView.swift | 147 ----- .../Legacy/View/SettingsSectionHeader.swift | 67 --- 11 files changed, 1486 deletions(-) delete mode 100644 Mastodon/Scene/Settings/Legacy/Cell/SettingsAppearanceTableViewCell+ViewModel.swift delete mode 100644 Mastodon/Scene/Settings/Legacy/Cell/SettingsAppearanceTableViewCell.swift delete mode 100644 Mastodon/Scene/Settings/Legacy/Cell/SettingsLinkTableViewCell.swift delete mode 100644 Mastodon/Scene/Settings/Legacy/Cell/SettingsToggleTableViewCell.swift delete mode 100644 Mastodon/Scene/Settings/Legacy/SettingsItem.swift delete mode 100644 Mastodon/Scene/Settings/Legacy/SettingsSection.swift delete mode 100644 Mastodon/Scene/Settings/Legacy/SettingsViewController.swift delete mode 100644 Mastodon/Scene/Settings/Legacy/SettingsViewModel.swift delete mode 100644 Mastodon/Scene/Settings/Legacy/View/AppearanceView.swift delete mode 100644 Mastodon/Scene/Settings/Legacy/View/SettingsSectionHeader.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index 7a3981c4f..5223ba6fd 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -397,7 +397,6 @@ DB98EB6227B215EB0082E365 /* ReportResultViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98EB6127B215EB0082E365 /* ReportResultViewController.swift */; }; DB98EB6527B216500082E365 /* ReportResultViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98EB6427B216500082E365 /* ReportResultViewModel.swift */; }; DB98EB6927B21A7C0082E365 /* ReportResultActionTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB98EB6827B21A7C0082E365 /* ReportResultActionTableViewCell.swift */; }; - DB9A486C26032AC1008B817C /* AttachmentContainerView+EmptyStateView.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9A486B26032AC1008B817C /* AttachmentContainerView+EmptyStateView.swift */; }; DB9D6BE925E4F5340051B173 /* SearchViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9D6BE825E4F5340051B173 /* SearchViewController.swift */; }; DB9D6BF825E4F5690051B173 /* NotificationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9D6BF725E4F5690051B173 /* NotificationViewController.swift */; }; DB9D6BFF25E4F5940051B173 /* ProfileViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DB9D6BFE25E4F5940051B173 /* ProfileViewController.swift */; }; @@ -730,11 +729,6 @@ 46DAB0EBDDFB678347CD96FF /* Pods-MastodonTests.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MastodonTests.asdk - release.xcconfig"; path = "Target Support Files/Pods-MastodonTests/Pods-MastodonTests.asdk - release.xcconfig"; sourceTree = ""; }; 5B24BBD7262DB14800A9381B /* ReportViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReportViewModel.swift; sourceTree = ""; }; 5B24BBD8262DB14800A9381B /* ReportStatusViewModel+Diffable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "ReportStatusViewModel+Diffable.swift"; sourceTree = ""; }; - 5B90C456262599800002E742 /* SettingsViewModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewModel.swift; sourceTree = ""; }; - 5B90C459262599800002E742 /* SettingsToggleTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsToggleTableViewCell.swift; sourceTree = ""; }; - 5B90C45A262599800002E742 /* SettingsAppearanceTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsAppearanceTableViewCell.swift; sourceTree = ""; }; - 5B90C45B262599800002E742 /* SettingsLinkTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsLinkTableViewCell.swift; sourceTree = ""; }; - 5B90C45C262599800002E742 /* SettingsSectionHeader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsSectionHeader.swift; sourceTree = ""; }; 5BB04FD4262E7AFF0043BFF6 /* ReportViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportViewController.swift; sourceTree = ""; }; 5BB04FF4262F0E6D0043BFF6 /* ReportSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportSection.swift; sourceTree = ""; }; 5CE45680252519F42FEA2D13 /* Pods-ShareActionExtension.asdk - release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ShareActionExtension.asdk - release.xcconfig"; path = "Target Support Files/Pods-ShareActionExtension/Pods-ShareActionExtension.asdk - release.xcconfig"; sourceTree = ""; }; @@ -938,7 +932,6 @@ DB427DF325BAA00100D1B89D /* MastodonUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MastodonUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; DB427DF725BAA00100D1B89D /* MastodonUITests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonUITests.swift; sourceTree = ""; }; DB427DF925BAA00100D1B89D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - DB443CD32694627B00159B29 /* AppearanceView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppearanceView.swift; sourceTree = ""; }; DB4481B825EE289600BEFB67 /* UITableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UITableView.swift; sourceTree = ""; }; DB45FAB525CA5485005A8AC7 /* UIAlertController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIAlertController.swift; sourceTree = ""; }; DB45FAD625CA6C76005A8AC7 /* UIBarButtonItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIBarButtonItem.swift; sourceTree = ""; }; @@ -1062,9 +1055,6 @@ DB6B74FF272FF73800C70B6E /* UserTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserTableViewCell.swift; sourceTree = ""; }; DB6B750327300B4000C70B6E /* TimelineFooterTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimelineFooterTableViewCell.swift; sourceTree = ""; }; DB6D9F3426351B7A008423CD /* NotificationService+Decrypt.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NotificationService+Decrypt.swift"; sourceTree = ""; }; - DB6D9F7C26358ED4008423CD /* SettingsSection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsSection.swift; sourceTree = ""; }; - DB6D9F8326358EEC008423CD /* SettingsItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsItem.swift; sourceTree = ""; }; - DB6D9F9626367249008423CD /* SettingsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SettingsViewController.swift; sourceTree = ""; }; DB72601B25E36A2100235243 /* MastodonServerRulesViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewController.swift; sourceTree = ""; }; DB72602625E36A6F00235243 /* MastodonServerRulesViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MastodonServerRulesViewModel.swift; sourceTree = ""; }; DB7274F3273BB9B200577D95 /* ListBatchFetchViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ListBatchFetchViewModel.swift; sourceTree = ""; }; @@ -1124,7 +1114,6 @@ DB98EB6127B215EB0082E365 /* ReportResultViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportResultViewController.swift; sourceTree = ""; }; DB98EB6427B216500082E365 /* ReportResultViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportResultViewModel.swift; sourceTree = ""; }; DB98EB6827B21A7C0082E365 /* ReportResultActionTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ReportResultActionTableViewCell.swift; sourceTree = ""; }; - DB98EB6A27B243470082E365 /* SettingsAppearanceTableViewCell+ViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "SettingsAppearanceTableViewCell+ViewModel.swift"; sourceTree = ""; }; DB9D6BE825E4F5340051B173 /* SearchViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SearchViewController.swift; sourceTree = ""; }; DB9D6BF725E4F5690051B173 /* NotificationViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NotificationViewController.swift; sourceTree = ""; }; DB9D6BFE25E4F5940051B173 /* ProfileViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProfileViewController.swift; sourceTree = ""; }; @@ -1768,32 +1757,11 @@ D8F917042A4B0657008A5370 /* General Settings */, D81D12432A4E181C005009D4 /* Notification Settings */, D8F917092A4B2AFF008A5370 /* About Mastodon */, - D8318A7E2A4466C900C0FB73 /* Legacy */, D8318A7F2A4466D300C0FB73 /* SettingsCoordinator.swift */, ); path = Settings; sourceTree = ""; }; - 5B90C457262599800002E742 /* View */ = { - isa = PBXGroup; - children = ( - 5B90C45C262599800002E742 /* SettingsSectionHeader.swift */, - DB443CD32694627B00159B29 /* AppearanceView.swift */, - ); - path = View; - sourceTree = ""; - }; - 5B90C458262599800002E742 /* Cell */ = { - isa = PBXGroup; - children = ( - 5B90C45A262599800002E742 /* SettingsAppearanceTableViewCell.swift */, - DB98EB6A27B243470082E365 /* SettingsAppearanceTableViewCell+ViewModel.swift */, - 5B90C459262599800002E742 /* SettingsToggleTableViewCell.swift */, - 5B90C45B262599800002E742 /* SettingsLinkTableViewCell.swift */, - ); - path = Cell; - sourceTree = ""; - }; 5D03938E2612D200007FE196 /* Webview */ = { isa = PBXGroup; children = ( @@ -1865,19 +1833,6 @@ path = Shared; sourceTree = ""; }; - D8318A7E2A4466C900C0FB73 /* Legacy */ = { - isa = PBXGroup; - children = ( - 5B90C458262599800002E742 /* Cell */, - 5B90C457262599800002E742 /* View */, - DB6D9F9626367249008423CD /* SettingsViewController.swift */, - 5B90C456262599800002E742 /* SettingsViewModel.swift */, - DB6D9F7C26358ED4008423CD /* SettingsSection.swift */, - DB6D9F8326358EEC008423CD /* SettingsItem.swift */, - ); - path = Legacy; - sourceTree = ""; - }; D8A6AB68291C50F3003AB663 /* Login */ = { isa = PBXGroup; children = ( diff --git a/Mastodon/Scene/Settings/Legacy/Cell/SettingsAppearanceTableViewCell+ViewModel.swift b/Mastodon/Scene/Settings/Legacy/Cell/SettingsAppearanceTableViewCell+ViewModel.swift deleted file mode 100644 index dac7e69ac..000000000 --- a/Mastodon/Scene/Settings/Legacy/Cell/SettingsAppearanceTableViewCell+ViewModel.swift +++ /dev/null @@ -1,59 +0,0 @@ -// -// SettingsAppearanceTableViewCell+ViewModel.swift -// Mastodon -// -// Created by MainasuK on 2022-2-8. -// - -import UIKit -import Combine -import CoreDataStack - -extension SettingsAppearanceTableViewCell { - final class ViewModel: ObservableObject { - var disposeBag = Set() - private var observations = Set() - - // input - @Published public var customUserInterfaceStyle: UIUserInterfaceStyle = .unspecified - - // output - @Published public var appearanceMode: SettingsItem.AppearanceMode = .system - - init() { - UserDefaults.shared.observe(\.customUserInterfaceStyle, options: [.initial, .new]) { [weak self] defaults, _ in - guard let self = self else { return } - self.customUserInterfaceStyle = defaults.customUserInterfaceStyle - } - .store(in: &observations) - } - - public func prepareForReuse() { - // do nothing - } - } -} - -extension SettingsAppearanceTableViewCell.ViewModel { - func bind(cell: SettingsAppearanceTableViewCell) { - $customUserInterfaceStyle.removeDuplicates() - .receive(on: DispatchQueue.main) - .sink { customUserInterfaceStyle in - cell.appearanceViews.forEach { view in - view.selected = false - } - - switch customUserInterfaceStyle { - case .unspecified: - cell.systemAppearanceView.selected = true - case .dark: - cell.darkAppearanceView.selected = true - case .light: - cell.lightAppearanceView.selected = true - @unknown default: - assertionFailure() - } - } - .store(in: &disposeBag) - } -} diff --git a/Mastodon/Scene/Settings/Legacy/Cell/SettingsAppearanceTableViewCell.swift b/Mastodon/Scene/Settings/Legacy/Cell/SettingsAppearanceTableViewCell.swift deleted file mode 100644 index 3bed79d0d..000000000 --- a/Mastodon/Scene/Settings/Legacy/Cell/SettingsAppearanceTableViewCell.swift +++ /dev/null @@ -1,135 +0,0 @@ -// -// SettingsAppearanceTableViewCell.swift -// Mastodon -// -// Created by ihugo on 2021/4/8. -// - -import UIKit -import Combine -import MastodonAsset -import MastodonLocalization - -protocol SettingsAppearanceTableViewCellDelegate: AnyObject { - func settingsAppearanceTableViewCell(_ cell: SettingsAppearanceTableViewCell, didSelectAppearanceMode appearanceMode: SettingsItem.AppearanceMode) -} - -class SettingsAppearanceTableViewCell: UITableViewCell { - - var disposeBag = Set() - var observations = Set() - - static let spacing: CGFloat = 28 - - weak var delegate: SettingsAppearanceTableViewCellDelegate? - - public private(set) var viewModel = ViewModel() - - lazy var stackView: UIStackView = { - let view = UIStackView() - view.axis = .horizontal - view.distribution = .fillEqually - view.spacing = SettingsAppearanceTableViewCell.spacing - return view - }() - - let systemAppearanceView = AppearanceView( - image: Asset.Settings.automatic.image, - title: L10n.Scene.Settings.Section.Appearance.automatic - ) - let darkAppearanceView = AppearanceView( - image: Asset.Settings.dark.image, - title: L10n.Scene.Settings.Section.Appearance.dark - ) - let lightAppearanceView = AppearanceView( - image: Asset.Settings.light.image, - title: L10n.Scene.Settings.Section.Appearance.light - ) - - var appearanceViews: [AppearanceView] { - return [ - systemAppearanceView, - darkAppearanceView, - lightAppearanceView, - ] - } - - override func prepareForReuse() { - super.prepareForReuse() - - disposeBag.removeAll() - observations.removeAll() - viewModel.prepareForReuse() - } - - // MARK: - Methods - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - setupUI() - viewModel.bind(cell: self) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func layoutSubviews() { - super.layoutSubviews() - - // remove separator line in section of group tableview - for subview in self.subviews { - if subview != self.contentView && subview.frame.width == self.frame.width { - subview.removeFromSuperview() - } - } - - // remove grouped style table corner radius - layer.cornerRadius = 0 - } - -} - -extension SettingsAppearanceTableViewCell { - - // MARK: Private methods - private func setupUI() { - backgroundColor = .clear - selectionStyle = .none - - stackView.translatesAutoresizingMaskIntoConstraints = false - contentView.addSubview(stackView) - stackView.pinToParent() - - stackView.addArrangedSubview(systemAppearanceView) - stackView.addArrangedSubview(darkAppearanceView) - stackView.addArrangedSubview(lightAppearanceView) - - appearanceViews.forEach { view in - let tapGestureRecognizer = UITapGestureRecognizer.singleTapGestureRecognizer - view.addGestureRecognizer(tapGestureRecognizer) - tapGestureRecognizer.addTarget(self, action: #selector(SettingsAppearanceTableViewCell.appearanceViewDidPressed(_:))) - } - } - -} - -// MARK: - Actions -extension SettingsAppearanceTableViewCell { - @objc func appearanceViewDidPressed(_ sender: UITapGestureRecognizer) { - let mode: SettingsItem.AppearanceMode - - switch sender.view { - case systemAppearanceView: - mode = .system - case darkAppearanceView: - mode = .dark - case lightAppearanceView: - mode = .light - default: - assertionFailure() - return - } - - delegate?.settingsAppearanceTableViewCell(self, didSelectAppearanceMode: mode) - } -} diff --git a/Mastodon/Scene/Settings/Legacy/Cell/SettingsLinkTableViewCell.swift b/Mastodon/Scene/Settings/Legacy/Cell/SettingsLinkTableViewCell.swift deleted file mode 100644 index 7fdbf7f02..000000000 --- a/Mastodon/Scene/Settings/Legacy/Cell/SettingsLinkTableViewCell.swift +++ /dev/null @@ -1,35 +0,0 @@ -// -// SettingsLinkTableViewCell.swift -// Mastodon -// -// Created by ihugo on 2021/4/8. -// - -import UIKit - -class SettingsLinkTableViewCell: UITableViewCell { - - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - - selectionStyle = .none - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func setHighlighted(_ highlighted: Bool, animated: Bool) { - super.setHighlighted(highlighted, animated: animated) - textLabel?.alpha = highlighted ? 0.6 : 1.0 - } - -} - -// MARK: - Methods -extension SettingsLinkTableViewCell { - func update(with link: SettingsItem.Link) { - textLabel?.text = link.title - textLabel?.textColor = link.textColor - } -} diff --git a/Mastodon/Scene/Settings/Legacy/Cell/SettingsToggleTableViewCell.swift b/Mastodon/Scene/Settings/Legacy/Cell/SettingsToggleTableViewCell.swift deleted file mode 100644 index c5d5e84c1..000000000 --- a/Mastodon/Scene/Settings/Legacy/Cell/SettingsToggleTableViewCell.swift +++ /dev/null @@ -1,75 +0,0 @@ -// -// SettingsToggleTableViewCell.swift -// Mastodon -// -// Created by ihugo on 2021/4/8. -// - -import UIKit -import Combine -import MastodonAsset -import MastodonLocalization - -protocol SettingsToggleCellDelegate: AnyObject { - func settingsToggleCell(_ cell: SettingsToggleTableViewCell, switchValueDidChange switch: UISwitch) -} - -class SettingsToggleTableViewCell: UITableViewCell { - - var disposeBag = Set() - - private(set) lazy var switchButton: UISwitch = { - let view = UISwitch(frame:.zero) - view.onTintColor = Asset.Colors.Brand.blurple.color - return view - }() - - weak var delegate: SettingsToggleCellDelegate? - - override func prepareForReuse() { - super.prepareForReuse() - - disposeBag.removeAll() - } - - // MARK: - Methods - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: .default, reuseIdentifier: reuseIdentifier) - setupUI() - } - - required init?(coder: NSCoder) { - super.init(coder: coder) - setupUI() - } - - // MARK: Private methods - private func setupUI() { - selectionStyle = .none - accessoryView = switchButton - textLabel?.numberOfLines = 0 - - switchButton.addTarget(self, action: #selector(switchValueDidChange(sender:)), for: .valueChanged) - } - -} - -// MARK: - Actions -extension SettingsToggleTableViewCell { - - @objc private func switchValueDidChange(sender: UISwitch) { - guard let delegate = delegate else { return } - delegate.settingsToggleCell(self, switchValueDidChange: sender) - } - -} - -extension SettingsToggleTableViewCell { - - func update(enabled: Bool?) { - switchButton.isEnabled = enabled != nil - textLabel?.textColor = enabled != nil ? Asset.Colors.Label.primary.color : Asset.Colors.Label.secondary.color - switchButton.isOn = enabled ?? false - } - -} diff --git a/Mastodon/Scene/Settings/Legacy/SettingsItem.swift b/Mastodon/Scene/Settings/Legacy/SettingsItem.swift deleted file mode 100644 index b977bc9ad..000000000 --- a/Mastodon/Scene/Settings/Legacy/SettingsItem.swift +++ /dev/null @@ -1,112 +0,0 @@ -// -// SettingsItem.swift -// Mastodon -// -// Created by MainasuK Cirno on 2021-4-25. -// - -import UIKit -import CoreData -import CoreDataStack -import MastodonAsset -import MastodonLocalization - -enum SettingsItem { - case appearance(record: ManagedObjectRecord) - case preference(settingRecord: ManagedObjectRecord, preferenceType: PreferenceType) - case notification(settingRecord: ManagedObjectRecord, switchMode: NotificationSwitchMode) - case boringZone(item: Link) - case spicyZone(item: Link) - - enum AppearanceMode: String { - case system - case dark - case light - } - - enum NotificationSwitchMode: CaseIterable, Hashable { - case favorite - case follow - case reblog - case mention - - var title: String { - switch self { - case .favorite: return L10n.Scene.Settings.Section.Notifications.favorites - case .follow: return L10n.Scene.Settings.Section.Notifications.follows - case .reblog: return L10n.Scene.Settings.Section.Notifications.boosts - case .mention: return L10n.Scene.Settings.Section.Notifications.mentions - } - } - } - - enum PreferenceType: CaseIterable { - case disableAvatarAnimation - case disableEmojiAnimation - case useDefaultBrowser - - var title: String { - switch self { - case .disableAvatarAnimation: return L10n.Scene.Settings.Section.Preference.disableAvatarAnimation - case .disableEmojiAnimation: return L10n.Scene.Settings.Section.Preference.disableEmojiAnimation - case .useDefaultBrowser: return L10n.Scene.Settings.Section.Preference.usingDefaultBrowser - } - } - } - - enum Link: CaseIterable, Hashable { - case accountSettings - case github - case termsOfService - case privacyPolicy - case clearMediaCache - case signOut - - var title: String { - switch self { - case .accountSettings: return L10n.Scene.Settings.Section.BoringZone.accountSettings - case .github: return "GitHub" - case .termsOfService: return L10n.Scene.Settings.Section.BoringZone.terms - case .privacyPolicy: return L10n.Scene.Settings.Section.BoringZone.privacy - case .clearMediaCache: return L10n.Scene.Settings.Section.SpicyZone.clear - case .signOut: return L10n.Scene.Settings.Section.SpicyZone.signout - } - } - - var textColor: UIColor? { - switch self { - case .accountSettings: return nil // tintColor - case .github: return nil - case .termsOfService: return nil - case .privacyPolicy: return nil - case .clearMediaCache: return .systemRed - case .signOut: return .systemRed - } - } - } - -} - -extension SettingsItem: Hashable { - func hash(into hasher: inout Hasher) { - switch self { - case .appearance(let record): - hasher.combine(String(describing: SettingsItem.AppearanceMode.self)) - hasher.combine(record) - case .notification(let settingObjectID, let switchMode): - hasher.combine(String(describing: SettingsItem.notification.self)) - hasher.combine(settingObjectID) - hasher.combine(switchMode) - case .preference(let settingObjectID, let preferenceType): - hasher.combine(String(describing: SettingsItem.preference.self)) - hasher.combine(settingObjectID) - hasher.combine(preferenceType) - case .boringZone(let link): - hasher.combine(String(describing: SettingsItem.boringZone.self)) - hasher.combine(link) - case .spicyZone(let link): - hasher.combine(String(describing: SettingsItem.spicyZone.self)) - hasher.combine(link) - } - } -} diff --git a/Mastodon/Scene/Settings/Legacy/SettingsSection.swift b/Mastodon/Scene/Settings/Legacy/SettingsSection.swift deleted file mode 100644 index f7c9884d9..000000000 --- a/Mastodon/Scene/Settings/Legacy/SettingsSection.swift +++ /dev/null @@ -1,137 +0,0 @@ -// -// SettingsSection.swift -// Mastodon -// -// Created by MainasuK Cirno on 2021-4-25. -// - -import UIKit -import CoreData -import CoreDataStack -import MastodonAsset -import MastodonCore -import MastodonLocalization - -enum SettingsSection: Hashable { - case appearance - case preference - case notifications - case boringZone - case spicyZone - - var title: String { - switch self { - case .appearance: return L10n.Scene.Settings.Section.LookAndFeel.title - case .preference: return "" - case .notifications: return L10n.Scene.Settings.Section.Notifications.title - case .boringZone: return L10n.Scene.Settings.Section.BoringZone.title - case .spicyZone: return L10n.Scene.Settings.Section.SpicyZone.title - } - } - - static func tableViewDiffableDataSource( - for tableView: UITableView, - managedObjectContext: NSManagedObjectContext, - settingsAppearanceTableViewCellDelegate: SettingsAppearanceTableViewCellDelegate, - settingsToggleCellDelegate: SettingsToggleCellDelegate - ) -> UITableViewDiffableDataSource { - UITableViewDiffableDataSource(tableView: tableView) { [ - weak settingsAppearanceTableViewCellDelegate, - weak settingsToggleCellDelegate - ] tableView, indexPath, item -> UITableViewCell? in - switch item { - case .appearance: - let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsAppearanceTableViewCell.self), for: indexPath) as! SettingsAppearanceTableViewCell - cell.delegate = settingsAppearanceTableViewCellDelegate - return cell - case .preference(let record, _): - let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsToggleTableViewCell.self), for: indexPath) as! SettingsToggleTableViewCell - cell.delegate = settingsToggleCellDelegate - managedObjectContext.performAndWait { - guard let setting = record.object(in: managedObjectContext) else { return } - SettingsSection.configureSettingToggle(cell: cell, item: item, setting: setting) - - ManagedObjectObserver.observe(object: setting) - .receive(on: DispatchQueue.main) - .sink(receiveCompletion: { _ in - // do nothing - }, receiveValue: { [weak cell] change in - guard let cell = cell else { return } - guard case .update(let object) = change.changeType, - let setting = object as? Setting else { return } - SettingsSection.configureSettingToggle(cell: cell, item: item, setting: setting) - }) - .store(in: &cell.disposeBag) - } - return cell - case .notification(let record, let switchMode): - let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsToggleTableViewCell.self), for: indexPath) as! SettingsToggleTableViewCell - managedObjectContext.performAndWait { - guard let setting = record.object(in: managedObjectContext) else { return } - if let subscription = setting.activeSubscription { - SettingsSection.configureSettingToggle(cell: cell, switchMode: switchMode, subscription: subscription) - } - ManagedObjectObserver.observe(object: setting) - .sink(receiveCompletion: { _ in - // do nothing - }, receiveValue: { [weak cell] change in - guard let cell = cell else { return } - guard case .update(let object) = change.changeType, - let setting = object as? Setting else { return } - guard let subscription = setting.activeSubscription else { return } - SettingsSection.configureSettingToggle(cell: cell, switchMode: switchMode, subscription: subscription) - }) - .store(in: &cell.disposeBag) - } - cell.delegate = settingsToggleCellDelegate - return cell - case .boringZone(let item), - .spicyZone(let item): - let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: SettingsLinkTableViewCell.self), for: indexPath) as! SettingsLinkTableViewCell - cell.update(with: item) - return cell - } // end switch - } - } - - public static func configureSettingToggle( - cell: SettingsToggleTableViewCell, - item: SettingsItem, - setting: Setting - ) { - switch item { - case .preference(_, let preferenceType): - cell.textLabel?.text = preferenceType.title - - switch preferenceType { - case .disableAvatarAnimation: - cell.switchButton.isOn = setting.preferredStaticAvatar - case .disableEmojiAnimation: - cell.switchButton.isOn = setting.preferredStaticEmoji - case .useDefaultBrowser: - cell.switchButton.isOn = setting.preferredUsingDefaultBrowser - } - - default: - assertionFailure() - } - } - - public static func configureSettingToggle( - cell: SettingsToggleTableViewCell, - switchMode: SettingsItem.NotificationSwitchMode, - subscription: NotificationSubscription - ) { - cell.textLabel?.text = switchMode.title - - let enabled: Bool? - switch switchMode { - case .favorite: enabled = subscription.alert.favourite - case .follow: enabled = subscription.alert.follow - case .reblog: enabled = subscription.alert.reblog - case .mention: enabled = subscription.alert.mention - } - cell.update(enabled: enabled) - } - -} diff --git a/Mastodon/Scene/Settings/Legacy/SettingsViewController.swift b/Mastodon/Scene/Settings/Legacy/SettingsViewController.swift deleted file mode 100644 index 6642d72b4..000000000 --- a/Mastodon/Scene/Settings/Legacy/SettingsViewController.swift +++ /dev/null @@ -1,515 +0,0 @@ -// -// SettingsViewController.swift -// Mastodon -// -// Created by ihugo on 2021/4/7. -// - -import UIKit -import Combine -import CoreData -import CoreDataStack -import AuthenticationServices -import MetaTextKit -import MastodonSDK -import MastodonMeta -import MastodonAsset -import MastodonCore -import MastodonUI -import MastodonLocalization - -class SettingsViewController: UIViewController, NeedsDependency { - - weak var context: AppContext! { willSet { precondition(!isViewLoaded) } } - weak var coordinator: SceneCoordinator! { willSet { precondition(!isViewLoaded) } } - - var viewModel: SettingsViewModel! { willSet { precondition(!isViewLoaded) } } - var disposeBag = Set() - var notificationPolicySubscription: AnyCancellable? - - var triggerMenu: UIMenu { - let anyone = L10n.Scene.Settings.Section.Notifications.Trigger.anyone - let follower = L10n.Scene.Settings.Section.Notifications.Trigger.follower - let follow = L10n.Scene.Settings.Section.Notifications.Trigger.follow - let noOne = L10n.Scene.Settings.Section.Notifications.Trigger.noone - let menu = UIMenu( - image: nil, - identifier: nil, - options: .displayInline, - children: [ - UIAction(title: anyone, image: UIImage(systemName: "person.3"), attributes: []) { [weak self] action in - self?.updateTrigger(policy: .all) - }, - UIAction(title: follower, image: UIImage(systemName: "person.crop.circle.badge.plus"), attributes: []) { [weak self] action in - self?.updateTrigger(policy: .follower) - }, - UIAction(title: follow, image: UIImage(systemName: "person.crop.circle.badge.checkmark"), attributes: []) { [weak self] action in - self?.updateTrigger(policy: .followed) - }, - UIAction(title: noOne, image: UIImage(systemName: "nosign"), attributes: []) { [weak self] action in - self?.updateTrigger(policy: .none) - }, - ] - ) - return menu - } - - private let notifySectionHeaderStackView: UIStackView = { - let view = UIStackView() - view.translatesAutoresizingMaskIntoConstraints = false - view.isLayoutMarginsRelativeArrangement = true - view.axis = .horizontal - view.spacing = 4 - return view - }() - - let notifyLabel = UILabel() - private(set) lazy var notifySectionHeader: UIView = { - let view = notifySectionHeaderStackView - - notifyLabel.translatesAutoresizingMaskIntoConstraints = false - notifyLabel.adjustsFontForContentSizeCategory = true - notifyLabel.font = UIFontMetrics(forTextStyle: .headline).scaledFont(for: UIFont.systemFont(ofSize: 20, weight: .semibold)) - notifyLabel.textColor = Asset.Colors.Label.primary.color - notifyLabel.text = L10n.Scene.Settings.Section.Notifications.Trigger.title - notifyLabel.adjustsFontSizeToFitWidth = true - notifyLabel.minimumScaleFactor = 0.5 - - view.addArrangedSubview(notifyLabel) - view.addArrangedSubview(whoButton) - whoButton.setContentHuggingPriority(.defaultHigh + 1, for: .horizontal) - whoButton.setContentHuggingPriority(.defaultHigh + 1, for: .vertical) - - return view - }() - - private(set) lazy var whoButton: UIButton = { - let whoButton = UIButton(type: .roundedRect) - whoButton.menu = triggerMenu - whoButton.showsMenuAsPrimaryAction = true - whoButton.setBackgroundColor(Asset.Colors.battleshipGrey.color, for: .normal) - whoButton.setTitleColor(Asset.Colors.Label.primary.color, for: .normal) - whoButton.titleLabel?.adjustsFontForContentSizeCategory = true - whoButton.titleLabel?.font = UIFontMetrics(forTextStyle: .title3).scaledFont(for: UIFont.systemFont(ofSize: 20, weight: .semibold)) - whoButton.contentEdgeInsets = UIEdgeInsets(top: 5, left: 5, bottom: 5, right: 5) - whoButton.layer.cornerRadius = 10 - whoButton.clipsToBounds = true - whoButton.titleLabel?.adjustsFontSizeToFitWidth = true - whoButton.titleLabel?.minimumScaleFactor = 0.5 - return whoButton - }() - - private(set) lazy var tableView: UITableView = { - // init with a frame to fix a conflict ('UIView-Encapsulated-Layout-Width' UIStackView:0x7f8c2b6c0590.width == 0) - let tableView = UITableView(frame: CGRect(x: 0, y: 0, width: 320, height: 320), style: .insetGrouped) - tableView.translatesAutoresizingMaskIntoConstraints = false - tableView.delegate = self - tableView.rowHeight = UITableView.automaticDimension - tableView.backgroundColor = .clear - tableView.separatorColor = SystemTheme.separator - - tableView.register(SettingsAppearanceTableViewCell.self, forCellReuseIdentifier: String(describing: SettingsAppearanceTableViewCell.self)) - tableView.register(SettingsToggleTableViewCell.self, forCellReuseIdentifier: String(describing: SettingsToggleTableViewCell.self)) - tableView.register(SettingsLinkTableViewCell.self, forCellReuseIdentifier: String(describing: SettingsLinkTableViewCell.self)) - return tableView - }() - - let tableFooterLabel = MetaLabel(style: .settingTableFooter) - lazy var tableFooterView: UIView = { - // init with a frame to fix a conflict ('UIView-Encapsulated-Layout-Height' UIStackView:0x7ffe41e47da0.height == 0) - let view = UIStackView(frame: CGRect(x: 0, y: 0, width: 320, height: 320)) - view.isLayoutMarginsRelativeArrangement = true - view.layoutMargins = UIEdgeInsets(top: 20, left: 20, bottom: 20, right: 20) - view.axis = .vertical - view.alignment = .center - - // tableFooterLabel.linkDelegate = self - view.addArrangedSubview(tableFooterLabel) - return view - }() -} - -extension SettingsViewController { - - override func viewDidLoad() { - super.viewDidLoad() - - setupView() - bindViewModel() - - viewModel.viewDidLoad.send() - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - // make large title not collapsed - navigationController?.navigationBar.sizeToFit() - } - - override func viewDidLayoutSubviews() { - super.viewDidLayoutSubviews() - guard let footerView = self.tableView.tableFooterView else { - return - } - - let width = self.tableView.bounds.size.width - let size = footerView.systemLayoutSizeFitting(CGSize(width: width, height: UIView.layoutFittingCompressedSize.height)) - if footerView.frame.size.height != size.height { - footerView.frame.size.height = size.height - self.tableView.tableFooterView = footerView - } - } - - override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { - super.traitCollectionDidChange(previousTraitCollection) - - updateSectionHeaderStackViewLayout() - } - - - // MAKR: - Private methods - private func updateSectionHeaderStackViewLayout() { - // accessibility - if traitCollection.preferredContentSizeCategory < .accessibilityMedium { - notifySectionHeaderStackView.axis = .horizontal - notifyLabel.numberOfLines = 1 - } else { - notifySectionHeaderStackView.axis = .vertical - notifyLabel.numberOfLines = 0 - } - } - - private func bindViewModel() { - self.whoButton.setTitle(viewModel.setting.value.activeSubscription?.policy.title, for: .normal) - viewModel.setting - .sink { [weak self] setting in - guard let self = self else { return } - self.notificationPolicySubscription = ManagedObjectObserver.observe(object: setting) - .sink { _ in - // do nothing - } receiveValue: { [weak self] change in - guard let self = self else { return } - guard case let .update(object) = change.changeType, - let setting = object as? Setting else { return } - if let activeSubscription = setting.activeSubscription { - self.whoButton.setTitle(activeSubscription.policy.title, for: .normal) - } else { - // assertionFailure() - } - } - } - .store(in: &disposeBag) - - let footer = "Mastodon for iOS v\(UIApplication.appVersion()) (\(UIApplication.appBuild()))" - let metaContent = PlaintextMetaContent(string: footer) - tableFooterLabel.configure(content: metaContent) - } - - private func setupView() { - setupBackgroundColor() - - setupNavigation() - view.addSubview(tableView) - tableView.pinToParent() - setupTableView() - - updateSectionHeaderStackViewLayout() - } - - private func setupBackgroundColor() { - view.backgroundColor = UIColor(dynamicProvider: { traitCollection in - switch traitCollection.userInterfaceLevel { - case .elevated where traitCollection.userInterfaceStyle == .dark: - return SystemTheme.systemElevatedBackgroundColor - default: - return .secondarySystemBackground - } - }) - - tableView.separatorColor = SystemTheme.separator - } - - private func setupNavigation() { - navigationController?.navigationBar.prefersLargeTitles = true - navigationItem.rightBarButtonItem - = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.done, - target: self, - action: #selector(doneButtonDidClick)) - navigationItem.title = L10n.Scene.Settings.title - } - - private func setupTableView() { - viewModel.setupDiffableDataSource( - for: tableView, - settingsAppearanceTableViewCellDelegate: self, - settingsToggleCellDelegate: self - ) - tableView.tableFooterView = tableFooterView - } - - -} - -// Mark: - Actions -extension SettingsViewController { - @objc private func doneButtonDidClick() { - dismiss(animated: true, completion: nil) - } -} - -// MARK: - UITableViewDelegate -extension SettingsViewController: UITableViewDelegate { - - func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { - let sections = viewModel.dataSource.snapshot().sectionIdentifiers - guard section < sections.count else { return nil } - - let sectionIdentifier = sections[section] - - let header: SettingsSectionHeader - switch sectionIdentifier { - case .preference: - return UIView() - case .notifications: - header = SettingsSectionHeader( - frame: CGRect(x: 0, y: 0, width: 375, height: 66), - customView: notifySectionHeader) - header.update(title: sectionIdentifier.title) - default: - header = SettingsSectionHeader(frame: CGRect(x: 0, y: 0, width: 375, height: 66)) - header.update(title: sectionIdentifier.title) - } - header.preservesSuperviewLayoutMargins = true - - return header - } - - // remove the gap of table's footer - func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? { - return UIView() - } - - // remove the gap of table's footer - func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat { - return CGFloat.leastNonzeroMagnitude - } - - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - guard let dataSource = viewModel.dataSource else { return } - guard let item = dataSource.itemIdentifier(for: indexPath) else { return } - - switch item { - case .appearance: - // do nothing - break - case .notification: - // do nothing - break - case .preference: - // do nothing - break - case .boringZone(let link), .spicyZone(let link): - let feedbackGenerator = UIImpactFeedbackGenerator(style: .light) - feedbackGenerator.impactOccurred() - switch link { - case .accountSettings: - case .github: - case .termsOfService, .privacyPolicy: - // same URL - case .clearMediaCache: - context.purgeCache() - .receive(on: RunLoop.main) - .sink { [weak self] byteCount in - guard let self = self else { return } - let byteCountFormatted = AppContext.byteCountFormatter.string(fromByteCount: Int64(byteCount)) - let alertController = UIAlertController( - title: L10n.Common.Alerts.CleanCache.title, - message: L10n.Common.Alerts.CleanCache.message(byteCountFormatted), - preferredStyle: .alert - ) - let okAction = UIAlertAction(title: L10n.Common.Controls.Actions.ok, style: .default, handler: nil) - alertController.addAction(okAction) - _ = self.coordinator.present(scene: .alertController(alertController: alertController), from: nil, transition: .alertController(animated: true, completion: nil)) - } - .store(in: &disposeBag) - case .signOut: - feedbackGenerator.impactOccurred() - alertToSignOut() - } - } - } -} - -// Update setting into core data -extension SettingsViewController { - func updateTrigger(policy: Mastodon.API.Subscriptions.Policy) { - let objectID = self.viewModel.setting.value.objectID - let managedObjectContext = context.backgroundManagedObjectContext - - managedObjectContext.performChanges { - let setting = managedObjectContext.object(with: objectID) as! Setting - let (subscription, _) = APIService.CoreData.createOrFetchSubscription( - into: managedObjectContext, - setting: setting, - policy: policy - ) - let now = Date() - subscription.update(activedAt: now) - setting.didUpdate(at: now) - } - .sink { _ in - // do nothing - } receiveValue: { _ in - // do nothing - } - .store(in: &disposeBag) - } -} - -// MARK: - SettingsAppearanceTableViewCellDelegate -extension SettingsViewController: SettingsAppearanceTableViewCellDelegate { - func settingsAppearanceTableViewCell( - _ cell: SettingsAppearanceTableViewCell, - didSelectAppearanceMode appearanceMode: SettingsItem.AppearanceMode - ) { - guard let dataSource = viewModel.dataSource else { return } - guard let indexPath = tableView.indexPath(for: cell) else { return } - let item = dataSource.itemIdentifier(for: indexPath) - guard case .appearance = item else { return } - - Task { @MainActor in - switch appearanceMode { - case .system: - UserDefaults.shared.customUserInterfaceStyle = .unspecified - case .dark: - UserDefaults.shared.customUserInterfaceStyle = .dark - case .light: - UserDefaults.shared.customUserInterfaceStyle = .light - } - - let feedbackGenerator = UIImpactFeedbackGenerator(style: .light) - feedbackGenerator.impactOccurred() - } // end Task - } - -} - -extension SettingsViewController: SettingsToggleCellDelegate { - func settingsToggleCell(_ cell: SettingsToggleTableViewCell, switchValueDidChange switch: UISwitch) { - guard let dataSource = viewModel.dataSource else { return } - guard let indexPath = tableView.indexPath(for: cell) else { return } - - let isOn = `switch`.isOn - let item = dataSource.itemIdentifier(for: indexPath) - - switch item { - case .notification(let record, let switchMode): - let managedObjectContext = context.backgroundManagedObjectContext - managedObjectContext.performChanges { - guard let setting = record.object(in: managedObjectContext) else { return } - guard let subscription = setting.activeSubscription else { return } - let alert = subscription.alert - switch switchMode { - case .favorite: alert.update(favourite: isOn) - case .follow: alert.update(follow: isOn) - case .reblog: alert.update(reblog: isOn) - case .mention: alert.update(mention: isOn) - } - // trigger setting update - alert.subscription.setting?.didUpdate(at: Date()) - } - .sink { _ in - // do nothing - } - .store(in: &disposeBag) - case .preference(let record, let preferenceType): - let managedObjectContext = context.backgroundManagedObjectContext - managedObjectContext.performChanges { - guard let setting = record.object(in: managedObjectContext) else { return } - switch preferenceType { - case .disableAvatarAnimation: - setting.update(preferredStaticAvatar: isOn) - case .disableEmojiAnimation: - setting.update(preferredStaticEmoji: isOn) - case .useDefaultBrowser: - setting.update(preferredUsingDefaultBrowser: isOn) - } - } - .sink { result in - switch result { - case .success: - switch preferenceType { - case .disableAvatarAnimation: - UserDefaults.shared.preferredStaticAvatar = isOn - case .disableEmojiAnimation: - UserDefaults.shared.preferredStaticEmoji = isOn - case .useDefaultBrowser: - UserDefaults.shared.preferredUsingDefaultBrowser = isOn - } - case .failure(let error): - assertionFailure(error.localizedDescription) - break - } - } - .store(in: &disposeBag) - default: - assertionFailure() - break - } - } -} - -// MARK: - MetaLabelDelegate -extension SettingsViewController: MetaLabelDelegate { - func metaLabel(_ metaLabel: MetaLabel, didSelectMeta meta: Meta) { - switch meta { - case .url(_, _, let url, _): - guard let url = URL(string: url) else { return } - _ = coordinator.present(scene: .safari(url: url), from: self, transition: .safariPresent(animated: true, completion: nil)) - default: - assertionFailure() - } - } -} - -// MARK: - ASAuthorizationControllerPresentationContextProviding -extension SettingsViewController: ASWebAuthenticationPresentationContextProviding { - func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor { - return view.window! - } -} - -// MARK: - UIAdaptivePresentationControllerDelegate -extension SettingsViewController: UIAdaptivePresentationControllerDelegate { - func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle { - return .pageSheet - } -} - -extension SettingsViewController { - - var closeKeyCommand: UIKeyCommand { - UIKeyCommand( - title: L10n.Scene.Settings.Keyboard.closeSettingsWindow, - image: nil, - action: #selector(SettingsViewController.closeSettingsWindowKeyCommandHandler(_:)), - input: "w", - modifierFlags: .command, - propertyList: nil, - alternates: [], - discoverabilityTitle: nil, - attributes: [], - state: .off - ) - } - - override var keyCommands: [UIKeyCommand]? { - return [closeKeyCommand] - } - - @objc private func closeSettingsWindowKeyCommandHandler(_ sender: UIKeyCommand) { - dismiss(animated: true, completion: nil) - } - -} diff --git a/Mastodon/Scene/Settings/Legacy/SettingsViewModel.swift b/Mastodon/Scene/Settings/Legacy/SettingsViewModel.swift deleted file mode 100644 index 6698dd535..000000000 --- a/Mastodon/Scene/Settings/Legacy/SettingsViewModel.swift +++ /dev/null @@ -1,159 +0,0 @@ -// -// SettingsViewModel.swift -// Mastodon -// -// Created by ihugo on 2021/4/7. -// - -import Combine -import CoreData -import CoreDataStack -import Foundation -import MastodonSDK -import UIKit -import AuthenticationServices -import MastodonCore - -class SettingsViewModel { - - var disposeBag = Set() - - // input - let context: AppContext - let authContext: AuthContext - var mastodonAuthenticationController: MastodonAuthenticationController? - - let setting: CurrentValueSubject - var updateDisposeBag = Set() - var createDisposeBag = Set() - - let viewDidLoad = PassthroughSubject() - - // output - var dataSource: UITableViewDiffableDataSource! - /// create a subscription when: - /// - does not has one - /// - does not find subscription for selected trigger when change trigger - let createSubscriptionSubject = PassthroughSubject<(triggerBy: String, values: [Bool?]), Never>() - let currentInstance = CurrentValueSubject(nil) - - /// update a subscription when: - /// - change switch for specified alerts - let updateSubscriptionSubject = PassthroughSubject<(triggerBy: String, values: [Bool?]), Never>() - - init(context: AppContext, authContext: AuthContext, setting: Setting) { - self.context = context - self.authContext = authContext - self.setting = CurrentValueSubject(setting) - - self.setting - .sink(receiveValue: { [weak self] setting in - guard let self = self else { return } - self.processDataSource(setting) - }) - .store(in: &disposeBag) - - context.apiService.instance(domain: authContext.mastodonAuthenticationBox.domain) - .sink { [weak self] completion in - guard let self = self else { return } - switch completion { - case .failure(_): - self.currentInstance.value = nil - case .finished: - break - } - } receiveValue: { [weak self] response in - guard let self = self else { return } - self.currentInstance.value = response.value - } - .store(in: &disposeBag) - } -} - -extension SettingsViewModel { - - func openAuthenticationPage( - authenticateURL: URL, - presentationContextProvider: ASWebAuthenticationPresentationContextProviding - ) { - let authenticationController = MastodonAuthenticationController( - context: self.context, - authenticateURL: authenticateURL - ) - - self.mastodonAuthenticationController = authenticationController - authenticationController.authenticationSession?.presentationContextProvider = presentationContextProvider - authenticationController.authenticationSession?.start() - } - - // MARK: - Private methods - private func processDataSource(_ setting: Setting) { - guard let dataSource = self.dataSource else { return } - var snapshot = NSDiffableDataSourceSnapshot() - - // appearance - let appearanceItems = [ - SettingsItem.appearance(record: .init(objectID: setting.objectID)) - ] - snapshot.appendSections([.appearance]) - snapshot.appendItems(appearanceItems, toSection: .appearance) - - // preference - snapshot.appendSections([.preference]) - let preferenceItems: [SettingsItem] = SettingsItem.PreferenceType.allCases.map { preferenceType in - SettingsItem.preference(settingRecord: .init(objectID: setting.objectID), preferenceType: preferenceType) - } - snapshot.appendItems(preferenceItems,toSection: .preference) - - // notification - let notificationItems = SettingsItem.NotificationSwitchMode.allCases.map { mode in - SettingsItem.notification(settingRecord: .init(objectID: setting.objectID), switchMode: mode) - } - snapshot.appendSections([.notifications]) - snapshot.appendItems(notificationItems, toSection: .notifications) - - // boring zone - let boringZoneSettingsItems: [SettingsItem] = { - let links: [SettingsItem.Link] = [ - .accountSettings, - .github, - .termsOfService, - .privacyPolicy - ] - let items = links.map { SettingsItem.boringZone(item: $0) } - return items - }() - snapshot.appendSections([.boringZone]) - snapshot.appendItems(boringZoneSettingsItems, toSection: .boringZone) - - let spicyZoneSettingsItems: [SettingsItem] = { - let links: [SettingsItem.Link] = [ - .clearMediaCache, - .signOut - ] - let items = links.map { SettingsItem.spicyZone(item: $0) } - return items - }() - snapshot.appendSections([.spicyZone]) - snapshot.appendItems(spicyZoneSettingsItems, toSection: .spicyZone) - - dataSource.apply(snapshot, animatingDifferences: false) - } - -} - -extension SettingsViewModel { - func setupDiffableDataSource( - for tableView: UITableView, - settingsAppearanceTableViewCellDelegate: SettingsAppearanceTableViewCellDelegate, - settingsToggleCellDelegate: SettingsToggleCellDelegate - ) { - dataSource = SettingsSection.tableViewDiffableDataSource( - for: tableView, - managedObjectContext: context.managedObjectContext, - settingsAppearanceTableViewCellDelegate: settingsAppearanceTableViewCellDelegate, - settingsToggleCellDelegate: settingsToggleCellDelegate - ) - processDataSource(self.setting.value) - } -} diff --git a/Mastodon/Scene/Settings/Legacy/View/AppearanceView.swift b/Mastodon/Scene/Settings/Legacy/View/AppearanceView.swift deleted file mode 100644 index a09401537..000000000 --- a/Mastodon/Scene/Settings/Legacy/View/AppearanceView.swift +++ /dev/null @@ -1,147 +0,0 @@ -// -// AppearanceView.swift -// Mastodon -// -// Created by MainasuK Cirno on 2021-7-6. -// - -import UIKit -import MastodonAsset -import MastodonLocalization -import MastodonUI - -class AppearanceView: UIView { - - let imageViewShadowBackgroundContainer = ShadowBackgroundContainer() - lazy var imageView: UIImageView = { - let view = UIImageView() - view.contentMode = .scaleAspectFill - view.layer.masksToBounds = true - view.layer.cornerRadius = 4 - view.layer.cornerCurve = .continuous - // accessibility - view.accessibilityIgnoresInvertColors = true - return view - }() - - lazy var titleLabel: UILabel = { - let label = UILabel() - label.font = .systemFont(ofSize: 12, weight: .regular) - label.textColor = Asset.Colors.Label.primary.color - label.textAlignment = .center - return label - }() - - lazy var checkmarkButton: UIButton = { - let button = UIButton() - button.isUserInteractionEnabled = false - button.setImage(UIImage(systemName: "circle"), for: .normal) - button.setImage(UIImage(systemName: "checkmark.circle.fill"), for: .selected) - button.imageView?.preferredSymbolConfiguration = UIImage.SymbolConfiguration(textStyle: .body) - button.imageView?.tintColor = Asset.Colors.Label.primary.color - button.imageView?.contentMode = .scaleAspectFill - return button - }() - - lazy var stackView: UIStackView = { - let view = UIStackView() - view.axis = .vertical - view.spacing = 8 - view.distribution = .equalSpacing - return view - }() - - var selected: Bool = false { - didSet { setNeedsLayout() } - } - - // MARK: - Methods - init(image: UIImage?, title: String) { - super.init(frame: .zero) - setupUI() - - imageView.image = image - titleLabel.text = title - } - - override var isAccessibilityElement: Bool { - get { return true } - set { } - - } - override var accessibilityLabel: String? { - get { titleLabel.text } - set { } - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} - -extension AppearanceView { - - private func setupUI() { - imageView.translatesAutoresizingMaskIntoConstraints = false - imageViewShadowBackgroundContainer.addSubview(imageView) - imageView.pinToParent() - imageViewShadowBackgroundContainer.cornerRadius = 4 - - stackView.addArrangedSubview(imageViewShadowBackgroundContainer) - stackView.addArrangedSubview(titleLabel) - stackView.addArrangedSubview(checkmarkButton) - - addSubview(stackView) - translatesAutoresizingMaskIntoConstraints = false - stackView.translatesAutoresizingMaskIntoConstraints = false - stackView.pinToParent() - NSLayoutConstraint.activate([ - imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor, multiplier: 121.0 / 100.0), // height / width - ]) - } - - private func configureForSelection() { - if selected { - accessibilityTraits.insert(.selected) - } else { - accessibilityTraits.remove(.selected) - } - - checkmarkButton.isSelected = selected - } - - override func layoutSubviews() { - super.layoutSubviews() - - configureForSelection() - } - - override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) { - super.traitCollectionDidChange(previousTraitCollection) - - setNeedsLayout() - } - -} - -extension AppearanceView { - override func touchesBegan(_ touches: Set, with event: UIEvent?) { - super.touchesBegan(touches, with: event) - self.alpha = 0.5 - } - - override func touchesEnded(_ touches: Set, with event: UIEvent?) { - super.touchesEnded(touches, with: event) - UIView.animate(withDuration: 0.33) { - self.alpha = 1 - } - } - - override func touchesCancelled(_ touches: Set, with event: UIEvent?) { - super.touchesCancelled(touches, with: event) - UIView.animate(withDuration: 0.33) { - self.alpha = 1 - } - } -} diff --git a/Mastodon/Scene/Settings/Legacy/View/SettingsSectionHeader.swift b/Mastodon/Scene/Settings/Legacy/View/SettingsSectionHeader.swift deleted file mode 100644 index 817dbf371..000000000 --- a/Mastodon/Scene/Settings/Legacy/View/SettingsSectionHeader.swift +++ /dev/null @@ -1,67 +0,0 @@ -// -// SettingsSectionHeader.swift -// Mastodon -// -// Created by ihugo on 2021/4/8. -// - -import UIKit -import MastodonAsset -import MastodonLocalization - -struct GroupedTableViewConstraints { - static let topMargin: CGFloat = 40 - static let bottomMargin: CGFloat = 10 -} - -/// section header which supports add a custom view blelow the title -class SettingsSectionHeader: UIView { - lazy var titleLabel: UILabel = { - let label = UILabel() - label.translatesAutoresizingMaskIntoConstraints = false - label.font = .systemFont(ofSize: 13, weight: .regular) - label.textColor = Asset.Colors.Label.secondary.color - return label - }() - - lazy var stackView: UIStackView = { - let view = UIStackView() - view.translatesAutoresizingMaskIntoConstraints = false - view.isLayoutMarginsRelativeArrangement = true - view.layoutMargins = UIEdgeInsets( - top: GroupedTableViewConstraints.topMargin, - left: 0, - bottom: GroupedTableViewConstraints.bottomMargin, - right: 0 - ) - view.axis = .vertical - return view - }() - - init(frame: CGRect, customView: UIView? = nil) { - super.init(frame: frame) - - backgroundColor = .clear - - stackView.addArrangedSubview(titleLabel) - if let view = customView { - stackView.addArrangedSubview(view) - } - - addSubview(stackView) - NSLayoutConstraint.activate([ - stackView.leadingAnchor.constraint(equalTo: self.readableContentGuide.leadingAnchor), - stackView.trailingAnchor.constraint(lessThanOrEqualTo: self.readableContentGuide.trailingAnchor), - stackView.bottomAnchor.constraint(equalTo: self.bottomAnchor), - stackView.topAnchor.constraint(equalTo: self.topAnchor), - ]) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func update(title: String?) { - titleLabel.text = title?.uppercased() - } -}