import 'package:flutter/widgets.dart'; import 'package:seshat/data/repositories/bal_repository.dart'; import 'package:seshat/data/repositories/owner_repository.dart'; import 'package:seshat/domain/models/bal.dart'; import 'package:seshat/domain/models/bal_stats.dart'; import 'package:seshat/domain/models/book.dart'; import 'package:seshat/domain/models/book_instance.dart'; import 'package:seshat/domain/models/enums.dart'; import 'package:seshat/domain/models/return_owner.dart'; import 'package:seshat/domain/models/search_result.dart'; import 'package:seshat/utils/command.dart'; import 'package:seshat/utils/result.dart'; class BalViewModel extends ChangeNotifier { BalViewModel({ required BalRepository balRepository, required this.selectedBalId, required OwnerRepository ownerRepository, }) : _balRepository = balRepository, _ownerRepository = ownerRepository { load = Command0(_load)..execute(); } final BalRepository _balRepository; final OwnerRepository _ownerRepository; /* * ===================== * =====< General >===== * ===================== */ /// Selected [Bal] Bal? _selectedBal; /// Selected [Bal] Bal? get selectedBal => _selectedBal; /// Selected [Bal.id] from path parameters int selectedBalId; /// Is one of the [Bal] [BalState.ongoing] bool isABalOngoing = false; /// Stops a [Bal] Future> stopBal(int balId) async { isLoaded = false; notifyListeners(); final result = await _balRepository.stopBal(balId); switch (result) { case Ok(): _selectedBal = result.value; break; default: } final result2 = await _loadEnded(); switch (result2) { case Ok(): isLoaded = true; break; case Error(): break; } notifyListeners(); return result; } /// Starts a [Bal] Future> startBal(int balId) async { if (isABalOngoing) { return Result.error(Exception("Cannot have multiple BALs ongoing !")); } final result = await _balRepository.startBal(balId); switch (result) { case Ok(): _selectedBal = result.value; notifyListeners(); break; default: } return result; } /// Edits a [Bal]'s [name], [startTime] or [endTime] Future> editBal( int id, String name, DateTime startTime, DateTime endTime, ) async { final result = await _balRepository.editBal(id, name, startTime, endTime); switch (result) { case Ok(): _selectedBal = result.value; notifyListeners(); break; case Error(): break; } return result; } /* * ============================ * =====< State Specific >===== * ============================ */ // Specific to ended state /// Owners a book or money is owed to List? owedToOwners; /// Statistics about the [_selectedBal] BalStats? stats; /// Froms [books], updates [owners] to include all the necessary information /// See [the api doc](https://bal.ueauvergne.fr/docs/#/bal-api/get_bal_accounting) for more details Future _updateOwedToOwnersWithBooks( List owners, Map books, ) async { owedToOwners = owners; for (ReturnOwner owedToOwner in owedToOwners!) { var res = await _ownerRepository.getOwnerById(owedToOwner.ownerId); switch (res) { case Ok(): owedToOwner.owner = res.value; break; default: } owedToOwner.owed = []; for (BookInstance instance in owedToOwner.owedInstances) { final bookId = instance.bookId; owedToOwner.owed.add(SearchResult(instance, books[bookId.toString()]!)); } } } /// Returns either Books, Money or All ([ReturnType]) to an [Owner] Future> returnById(ReturnType type, int ownerId) async { final result = await _balRepository.returnToId( selectedBalId, ownerId, type, ); final result2 = await _balRepository.getAccounting(selectedBalId); switch (result2) { case Ok(): _updateOwedToOwnersWithBooks(result2.value.owners, result2.value.books); break; case Error(): break; } notifyListeners(); return result; } /* * ================================= * =====< COMMAND AND LOADING >===== * ================================= */ /// Loads all the necessary information late final Command0 load; bool isLoaded = false; /// Manages loaders Future> _load() async { isABalOngoing = _balRepository.isABalOngoing(); final result1 = await _loadBal(); switch (result1) { case Ok(): isLoaded = (_selectedBal == null || _selectedBal?.state != BalState.ended) ? true : false; break; default: break; } if (_selectedBal?.state == BalState.ended) { final result2 = await _loadEnded(); switch (result2) { case Ok(): isLoaded = true; break; case Error(): break; } } notifyListeners(); return result1; } /// Loads all common [Bal] information Future> _loadBal() async { final result = await _balRepository.balById(selectedBalId); switch (result) { case Ok(): _selectedBal = result.value; break; case Error(): break; } return result; } /// Loads [Bal] information when it is [BalState.ended] Future> _loadEnded() async { final result = await _balRepository.getAccountingNoCache(selectedBalId); switch (result) { case Ok(): _updateOwedToOwnersWithBooks(result.value.owners, result.value.books); break; default: } final result2 = await _balRepository.getBalStats(selectedBalId); switch (result2) { case Ok(): stats = result2.value; break; default: } return result; } }