import 'package:flutter/widgets.dart'; import 'package:mobile_scanner/mobile_scanner.dart'; import 'package:seshat/data/repositories/bal_repository.dart'; import 'package:seshat/data/repositories/book_instance_repository.dart'; import 'package:seshat/data/repositories/book_repository.dart'; import 'package:seshat/data/repositories/owner_repository.dart'; import 'package:seshat/domain/models/bal.dart'; import 'package:seshat/domain/models/book.dart'; import 'package:seshat/domain/models/book_instance.dart'; import 'package:seshat/domain/models/book_stack.dart'; import 'package:seshat/domain/models/owner.dart'; import 'package:seshat/domain/models/search_result.dart'; import 'package:seshat/utils/command.dart'; import 'package:seshat/utils/result.dart'; class SellViewModel extends ChangeNotifier { SellViewModel({ required BalRepository balRepository, required BookInstanceRepository bookInstanceRepository, required BookRepository bookRepository, required OwnerRepository ownerRepository, }) : _balRepository = balRepository, _bookInstanceRepository = bookInstanceRepository, _bookRepository = bookRepository, _ownerRepository = ownerRepository { load = Command0(_load)..execute(); } final BalRepository _balRepository; final BookInstanceRepository _bookInstanceRepository; final BookRepository _bookRepository; final OwnerRepository _ownerRepository; /// Wether to show the scan screen bool _showScanScreen = false; /// Wether to show the scan screen bool get showScanScreen => _showScanScreen; set showScanScreen(bool newValue) { _showScanScreen = newValue; notifyListeners(); } /* * =============================== * =====[ BOOKS & INSTANCES ]===== * =============================== */ /// Books in the sell final List _booksInSell = []; /// Books in the sell List get booksInSell => _booksInSell; /// Books scanned on the scan screen final List _scannedBooks = []; /// Books scanned on the scan screen List get scannedBooks => _scannedBooks; bool isScanLoaded = false; bool isSendingSell = false; double minimumAmountToPay = 0; /// Adds a book to the [_booksInSell] void addBookToSell(BookStack bookToAdd) { minimumAmountToPay += bookToAdd.instance.price; _booksInSell.add(bookToAdd); notifyListeners(); } /// Sends the sell void sendSell(double givenMoney) async { isSendingSell = true; notifyListeners(); List booksToSend = []; int numberOfPL = 0; for (BookStack book in _booksInSell) { if (book.instance.price != 0) { book.instance.soldPrice = book.instance.price; givenMoney -= book.instance.price; booksToSend.add(book.instance); } else { numberOfPL++; } } if (numberOfPL != 0) { double moneyPerPL = givenMoney / numberOfPL; for (BookStack book in _booksInSell) { if (book.instance.price == 0) { book.instance.soldPrice = moneyPerPL; booksToSend.add(book.instance); } } } await _bookInstanceRepository.sellBooks(booksToSend); _booksInSell.clear(); isSendingSell = false; notifyListeners(); } /// Removes a book from the sell void removeBookFromSell(int bookId) { _booksInSell.removeWhere((book) => book.instance.id == bookId); notifyListeners(); } /// Search a book by [title] or [author] Future searchBook(String title, String author) async { Bal? bal = await _balRepository.ongoingBal(); isScanLoaded = false; _scannedBooks.clear(); final result = await _bookInstanceRepository.getBySearch( bal!.id, title, author, ); switch (result) { case Ok(): // For each result value, you need to complete some values for (SearchResult searchResult in result.value) { // In case you get a book that's actually not available if (searchResult.instance.available == false) { continue; } // In case the instance is already in the sell if (_booksInSell .where((book) => book.instance.id == searchResult.instance.id) .isNotEmpty) { continue; } // Search for the owner Owner owner; final result2 = await _ownerRepository.getOwnerById( searchResult.instance.ownerId, ); switch (result2) { case Ok(): owner = result2.value; break; case Error(): continue; } _scannedBooks.add( BookStack(searchResult.book, searchResult.instance, owner), ); } break; case Error(): break; } isScanLoaded = true; notifyListeners(); return; } /// Gets [BookInstance]s from its ean in a [barcode] Future scanBook(BarcodeCapture barcode) async { isScanLoaded = false; int ean = int.parse(barcode.barcodes.first.rawValue!); Bal? ongoingBal = await _balRepository.ongoingBal(); _scannedBooks.clear(); final result1 = await _bookInstanceRepository.getByEan(ongoingBal!.id, ean); switch (result1) { case Ok(): Book book; final result2 = await _bookRepository.getBookById( result1.value.first.bookId, ); switch (result2) { case Ok(): book = result2.value; break; case Error(): return; } // For each result value, you need to complete some values for (BookInstance instance in result1.value) { // In case you get a book that's actually not available if (instance.available == false) { continue; } // In case the instance is already in the sell if (_booksInSell .where((book) => book.instance.id == instance.id) .isNotEmpty) { continue; } // Search for the owner Owner owner; final result3 = await _ownerRepository.getOwnerById(instance.ownerId); switch (result3) { case Ok(): owner = result3.value; break; case Error(): continue; } _scannedBooks.add(BookStack(book, instance, owner)); } break; case Error(): break; } isScanLoaded = true; notifyListeners(); return; } /* * ================= * =====[ BAL ]===== * ================= */ /// The currently ongoing [Bal] Bal? _ongoingBal; /// The currently ongoing [Bal] get ongoingBal => _ongoingBal; /* * ================================= * =====[ COMMAND AND LOADING ]===== * ================================= */ /// Command to load necessary data late final Command0 load; bool isLoaded = false; /// Manages loaders Future> _load() async { final result1 = await _loadBal(); switch (result1) { case Ok(): isLoaded = true; break; default: break; } notifyListeners(); return result1; } /// Loads information about [Bal] Future> _loadBal() async { final result = await _balRepository.getBals(); switch (result) { case Ok(): _ongoingBal = result.value .where((bal) => bal.state == BalState.ongoing) .firstOrNull; break; case Error(): break; } return result; } }