mirror of
https://github.com/mastodon/mastodon-ios
synced 2025-04-11 22:58:02 +02:00
Implement loading and saving of privacy & safety preferences (IOS-168)
This commit is contained in:
parent
f31fd74abe
commit
d77e8d1eac
@ -1,5 +1,6 @@
|
||||
// Copyright © 2024 Mastodon gGmbH. All rights reserved.
|
||||
|
||||
import Combine
|
||||
import UIKit
|
||||
import SwiftUI
|
||||
import MastodonSDK
|
||||
@ -7,14 +8,24 @@ import MastodonCore
|
||||
import MastodonLocalization
|
||||
import MastodonAsset
|
||||
|
||||
final class PrivacySafetyViewController: UIHostingController<PrivacySafetyView>, NeedsDependency {
|
||||
weak var context: AppContext!
|
||||
weak var coordinator: SceneCoordinator!
|
||||
final class PrivacySafetyViewController: UIHostingController<PrivacySafetyView> {
|
||||
private let viewModel: PrivacySafetyViewModel
|
||||
private var disposeBag = [AnyCancellable]()
|
||||
|
||||
init(context: AppContext, coordinator: SceneCoordinator) {
|
||||
self.context = context
|
||||
self.coordinator = coordinator
|
||||
super.init(rootView: PrivacySafetyView(viewModel: PrivacySafetyViewModel()))
|
||||
init(appContext: AppContext, authContext: AuthContext, coordinator: SceneCoordinator) {
|
||||
self.viewModel = PrivacySafetyViewModel(
|
||||
appContext: appContext, authContext: authContext, coordinator: coordinator
|
||||
)
|
||||
super.init(
|
||||
rootView: PrivacySafetyView(
|
||||
viewModel: self.viewModel
|
||||
)
|
||||
)
|
||||
self.viewModel.onDismiss.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] _ in
|
||||
self?.dismiss(animated: true)
|
||||
}
|
||||
.store(in: &disposeBag)
|
||||
}
|
||||
|
||||
@MainActor required dynamic init?(coder aDecoder: NSCoder) {
|
||||
@ -72,6 +83,7 @@ struct PrivacySafetyView: View {
|
||||
}
|
||||
}
|
||||
.onAppear(perform: viewModel.viewDidAppear)
|
||||
.onDisappear(perform: viewModel.saveSettings)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
// Copyright © 2024 Mastodon gGmbH. All rights reserved.
|
||||
|
||||
import Combine
|
||||
import Foundation
|
||||
import MastodonLocalization
|
||||
import MastodonCore
|
||||
@ -23,9 +24,41 @@ class PrivacySafetyViewModel: ObservableObject {
|
||||
return L10n.Scene.Settings.PrivacySafety.DefaultPostVisibility.onlyPeopleMentioned
|
||||
}
|
||||
}
|
||||
|
||||
static func from(_ privacy: Mastodon.Entity.Source.Privacy) -> Self {
|
||||
switch privacy {
|
||||
case .public:
|
||||
return .public
|
||||
case .unlisted:
|
||||
return .followersOnly
|
||||
case .private, .direct:
|
||||
return .onlyPeopleMentioned
|
||||
case ._other(_):
|
||||
return .public
|
||||
}
|
||||
}
|
||||
|
||||
func toPrivacy() -> Mastodon.Entity.Source.Privacy {
|
||||
switch self {
|
||||
case .public:
|
||||
return .public
|
||||
case .followersOnly:
|
||||
return .unlisted
|
||||
case .onlyPeopleMentioned:
|
||||
return .private
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
weak var appContext: AppContext?
|
||||
private var appContext: AppContext?
|
||||
private var authContext: AuthContext?
|
||||
private var coordinator: SceneCoordinator?
|
||||
|
||||
init(appContext: AppContext?, authContext: AuthContext?, coordinator: SceneCoordinator?) {
|
||||
self.appContext = appContext
|
||||
self.authContext = authContext
|
||||
self.coordinator = coordinator
|
||||
}
|
||||
|
||||
@Published var preset: Preset = .openPublic {
|
||||
didSet { applyPreset(preset) }
|
||||
@ -52,6 +85,7 @@ class PrivacySafetyViewModel: ObservableObject {
|
||||
|
||||
private var doNotEvaluate = true
|
||||
@Published var isInitialized = false
|
||||
let onDismiss = PassthroughSubject<Void, Never>()
|
||||
|
||||
func viewDidAppear() {
|
||||
doNotEvaluate = false
|
||||
@ -96,7 +130,26 @@ extension PrivacySafetyViewModel {
|
||||
|
||||
func loadSettings() {
|
||||
Task { @MainActor in
|
||||
guard let appContext, let authContext else {
|
||||
return dismiss()
|
||||
}
|
||||
|
||||
let domain = authContext.mastodonAuthenticationBox.domain
|
||||
let userAuthorization = authContext.mastodonAuthenticationBox.userAuthorization
|
||||
|
||||
let account = try await appContext.apiService.accountVerifyCredentials(
|
||||
domain: domain,
|
||||
authorization: userAuthorization
|
||||
).singleOutput().value
|
||||
|
||||
if let privacy = account.source?.privacy {
|
||||
visibility = .from(privacy)
|
||||
}
|
||||
|
||||
manuallyApproveFollowRequests = account.locked == true
|
||||
showFollowersAndFollowing = account.hideCollections == false
|
||||
suggestMyAccountToOthers = account.discoverable == true
|
||||
appearInSearches = account.indexable == true
|
||||
|
||||
isInitialized = true
|
||||
}
|
||||
@ -104,15 +157,36 @@ extension PrivacySafetyViewModel {
|
||||
|
||||
func saveSettings() {
|
||||
Task {
|
||||
guard let appContext, let authContext else {
|
||||
return
|
||||
}
|
||||
|
||||
let domain = authContext.mastodonAuthenticationBox.domain
|
||||
let userAuthorization = authContext.mastodonAuthenticationBox.userAuthorization
|
||||
|
||||
let _ = try await appContext.apiService.accountUpdateCredentials(
|
||||
domain: domain,
|
||||
query: .init(
|
||||
discoverable: suggestMyAccountToOthers,
|
||||
locked: manuallyApproveFollowRequests,
|
||||
source: .withPrivacy(visibility.toPrivacy()),
|
||||
indexable: appearInSearches,
|
||||
hideCollections: !showFollowersAndFollowing
|
||||
),
|
||||
authorization: userAuthorization
|
||||
).value
|
||||
}
|
||||
}
|
||||
|
||||
func dismiss() {
|
||||
onDismiss.send(())
|
||||
}
|
||||
}
|
||||
|
||||
// Preset Rules Definition
|
||||
extension PrivacySafetyViewModel {
|
||||
static let openPublic: PrivacySafetyViewModel = {
|
||||
let vm = PrivacySafetyViewModel()
|
||||
let vm = PrivacySafetyViewModel(appContext: nil, authContext: nil, coordinator: nil)
|
||||
vm.visibility = .public
|
||||
vm.manuallyApproveFollowRequests = false
|
||||
vm.showFollowersAndFollowing = true
|
||||
@ -122,7 +196,7 @@ extension PrivacySafetyViewModel {
|
||||
}()
|
||||
|
||||
static let privateRestricted: PrivacySafetyViewModel = {
|
||||
let vm = PrivacySafetyViewModel()
|
||||
let vm = PrivacySafetyViewModel(appContext: nil, authContext: nil, coordinator: nil)
|
||||
vm.visibility = .followersOnly
|
||||
vm.manuallyApproveFollowRequests = true
|
||||
vm.showFollowersAndFollowing = false
|
||||
|
@ -72,7 +72,11 @@ extension SettingsCoordinator: SettingsViewControllerDelegate {
|
||||
|
||||
navigationController.pushViewController(notificationViewController, animated: true)
|
||||
case .privacySafety:
|
||||
let privacySafetyViewController = PrivacySafetyViewController(context: appContext, coordinator: sceneCoordinator)
|
||||
let privacySafetyViewController = PrivacySafetyViewController(
|
||||
appContext: appContext,
|
||||
authContext: authContext,
|
||||
coordinator: sceneCoordinator
|
||||
)
|
||||
navigationController.pushViewController(privacySafetyViewController, animated: true)
|
||||
case .serverDetails(let domain):
|
||||
let serverDetailsViewController = ServerDetailsViewController(domain: domain, appContext: appContext, authContext: authContext, sceneCoordinator: sceneCoordinator)
|
||||
|
@ -159,6 +159,7 @@ extension Mastodon.API.Account {
|
||||
public let source: Mastodon.Entity.Source?
|
||||
public let fieldsAttributes: [Mastodon.Entity.Field]?
|
||||
public let indexable: Bool?
|
||||
public let hideCollections: Bool?
|
||||
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case discoverable
|
||||
@ -172,6 +173,7 @@ extension Mastodon.API.Account {
|
||||
case source
|
||||
case fieldsAttributes = "fields_attributes"
|
||||
case indexable
|
||||
case hideCollections = "hide_collections"
|
||||
}
|
||||
|
||||
public init(
|
||||
@ -184,7 +186,8 @@ extension Mastodon.API.Account {
|
||||
locked: Bool? = nil,
|
||||
source: Mastodon.Entity.Source? = nil,
|
||||
fieldsAttributes: [Mastodon.Entity.Field]? = nil,
|
||||
indexable: Bool? = nil
|
||||
indexable: Bool? = nil,
|
||||
hideCollections: Bool? = nil
|
||||
) {
|
||||
self.discoverable = discoverable
|
||||
self.bot = bot
|
||||
@ -196,6 +199,7 @@ extension Mastodon.API.Account {
|
||||
self.source = source
|
||||
self.fieldsAttributes = fieldsAttributes
|
||||
self.indexable = indexable
|
||||
self.hideCollections = hideCollections
|
||||
}
|
||||
|
||||
var contentType: String? {
|
||||
@ -209,6 +213,7 @@ extension Mastodon.API.Account {
|
||||
var body: Data? {
|
||||
var data = Data()
|
||||
|
||||
hideCollections.flatMap { data.append(Data.multipart(key: "hide_collections", value: $0)) }
|
||||
discoverable.flatMap { data.append(Data.multipart(key: "discoverable", value: $0)) }
|
||||
bot.flatMap { data.append(Data.multipart(key: "bot", value: $0)) }
|
||||
displayName.flatMap { data.append(Data.multipart(key: "display_name", value: $0)) }
|
||||
|
@ -1,8 +0,0 @@
|
||||
//
|
||||
// File.swift
|
||||
//
|
||||
//
|
||||
// Created by Marcus Kida on 29.05.24.
|
||||
//
|
||||
|
||||
import Foundation
|
@ -37,6 +37,8 @@ extension Mastodon.Entity {
|
||||
public let locked: Bool
|
||||
public let emojis: [Emoji]
|
||||
public let discoverable: Bool?
|
||||
public let hideCollections: Bool?
|
||||
public let indexable: Bool?
|
||||
|
||||
// Statistical
|
||||
public let createdAt: Date
|
||||
@ -71,6 +73,8 @@ extension Mastodon.Entity.Account: Codable {
|
||||
case locked
|
||||
case emojis
|
||||
case discoverable
|
||||
case hideCollections = "hide_collections"
|
||||
case indexable
|
||||
|
||||
case createdAt = "created_at"
|
||||
case lastStatusAt = "last_status_at"
|
||||
|
@ -36,6 +36,10 @@ extension Mastodon.Entity {
|
||||
case language
|
||||
case followRequestsCount = "follow_requests_count"
|
||||
}
|
||||
|
||||
public static func withPrivacy(_ privacy: Privacy) -> Self {
|
||||
Source(note: "", fields: nil, privacy: privacy, sensitive: nil, language: nil, followRequestsCount: nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user