feat: enhance models and services with Sendable conformance, add preview data for debugging

This commit is contained in:
2026-03-14 07:18:35 +07:00
parent a4b475b13f
commit 758f5ec05f
17 changed files with 851 additions and 198 deletions
+25
View File
@@ -12,6 +12,13 @@ class AuthViewModel: ObservableObject {
private let keychain = KeychainService.shared
func checkAuthStatus() async {
#if DEBUG
if PreviewData.isPreviewMode {
currentUser = PreviewData.mockUser
isAuthenticated = true
return
}
#endif
guard keychain.loadAccessToken() != nil else {
isAuthenticated = false
return
@@ -29,6 +36,15 @@ class AuthViewModel: ObservableObject {
}
}
#if DEBUG
func enterPreviewMode() async {
PreviewData.isPreviewMode = true
currentUser = PreviewData.mockUser
isAuthenticated = true
await PreviewData.startMockLiveActivity()
}
#endif
func login(email: String, password: String) async {
isLoading = true
error = nil
@@ -68,6 +84,15 @@ class AuthViewModel: ObservableObject {
}
func logout() async {
#if DEBUG
if PreviewData.isPreviewMode {
await PreviewData.stopMockLiveActivity()
PreviewData.isPreviewMode = false
isAuthenticated = false
currentUser = nil
return
}
#endif
isLoading = true
defer { isLoading = false }
do {
+34 -1
View File
@@ -16,6 +16,13 @@ class NotificationsViewModel: ObservableObject {
private var pollingTask: Task<Void, Never>?
func load() async {
#if DEBUG
if PreviewData.isPreviewMode {
notifications = PreviewData.mockNotifications
hasMore = false
return
}
#endif
isLoading = true
error = nil
currentPage = 1
@@ -31,6 +38,9 @@ class NotificationsViewModel: ObservableObject {
}
func loadMore() async {
#if DEBUG
if PreviewData.isPreviewMode { return }
#endif
guard !isLoadingMore && hasMore else { return }
isLoadingMore = true
defer { isLoadingMore = false }
@@ -47,6 +57,26 @@ class NotificationsViewModel: ObservableObject {
func markAsRead(_ notification: AppNotification) async {
guard !notification.isRead else { return }
#if DEBUG
if PreviewData.isPreviewMode {
if let index = notifications.firstIndex(where: { $0.id == notification.id }) {
let updated = AppNotification(
id: notification.id,
topic: notification.topic,
subject: notification.subject,
body: notification.body,
metadata: notification.metadata,
status: .read,
channel: notification.channel,
readAt: Date(),
createdAt: notification.createdAt,
updatedAt: Date()
)
notifications[index] = updated
}
return
}
#endif
do {
try await service.markAsRead(id: notification.id)
if let index = notifications.firstIndex(where: { $0.id == notification.id }) {
@@ -71,6 +101,9 @@ class NotificationsViewModel: ObservableObject {
}
func startPolling() {
#if DEBUG
if PreviewData.isPreviewMode { return }
#endif
// Guard against starting a second polling loop if already running.
guard pollingTask == nil else { return }
pollingTask = Task {
@@ -89,6 +122,6 @@ class NotificationsViewModel: ObservableObject {
private func updateBadge() {
let unreadCount = notifications.filter { !$0.isRead }.count
UIApplication.shared.applicationIconBadgeNumber = unreadCount
UNUserNotificationCenter.current().setBadgeCount(unreadCount)
}
}
+18
View File
@@ -11,6 +11,12 @@ class SettingsViewModel: ObservableObject {
private let service = NotificationsAPIService.shared
func loadSessions() async {
#if DEBUG
if PreviewData.isPreviewMode {
sessions = PreviewData.mockSessions
return
}
#endif
isLoading = true
defer { isLoading = false }
do {
@@ -21,6 +27,12 @@ class SettingsViewModel: ObservableObject {
}
func deleteSession(_ session: SessionResponse) async {
#if DEBUG
if PreviewData.isPreviewMode {
sessions.removeAll { $0.id == session.id }
return
}
#endif
do {
try await service.deleteSession(id: session.id)
sessions.removeAll { $0.id == session.id }
@@ -30,6 +42,12 @@ class SettingsViewModel: ObservableObject {
}
func changePassword(current: String, new: String) async -> Bool {
#if DEBUG
if PreviewData.isPreviewMode {
successMessage = "Пароль успешно изменён"
return true
}
#endif
isLoading = true
error = nil
defer { isLoading = false }