import 'package:flutter/material.dart'; import 'package:share_plus/share_plus.dart'; import 'package:pshared/api/errors/unauthorized.dart'; import 'package:pshared/api/requests/signup.dart'; import 'package:pshared/models/account/account.dart'; import 'package:pshared/provider/exception.dart'; import 'package:pshared/provider/resource.dart'; import 'package:pshared/service/account.dart'; class AccountProvider extends ChangeNotifier { // The resource now wraps our Account? state along with its loading/error state. Resource _resource = Resource(data: null); Resource get resource => _resource; Account? get account => _resource.data; bool get isLoggedIn => account != null; bool get isLoading => _resource.isLoading; Object? get error => _resource.error; // Private helper to update the resource and notify listeners. void _setResource(Resource newResource) { _resource = newResource; notifyListeners(); } Future login({ required String email, required String password, required String locale, }) async { _setResource(_resource.copyWith(isLoading: true, error: null)); try { final acc = await AccountService.login(email, password, locale); _setResource(Resource(data: acc, isLoading: false)); return acc; } catch (e) { _setResource(_resource.copyWith(isLoading: false, error: toException(e))); rethrow; } } Future restore() async { _setResource(_resource.copyWith(isLoading: true, error: null)); try { final acc = await AccountService.restore(); _setResource(Resource(data: acc, isLoading: false)); return acc; } catch (e) { _setResource(_resource.copyWith(isLoading: false, error: toException(e))); rethrow; } } Future signup( String name, String login, String password, String locale, String organizationName, String timezone, ) async { _setResource(_resource.copyWith(isLoading: true, error: null)); try { await AccountService.signup( SignupRequest.build( name: name, login: login.trim().toLowerCase(), password: password, locale: locale, organizationName: organizationName, organizationTimeZone: timezone, ), ); // Signup might not automatically log in the user, // so we just mark the request as complete. _setResource(_resource.copyWith(isLoading: false)); } catch (e) { _setResource(_resource.copyWith(isLoading: false, error: toException(e))); rethrow; } } Future logout() async { _setResource(_resource.copyWith(isLoading: true, error: null)); try { await AccountService.logout(); _setResource(Resource(data: null, isLoading: false)); } catch (e) { _setResource(_resource.copyWith(isLoading: false, error: toException(e))); rethrow; } } Future update({ String? locale, String? avatarUrl, String? notificationFrequency, }) async { if (account == null) throw ErrorUnauthorized(); _setResource(_resource.copyWith(isLoading: true, error: null)); try { final updated = await AccountService.update( account!.copyWith( avatarUrl: () => avatarUrl ?? account!.avatarUrl, locale: locale ?? account!.locale, ), ); _setResource(Resource(data: updated, isLoading: false)); return updated; } catch (e) { _setResource(_resource.copyWith(isLoading: false, error: toException(e))); rethrow; } } Future changePassword(String oldPassword, String newPassword) async { if (account == null) throw ErrorUnauthorized(); _setResource(_resource.copyWith(isLoading: true, error: null)); try { final updated = await AccountService.changePassword(oldPassword, newPassword); _setResource(Resource(data: updated, isLoading: false)); } catch (e) { _setResource(_resource.copyWith(isLoading: false, error: toException(e))); rethrow; } } Future uploadAvatar(XFile avatarFile) async { if (account == null) throw ErrorUnauthorized(); _setResource(_resource.copyWith(isLoading: true, error: null)); try { final avatarUrl = await AccountService.uploadAvatar(account!.id, avatarFile); // Reuse the update method to update the avatar URL. return update(avatarUrl: avatarUrl); } catch (e) { _setResource(_resource.copyWith(isLoading: false, error: toException(e))); rethrow; } } }