| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- import Foundation
- import Combine
- /// Manages authentication state, user session, profile management, and audio sync access authorization.
- final class AuthManager: ObservableObject {
- static let shared = AuthManager()
- @Published private(set) var currentUser: UserAccount?
- @Published var isProcessing: Bool = false
- @Published var authErrorMessage: String?
-
- @Published var isSyncing: Bool = false
- @Published var lastSyncDate: Date?
- @Published var syncErrorMessage: String?
-
- var isLoggedIn: Bool {
- currentUser != nil
- }
-
- /// Auth repository interface. Can be swapped for `RemoteAuthServiceStub()` or mock services.
- private let authService: AuthServiceProtocol
-
- init(authService: AuthServiceProtocol = LocalAuthRepository()) {
- self.authService = authService
- self.currentUser = authService.getCurrentUser()
- }
-
- // MARK: - Auth Actions
-
- /// User login via username/email/phone & password.
- func login(identifier: String, password: String, completion: ((Bool, String?) -> Void)? = nil) {
- isProcessing = true
- authErrorMessage = nil
-
- let req = LoginRequest(identifier: identifier, password: password)
- authService.login(request: req) { [weak self] result in
- DispatchQueue.main.async {
- guard let self = self else { return }
- self.isProcessing = false
- switch result {
- case .success(let user):
- self.currentUser = user
- completion?(true, nil)
- case .failure(let error):
- self.authErrorMessage = error.localizedDescription
- completion?(false, error.localizedDescription)
- }
- }
- }
- }
-
- /// User registration.
- func register(username: String, identifier: String, password: String, completion: ((Bool, String?) -> Void)? = nil) {
- isProcessing = true
- authErrorMessage = nil
-
- let req = RegisterRequest(username: username, identifier: identifier, password: password)
- authService.register(request: req) { [weak self] result in
- DispatchQueue.main.async {
- guard let self = self else { return }
- self.isProcessing = false
- switch result {
- case .success(let user):
- self.currentUser = user
- completion?(true, nil)
- case .failure(let error):
- self.authErrorMessage = error.localizedDescription
- completion?(false, error.localizedDescription)
- }
- }
- }
- }
-
- /// Update profile information (nickname, email, phone, avatar).
- func updateProfile(username: String?, email: String?, phoneNumber: String?, avatarURL: String?, completion: ((Bool, String?) -> Void)? = nil) {
- isProcessing = true
- authErrorMessage = nil
-
- let req = UpdateProfileRequest(username: username, email: email, phoneNumber: phoneNumber, avatarURL: avatarURL)
- authService.updateProfile(request: req) { [weak self] result in
- DispatchQueue.main.async {
- guard let self = self else { return }
- self.isProcessing = false
- switch result {
- case .success(let user):
- self.currentUser = user
- completion?(true, nil)
- case .failure(let error):
- self.authErrorMessage = error.localizedDescription
- completion?(false, error.localizedDescription)
- }
- }
- }
- }
-
- /// Change password.
- func changePassword(oldPassword: String, newPassword: String, completion: ((Bool, String?) -> Void)? = nil) {
- isProcessing = true
- authErrorMessage = nil
-
- let req = ChangePasswordRequest(oldPassword: oldPassword, newPassword: newPassword)
- authService.changePassword(request: req) { [weak self] result in
- DispatchQueue.main.async {
- guard let self = self else { return }
- self.isProcessing = false
- switch result {
- case .success:
- completion?(true, nil)
- case .failure(let error):
- self.authErrorMessage = error.localizedDescription
- completion?(false, error.localizedDescription)
- }
- }
- }
- }
-
- /// Logout current user.
- func logout() {
- authService.logout { [weak self] in
- DispatchQueue.main.async {
- self?.currentUser = nil
- }
- }
- }
-
- // MARK: - Audio Sync
-
- /// Triggers audio synchronization. Requires authenticated user.
- func syncRecordings(onRequireAuth: @escaping () -> Void, onComplete: @escaping (Bool) -> Void) {
- guard isLoggedIn else {
- onRequireAuth()
- return
- }
-
- isSyncing = true
- syncErrorMessage = nil
-
- // Mock sync delay
- DispatchQueue.main.asyncAfter(deadline: .now() + 1.2) { [weak self] in
- guard let self = self else { return }
- self.isSyncing = false
- self.lastSyncDate = Date()
- onComplete(true)
- }
- }
- }
|