Implement links on about-mastodon-screen (IOS-14)

This commit is contained in:
Nathan Mattes 2023-06-27 19:04:41 +02:00
parent de9bf24122
commit 921c97b2a7
11 changed files with 241 additions and 31 deletions

View File

@ -160,6 +160,8 @@
D8F8A03C29CA5CB6000195DD /* HashtagWidget.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8F8A03B29CA5CB6000195DD /* HashtagWidget.swift */; };
D8F917012A4AD8A5008A5370 /* SettingsTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8F917002A4AD8A4008A5370 /* SettingsTableViewCell.swift */; };
D8F917032A4B063D008A5370 /* Settings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8F917022A4B063D008A5370 /* Settings.swift */; };
D8F9170B2A4B2C80008A5370 /* AboutSettings.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8F9170A2A4B2C80008A5370 /* AboutSettings.swift */; };
D8F9170D2A4B3C6F008A5370 /* AboutMastodonTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8F9170C2A4B3C6F008A5370 /* AboutMastodonTableViewCell.swift */; };
D8F9170F2A4B47EF008A5370 /* Coordinator.swift in Sources */ = {isa = PBXBuildFile; fileRef = D8F9170E2A4B47EF008A5370 /* Coordinator.swift */; };
DB0009A626AEE5DC009B9D2D /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DB0009A926AEE5DC009B9D2D /* Intents.intentdefinition */; settings = {ATTRIBUTES = (codegen, ); }; };
DB0009A726AEE5DC009B9D2D /* Intents.intentdefinition in Sources */ = {isa = PBXBuildFile; fileRef = DB0009A926AEE5DC009B9D2D /* Intents.intentdefinition */; };
@ -814,6 +816,8 @@
D8F8A03B29CA5CB6000195DD /* HashtagWidget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = HashtagWidget.swift; sourceTree = "<group>"; };
D8F917002A4AD8A4008A5370 /* SettingsTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableViewCell.swift; sourceTree = "<group>"; };
D8F917022A4B063D008A5370 /* Settings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Settings.swift; sourceTree = "<group>"; };
D8F9170A2A4B2C80008A5370 /* AboutSettings.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutSettings.swift; sourceTree = "<group>"; };
D8F9170C2A4B3C6F008A5370 /* AboutMastodonTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AboutMastodonTableViewCell.swift; sourceTree = "<group>"; };
D8F9170E2A4B47EF008A5370 /* Coordinator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Coordinator.swift; sourceTree = "<group>"; };
DB0009A826AEE5DC009B9D2D /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.intentdefinition; name = Base; path = Base.lproj/Intents.intentdefinition; sourceTree = "<group>"; };
DB0009AD26AEE5E4009B9D2D /* ar */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = ar; path = ar.lproj/Intents.strings; sourceTree = "<group>"; };
@ -1738,12 +1742,12 @@
5B90C455262599800002E742 /* Settings */ = {
isa = PBXGroup;
children = (
D8F917092A4B2AFF008A5370 /* About Mastodon */,
D8F916FF2A4AD898008A5370 /* Settings Overview */,
D8318A7E2A4466C900C0FB73 /* Legacy */,
D8318A7F2A4466D300C0FB73 /* SettingsCoordinator.swift */,
D8318A832A4468A800C0FB73 /* GeneralSettingsViewController.swift */,
D8318A872A4468D300C0FB73 /* NotificationSettingsViewController.swift */,
D8318A892A4468DC00C0FB73 /* AboutViewController.swift */,
D8318A8B2A4468E600C0FB73 /* SupportMastodonViewController.swift */,
);
path = Settings;
@ -1888,6 +1892,16 @@
path = "Settings Overview";
sourceTree = "<group>";
};
D8F917092A4B2AFF008A5370 /* About Mastodon */ = {
isa = PBXGroup;
children = (
D8318A892A4468DC00C0FB73 /* AboutViewController.swift */,
D8F9170A2A4B2C80008A5370 /* AboutSettings.swift */,
D8F9170C2A4B3C6F008A5370 /* AboutMastodonTableViewCell.swift */,
);
path = "About Mastodon";
sourceTree = "<group>";
};
DB01409B25C40BB600F9F3CF /* Onboarding */ = {
isa = PBXGroup;
children = (
@ -3790,6 +3804,7 @@
DB0FCB942797E2B0006C02E2 /* SearchResultViewModel+Diffable.swift in Sources */,
DB63F752279944AA00455B82 /* SearchHistorySectionHeaderCollectionReusableView.swift in Sources */,
DB3E6FDD2806A40F00B035AE /* DiscoveryHashtagsViewController.swift in Sources */,
D8F9170B2A4B2C80008A5370 /* AboutSettings.swift in Sources */,
DB938EED2623F79B00E5B6C1 /* ThreadViewModel.swift in Sources */,
DB6988DE2848D11C002398EF /* PagerTabStripNavigateable.swift in Sources */,
2DCB73FD2615C13900EC03D4 /* SearchRecommendCollectionHeader.swift in Sources */,
@ -3825,6 +3840,7 @@
DBA5E7A9263BD3A4004598BB /* ContextMenuImagePreviewViewController.swift in Sources */,
DBF156E22702DA6900EC00B7 /* UIStatusBarManager+HandleTapAction.m in Sources */,
2D38F20825CD491300561493 /* DisposeBagCollectable.swift in Sources */,
D8F9170D2A4B3C6F008A5370 /* AboutMastodonTableViewCell.swift in Sources */,
DB697DE1278F5296004EF2F7 /* DataSourceFacade+Model.swift in Sources */,
DBCC3B8F26148F7B0045B23D /* CachedProfileViewModel.swift in Sources */,
DB4F097526A037F500D62E92 /* SearchHistoryViewModel.swift in Sources */,

View File

@ -31,6 +31,8 @@ final public class SceneCoordinator {
private(set) var secondaryStackHashValues = Set<Int>()
var childCoordinator: Coordinator?
private var mastodonAuthenticationController: MastodonAuthenticationController?
init(
scene: UIScene,
@ -542,7 +544,6 @@ private extension SceneCoordinator {
settingsCoordinator.start()
viewController = settingsCoordinator.navigationController
childCoordinator = settingsCoordinator
case .editStatus(let viewModel):
let composeViewController = ComposeViewController(viewModel: viewModel)
viewController = composeViewController
@ -595,10 +596,50 @@ extension SceneCoordinator: SettingsCoordinatorDelegate {
}
}
alertController.addAction(cancelAction)
alertController.addAction(signOutAction)
settingsCoordinator.navigationController.present(alertController, animated: true)
}
@MainActor
func openGithubURL(_ settingsCoordinator: SettingsCoordinator) {
guard let githubURL = URL(string: "https://github.com/mastodon/mastodon-ios") else { return }
_ = present(
scene: .safari(url: githubURL),
from: settingsCoordinator.navigationController,
transition: .safariPresent(animated: true)
)
}
@MainActor
func openPrivacyURL(_ settingsCoordinator: SettingsCoordinator) {
guard let authContext else { return }
let domain = authContext.mastodonAuthenticationBox.domain
let privacyURL = Mastodon.API.privacyURL(domain: domain)
_ = present(scene: .safari(url: privacyURL),
from: settingsCoordinator.navigationController,
transition: .safariPresent(animated: true))
}
func openProfileSettingsURL(_ settingsCoordinator: SettingsCoordinator) {
guard let authContext else { return }
let domain = authContext.mastodonAuthenticationBox.domain
let profileSettingsURL = Mastodon.API.profileSettingsURL(domain: domain)
let authenticationController = MastodonAuthenticationController(context: appContext, authenticateURL: profileSettingsURL)
authenticationController.authenticationSession?.presentationContextProvider = settingsCoordinator
authenticationController.authenticationSession?.start()
self.mastodonAuthenticationController = authenticationController
}
}

View File

@ -0,0 +1,18 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
import MastodonAsset
class AboutMastodonTableViewCell: UITableViewCell {
static let reuseIdentifier = "AboutMastodonTableViewCell"
func configure(with entry: AboutSettingsEntry) {
var contentConfiguration = UIListContentConfiguration.valueCell()
contentConfiguration.text = entry.text
contentConfiguration.secondaryText = entry.secondaryText
contentConfiguration.textProperties.color = Asset.Colors.Brand.blurple.color
self.contentConfiguration = contentConfiguration
}
}

View File

@ -0,0 +1,38 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import Foundation
import MastodonCore
struct AboutSettingsSection: Hashable {
let entries: [AboutSettingsEntry]
}
enum AboutSettingsEntry: Hashable {
case evenMoreSettings
case contributeToMastodon
case privacyPolicy
case clearMediaCache(Int)
var text: String {
switch self {
//TODO: @zeitschlag Add Localization
case .evenMoreSettings:
return "Even More Settings"
case .contributeToMastodon:
return "Contribute to Mastodon"
case .privacyPolicy:
return "Privacy Policy"
case .clearMediaCache(_):
return "Clear Media Storage"
}
}
var secondaryText: String? {
switch self {
case .evenMoreSettings, .contributeToMastodon, .privacyPolicy:
return nil
case .clearMediaCache(let mediaStorage):
return AppContext.byteCountFormatter.string(fromByteCount: Int64(mediaStorage))
}
}
}

View File

@ -0,0 +1,82 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
import MastodonCore
protocol AboutViewControllerDelegate: AnyObject {
func didSelect(_ viewController: AboutViewController, entry: AboutSettingsEntry)
}
class AboutViewController: UIViewController {
let tableView: UITableView
let sections: [AboutSettingsSection]
var tableViewDataSource: UITableViewDiffableDataSource<AboutSettingsSection, AboutSettingsEntry>?
weak var delegate: AboutViewControllerDelegate?
init() {
tableView = UITableView(frame: .zero, style: .insetGrouped)
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.register(AboutMastodonTableViewCell.self, forCellReuseIdentifier: AboutMastodonTableViewCell.reuseIdentifier)
sections = [
AboutSettingsSection(entries: [
.evenMoreSettings,
.contributeToMastodon,
.privacyPolicy
]),
AboutSettingsSection(entries: [
.clearMediaCache(AppContext.shared.currentDiskUsage())
])
]
super.init(nibName: nil, bundle: nil)
let tableViewDataSource = UITableViewDiffableDataSource<AboutSettingsSection, AboutSettingsEntry>(tableView: tableView) { [weak self] tableView, indexPath, itemIdentifier in
guard let self,
let cell = tableView.dequeueReusableCell(withIdentifier: AboutMastodonTableViewCell.reuseIdentifier, for: indexPath) as? AboutMastodonTableViewCell else { fatalError("WTF?? Wrong Cell dude!") }
let entry = sections[indexPath.section].entries[indexPath.row]
cell.configure(with: entry)
return cell
}
tableView.delegate = self
tableView.dataSource = tableViewDataSource
self.tableViewDataSource = tableViewDataSource
view.addSubview(tableView)
view.backgroundColor = .systemGroupedBackground
tableView.pinToParent()
}
required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") }
override func viewDidLoad() {
super.viewDidLoad()
var snapshot = NSDiffableDataSourceSnapshot<AboutSettingsSection, AboutSettingsEntry>()
for section in sections {
snapshot.appendSections([section])
snapshot.appendItems(section.entries)
}
tableViewDataSource?.apply(snapshot)
}
}
extension AboutViewController: UITableViewDelegate {
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let entry = sections[indexPath.section].entries[indexPath.row]
delegate?.didSelect(self, entry: entry)
tableView.deselectRow(at: indexPath, animated: true)
}
}

View File

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

View File

@ -314,24 +314,9 @@ extension SettingsViewController: UITableViewDelegate {
feedbackGenerator.impactOccurred()
switch link {
case .accountSettings:
let domain = viewModel.authContext.mastodonAuthenticationBox.domain
guard let url = URL(string: "https://\(domain)/auth/edit") else { return }
viewModel.openAuthenticationPage(authenticateURL: url, presentationContextProvider: self)
case .github:
guard let url = URL(string: "https://github.com/mastodon/mastodon-ios") else { break }
_ = coordinator.present(
scene: .safari(url: url),
from: self,
transition: .safariPresent(animated: true, completion: nil)
)
case .termsOfService, .privacyPolicy:
// same URL
guard let url = viewModel.privacyURL else { break }
_ = coordinator.present(
scene: .safari(url: url),
from: self,
transition: .safariPresent(animated: true, completion: nil)
)
case .clearMediaCache:
context.purgeCache()
.receive(on: RunLoop.main)

View File

@ -41,11 +41,6 @@ class SettingsViewModel {
/// - change switch for specified alerts
let updateSubscriptionSubject = PassthroughSubject<(triggerBy: String, values: [Bool?]), Never>()
lazy var privacyURL: URL? = {
let domain = authContext.mastodonAuthenticationBox.domain
return Mastodon.API.privacyURL(domain: domain)
}()
init(context: AppContext, authContext: AuthContext, setting: Setting) {
self.context = context
self.authContext = authContext

View File

@ -1,12 +1,16 @@
// Copyright © 2023 Mastodon gGmbH. All rights reserved.
import UIKit
import AuthenticationServices
protocol SettingsCoordinatorDelegate: AnyObject {
func logout(_ settingsCoordinator: SettingsCoordinator)
func openGithubURL(_ settingsCoordinator: SettingsCoordinator)
func openPrivacyURL(_ settingsCoordinator: SettingsCoordinator)
func openProfileSettingsURL(_ settingsCoordinator: SettingsCoordinator)
}
class SettingsCoordinator: Coordinator {
class SettingsCoordinator: NSObject, Coordinator {
let navigationController: UINavigationController
let presentedOn: UIViewController
@ -15,11 +19,11 @@ class SettingsCoordinator: Coordinator {
private let settingsViewController: SettingsViewController
init(presentedOn: UIViewController) {
init(presentedOn: UIViewController, accountName: String) {
self.presentedOn = presentedOn
navigationController = UINavigationController()
settingsViewController = SettingsViewController(accountName: "born2jort")
settingsViewController = SettingsViewController(accountName: accountName)
}
func start() {
@ -44,8 +48,10 @@ extension SettingsCoordinator: SettingsViewControllerDelegate {
break
// show notifications
case .aboutMastodon:
break
// show about
let aboutViewController = AboutViewController()
aboutViewController.delegate = self
navigationController.pushViewController(aboutViewController, animated: true)
case .supportMastodon:
break
// present support-screen
@ -53,5 +59,27 @@ extension SettingsCoordinator: SettingsViewControllerDelegate {
delegate?.logout(self)
}
}
}
extension SettingsCoordinator: AboutViewControllerDelegate {
func didSelect(_ viewController: AboutViewController, entry: AboutSettingsEntry) {
switch entry {
case .evenMoreSettings:
delegate?.openProfileSettingsURL(self)
case .contributeToMastodon:
delegate?.openGithubURL(self)
case .privacyPolicy:
delegate?.openPrivacyURL(self)
case .clearMediaCache(_):
//TODO: appContext.purgeCache()
//FIXME: maybe we should inject an AppContext/AuthContext here instead of delegating everything to SceneCoordinator?
break
}
}
}
extension SettingsCoordinator: ASWebAuthenticationPresentationContextProviding {
func presentationAnchor(for session: ASWebAuthenticationSession) -> ASPresentationAnchor {
return navigationController.view.window!
}
}

View File

@ -136,6 +136,12 @@ extension AppContext {
.reduce(0, +)
.eraseToAnyPublisher()
}
public func currentDiskUsage() -> Int {
let alamoFireDiskBytes = ImageDownloader.defaultURLCache().currentDiskUsage
//TODO: Add temp directory files
return alamoFireDiskBytes
}
private static func purgeAlamofireImageCache() -> AnyPublisher<ByteCount, Never> {
Future<ByteCount, Never> { promise in

View File

@ -95,6 +95,10 @@ extension Mastodon.API {
public static func privacyURL(domain: String) -> URL {
return URL(string: "\(URL.httpScheme(domain: domain))://" + domain + "/terms")!
}
public static func profileSettingsURL(domain: String) -> URL {
return URL(string: "\(URL.httpScheme(domain: domain))://" + domain + "/auth/edit")!
}
}
extension Mastodon.API {