170 lines
5.0 KiB
Swift
170 lines
5.0 KiB
Swift
import SwiftUI
|
|
import SFSafeSymbols
|
|
import UniformTypeIdentifiers
|
|
|
|
struct ContentView: View {
|
|
|
|
@AppStorage("pushToken")
|
|
var pushToken: String?
|
|
|
|
var hasPushToken: Bool {
|
|
pushToken != nil
|
|
}
|
|
|
|
@State
|
|
var hasNotificationPermissions: Bool? = nil
|
|
|
|
func statusView(_ state: Bool?) -> some View {
|
|
let symbol: SFSymbol
|
|
let color: Color
|
|
if let state = state {
|
|
symbol = state ? .checkmarkCircle : .xmarkCircle
|
|
color = state ? .green : .red
|
|
} else {
|
|
symbol = .questionmarkCircle
|
|
color = .gray
|
|
}
|
|
return Image(systemSymbol: symbol)
|
|
.renderingMode(.template)
|
|
.foregroundColor(color)
|
|
}
|
|
|
|
func updateNotificationPermissionState() {
|
|
Task {
|
|
let state = await getPushPermissionState()
|
|
DispatchQueue.main.async {
|
|
hasNotificationPermissions = state
|
|
}
|
|
}
|
|
}
|
|
|
|
private func getPushPermissionState() async -> Bool? {
|
|
let settings = await UNUserNotificationCenter.current().notificationSettings()
|
|
switch settings.authorizationStatus {
|
|
case .authorized, .provisional, .ephemeral:
|
|
return true
|
|
case .denied:
|
|
return false
|
|
case .notDetermined:
|
|
return nil
|
|
@unknown default:
|
|
return nil
|
|
}
|
|
}
|
|
|
|
@State
|
|
private var didTapText = false
|
|
|
|
var tapFootnote: String {
|
|
if didTapText {
|
|
return "Copied to clipboard"
|
|
}
|
|
return "Double tap to copy token"
|
|
}
|
|
|
|
var body: some View {
|
|
NavigationView {
|
|
VStack(spacing: 8) {
|
|
HStack {
|
|
statusView(hasPushToken)
|
|
Text("remote-notifications-title")
|
|
}
|
|
HStack {
|
|
statusView(hasNotificationPermissions)
|
|
Text("notification-permissions-title")
|
|
}
|
|
Spacer()
|
|
if let token = pushToken {
|
|
Text("push-token-title")
|
|
Text(token)
|
|
.font(.body.monospaced())
|
|
.padding()
|
|
.onTapGesture(count: 2, perform: didDoubleTapToken)
|
|
Text(tapFootnote)
|
|
.font(.footnote)
|
|
} else {
|
|
Text("register-for-remote-notifications-text")
|
|
.padding()
|
|
.multilineTextAlignment(.center)
|
|
Button("register-for-remote-notifications-button", action: registerForRemoteNotifications)
|
|
.padding()
|
|
}
|
|
if hasNotificationPermissions == nil {
|
|
Button("request-notification-permission-button", action: requestNotificationPermission)
|
|
.padding()
|
|
} else if hasNotificationPermissions == false {
|
|
Text("no-notification-permissions-text")
|
|
.padding()
|
|
.multilineTextAlignment(.center)
|
|
Button("no-notification-permissions-button", action: openNotificationSettings)
|
|
.padding()
|
|
}
|
|
Spacer()
|
|
}
|
|
.navigationTitle("FlurSchnaps")
|
|
}
|
|
.onAppear {
|
|
startPeriodicUpdates()
|
|
}.onDisappear {
|
|
stopPeriodicUpdates()
|
|
}
|
|
}
|
|
|
|
private func didDoubleTapToken() {
|
|
UIPasteboard.general
|
|
.setValue(pushToken!, forPasteboardType: UTType.plainText.identifier)
|
|
didTapText = true
|
|
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) {
|
|
self.didTapText = false
|
|
}
|
|
}
|
|
|
|
@State
|
|
private var timer: Timer?
|
|
|
|
private func startPeriodicUpdates() {
|
|
guard timer == nil else {
|
|
return
|
|
}
|
|
timer = Timer.scheduledTimer(withTimeInterval: 5, repeats: true) { _ in
|
|
updateState()
|
|
}
|
|
updateState()
|
|
}
|
|
|
|
private func stopPeriodicUpdates() {
|
|
timer?.invalidate()
|
|
timer = nil
|
|
}
|
|
|
|
private func updateState() {
|
|
updateNotificationPermissionState()
|
|
}
|
|
|
|
func registerForRemoteNotifications() {
|
|
UIApplication.shared.registerForRemoteNotifications()
|
|
}
|
|
|
|
func requestNotificationPermission() {
|
|
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
|
|
UNUserNotificationCenter.current().requestAuthorization(
|
|
options: authOptions,
|
|
completionHandler: {_, _ in
|
|
updateNotificationPermissionState()
|
|
})
|
|
}
|
|
|
|
func openNotificationSettings() {
|
|
if let appSettings = URL(string: UIApplication.openSettingsURLString), UIApplication.shared.canOpenURL(appSettings) {
|
|
UIApplication.shared.open(appSettings)
|
|
}
|
|
}
|
|
}
|
|
|
|
struct ContentView_Previews: PreviewProvider {
|
|
static var previews: some View {
|
|
ContentView()
|
|
.previewDevice("iPhone 8")
|
|
}
|
|
}
|