From cea13cb3de41f292192e68adce6e744b6ff907d7 Mon Sep 17 00:00:00 2001 From: Marcus Kida Date: Tue, 28 May 2024 17:13:25 +0200 Subject: [PATCH] Begin implementing PrivacySafetyViewController (IOS-168) --- Mastodon.xcodeproj/project.pbxproj | 16 +++++ .../PrivacySafetyViewController.swift | 67 +++++++++++++++++++ .../PrivacySafetyViewModel.swift | 11 +++ .../Scene/Settings/SettingsCoordinator.swift | 3 +- 4 files changed, 96 insertions(+), 1 deletion(-) create mode 100644 Mastodon/Scene/Settings/Privacy and Safety/PrivacySafetyViewController.swift create mode 100644 Mastodon/Scene/Settings/Privacy and Safety/PrivacySafetyViewModel.swift diff --git a/Mastodon.xcodeproj/project.pbxproj b/Mastodon.xcodeproj/project.pbxproj index ba1946d0f..e8c43475a 100644 --- a/Mastodon.xcodeproj/project.pbxproj +++ b/Mastodon.xcodeproj/project.pbxproj @@ -21,6 +21,8 @@ 0FB3D33825E6401400AAD544 /* PickServerCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0FB3D33725E6401400AAD544 /* PickServerCell.swift */; }; 164F0EBC267D4FE400249499 /* BoopSound.caf in Resources */ = {isa = PBXBuildFile; fileRef = 164F0EBB267D4FE400249499 /* BoopSound.caf */; }; 27D701F5292FC2D60031BCBB /* DataSourceFacade+URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 27D701F4292FC2D60031BCBB /* DataSourceFacade+URL.swift */; }; + 2A0BF97F2C0622AA004A1E29 /* PrivacySafetyViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A0BF97E2C0622AA004A1E29 /* PrivacySafetyViewController.swift */; }; + 2A0BF9812C06252A004A1E29 /* PrivacySafetyViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A0BF9802C06252A004A1E29 /* PrivacySafetyViewModel.swift */; }; 2A1BF99529F7E68400FA1BA5 /* DataSourceFacade+UserView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1BF99429F7E68400FA1BA5 /* DataSourceFacade+UserView.swift */; }; 2A1FE47C2938BB2600784BF1 /* FollowedTagsViewModel+DiffableDataSource.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1FE47B2938BB2600784BF1 /* FollowedTagsViewModel+DiffableDataSource.swift */; }; 2A1FE47E2938C11200784BF1 /* Collection+IsNotEmpty.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2A1FE47D2938C11200784BF1 /* Collection+IsNotEmpty.swift */; }; @@ -622,6 +624,8 @@ 0FB3D33725E6401400AAD544 /* PickServerCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PickServerCell.swift; sourceTree = ""; }; 164F0EBB267D4FE400249499 /* BoopSound.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = BoopSound.caf; sourceTree = ""; }; 27D701F4292FC2D60031BCBB /* DataSourceFacade+URL.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataSourceFacade+URL.swift"; sourceTree = ""; }; + 2A0BF97E2C0622AA004A1E29 /* PrivacySafetyViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySafetyViewController.swift; sourceTree = ""; }; + 2A0BF9802C06252A004A1E29 /* PrivacySafetyViewModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PrivacySafetyViewModel.swift; sourceTree = ""; }; 2A1BF99429F7E68400FA1BA5 /* DataSourceFacade+UserView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DataSourceFacade+UserView.swift"; sourceTree = ""; }; 2A1FE47B2938BB2600784BF1 /* FollowedTagsViewModel+DiffableDataSource.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "FollowedTagsViewModel+DiffableDataSource.swift"; sourceTree = ""; }; 2A1FE47D2938C11200784BF1 /* Collection+IsNotEmpty.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Collection+IsNotEmpty.swift"; sourceTree = ""; }; @@ -1372,6 +1376,15 @@ path = CollectionViewCell; sourceTree = ""; }; + 2A0BF97D2C062278004A1E29 /* Privacy and Safety */ = { + isa = PBXGroup; + children = ( + 2A0BF97E2C0622AA004A1E29 /* PrivacySafetyViewController.swift */, + 2A0BF9802C06252A004A1E29 /* PrivacySafetyViewModel.swift */, + ); + path = "Privacy and Safety"; + sourceTree = ""; + }; 2A506CF2292CD83B00059C37 /* FollowedTags */ = { isa = PBXGroup; children = ( @@ -1686,6 +1699,7 @@ D8F916FF2A4AD898008A5370 /* Settings Overview */, D8F917042A4B0657008A5370 /* General Settings */, D81D12432A4E181C005009D4 /* Notification Settings */, + 2A0BF97D2C062278004A1E29 /* Privacy and Safety */, D80911062AC4BFD100EB4D15 /* Server Details */, D8F917092A4B2AFF008A5370 /* About Mastodon */, D8318A7F2A4466D300C0FB73 /* SettingsCoordinator.swift */, @@ -3534,6 +3548,7 @@ 2DAC9E3E262FC2400062E1A6 /* SuggestionAccountViewModel.swift in Sources */, DB603113279EBEBA00A935FE /* DataSourceFacade+Block.swift in Sources */, DB63F777279A9A2A00455B82 /* NotificationView+Configuration.swift in Sources */, + 2A0BF9812C06252A004A1E29 /* PrivacySafetyViewModel.swift in Sources */, DB029E95266A20430062874E /* MastodonAuthenticationController.swift in Sources */, DB6180DD263918E30018D199 /* MediaPreviewViewController.swift in Sources */, DBE3CDEC261C6B2900430CC6 /* FavoriteViewController.swift in Sources */, @@ -3728,6 +3743,7 @@ D809907C294D25510050219F /* PrivacyViewModel.swift in Sources */, D8318A862A4468C700C0FB73 /* SettingsViewController.swift in Sources */, DB5B549A2833A60400DEF8B2 /* FamiliarFollowersViewController.swift in Sources */, + 2A0BF97F2C0622AA004A1E29 /* PrivacySafetyViewController.swift in Sources */, DB3E6FE22806A50100B035AE /* DiscoveryHashtagsViewModel+Diffable.swift in Sources */, DB427DD625BAA00100D1B89D /* AppDelegate.swift in Sources */, DB0FCB822796AC78006C02E2 /* UserTimelineViewController+DataSourceProvider.swift in Sources */, diff --git a/Mastodon/Scene/Settings/Privacy and Safety/PrivacySafetyViewController.swift b/Mastodon/Scene/Settings/Privacy and Safety/PrivacySafetyViewController.swift new file mode 100644 index 000000000..f6c0b2b95 --- /dev/null +++ b/Mastodon/Scene/Settings/Privacy and Safety/PrivacySafetyViewController.swift @@ -0,0 +1,67 @@ +// Copyright © 2024 Mastodon gGmbH. All rights reserved. + +import UIKit +import SwiftUI +import MastodonSDK +import MastodonCore +import MastodonLocalization +import MastodonAsset + +final class PrivacySafetyViewController: UIHostingController, NeedsDependency { + weak var context: AppContext! + weak var coordinator: SceneCoordinator! + + init(context: AppContext, coordinator: SceneCoordinator) { + self.context = context + self.coordinator = coordinator + super.init(rootView: PrivacySafetyView(viewModel: PrivacySafetyViewModel())) + } + + @MainActor required dynamic init?(coder aDecoder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + override func viewDidLoad() { + super.viewDidLoad() + title = L10n.Scene.Settings.PrivacySafety.title + } +} + +struct PrivacySafetyView: View { + @StateObject var viewModel: PrivacySafetyViewModel + + var body: some View { + Form { + Section(L10n.Scene.Settings.PrivacySafety.Preset.title) { + CheckableButton(text: L10n.Scene.Settings.PrivacySafety.Preset.openAndPublic, isChecked: viewModel.preset == .openPublic, action: { + viewModel.preset = .openPublic + }) + CheckableButton(text: L10n.Scene.Settings.PrivacySafety.Preset.privateAndRestricted, isChecked: viewModel.preset == .privateRestricted, action: { + viewModel.preset = .privateRestricted + }) + CheckableButton(text: L10n.Scene.Settings.PrivacySafety.Preset.custom, isChecked: viewModel.preset == .custom, action: { + viewModel.preset = .custom + }) + } + } + } +} + +private struct CheckableButton: View { + let text: String + let isChecked: Bool + let action: () -> Void + + var body: some View { + Button(action: action) { + HStack { + Text(text) + Spacer() + if isChecked { + Image(systemName: "checkmark") + .foregroundStyle(Asset.Colors.Brand.blurple.swiftUIColor) + } + } + } + } +} diff --git a/Mastodon/Scene/Settings/Privacy and Safety/PrivacySafetyViewModel.swift b/Mastodon/Scene/Settings/Privacy and Safety/PrivacySafetyViewModel.swift new file mode 100644 index 000000000..f1972eac8 --- /dev/null +++ b/Mastodon/Scene/Settings/Privacy and Safety/PrivacySafetyViewModel.swift @@ -0,0 +1,11 @@ +// Copyright © 2024 Mastodon gGmbH. All rights reserved. + +import Foundation + +class PrivacySafetyViewModel: ObservableObject { + enum Preset { + case openPublic, privateRestricted, custom + } + + @Published var preset: Preset = .openPublic +} diff --git a/Mastodon/Scene/Settings/SettingsCoordinator.swift b/Mastodon/Scene/Settings/SettingsCoordinator.swift index 819f35730..969e50803 100644 --- a/Mastodon/Scene/Settings/SettingsCoordinator.swift +++ b/Mastodon/Scene/Settings/SettingsCoordinator.swift @@ -72,7 +72,8 @@ extension SettingsCoordinator: SettingsViewControllerDelegate { navigationController.pushViewController(notificationViewController, animated: true) case .privacySafety: - break + let privacySafetyViewController = PrivacySafetyViewController(context: appContext, coordinator: sceneCoordinator) + navigationController.pushViewController(privacySafetyViewController, animated: true) case .serverDetails(let domain): let serverDetailsViewController = ServerDetailsViewController(domain: domain, appContext: appContext, authContext: authContext, sceneCoordinator: sceneCoordinator) serverDetailsViewController.delegate = self