MobileMkch-iOS/MobileMkch/NotificationSettingsView.swift
2025-08-07 13:27:12 +03:00

194 lines
8.7 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import SwiftUI
struct NotificationSettingsView: View {
@EnvironmentObject var settings: Settings
@EnvironmentObject var notificationManager: NotificationManager
@EnvironmentObject var apiClient: APIClient
@State private var showingPermissionAlert = false
@State private var boards: [Board] = []
@State private var isLoadingBoards = false
var body: some View {
VStack {
if !settings.enableUnstableFeatures {
VStack(spacing: 16) {
Image(systemName: "lock.fill")
.font(.system(size: 50))
.foregroundColor(.gray)
Text("Функция заблокирована")
.font(.title2)
.fontWeight(.bold)
Text("Для использования уведомлений необходимо включить нестабильные функции в настройках.")
.font(.body)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
.padding(.horizontal)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else {
HStack {
Image(systemName: "exclamationmark.triangle.fill")
.foregroundColor(.orange)
Text("BETA Функция")
.font(.headline)
.foregroundColor(.orange)
}
.padding()
.background(Color.orange.opacity(0.1))
.cornerRadius(8)
.padding(.horizontal)
Text("Уведомления находятся в бета-версии и могут работать нестабильно. Функция может работать нестабильно или не работать ВОВСЕ.")
.font(.caption)
.foregroundColor(.secondary)
.multilineTextAlignment(.center)
.padding(.horizontal)
.padding(.bottom)
Form {
Section(header: Text("Уведомления")) {
Toggle("Включить уведомления", isOn: $settings.notificationsEnabled)
.onChange(of: settings.notificationsEnabled) { newValue in
if newValue {
requestNotificationPermission()
}
settings.saveSettings()
}
if settings.notificationsEnabled {
HStack {
Text("Интервал проверки")
Spacer()
Picker("", selection: $settings.notificationInterval) {
Text("5 мин").tag(300)
Text("15 мин").tag(900)
Text("30 мин").tag(1800)
Text("1 час").tag(3600)
}
.pickerStyle(MenuPickerStyle())
}
.onChange(of: settings.notificationInterval) { _ in
settings.saveSettings()
}
Button("Проверить новые треды сейчас") {
checkNewThreadsNow()
}
.foregroundColor(.blue)
}
}
if settings.notificationsEnabled {
Section(header: Text("Подписки на доски")) {
if isLoadingBoards {
HStack {
ProgressView()
.scaleEffect(0.8)
Text("Загрузка досок...")
.foregroundColor(.secondary)
}
} else {
ForEach(boards) { board in
HStack {
VStack(alignment: .leading, spacing: 2) {
Text("/\(board.code)/")
.font(.headline)
Text(board.description.isEmpty ? "Без описания" : board.description)
.font(.caption)
.foregroundColor(.secondary)
.lineLimit(1)
}
Spacer()
Toggle("", isOn: Binding(
get: { notificationManager.subscribedBoards.contains(board.code) },
set: { isSubscribed in
if isSubscribed {
notificationManager.subscribeToBoard(board.code)
} else {
notificationManager.unsubscribeFromBoard(board.code)
}
}
))
}
}
}
}
}
}
}
}
.navigationTitle("Уведомления")
.onAppear {
if boards.isEmpty {
loadBoards()
}
}
.alert("Разрешить уведомления", isPresented: $showingPermissionAlert) {
Button("Настройки") {
if let url = URL(string: UIApplication.openSettingsURLString) {
UIApplication.shared.open(url)
}
}
Button("Отмена", role: .cancel) {
settings.notificationsEnabled = false
}
} message: {
Text("Для получения уведомлений о новых тредах необходимо разрешить уведомления в настройках")
}
}
}
extension NotificationSettingsView {
private func requestNotificationPermission() {
notificationManager.requestPermission { granted in
if !granted {
showingPermissionAlert = true
}
}
}
private func checkNewThreadsNow() {
guard !notificationManager.subscribedBoards.isEmpty else { return }
for boardCode in notificationManager.subscribedBoards {
let lastKnownId = UserDefaults.standard.integer(forKey: "lastThreadId_\(boardCode)")
apiClient.checkNewThreads(forBoard: boardCode, lastKnownThreadId: lastKnownId) { result in
DispatchQueue.main.async {
switch result {
case .success(let newThreads):
if !newThreads.isEmpty {
for thread in newThreads {
notificationManager.scheduleNotification(for: thread, boardCode: boardCode)
}
UserDefaults.standard.set(newThreads.first?.id ?? lastKnownId, forKey: "lastThreadId_\(boardCode)")
}
case .failure:
break
}
}
}
}
}
private func loadBoards() {
isLoadingBoards = true
apiClient.getBoards { result in
DispatchQueue.main.async {
isLoadingBoards = false
switch result {
case .success(let loadedBoards):
boards = loadedBoards
case .failure:
boards = []
}
}
}
}
}