116 lines
3.9 KiB
Swift
116 lines
3.9 KiB
Swift
//
|
|
// PushSubscriptionView.swift
|
|
// Tusker
|
|
//
|
|
// Created by Shadowfacts on 4/7/24.
|
|
// Copyright © 2024 Shadowfacts. All rights reserved.
|
|
//
|
|
|
|
import SwiftUI
|
|
import UserAccounts
|
|
import PushNotifications
|
|
import TuskerComponents
|
|
|
|
struct PushSubscriptionView: View {
|
|
let account: UserAccountInfo
|
|
let subscription: PushSubscription?
|
|
let updateSubscription: (PushSubscription.Alerts, PushSubscription.Policy) async -> Bool
|
|
|
|
var body: some View {
|
|
if let subscription {
|
|
PushSubscriptionSettingsView(account: account, subscription: subscription, updateSubscription: updateSubscription)
|
|
} else {
|
|
Text("No notifications")
|
|
.font(.callout)
|
|
.foregroundStyle(.secondary)
|
|
}
|
|
}
|
|
}
|
|
|
|
private struct PushSubscriptionSettingsView: View {
|
|
let account: UserAccountInfo
|
|
let subscription: PushSubscription
|
|
let updateSubscription: (PushSubscription.Alerts, PushSubscription.Policy) async -> Bool
|
|
@State private var isLoading: [PushSubscription.Alerts: Bool] = [:]
|
|
|
|
init(account: UserAccountInfo, subscription: PushSubscription, updateSubscription: @escaping (PushSubscription.Alerts, PushSubscription.Policy) async -> Bool) {
|
|
self.account = account
|
|
self.subscription = subscription
|
|
self.updateSubscription = updateSubscription
|
|
}
|
|
|
|
var body: some View {
|
|
VStack {
|
|
alertsToggles
|
|
|
|
AsyncPicker("From", alignment: .trailing, value: .constant(subscription.policy)) { newPolicy in
|
|
await updateSubscription(subscription.alerts, newPolicy)
|
|
} content: {
|
|
ForEach(PushSubscription.Policy.allCases) {
|
|
Text($0.displayName).tag($0)
|
|
}
|
|
}
|
|
.pickerStyle(.menu)
|
|
}
|
|
// this is the default value of the alignment guide, but this modifier is loading bearing
|
|
.alignmentGuide(.prefsAvatar, computeValue: { dimension in
|
|
dimension[.leading]
|
|
})
|
|
// otherwise the flexible view makes the containing stack extend under the edge of the list row
|
|
.padding(.leading, 38)
|
|
}
|
|
|
|
private var alertsToggles: some View {
|
|
GroupBox("Get notifications for") {
|
|
VStack {
|
|
toggle("All", alert: [.mention, .favorite, .reblog, .follow, .followRequest, .poll, .update])
|
|
toggle("Mentions", alert: .mention)
|
|
toggle("Favorites", alert: .favorite)
|
|
toggle("Reblogs", alert: .reblog)
|
|
toggle("Follows", alert: [.follow, .followRequest])
|
|
toggle("Polls finishing", alert: .poll)
|
|
toggle("Edits", alert: .update)
|
|
// status notifications not supported until we can enable/disable them in the app
|
|
}
|
|
}
|
|
}
|
|
|
|
private func toggle(_ titleKey: LocalizedStringKey, alert: PushSubscription.Alerts) -> some View {
|
|
let binding: Binding<AsyncToggle.Mode> = Binding {
|
|
isLoading[alert] == true ? .loading : subscription.alerts.contains(alert) ? .on : .off
|
|
} set: { newValue in
|
|
isLoading[alert] = newValue == .loading
|
|
}
|
|
return AsyncToggle(titleKey, mode: binding) {
|
|
return await updateAlert(alert, isOn: $0)
|
|
}
|
|
}
|
|
|
|
private func updateAlert(_ alert: PushSubscription.Alerts, isOn: Bool) async -> Bool {
|
|
var newAlerts = subscription.alerts
|
|
if isOn {
|
|
newAlerts.insert(alert)
|
|
} else {
|
|
newAlerts.remove(alert)
|
|
}
|
|
return await updateSubscription(newAlerts, subscription.policy)
|
|
}
|
|
}
|
|
|
|
private extension PushSubscription.Policy {
|
|
var displayName: String {
|
|
switch self {
|
|
case .all:
|
|
"Anyone"
|
|
case .followed:
|
|
"Accounts you follow"
|
|
case .followers:
|
|
"Your followers"
|
|
}
|
|
}
|
|
}
|
|
|
|
//#Preview {
|
|
// PushSubscriptionView()
|
|
//}
|