diff --git a/.github/workflows/pr_test.yaml b/.github/workflows/ci_tests.yaml similarity index 87% rename from .github/workflows/pr_test.yaml rename to .github/workflows/ci_tests.yaml index 9ffa3873..75623259 100644 --- a/.github/workflows/pr_test.yaml +++ b/.github/workflows/ci_tests.yaml @@ -1,6 +1,10 @@ -name: PR - Test Bookify Flutter App +name: CI - Test Bookify Flutter App on: + push: + branches: + - '**' + pull_request: branches: - main diff --git a/.gitignore b/.gitignore index 855c1273..5aeb1bb0 100644 --- a/.gitignore +++ b/.gitignore @@ -38,6 +38,9 @@ # Web related lib/generated_plugin_registrant.dart +# Debug Symbols +/debug_symbols/ + # Symbolication related app.*.symbols diff --git a/android/gradle.properties b/android/gradle.properties index 487ca27f..7f559cfb 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -14,3 +14,6 @@ android.uniquePackageNames=false android.dependency.useConstraints=true android.r8.strictFullModeForKeepRules=false android.r8.optimizedResourceShrinking=false + +#! TODO: Temporarily ignore JVM target validation until Facebook Auth Plugin is updated to support Java 17. --- IGNORE --- +kotlin.jvm.target.validation.mode = IGNORE diff --git a/assets/lang/en_US.json b/assets/lang/en_US.json index 66dc4bd2..cee5ff47 100644 --- a/assets/lang/en_US.json +++ b/assets/lang/en_US.json @@ -35,6 +35,8 @@ "reading-time-description": "Scheduling time for reading is the first step to creating a habit.\n\nSet the days and times that work best for your reading, and we'll remind you here in the notifications!", "reading-time-calculate-success-snackbar": "Reading time successfully calculated.", "reading-time-notification-removed-success-snackbar": "Notification successfully removed.", + "reading-time-notification-title": "Time to read!", + "reading-time-notification-body": "Many adventures await you!", "repeat-time-title": "Set the repetition to be notified for your readings:", "daily-dropdown-menu-entry": "Daily", "weekly-dropdown-menu-entry": "Weekly", @@ -87,6 +89,7 @@ "page-tooltip": "Page %s", "try-again-button": "Try again", "no-books-found-with-terms": "No books were found with these terms.\nCheck that you have typed them correctly.", + "no-books-registered": "No books registered. Go back to the home page to register.", "enter-title-label": "Enter the Title", "enter-author-label": "Enter the Author", "enter-category-label": "Enter the Category", @@ -101,6 +104,8 @@ "search-by-isbn-tooltip": "Search by ISBN", "book-successfully-added-snackbar": "Book successfully added.", "book-successfully-removed-snackbar": "Book successfully removed.", + "bookcase-inserted-success-snackbar": "Bookcase successfully added.", + "bookcase-updated-success-snackbar": "Bookcase successfully updated.", "remove-book-title": "Remove the book %s", "remove-book-description": "By clicking \"CONFIRM\" you will remove this book from your bookcase.\nAre you sure?", "pages-label": "%s PAGES", @@ -122,7 +127,6 @@ "field-cannot-be-empty-error": "This field cannot be empty", "invalid-ISBN-format-error": "Invalid ISBN format", "camera-error": "An error occurred with the camera: %s", - "unknown-error": "unknown error", "enter-loaned-title-label": "Enter the title of the loaned book.", "enter-title-your-book-label": "Enter the title of your book.", "enter-bookcase-name-label": "Enter the name of the bookcase.", @@ -153,6 +157,7 @@ "delete-bookcase-description": "By clicking \"CONFIRM\" you will delete the bookcase %s.\nAre you sure?", "delete-books-title": "Delete books", "delete-books-description": "By clicking \"CONFIRM\" you will delete the selected books in this bookcase.\nAre you sure?", + "all-books-already-inserted": "All registered books have already been added to this bookcase.", "book-added-successfully-snackbar": "Book added successfully.\nWait until you are redirected to the previous page.", "select-books-title": "Select the books", "selected-books-quantity-label": "Selected books: %s", @@ -178,6 +183,9 @@ "contact-required-field": "Contact *", "observation-optional-field": "Observation (optional)", "loan-date-required-field": "Loan date *", + "loan-notification-title": "Hey, your book is coming back!", + "loan-notification-body": "Hi! Just dropping by to remind you that it's time for %s0 to return %s1 that you loaned on %s2.", + "loan-insertion-success-snackbar": "Loan added successfully!", "devolution-date-required-field": "Devolution date *", "send-button": "Send", "contact-selected-label": "Contact selected", @@ -243,5 +251,34 @@ "book-on-loan-label": "on loan", "book-on-reading-label": "on reading", "previous-month-tooltip": "Previous month", - "next-month-tooltip": "Next month" + "next-month-tooltip": "Next month", + "error-rest-client-connection-timeout": "Connection to server failed due to timeout. Check your internet connection and try again: %s", + "error-rest-client-receive-timeout": "Server response took too long to arrive. Verify your connection quality and retry: %s", + "error-rest-client-not-found": "The requested resource was not found. Verify your search terms or try a different query: %s", + "error-rest-client-socket-exception": "Network connection error detected. Check your internet connection and try again: %s", + "error-invalid-isbn": "The ISBN format is invalid. Enter a valid ISBN number (10 or 13 digits): %s", + "error-unknown": "An unexpected error occurred. Please try again later or contact support: %s", + "error-auth-user-not-found": "Unable to log in. Check that your email is registered or sign up if you don't have an account: %s", + "error-auth-wrong-password": "Incorrect password. Verify your credentials and try again: %s", + "error-auth-invalid-email": "Invalid email format. Enter a valid email address: %s", + "error-auth-account-disabled": "Your account has been temporarily disabled. Contact support for help: %s", + "error-auth-too-many-requests": "Too many login attempts. Wait a few minutes and try again: %s", + "error-auth-operation-not-allowed": "This authentication method is not available right now. Try again later: %s", + "error-auth-network-request-failed": "Connection lost. Check your internet connection and try again: %s", + "error-auth-internal-error": "Something went wrong. If the problem persists, please contact support: %s", + "error-storage-invalid-value": "Data storage issue detected. Try logging out and logging back in: %s", + "error-storage-write-failed": "Unable to save your changes. Check your storage space and try again: %s", + "error-storage-read-failed": "Unable to load your data. Check your internet connection and try again: %s", + "error-local-database-conversion-failed": "Failed to process data from database. %s", + "error-local-database-not-null-constraint": "A required field is empty. %s", + "error-local-database-open-failed": "Could not open the database. %s", + "error-local-database-operation-failed": "Database operation failed during read, write, or update. %s", + "error-local-database-unique-constraint": "This record already exists in the database. %s", + "notification-channel-loan-description": "Channel that notifies when it's time to receive your loaned book.", + "notification-channel-loan-label": "Loans", + "notification-channel-read-description": "Channel that notifies when it's time for reading.", + "notification-channel-read-label": "Readings", + "error-platform-permission-denied": "Permission denied: %s", + "error-platform-permission-permanently-denied": "Permission permanently denied. Open settings to grant it: %s", + "error-platform-unsupported": "Operation not supported on this device: %s" } diff --git a/assets/lang/it_IT.json b/assets/lang/it_IT.json index d62248fa..2b578146 100644 --- a/assets/lang/it_IT.json +++ b/assets/lang/it_IT.json @@ -20,7 +20,7 @@ "auth-success-snackbar": "Autenticazione avvenuta con successo.", "reading-time-success-snackbar": "Tempo di lettura calcolato con successo.", "reading-instruction-title": "Calcoliamo la tua velocità di lettura?", - "reading-instruction-description": "Leggi un breve estratto da un libro generato dall'IA mentre tracciamo il tuo tempo con un cronometro. Dopo il calcolo, ti verrà comunicato il tempo medio che ti ci è voluto per finire di leggere qualsiasi libro nell'app, basato sul tempo impiegato per leggere il testo.", + "reading-instruction-description": "Leggi un breve estratto da un libro generato dalla IA mentre tracciamo il tuo tempo con un cronometro. Dopo il calcolo, ti verrà comunicato il tempo medio che ti ci è voluto per finire di leggere qualsiasi libro nell'app, basato sul tempo impiegato per leggere il testo.", "calculate-later-button": "Calcola più tardi", "calculate-time-button": "Calcola tempo", "close-page-button-tooltip": "Chiudi la pagina", @@ -35,6 +35,8 @@ "reading-time-description": "Pianificare un momento dedicato alla lettura è il primo passo per creare l'abitudine.\n\nDecidi quali giorni e quali sono gli orari migliori per le tue letture e noi te lo ricorderemo qui nelle notifiche!", "reading-time-calculate-success-snackbar": "Tempo di lettura calcolato con successo.", "reading-time-notification-removed-success-snackbar": "Notifica rimossa con successo.", + "reading-time-notification-title": "È l'ora di leggere!", + "reading-time-notification-body": "Molte avventure ti aspettano!", "repeat-time-title": "Imposta la ripetizione per ricevere una notifica per le tue letture:", "daily-dropdown-menu-entry": "Giornaliera", "weekly-dropdown-menu-entry": "Settimanale", @@ -87,9 +89,10 @@ "page-tooltip": "Pagina %s", "try-again-button": "Riprova", "no-books-found-with-terms": "Nessun libro trovato con questi termini.\nVerifica che sia stato digitato correttamente.", + "no-books-registered": "Nessun libro registrato. Torna alla pagina iniziale per registrare.", "enter-title-label": "Inserisci il Titolo", "enter-author-label": "Inserisci l'Autore", - "enter-category-label": "Inserisci la Categoria", + "enter-category-label": "Inserisci la Categoria (Inglese)", "enter-publisher-label": "Inserisci l'Editore", "enter-isbn-label": "Inserisci l'ISBN", "delete-text-typed-tooltip": "Cancella il testo digitato.", @@ -101,6 +104,8 @@ "search-by-isbn-tooltip": "Cerca per ISBN", "book-successfully-added-snackbar": "Libro aggiunto con successo.", "book-successfully-removed-snackbar": "Libro rimosso con successo.", + "bookcase-inserted-success-snackbar": "Libreria aggiunta con successo.", + "bookcase-updated-success-snackbar": "Libreria aggiornata con successo.", "remove-book-title": "Rimuovere il libro %s", "remove-book-description": "Cliccando su “CONFERMA” rimuoverai questo libro dal tuo Scaffale.\nSei sicuro?", "pages-label": "%s PAGINE", @@ -122,7 +127,6 @@ "field-cannot-be-empty-error": "Questo campo non può essere vuoto", "invalid-ISBN-format-error": "Formato del ISBN non valido", "camera-error": "Si è verificato un errore con la fotocamera: %s", - "unknown-error": "errore sconosciuto", "enter-loaned-title-label": "Inserisci il titolo del libro in prestito.", "enter-title-your-book-label": "Inserisci il titolo del tuo libro.", "enter-bookcase-name-label": "Inserisci il nome dello scaffale.", @@ -153,6 +157,7 @@ "delete-bookcase-description": "Cliccando su “CONFERMA” eliminerai il scaffale %s.\nSei sicuro?", "delete-books-title": "Eliminare libri", "delete-books-description": "Cliccando su “CONFERMA” eliminerai i libri selezionati in questo scaffale.\nSei sicuro?", + "all-books-already-inserted": "Tutti i libri registrati sono già stati aggiunti a questo scaffale.", "books-added-successfully-snackbar": "Libro aggiunto con successo.\nAttendere fino al ritorno alla pagina precedente.", "select-books-title": "Seleziona i libri", "selected-books-quantity-label": "Libri selezionati: %s", @@ -178,6 +183,9 @@ "contact-required-field": "Contatto *", "observation-optional-field": "Osservazione (opzionale)", "loan-date-required-field": "Data del prestito *", + "loan-notification-title": "Ehi, il tuo libro sta per tornare!", + "loan-notification-body": "Ciao! Solo un promemoria per ricordarti che è ora che %s0 restituisca il libro %s1 che hai prestato il giorno %s2.", + "loan-insertion-success-snackbar": "Prestito inserito con successo!", "devolution-date-required-field": "Data di restituzione *", "send-button": "Inviare", "contact-selected-label": "Contatto selezionato", @@ -243,5 +251,34 @@ "book-on-loan-label": "in prestito", "book-on-reading-label": "in lettura", "previous-month-tooltip": "Mese precedente", - "next-month-tooltip": "Mese successivo" + "next-month-tooltip": "Mese successivo", + "error-rest-client-connection-timeout": "La connessione al server è scaduta. Controlla la tua connessione internet e riprova: %s", + "error-rest-client-receive-timeout": "Il server ha impiegato troppo tempo per rispondere. Verifica la qualità della connessione e riprova: %s", + "error-rest-client-not-found": "La risorsa cercata non è stata trovata. Verifica i termini di ricerca o prova una query diversa: %s", + "error-rest-client-socket-exception": "Errore di connessione di rete rilevato. Controlla la tua connessione internet e riprova: %s", + "error-invalid-isbn": "Il formato dell'ISBN non è valido. Inserisci un numero ISBN valido (10 o 13 cifre): %s", + "error-unknown": "Si è verificato un errore imprevisto. Riprova più tardi o contatta il supporto: %s", + "error-auth-user-not-found": "Impossibile accedere. Verifica che la tua email sia registrata o iscriviti se non hai ancora un account: %s", + "error-auth-wrong-password": "Password non corretta. Verifica le tue credenziali e riprova: %s", + "error-auth-invalid-email": "Formato email non valido. Inserisci un indirizzo email valido: %s", + "error-auth-account-disabled": "Il tuo account è stato temporaneamente disabilitato. Contatta l'assistenza per ricevere aiuto: %s", + "error-auth-too-many-requests": "Troppi tentativi di accesso. Attendi alcuni minuti e riprova: %s", + "error-auth-operation-not-allowed": "Questo metodo di autenticazione non è disponibile al momento. Riprova più tardi: %s", + "error-auth-network-request-failed": "Connessione persa. Verifica la tua connessione internet e riprova: %s", + "error-auth-internal-error": "Qualcosa è andato storto. Se il problema persiste, contatta l'assistenza: %s", + "error-storage-invalid-value": "Problema rilevato nel salvataggio dei dati. Prova a disconnetterti e riconnetterti: %s", + "error-storage-write-failed": "Impossibile salvare le tue modifiche. Verifica lo spazio di archiviazione e riprova: %s", + "error-storage-read-failed": "Impossibile caricare i tuoi dati. Verifica la tua connessione internet e riprova: %s", + "error-local-database-conversion-failed": "Errore nell'elaborazione dei dati dal database. %s", + "error-local-database-not-null-constraint": "Un campo obbligatorio è vuoto. %s", + "error-local-database-open-failed": "Impossibile aprire il database. %s", + "error-local-database-operation-failed": "Operazione del database fallita durante lettura, scrittura o aggiornamento. %s", + "error-local-database-unique-constraint": "Questo record esiste già nel database. %s", + "notification-channel-loan-description": "Canale che notifica quando è il momento di ricevere il libro prestato.", + "notification-channel-loan-label": "Prestiti", + "notification-channel-read-description": "Canale che notifica quando è il momento della lettura.", + "notification-channel-read-label": "Letture", + "error-platform-permission-denied": "Permesso negato: %s", + "error-platform-permission-permanently-denied": "Permesso negato permanentemente. Apri le impostazioni per concederlo: %s", + "error-platform-unsupported": "Operazione non supportata su questo dispositivo: %s" } diff --git a/assets/lang/pt_BR.json b/assets/lang/pt_BR.json index 050736e1..40d7c444 100644 --- a/assets/lang/pt_BR.json +++ b/assets/lang/pt_BR.json @@ -35,6 +35,8 @@ "reading-time-description": "A programação para um momento de leitura é o primeiro passo para criar o hábito.\n\nDefina quais dias e o melhor horário para as suas leituras, e a gente te lembrará aqui nas notificações!", "reading-time-calculate-success-snackbar": "Hora de leitura calculado com sucesso.", "reading-time-notification-removed-success-snackbar": "Notificação removida com sucesso.", + "reading-time-notification-title": "A hora da leitura chegou!", + "reading-time-notification-body": "Muitas aventuras te aguardam!", "repeat-time-title": "Defina a repetição para ser notificado para a suas leituras:", "daily-dropdown-menu-entry": "Diariamente", "weekly-dropdown-menu-entry": "Semanalmente", @@ -87,9 +89,10 @@ "page-tooltip": "Página %s", "try-again-button": "Tentar novamente", "no-books-found-with-terms": "Não foi encontrado nenhum livro com esses termos.\nVerifique se digitou corretamente.", + "no-books-registered": "Nenhum livro cadastrado. Volte à página início para cadastrar.", "enter-title-label": "Digite o Título", "enter-author-label": "Digite o Autor", - "enter-category-label": "Digite o Gênero", + "enter-category-label": "Digite o Gênero (Inglês)", "enter-publisher-label": "Digite a Editora", "enter-isbn-label": "Digite o ISBN", "delete-text-typed-tooltip": "Apagar o texto digitado.", @@ -101,6 +104,8 @@ "search-by-isbn-tooltip": "Buscar por ISBN", "book-successfully-added-snackbar": "Livro adicionado com sucesso.", "book-successfully-removed-snackbar": "Livro removido com sucesso.", + "bookcase-inserted-success-snackbar": "Estante inserida com sucesso.", + "bookcase-updated-success-snackbar": "Estante atualizada com sucesso.", "remove-book-title": "Remover o livro %s", "remove-book-description": "Clicando em \"CONFIRMAR\" você removerá este livro da sua estante.\nTem Certeza?", "pages-label": "%s PÁGINAS", @@ -122,7 +127,6 @@ "field-cannot-be-empty-error": "Esse campo não pode estar vazio", "invalid-ISBN-format-error": "Formato do ISBN inválido", "camera-error": "Ocorreu algum erro com a câmera: %s", - "unknown-error": "erro desconhecido", "enter-loaned-title-label": "Digite o título do livro emprestado.", "enter-title-your-book-label": "Digite o título do seu livro.", "enter-bookcase-name-label": "Digite o nome da estante.", @@ -153,6 +157,7 @@ "delete-bookcase-description": "Clicando em \"CONFIRMAR\" você removerá a estante %s.\nTem Certeza?", "delete-books-title": "Deletar livros", "delete-books-description": "Clicando em \"CONFIRMAR\" você removerá os livros selecionados dessa estante.\nTem certeza?", + "all-books-already-inserted": "Todos os livros cadastrados já foram adicionados nessa estante.", "books-added-successfully-snackbar": "Livro adicionado com sucesso.\nAguarde até voltar à página anterior.", "select-books-title": "Selecionar os livros", "selected-books-quantity-label": "Livros selecionados: %s", @@ -178,6 +183,9 @@ "contact-required-field": "Contato *", "observation-optional-field": "Observação (opcional)", "loan-date-required-field": "Data do empréstimo *", + "loan-notification-title": "Ei, seu livro tá voltando!", + "loan-notification-body": "Olá! Só passando pra lembrar que tá na hora de %s0 devolver o %s1 que você emprestou no dia %s2.", + "loan-insertion-success-snackbar": "Empréstimo inserido com sucesso!", "devolution-date-required-field": "Data para devolução *", "send-button": "Enviar", "contact-selected-label": "Contato selecionado", @@ -243,5 +251,34 @@ "book-on-loan-label": "em leitura", "book-on-reading-label": "em empréstimo", "previous-month-tooltip": "Mês anterior", - "next-month-tooltip": "Próximo mês" + "next-month-tooltip": "Próximo mês", + "error-rest-client-connection-timeout": "A conexão com o servidor expirou. Verifique sua conexão de internet e tente novamente: %s", + "error-rest-client-receive-timeout": "O servidor demorou muito para responder. Verifique a qualidade da sua conexão e tente novamente: %s", + "error-rest-client-not-found": "O recurso solicitado não foi encontrado. Verifique os termos de pesquisa ou tente uma busca diferente: %s", + "error-rest-client-socket-exception": "Erro de conexão de rede detectado. Verifique sua conexão de internet e tente novamente: %s", + "error-invalid-isbn": "O formato do ISBN é inválido. Digite um número ISBN válido (10 ou 13 dígitos): %s", + "error-unknown": "Ocorreu um erro inesperado. Tente novamente mais tarde ou entre em contato com o suporte: %s", + "error-auth-user-not-found": "Impossível fazer login. Verifique se seu email está registrado ou se inscreva se não tiver uma conta: %s", + "error-auth-wrong-password": "Senha incorreta. Verifique suas credenciais e tente novamente: %s", + "error-auth-invalid-email": "Formato de email inválido. Digite um endereço de email válido: %s", + "error-auth-account-disabled": "Sua conta foi temporariamente desativada. Entre em contato com o suporte para obter ajuda: %s", + "error-auth-too-many-requests": "Muitas tentativas de login. Aguarde alguns minutos e tente novamente: %s", + "error-auth-operation-not-allowed": "Este método de autenticação não está disponível no momento. Tente novamente mais tarde: %s", + "error-auth-network-request-failed": "Conexão perdida. Verifique sua conexão com a internet e tente novamente: %s", + "error-auth-internal-error": "Algo deu errado. Se o problema persistir, entre em contato com o suporte: %s", + "error-storage-invalid-value": "Problema detectado ao salvar dados. Tente fazer logout e depois login novamente: %s", + "error-storage-write-failed": "Impossível salvar suas alterações. Verifique o espaço de armazenamento e tente novamente: %s", + "error-storage-read-failed": "Impossível carregar seus dados. Verifique sua conexão com a internet e tente novamente: %s", + "error-local-database-conversion-failed": "Falha ao processar dados do banco de dados. %s", + "error-local-database-not-null-constraint": "Um campo obrigatório está vazio. %s", + "error-local-database-open-failed": "Não foi possível abrir o banco de dados. %s", + "error-local-database-operation-failed": "Operação do banco de dados falhou durante leitura, escrita ou atualização. %s", + "error-local-database-unique-constraint": "Este registro já existe no banco de dados. %s", + "notification-channel-loan-description": "Canal que notifica quando é o dia de receber o livro emprestado.", + "notification-channel-loan-label": "Empréstimos", + "notification-channel-read-description": "Canal que notifica que está na hora da leitura.", + "notification-channel-read-label": "Leituras", + "error-platform-permission-denied": "Permissão negada: %s", + "error-platform-permission-permanently-denied": "Permissão negada permanentemente. Abra as configurações para concedê-la: %s", + "error-platform-unsupported": "Operação não suportada neste dispositivo: %s" } diff --git a/coverage/lcov.info b/coverage/lcov.info index fd4292e4..32f5d64d 100644 --- a/coverage/lcov.info +++ b/coverage/lcov.info @@ -9,6 +9,29 @@ DA:15,9 LF:7 LH:7 end_of_record +SF:lib/src/shared/constants/database_scripts/database_scripts.dart +DA:3,0 +DA:6,4 +DA:7,2 +DA:8,2 +DA:9,2 +DA:10,2 +DA:11,2 +DA:12,2 +DA:13,2 +DA:14,2 +DA:18,1 +DA:21,1 +DA:24,1 +DA:27,1 +DA:30,1 +DA:34,1 +DA:41,1 +DA:44,1 +DA:47,1 +LF:19 +LH:18 +end_of_record SF:lib/src/core/models/author_model.dart DA:5,10 DA:10,9 @@ -157,34 +180,11 @@ DA:53,0 LF:22 LH:11 end_of_record -SF:lib/src/shared/constants/database_scripts/database_scripts.dart -DA:3,0 -DA:6,4 -DA:7,2 -DA:8,2 -DA:9,2 -DA:10,2 -DA:11,2 -DA:12,2 -DA:13,2 -DA:14,2 -DA:18,1 -DA:21,1 -DA:24,1 -DA:27,1 -DA:30,1 -DA:34,1 -DA:41,1 -DA:44,1 -DA:47,1 -LF:19 -LH:18 -end_of_record SF:lib/src/core/helpers/date_time_format/date_time_format_extension.dart -DA:14,2 +DA:14,1 DA:16,1 -DA:17,2 -DA:18,2 +DA:17,1 +DA:18,1 DA:32,1 DA:34,1 DA:35,1 @@ -219,11 +219,11 @@ LF:15 LH:8 end_of_record SF:lib/src/core/errors/storage_exception/storage_exception.dart -DA:4,2 -DA:6,5 -DA:7,5 +DA:7,4 +DA:12,0 +DA:13,0 LF:3 -LH:3 +LH:1 end_of_record SF:lib/src/core/models/user_model.dart DA:9,2 @@ -257,32 +257,39 @@ LF:27 LH:18 end_of_record SF:lib/src/core/repositories/auth_repository/auth_repository_impl.dart -DA:10,1 -DA:14,1 -DA:17,2 -DA:18,1 -DA:25,1 +DA:11,1 +DA:15,1 +DA:19,2 +DA:20,1 DA:28,1 -DA:30,1 -DA:35,1 -DA:38,2 -DA:39,1 -DA:40,1 -DA:43,1 -DA:44,1 -LF:13 -LH:13 +DA:31,1 +DA:36,1 +DA:41,1 +DA:44,2 +DA:45,1 +DA:46,1 +DA:49,1 +DA:50,1 +DA:53,0 +DA:55,0 +DA:60,1 +DA:63,3 +DA:64,1 +DA:67,0 +DA:69,0 +LF:20 +LH:16 end_of_record SF:lib/src/shared/enums/sign_in_type.dart -DA:7,1 -DA:9,1 +DA:6,1 +DA:8,1 +DA:9,0 DA:10,0 DA:11,0 -DA:12,0 -DA:16,1 -DA:18,1 +DA:15,1 +DA:17,1 +DA:18,0 DA:19,0 -DA:20,0 LF:9 LH:4 end_of_record @@ -294,100 +301,116 @@ LF:3 LH:0 end_of_record SF:lib/src/core/errors/local_database_exception/local_database_exception.dart -DA:4,3 -DA:6,1 -DA:7,1 +DA:7,9 +DA:12,0 +DA:13,0 LF:3 -LH:3 +LH:1 end_of_record SF:lib/src/core/repositories/author_repository/authors_repository_impl.dart -DA:11,1 -DA:13,1 -DA:16,2 -DA:17,1 -DA:22,1 -DA:24,1 -DA:26,0 -DA:33,1 -DA:36,2 -DA:37,1 -DA:42,1 -DA:43,1 -DA:46,2 -DA:48,1 -DA:50,0 -DA:55,1 -DA:58,2 -DA:59,1 -DA:60,1 -DA:63,1 -DA:68,1 -DA:71,2 -DA:72,1 -DA:78,1 -LF:24 -LH:22 -end_of_record -SF:lib/src/core/repositories/book_authors_repository/book_authors_repository_impl.dart -DA:10,1 DA:12,1 +DA:14,1 DA:17,2 DA:18,1 -DA:23,2 +DA:23,1 +DA:25,1 +DA:26,1 DA:28,1 -DA:33,1 -DA:37,4 -DA:43,1 -DA:48,1 -DA:51,2 +DA:30,0 +DA:37,1 +DA:40,2 +DA:41,1 +DA:46,1 +DA:47,1 +DA:50,2 DA:52,1 -DA:58,1 -LF:13 -LH:13 +DA:53,1 +DA:55,1 +DA:57,0 +DA:62,1 +DA:65,2 +DA:66,1 +DA:67,1 +DA:70,1 +DA:75,1 +DA:78,2 +DA:79,1 +DA:85,1 +LF:28 +LH:26 +end_of_record +SF:lib/src/core/repositories/book_authors_repository/book_authors_repository_impl.dart +DA:11,1 +DA:13,1 +DA:18,2 +DA:19,1 +DA:24,2 +DA:32,1 +DA:33,0 +DA:35,0 +DA:40,1 +DA:43,2 +DA:44,1 +DA:45,1 +DA:52,1 +DA:57,1 +DA:60,2 +DA:61,1 +DA:67,1 +LF:17 +LH:15 end_of_record SF:lib/src/core/repositories/book_categories_repository/book_categories_repository_impl.dart -DA:10,1 -DA:12,1 -DA:17,2 -DA:18,1 -DA:23,2 -DA:28,1 -DA:33,1 -DA:37,4 -DA:43,1 -DA:48,1 -DA:51,2 +DA:11,1 +DA:13,1 +DA:18,2 +DA:19,1 +DA:24,2 +DA:32,1 +DA:33,0 +DA:35,0 +DA:40,1 +DA:43,2 +DA:44,1 +DA:45,1 DA:52,1 -DA:58,1 -LF:13 -LH:13 +DA:57,1 +DA:60,2 +DA:61,1 +DA:67,1 +LF:17 +LH:15 end_of_record SF:lib/src/core/repositories/book_on_case_repository/book_on_case_repository_impl.dart -DA:10,1 -DA:12,1 -DA:17,2 -DA:18,1 -DA:24,1 -DA:29,1 -DA:32,2 -DA:33,1 +DA:11,1 +DA:13,1 +DA:18,2 +DA:19,1 +DA:25,1 +DA:30,1 +DA:33,2 DA:34,1 -DA:39,1 -DA:41,1 +DA:35,1 +DA:40,1 +DA:42,1 DA:43,1 -DA:48,1 -DA:52,4 -DA:58,1 -DA:63,1 -DA:66,2 -DA:67,1 -DA:73,1 -DA:78,1 -DA:84,2 -DA:85,1 -DA:92,1 -LF:23 -LH:23 +DA:45,1 +DA:47,1 +DA:52,1 +DA:55,2 +DA:56,1 +DA:57,1 +DA:64,1 +DA:69,1 +DA:72,2 +DA:73,1 +DA:79,1 +DA:84,1 +DA:90,2 +DA:91,1 +DA:98,1 +LF:27 +LH:27 end_of_record SF:lib/src/core/models/bookcase_model.dart DA:10,3 @@ -428,137 +451,160 @@ LF:34 LH:25 end_of_record SF:lib/src/core/repositories/bookcase_repository/bookcase_repository_impl.dart -DA:11,1 -DA:13,1 -DA:16,3 -DA:17,2 -DA:20,1 +DA:12,1 +DA:14,1 +DA:17,3 +DA:18,2 +DA:21,1 +DA:22,1 DA:24,1 -DA:29,1 -DA:32,2 -DA:33,1 -DA:37,2 -DA:40,1 -DA:44,1 -DA:49,1 -DA:52,2 -DA:53,1 -DA:57,1 +DA:26,1 +DA:31,1 +DA:34,2 +DA:35,1 +DA:39,2 +DA:42,1 +DA:43,1 +DA:45,1 +DA:47,1 +DA:52,1 +DA:55,2 +DA:56,1 DA:60,1 +DA:63,1 DA:64,1 -DA:69,1 -DA:72,2 +DA:66,1 +DA:68,1 DA:73,1 +DA:76,2 DA:77,1 -DA:82,1 -DA:85,2 +DA:81,1 DA:86,1 -DA:87,1 +DA:89,2 +DA:90,1 DA:91,1 -DA:96,1 -DA:99,2 +DA:95,1 DA:100,1 -DA:101,1 -DA:103,1 +DA:103,2 +DA:104,1 +DA:105,1 DA:107,1 -DA:112,1 -DA:115,2 +DA:111,1 DA:116,1 -DA:122,1 -LF:37 -LH:37 +DA:119,2 +DA:120,1 +DA:126,1 +LF:43 +LH:43 end_of_record SF:lib/src/core/repositories/books_repository/books_repository_impl.dart -DA:11,1 -DA:13,1 -DA:16,3 -DA:17,2 -DA:19,1 +DA:12,1 +DA:14,1 +DA:17,3 +DA:18,2 +DA:20,1 +DA:21,1 DA:23,1 -DA:28,1 -DA:31,2 -DA:32,1 -DA:37,1 +DA:25,1 +DA:30,1 +DA:33,2 +DA:34,1 DA:39,1 -DA:43,1 -DA:48,1 -DA:51,2 -DA:52,1 -DA:53,1 +DA:41,1 +DA:42,1 +DA:44,1 +DA:46,1 +DA:51,1 +DA:54,2 +DA:55,1 DA:56,1 -DA:61,1 -DA:64,2 -DA:65,1 -DA:66,1 -DA:71,1 -DA:73,1 +DA:59,1 +DA:64,1 +DA:67,2 +DA:68,1 +DA:69,1 +DA:74,1 +DA:76,1 DA:77,1 -DA:82,1 -DA:85,2 +DA:79,1 +DA:81,1 DA:86,1 -DA:90,2 -DA:93,1 +DA:89,2 +DA:90,1 +DA:94,2 DA:97,1 +DA:98,1 +DA:100,1 DA:102,1 -DA:105,2 -DA:106,1 +DA:107,1 +DA:110,2 DA:111,1 DA:116,1 -DA:119,2 -DA:120,1 DA:121,1 -DA:126,2 -DA:128,1 -DA:132,1 -DA:137,1 -DA:143,2 -DA:144,1 -DA:147,2 -DA:151,1 -DA:156,1 -DA:161,2 -DA:164,2 -DA:165,1 -DA:168,1 -DA:172,1 -DA:177,1 -DA:180,2 +DA:124,2 +DA:125,1 +DA:126,1 +DA:131,2 +DA:133,1 +DA:134,1 +DA:136,1 +DA:138,1 +DA:143,1 +DA:149,2 +DA:150,1 +DA:153,2 +DA:157,1 +DA:162,1 +DA:168,2 +DA:170,2 +DA:171,1 +DA:174,1 +DA:178,1 +DA:180,1 DA:181,1 -DA:185,1 -DA:190,1 -DA:193,2 -DA:194,1 -DA:199,1 -LF:60 -LH:60 +DA:183,1 +DA:188,1 +DA:191,2 +DA:192,1 +DA:196,1 +DA:201,1 +DA:204,2 +DA:205,1 +DA:210,1 +LF:73 +LH:73 end_of_record SF:lib/src/core/repositories/category_repository/categories_repository_impl.dart -DA:11,1 -DA:13,1 -DA:16,2 -DA:17,1 -DA:22,1 -DA:24,1 -DA:26,0 -DA:33,1 -DA:36,2 +DA:12,1 +DA:14,1 +DA:17,2 +DA:18,1 +DA:23,1 +DA:25,1 +DA:26,1 +DA:28,1 +DA:30,0 DA:37,1 -DA:42,1 -DA:43,1 -DA:46,2 -DA:48,1 -DA:50,0 +DA:40,2 +DA:41,1 +DA:46,1 +DA:47,1 +DA:50,2 +DA:52,1 +DA:53,1 DA:55,1 -DA:58,2 -DA:59,1 -DA:60,1 -DA:64,1 -DA:69,1 -DA:72,2 -DA:73,1 -DA:79,1 -LF:24 -LH:22 +DA:57,0 +DA:62,1 +DA:65,2 +DA:66,1 +DA:67,1 +DA:71,1 +DA:76,1 +DA:79,2 +DA:80,1 +DA:86,1 +LF:28 +LH:26 end_of_record SF:lib/src/core/models/loan_model.dart DA:9,5 @@ -608,50 +654,56 @@ LF:43 LH:33 end_of_record SF:lib/src/core/repositories/loan_repository/loan_repository_impl.dart -DA:12,1 -DA:14,1 -DA:17,2 -DA:18,1 -DA:22,2 -DA:25,1 +DA:13,1 +DA:15,1 +DA:18,2 +DA:19,1 +DA:23,2 +DA:26,1 +DA:27,1 DA:29,1 -DA:34,1 -DA:37,2 -DA:38,3 -DA:39,1 -DA:40,1 -DA:41,2 -DA:42,2 -DA:47,2 -DA:50,1 -DA:54,1 -DA:59,1 -DA:62,2 -DA:63,1 -DA:67,1 +DA:31,1 +DA:36,1 +DA:39,2 +DA:40,3 +DA:41,1 +DA:42,1 +DA:43,2 +DA:44,2 +DA:49,2 +DA:52,1 +DA:53,1 +DA:55,1 +DA:57,1 +DA:62,1 +DA:65,2 +DA:66,1 DA:70,1 +DA:73,1 DA:74,1 -DA:79,1 -DA:82,2 +DA:76,1 +DA:78,1 DA:83,1 +DA:86,2 DA:87,1 -DA:92,1 -DA:95,2 +DA:91,1 DA:96,1 -DA:97,1 +DA:99,2 +DA:100,1 DA:101,1 -DA:106,1 -DA:109,2 +DA:105,1 DA:110,1 -DA:111,1 -DA:113,1 +DA:113,2 +DA:114,1 +DA:115,1 DA:117,1 -DA:122,1 -DA:125,2 +DA:121,1 DA:126,1 -DA:132,1 -LF:42 -LH:42 +DA:129,2 +DA:130,1 +DA:136,1 +LF:48 +LH:48 end_of_record SF:lib/src/core/models/reading_model.dart DA:7,5 @@ -690,52 +742,58 @@ LF:32 LH:24 end_of_record SF:lib/src/core/repositories/reading_repository/reading_repository_impl.dart -DA:12,1 -DA:16,1 -DA:19,2 -DA:20,1 -DA:25,2 -DA:28,1 +DA:13,1 +DA:17,1 +DA:20,2 +DA:21,1 +DA:26,2 +DA:29,1 +DA:30,1 DA:32,1 -DA:37,1 -DA:42,2 -DA:43,3 -DA:44,1 -DA:45,1 -DA:46,2 -DA:47,2 -DA:53,2 -DA:56,1 -DA:60,1 -DA:65,1 -DA:68,2 -DA:69,1 -DA:74,1 +DA:34,1 +DA:39,1 +DA:44,2 +DA:45,3 +DA:46,1 +DA:47,1 +DA:48,2 +DA:49,2 +DA:55,2 +DA:58,1 +DA:59,1 +DA:61,1 +DA:63,1 +DA:68,1 +DA:71,2 +DA:72,1 DA:77,1 +DA:80,1 DA:81,1 -DA:86,1 -DA:89,2 +DA:83,1 +DA:85,1 DA:90,1 +DA:93,2 DA:94,1 -DA:99,1 -DA:102,2 +DA:98,1 DA:103,1 -DA:104,1 +DA:106,2 +DA:107,1 DA:108,1 -DA:113,1 -DA:116,2 +DA:112,1 DA:117,1 -DA:118,1 -DA:120,1 +DA:120,2 +DA:121,1 +DA:122,1 DA:124,1 -DA:129,1 -DA:132,2 +DA:128,1 DA:133,1 -DA:139,1 -LF:42 -LH:42 +DA:136,2 +DA:137,1 +DA:143,1 +LF:48 +LH:48 end_of_record -SF:lib/src/core/enums/repeat_hour_time_type.dart +SF:lib/src/shared/enums/repeat_hour_time_type.dart DA:5,1 DA:7,1 DA:8,0 @@ -772,216 +830,119 @@ DA:62,1 DA:63,1 DA:67,1 DA:68,1 -DA:70,2 -DA:71,1 +DA:69,1 +DA:70,1 DA:72,1 DA:73,1 DA:74,1 -DA:78,3 -DA:80,1 -DA:81,2 -DA:83,0 -DA:85,0 -DA:88,2 -DA:92,3 +DA:75,1 +DA:79,3 +DA:81,1 +DA:82,2 +DA:84,0 +DA:86,0 +DA:89,2 DA:93,3 DA:94,3 DA:95,3 DA:96,3 -DA:99,0 -DA:101,0 +DA:97,3 +DA:100,0 DA:102,0 DA:103,0 DA:104,0 DA:105,0 -LF:47 -LH:31 +DA:106,0 +LF:48 +LH:32 end_of_record SF:lib/src/core/repositories/user_hour_time_repository/user_hour_time_repository_impl.dart -DA:10,1 -DA:14,1 -DA:17,2 -DA:18,1 -DA:25,1 +DA:11,1 +DA:15,1 +DA:19,2 +DA:20,1 DA:28,1 -DA:30,1 -DA:35,1 -DA:40,2 +DA:31,1 +DA:36,1 DA:41,1 -DA:42,1 -DA:45,1 -DA:46,1 -LF:13 +DA:46,2 +DA:47,1 +DA:48,1 +DA:51,1 +DA:52,1 +DA:55,0 +DA:57,0 +LF:15 LH:13 end_of_record SF:lib/src/core/repositories/user_page_reading_time_repository/user_page_reading_time_repository_impl.dart -DA:11,1 -DA:15,1 -DA:18,2 -DA:19,1 -DA:22,1 -DA:27,1 +DA:12,1 +DA:16,1 +DA:20,2 +DA:21,1 +DA:25,1 DA:30,1 DA:35,1 -DA:39,2 DA:40,1 -DA:41,1 -LF:11 -LH:11 +DA:45,2 +DA:46,1 +DA:47,1 +DA:51,1 +DA:54,0 +DA:56,0 +LF:14 +LH:12 end_of_record SF:lib/src/core/repositories/user_theme_repository/user_theme_repository_impl.dart -DA:10,1 -DA:14,1 -DA:17,3 -DA:20,1 -DA:22,0 -DA:24,0 -DA:29,1 -DA:31,1 -DA:36,1 -DA:39,2 +DA:11,1 +DA:15,1 +DA:18,3 +DA:21,1 +DA:23,0 +DA:25,0 +DA:30,1 +DA:35,1 DA:40,1 -DA:41,1 +DA:43,2 DA:44,1 -LF:13 +DA:45,1 +DA:48,1 +DA:51,0 +DA:53,0 +LF:15 LH:11 end_of_record -SF:lib/src/core/errors/book_exception/book_exception.dart -DA:4,1 -DA:6,1 -DA:8,2 -DA:13,1 -DA:15,0 -DA:17,0 -LF:6 -LH:4 -end_of_record SF:lib/src/core/repositories/remote_books_repository/remote_books_repository_impl.dart -DA:13,1 +DA:8,1 +DA:10,1 +DA:12,2 DA:15,1 -DA:18,2 +DA:17,2 +DA:20,1 +DA:24,2 +DA:27,1 +DA:31,2 +DA:34,1 +DA:36,2 +DA:39,1 +DA:41,2 +LF:13 +LH:13 +end_of_record +SF:lib/src/core/models/app_version_model.dart +DA:7,1 +DA:14,0 +DA:20,0 +DA:21,0 DA:22,0 +DA:23,0 DA:24,0 -DA:26,0 -DA:31,1 -DA:34,2 +DA:28,0 +DA:30,0 +DA:33,0 +DA:37,0 DA:38,0 -DA:40,0 -DA:42,0 -DA:47,1 -DA:51,2 -DA:55,0 -DA:57,0 -DA:59,0 -DA:64,1 -DA:68,2 -DA:72,0 -DA:74,0 -DA:76,0 -DA:81,1 -DA:84,2 -DA:88,0 -DA:90,0 -DA:92,0 -DA:97,1 -DA:100,2 -DA:102,1 -DA:104,1 -DA:106,1 -LF:31 -LH:16 -end_of_record -SF:lib/src/core/services/book_service/book_service_impl.dart -DA:21,1 -DA:33,1 -DA:36,2 -DA:38,3 -DA:40,3 -DA:41,3 -DA:48,1 -DA:53,1 -DA:56,2 -DA:58,1 -DA:60,1 -DA:66,1 -DA:71,1 -DA:74,2 -DA:76,3 -DA:78,3 -DA:79,3 -DA:86,1 -DA:91,1 -DA:94,2 -DA:96,1 -DA:98,2 -DA:99,2 -DA:100,1 -DA:103,2 -DA:104,2 -DA:107,2 -DA:108,1 -DA:113,1 -DA:115,2 -DA:116,2 -DA:117,1 -DA:120,2 -DA:122,0 -DA:125,2 -DA:126,1 -DA:132,1 -DA:137,1 -DA:141,2 -DA:143,1 -DA:148,1 -DA:151,2 -DA:153,1 -DA:158,1 -DA:161,2 -DA:163,1 -DA:168,1 -DA:174,2 -DA:179,1 -DA:184,1 -DA:190,2 -DA:195,1 -DA:200,1 -DA:203,2 -DA:205,1 -DA:210,1 -DA:213,2 -DA:215,1 -DA:220,1 -DA:222,2 -DA:225,3 -DA:226,1 -DA:228,1 -DA:229,2 -DA:230,2 -DA:231,1 -DA:235,2 -DA:238,3 -DA:239,1 -DA:241,1 -DA:242,2 -DA:243,2 -DA:244,1 -LF:73 -LH:72 -end_of_record -SF:lib/src/core/models/app_version_model.dart -DA:7,1 -DA:14,0 -DA:20,0 -DA:21,0 -DA:22,0 -DA:23,0 -DA:24,0 -DA:28,0 -DA:30,0 -DA:33,0 -DA:37,0 -DA:38,0 -DA:39,0 +DA:39,0 DA:40,0 DA:43,0 DA:45,0 @@ -992,17 +953,108 @@ LF:19 LH:1 end_of_record SF:lib/src/core/services/app_services/app_version_service/app_version_service_impl.dart -DA:6,0 DA:8,0 DA:10,0 -DA:12,0 DA:13,0 -DA:14,0 DA:15,0 DA:16,0 -LF:8 +DA:17,0 +DA:18,0 +DA:19,0 +DA:23,0 +DA:26,0 +DA:28,0 +LF:11 +LH:0 +end_of_record +SF:lib/src/core/errors/platform_exception/platform_exception.dart +DA:7,0 +DA:12,0 +DA:13,0 +LF:3 LH:0 end_of_record +SF:lib/src/core/services/book_service/book_service_impl.dart +DA:21,1 +DA:33,1 +DA:36,2 +DA:38,3 +DA:39,1 +DA:40,2 +DA:42,3 +DA:49,1 +DA:54,1 +DA:57,2 +DA:59,1 +DA:61,1 +DA:67,1 +DA:72,1 +DA:75,2 +DA:77,3 +DA:78,1 +DA:79,2 +DA:81,3 +DA:88,1 +DA:93,1 +DA:96,2 +DA:98,1 +DA:100,2 +DA:101,2 +DA:102,1 +DA:105,2 +DA:106,2 +DA:109,2 +DA:110,1 +DA:115,1 +DA:117,2 +DA:118,2 +DA:119,1 +DA:122,2 +DA:123,0 +DA:128,2 +DA:129,1 +DA:135,1 +DA:140,1 +DA:143,2 +DA:147,1 +DA:152,1 +DA:155,2 +DA:157,1 +DA:162,1 +DA:165,2 +DA:167,1 +DA:172,1 +DA:178,2 +DA:183,1 +DA:188,1 +DA:194,2 +DA:199,1 +DA:204,1 +DA:207,2 +DA:209,1 +DA:214,1 +DA:217,2 +DA:219,1 +DA:224,1 +DA:225,1 +DA:226,1 +DA:229,3 +DA:230,1 +DA:232,1 +DA:233,2 +DA:234,2 +DA:235,1 +DA:238,1 +DA:239,1 +DA:242,3 +DA:243,1 +DA:245,1 +DA:246,2 +DA:247,2 +DA:248,1 +LF:77 +LH:76 +end_of_record SF:lib/src/core/services/bookcase_service/bookcase_service_impl.dart DA:11,1 DA:17,1 @@ -1012,38 +1064,39 @@ DA:27,1 DA:30,2 DA:34,1 DA:39,1 -DA:43,1 DA:44,1 -DA:46,1 -DA:51,1 -DA:56,2 -DA:61,1 -DA:66,1 -DA:69,2 -DA:73,1 -DA:78,1 -DA:82,2 -DA:84,1 -DA:89,1 -DA:93,2 -DA:95,1 +DA:45,1 +DA:47,1 +DA:52,1 +DA:58,1 +DA:59,1 +DA:64,1 +DA:69,1 +DA:72,2 +DA:76,1 +DA:81,1 +DA:84,2 +DA:88,1 +DA:93,1 +DA:96,2 DA:100,1 -DA:106,2 -DA:111,1 +DA:105,1 +DA:111,2 DA:116,1 -DA:119,2 DA:121,1 +DA:124,2 DA:126,1 -DA:129,2 -DA:134,1 +DA:131,1 +DA:134,2 DA:139,1 -DA:142,2 -DA:147,1 +DA:144,1 +DA:147,2 DA:152,1 -DA:155,2 -DA:160,1 -LF:38 -LH:38 +DA:157,1 +DA:160,2 +DA:165,1 +LF:39 +LH:39 end_of_record SF:lib/src/core/services/loan_services/loan_service_impl.dart DA:9,1 @@ -1098,42 +1151,54 @@ LF:22 LH:22 end_of_record SF:lib/src/core/errors/auth_exception/auth_exception.dart -DA:4,1 -DA:6,0 -DA:7,0 +DA:7,1 +DA:12,0 +DA:13,0 LF:3 LH:1 end_of_record SF:lib/src/core/services/auth_service/auth_service_impl.dart -DA:14,1 -DA:20,1 -DA:23,2 -DA:25,1 -DA:26,2 -DA:31,1 +DA:16,1 +DA:22,0 +DA:24,0 +DA:27,0 DA:33,1 -DA:34,2 -DA:35,0 -DA:36,0 -DA:40,1 -DA:43,2 +DA:36,2 +DA:38,1 +DA:39,2 DA:44,1 -DA:45,1 -DA:47,0 -DA:48,0 +DA:46,1 +DA:47,1 +DA:49,1 +DA:51,0 DA:52,0 -DA:55,0 -DA:57,0 -DA:58,0 -DA:59,0 -DA:60,0 -LF:22 -LH:12 -end_of_record -SF:lib/src/core/services/auth_service/auth_strategy/auth_strategy_factory.dart -DA:12,0 -DA:14,0 -DA:15,0 +DA:54,0 +DA:59,1 +DA:62,2 +DA:63,1 +DA:66,2 +DA:69,1 +DA:71,0 +DA:72,0 +DA:74,0 +DA:76,0 +DA:77,0 +DA:79,0 +DA:84,0 +DA:87,0 +DA:89,0 +DA:90,0 +DA:92,0 +DA:94,0 +DA:95,0 +DA:97,0 +LF:34 +LH:14 +end_of_record +SF:lib/src/core/services/auth_service/auth_strategy/auth_strategy_factory.dart +DA:12,0 +DA:14,0 +DA:15,0 DA:16,0 DA:18,0 DA:19,0 @@ -1144,188 +1209,286 @@ LF:9 LH:0 end_of_record SF:lib/src/core/services/auth_service/auth_strategy/apple_auth_strategy.dart -DA:15,0 -DA:19,0 -DA:23,0 +DA:16,0 +DA:20,0 DA:24,0 DA:25,0 +DA:27,0 DA:28,0 -DA:29,0 -DA:30,0 DA:31,0 +DA:32,0 +DA:33,0 DA:34,0 DA:37,0 -DA:38,0 DA:40,0 DA:41,0 -DA:47,0 -DA:48,0 -DA:52,0 -DA:56,0 -DA:57,0 -DA:58,0 -DA:63,0 -DA:64,0 -DA:65,0 +DA:43,0 +DA:44,0 +DA:50,0 +DA:51,0 +DA:55,0 +DA:59,0 +DA:60,0 +DA:61,0 DA:66,0 +DA:67,0 +DA:68,0 +DA:69,0 DA:70,0 +DA:71,0 +DA:72,0 DA:73,0 -DA:75,0 -DA:76,0 +DA:74,0 DA:77,0 -DA:78,0 -LF:30 +DA:79,0 +DA:81,0 +DA:83,0 +DA:84,0 +DA:86,0 +DA:91,0 +DA:94,0 +DA:96,0 +DA:97,0 +DA:98,0 +DA:99,0 +DA:100,0 +DA:101,0 +DA:102,0 +DA:103,0 +DA:104,0 +DA:107,0 +DA:109,0 +DA:111,0 +DA:112,0 +DA:114,0 +LF:52 LH:0 end_of_record SF:lib/src/core/services/auth_service/auth_strategy/facebook_auth_strategy.dart -DA:16,0 -DA:22,0 -DA:26,0 +DA:17,0 +DA:23,0 DA:27,0 DA:28,0 +DA:30,0 DA:31,0 -DA:32,0 -DA:33,0 DA:34,0 +DA:35,0 +DA:36,0 DA:37,0 DA:40,0 -DA:41,0 DA:43,0 -DA:47,0 +DA:44,0 +DA:46,0 DA:50,0 -DA:51,0 -DA:52,0 -DA:56,0 -DA:57,0 -DA:61,0 -DA:65,0 -DA:66,0 -DA:67,0 -DA:75,0 -DA:76,0 +DA:53,0 +DA:54,0 +DA:55,0 +DA:59,0 +DA:60,0 +DA:64,0 +DA:68,0 +DA:69,0 +DA:70,0 DA:77,0 -DA:78,0 +DA:79,0 +DA:81,0 DA:82,0 +DA:83,0 +DA:84,0 DA:85,0 DA:86,0 +DA:87,0 DA:88,0 DA:89,0 -DA:90,0 -DA:91,0 -LF:34 +DA:93,0 +DA:95,0 +DA:97,0 +DA:99,0 +DA:100,0 +DA:102,0 +DA:107,0 +DA:110,0 +DA:111,0 +DA:113,0 +DA:114,0 +DA:115,0 +DA:116,0 +DA:117,0 +DA:118,0 +DA:119,0 +DA:120,0 +DA:121,0 +DA:124,0 +DA:126,0 +DA:128,0 +DA:129,0 +DA:131,0 +LF:58 LH:0 end_of_record SF:lib/src/core/services/auth_service/auth_strategy/google_auth_strategy.dart -DA:12,0 -DA:18,0 -DA:21,0 +DA:13,0 +DA:19,0 DA:22,0 -DA:27,0 -DA:29,0 +DA:23,0 +DA:25,0 DA:31,0 DA:32,0 DA:33,0 +DA:35,0 DA:36,0 +DA:37,0 DA:40,0 -DA:41,0 -DA:42,0 -DA:47,0 -DA:48,0 -DA:49,0 -DA:50,0 +DA:44,0 +DA:45,0 +DA:46,0 +DA:51,0 +DA:52,0 +DA:53,0 DA:54,0 +DA:55,0 +DA:56,0 DA:57,0 DA:58,0 -DA:60,0 -DA:61,0 -DA:62,0 +DA:59,0 DA:63,0 -LF:24 +DA:65,0 +DA:67,0 +DA:69,0 +DA:70,0 +DA:72,0 +DA:77,0 +DA:80,0 +DA:81,0 +DA:83,0 +DA:84,0 +DA:85,0 +DA:86,0 +DA:87,0 +DA:88,0 +DA:89,0 +DA:90,0 +DA:91,0 +DA:94,0 +DA:96,0 +DA:98,0 +DA:99,0 +DA:101,0 +LF:47 LH:0 end_of_record SF:lib/src/core/utils/verifier/isbn_verifier.dart DA:11,9 -DA:16,6 -DA:25,2 +DA:17,6 DA:26,2 -DA:28,6 -DA:29,4 -DA:31,4 -DA:43,2 -DA:44,4 -DA:48,2 -DA:49,1 -DA:50,2 -DA:51,1 +DA:27,2 +DA:29,6 +DA:30,4 +DA:32,4 +DA:44,2 +DA:45,4 +DA:49,2 +DA:50,1 +DA:51,2 DA:52,1 DA:53,1 -DA:56,2 -DA:69,2 -DA:70,4 -DA:74,4 -DA:75,2 -DA:76,4 -DA:78,2 -DA:81,4 +DA:54,1 +DA:57,2 +DA:70,2 +DA:71,4 +DA:75,4 +DA:76,2 +DA:77,4 +DA:79,2 +DA:82,4 LF:23 LH:23 end_of_record SF:lib/src/core/data_sources/remote_books_data_source/google_books_data_source_impl.dart -DA:13,1 -DA:18,1 -DA:19,1 -DA:21,1 -DA:23,2 -DA:25,1 -DA:27,2 -DA:29,1 -DA:31,2 -DA:33,1 -DA:35,2 -DA:37,1 -DA:39,2 -DA:41,1 -DA:43,2 -DA:45,1 -DA:52,1 -DA:55,1 -DA:58,1 -DA:59,1 -DA:60,1 -DA:62,1 -DA:64,1 -DA:67,2 -LF:24 -LH:24 -end_of_record -SF:lib/src/core/adapters/google_books_adapter.dart DA:12,1 -DA:13,1 -DA:14,0 -DA:16,1 -DA:17,3 +DA:17,1 DA:18,1 -DA:23,1 +DA:20,1 +DA:22,2 DA:24,1 -DA:25,1 DA:26,2 -DA:28,3 -DA:29,3 -DA:30,1 -DA:31,2 -DA:33,2 -DA:34,1 -DA:35,3 -DA:36,3 -DA:37,1 +DA:28,1 +DA:30,2 +DA:32,1 +DA:34,2 +DA:36,1 DA:38,2 -DA:39,3 -DA:41,2 -DA:43,3 -DA:44,2 -LF:24 +DA:40,1 +DA:42,2 +DA:44,1 +DA:51,1 +DA:54,1 +DA:57,1 +DA:58,1 +DA:59,1 +DA:62,1 +DA:64,1 +LF:23 LH:23 end_of_record +SF:lib/src/core/errors/rest_client_exception/rest_client_exception.dart +DA:7,1 +DA:12,0 +DA:13,0 +LF:3 +LH:1 +end_of_record +SF:lib/src/core/adapters/google_books_adapter.dart +DA:12,1 +DA:13,1 +DA:14,0 +DA:16,5 +DA:21,1 +DA:22,1 +DA:23,1 +DA:24,2 +DA:25,1 +DA:26,2 +DA:27,4 +DA:28,2 +DA:30,2 +DA:31,1 +DA:32,3 +DA:33,4 +DA:34,2 +DA:36,3 +DA:39,2 +DA:41,3 +DA:42,2 +LF:21 +LH:20 +end_of_record +SF:lib/src/shared/cubits/user_logged_cubit/user_logged_state.dart +DA:11,1 +DA:20,1 +LF:2 +LH:2 +end_of_record +SF:lib/src/shared/cubits/user_logged_cubit/user_logged_cubit.dart +DA:12,1 +DA:14,2 +DA:16,1 +DA:18,2 +DA:20,2 +DA:22,1 +DA:23,1 +DA:25,1 +DA:26,1 +DA:27,1 +DA:28,1 +DA:29,1 +DA:32,1 +DA:33,1 +DA:34,1 +DA:36,1 +LF:16 +LH:16 +end_of_record SF:lib/src/shared/blocs/book_bloc/book_event.dart DA:10,1 DA:18,1 @@ -1337,7 +1500,7 @@ LH:5 end_of_record SF:lib/src/shared/blocs/book_bloc/book_state.dart DA:12,2 -DA:20,2 +DA:21,2 LF:2 LH:2 end_of_record @@ -1356,131 +1519,245 @@ DA:33,1 DA:34,2 DA:38,2 DA:39,1 -DA:40,0 +DA:40,1 DA:41,1 -DA:42,3 -DA:46,1 -DA:51,2 -DA:53,3 -DA:55,1 -DA:56,2 -DA:59,2 -DA:60,1 -DA:61,0 -DA:62,1 +DA:42,1 +DA:43,1 +DA:47,0 +DA:48,0 +DA:50,0 +DA:56,1 +DA:61,2 DA:63,3 -DA:67,1 -DA:72,2 -DA:75,3 -DA:77,1 -DA:78,2 -DA:82,2 -DA:83,1 -DA:84,0 -DA:85,1 -DA:86,3 -DA:90,1 -DA:95,2 -DA:98,3 -DA:100,1 -DA:101,2 -DA:105,2 +DA:65,1 +DA:66,2 +DA:69,2 +DA:70,1 +DA:71,1 +DA:72,1 +DA:73,1 +DA:74,1 +DA:78,0 +DA:79,0 +DA:81,0 +DA:87,1 +DA:92,2 +DA:94,2 +DA:95,1 +DA:98,1 +DA:99,2 +DA:103,2 +DA:104,1 +DA:105,1 DA:106,1 -DA:107,0 +DA:107,1 DA:108,1 -DA:109,3 -DA:113,1 -DA:118,2 -DA:120,2 +DA:112,0 +DA:113,0 +DA:115,0 DA:121,1 -DA:123,1 -DA:124,2 +DA:126,2 DA:128,2 DA:129,1 -DA:130,0 -DA:131,1 -DA:132,3 -DA:136,1 -DA:141,2 -DA:143,1 -DA:144,2 -DA:146,2 -DA:150,2 -DA:152,1 -DA:153,2 -DA:157,2 -DA:158,0 -DA:159,0 -DA:160,0 -DA:161,0 -LF:71 -LH:62 +DA:132,1 +DA:133,2 +DA:137,2 +DA:138,1 +DA:139,1 +DA:140,1 +DA:141,1 +DA:142,1 +DA:146,0 +DA:147,0 +DA:149,0 +DA:155,1 +DA:160,2 +DA:162,2 +DA:163,1 +DA:166,1 +DA:167,2 +DA:171,2 +DA:172,1 +DA:173,1 +DA:174,1 +DA:175,1 +DA:176,1 +DA:180,0 +DA:181,0 +DA:183,0 +DA:189,1 +DA:194,2 +DA:196,1 +DA:197,2 +DA:199,1 +DA:200,1 +DA:208,2 +DA:210,1 +DA:211,2 +DA:215,2 +DA:216,0 +DA:217,0 +DA:218,0 +DA:219,0 +DA:220,0 +DA:224,0 +DA:225,0 +DA:227,0 +LF:98 +LH:75 end_of_record SF:lib/src/shared/cubits/user_theme_cubit/user_theme_cubit.dart -DA:11,1 -DA:13,2 -DA:15,1 -DA:17,2 -DA:19,2 -DA:22,2 -DA:25,1 +DA:12,1 +DA:14,2 +DA:16,1 +DA:18,2 +DA:20,2 +DA:23,2 DA:26,1 -DA:31,1 +DA:27,1 DA:32,1 -DA:34,1 +DA:33,1 DA:35,1 DA:36,1 DA:37,1 -DA:40,1 -DA:41,1 +DA:38,1 +DA:39,1 DA:42,1 DA:43,1 -DA:49,1 -DA:51,2 -DA:53,2 -DA:57,1 -DA:58,1 -DA:59,1 -DA:66,1 -DA:67,1 -DA:69,1 +DA:44,1 +DA:46,1 +DA:52,1 +DA:54,2 +DA:56,2 +DA:60,1 +DA:61,1 +DA:62,1 DA:70,1 DA:71,1 -DA:72,1 +DA:73,1 +DA:74,1 DA:75,1 DA:76,1 DA:77,1 -DA:78,1 -LF:34 -LH:34 +DA:80,1 +DA:81,1 +DA:82,1 +DA:84,1 +LF:36 +LH:36 end_of_record SF:lib/src/shared/cubits/user_theme_cubit/user_theme_state.dart DA:11,1 -DA:19,1 +DA:20,1 LF:2 LH:2 end_of_record -SF:lib/src/features/auth/bloc/auth_bloc.dart -DA:12,3 -DA:13,2 +SF:lib/src/shared/cubits/user_notification_cubit/user_notification_state.dart +DA:14,1 +LF:1 +LH:1 +end_of_record +SF:lib/src/shared/cubits/user_notification_cubit/user_notification_cubit.dart +DA:12,1 +DA:14,2 DA:16,1 -DA:21,2 +DA:18,2 +DA:20,2 +DA:22,2 +DA:23,1 +DA:24,0 +DA:25,0 +DA:26,0 +DA:27,0 +DA:30,1 +DA:31,1 +DA:32,1 +DA:34,1 +LF:15 +LH:11 +end_of_record +SF:lib/src/core/models/custom_notification_model.dart +DA:5,0 +DA:7,0 +DA:8,0 +DA:12,0 +DA:14,0 +DA:15,0 +DA:28,2 +DA:37,0 +DA:45,0 +DA:46,0 +DA:47,0 +DA:48,0 +DA:49,0 +DA:50,0 +DA:51,0 +DA:55,0 +DA:57,0 +DA:60,0 +DA:64,0 +DA:65,0 +DA:66,0 +DA:67,0 +DA:68,0 +DA:69,0 +DA:72,0 +DA:74,0 +DA:75,0 +DA:76,0 +DA:77,0 +DA:78,0 +DA:79,0 +LF:31 +LH:1 +end_of_record +SF:lib/src/features/about/bloc/about_bloc.dart +DA:13,3 +DA:14,2 +DA:17,1 +DA:22,2 DA:23,2 -DA:24,1 -DA:27,1 +DA:24,2 +DA:25,1 +DA:26,0 +DA:27,0 +DA:28,0 +DA:29,0 +DA:32,1 +DA:33,1 +DA:34,1 +DA:36,1 +LF:15 +LH:11 +end_of_record +SF:lib/src/features/about/bloc/about_state.dart +DA:10,1 +DA:19,1 +LF:2 +LH:2 +end_of_record +SF:lib/src/features/auth/bloc/auth_bloc.dart +DA:13,3 +DA:14,2 +DA:17,1 +DA:22,2 +DA:24,2 +DA:25,1 DA:28,1 DA:29,1 -DA:36,2 -DA:37,1 -DA:38,1 -DA:39,1 -DA:40,2 +DA:30,1 +DA:39,2 +DA:40,1 +DA:41,1 +DA:42,1 DA:43,1 DA:44,1 -DA:45,1 -DA:46,1 -LF:18 -LH:18 +DA:47,1 +DA:48,1 +DA:49,1 +DA:51,1 +LF:19 +LH:19 end_of_record SF:lib/src/features/auth/bloc/auth_event.dart DA:8,1 @@ -1488,29 +1765,10 @@ LF:1 LH:1 end_of_record SF:lib/src/features/auth/bloc/auth_state.dart -DA:14,1 +DA:15,1 LF:1 LH:1 end_of_record -SF:lib/src/features/about/bloc/about_bloc.dart -DA:11,3 -DA:12,2 -DA:15,1 -DA:20,2 -DA:21,2 -DA:22,2 -DA:24,1 -DA:25,1 -DA:26,2 -LF:9 -LH:9 -end_of_record -SF:lib/src/features/about/bloc/about_state.dart -DA:10,1 -DA:18,1 -LF:2 -LH:2 -end_of_record SF:lib/src/features/book_detail/bloc/book_detail_event.dart DA:8,2 DA:16,2 @@ -1520,64 +1778,67 @@ LH:3 end_of_record SF:lib/src/features/book_detail/bloc/book_detail_state.dart DA:10,2 -DA:18,2 +DA:19,2 LF:2 LH:2 end_of_record SF:lib/src/features/book_detail/bloc/book_detail_bloc.dart -DA:14,1 -DA:16,2 +DA:15,1 DA:17,2 DA:18,2 DA:19,2 -DA:22,1 -DA:27,2 -DA:29,2 -DA:30,1 -DA:33,2 -DA:34,1 +DA:20,2 +DA:23,1 +DA:28,2 +DA:30,2 +DA:31,1 +DA:34,2 DA:35,1 DA:36,1 -DA:37,2 -DA:41,1 -DA:42,1 -DA:43,2 -DA:49,1 -DA:54,2 -DA:56,2 -DA:57,1 +DA:37,1 +DA:38,1 +DA:39,1 +DA:43,1 +DA:44,1 +DA:46,1 +DA:52,1 +DA:57,2 +DA:59,2 DA:60,1 -DA:61,1 -DA:62,1 -DA:67,2 -DA:68,1 -DA:69,1 -DA:70,1 -DA:71,2 +DA:63,1 +DA:64,1 +DA:65,1 +DA:73,2 +DA:74,1 DA:75,1 DA:76,1 -DA:77,2 +DA:77,1 +DA:78,1 +DA:82,1 DA:83,1 -DA:88,2 -DA:90,3 -DA:92,1 -DA:93,1 -DA:94,1 +DA:85,1 +DA:91,1 DA:96,2 -DA:102,3 -DA:103,1 -DA:104,1 -DA:105,1 -DA:111,2 +DA:98,3 +DA:100,1 +DA:101,1 +DA:102,1 +DA:105,2 +DA:111,3 +DA:112,1 DA:113,1 DA:114,1 -DA:115,1 -DA:116,2 -DA:120,1 -DA:121,1 -DA:122,2 -LF:51 -LH:51 +DA:121,2 +DA:123,1 +DA:124,1 +DA:125,1 +DA:126,1 +DA:127,1 +DA:131,1 +DA:132,1 +DA:134,1 +LF:54 +LH:54 end_of_record SF:lib/src/core/helpers/book_status/book_status_extension.dart DA:7,0 @@ -1591,44 +1852,128 @@ DA:19,2 LF:8 LH:4 end_of_record -SF:lib/src/features/book_detail/views/widgets/book_pages_reading_time/bloc/book_pages_reading_time_bloc.dart +SF:lib/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_event.dart +DA:8,1 +DA:17,1 +LF:2 +LH:2 +end_of_record +SF:lib/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_state.dart +DA:11,1 +DA:23,1 +LF:2 +LH:2 +end_of_record +SF:lib/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_bloc.dart DA:13,1 DA:15,2 DA:16,2 -DA:19,1 -DA:24,2 +DA:17,2 +DA:20,1 +DA:25,2 DA:27,2 -DA:29,1 -DA:30,1 -DA:34,1 -DA:35,1 +DA:28,1 +DA:31,1 +DA:32,1 DA:36,1 DA:37,1 +DA:38,1 +DA:39,1 DA:40,1 -DA:41,1 -DA:42,1 DA:43,1 -LF:16 -LH:16 -end_of_record -SF:lib/src/features/book_detail/views/widgets/book_pages_reading_time/bloc/book_pages_reading_time_state.dart -DA:11,1 -DA:19,1 -LF:2 -LH:2 -end_of_record -SF:lib/src/core/services/app_services/launcher_service/launcher_service.dart -DA:4,0 -DA:6,0 -DA:8,0 -DA:17,0 -DA:21,0 +DA:44,1 +DA:45,1 +DA:47,1 +DA:53,1 +DA:58,2 +DA:60,2 +DA:61,1 +DA:62,1 +DA:65,1 +DA:66,1 +DA:67,1 +DA:76,2 +DA:77,1 +DA:78,1 +DA:79,1 +DA:80,1 +DA:81,1 +DA:84,1 +DA:85,1 +DA:86,1 +DA:88,1 +LF:37 +LH:37 +end_of_record +SF:lib/src/features/book_detail/views/widgets/book_pages_reading_time/bloc/book_pages_reading_time_bloc.dart +DA:14,1 +DA:16,2 +DA:17,2 +DA:20,1 +DA:25,2 +DA:27,1 +DA:28,1 +DA:30,1 +DA:31,1 +DA:35,1 +DA:36,1 +DA:37,1 +DA:38,1 +DA:39,1 +DA:42,1 +DA:43,1 +DA:44,1 +DA:46,1 +LF:18 +LH:18 +end_of_record +SF:lib/src/features/book_detail/views/widgets/book_pages_reading_time/bloc/book_pages_reading_time_state.dart +DA:11,1 +DA:20,1 +LF:2 +LH:2 +end_of_record +SF:lib/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart +DA:5,3 +DA:9,3 +DA:10,0 +DA:14,3 +DA:15,0 +DA:18,3 +DA:19,0 +DA:22,3 DA:23,0 +DA:26,9 +DA:29,0 +DA:30,0 +LF:12 +LH:6 +end_of_record +SF:lib/src/core/helpers/error_code/storage_error_code/storage_error_code_extension.dart +DA:5,0 +DA:9,0 +DA:12,0 +DA:15,0 +DA:18,0 +LF:5 +LH:0 +end_of_record +SF:lib/src/core/services/app_services/launcher_service/launcher_service.dart +DA:6,0 +DA:8,0 +DA:10,0 +DA:21,0 DA:24,0 -DA:27,0 -DA:28,0 -DA:40,0 -LF:10 +DA:26,0 +DA:31,0 +DA:33,0 +DA:34,0 +DA:37,0 +DA:38,0 +DA:55,0 +DA:58,0 +DA:60,0 +LF:14 LH:0 end_of_record SF:lib/src/core/services/app_services/show_dialog_service/show_dialog_service.dart @@ -1642,37 +1987,36 @@ DA:32,2 DA:38,2 DA:39,2 DA:40,2 -DA:47,2 +DA:46,2 +DA:48,2 DA:49,2 -DA:50,2 +DA:52,2 DA:53,2 -DA:54,2 -DA:55,0 -DA:57,0 -DA:60,0 +DA:54,0 +DA:56,0 +DA:59,0 +DA:64,2 DA:65,2 -DA:66,2 -DA:68,0 -DA:71,2 -DA:84,0 -DA:88,0 -DA:90,0 +DA:67,0 +DA:70,2 +DA:83,0 +DA:87,0 +DA:89,0 +DA:97,0 DA:98,0 DA:99,0 -DA:100,0 -DA:102,0 -DA:106,0 +DA:101,0 +DA:105,0 +DA:107,0 DA:108,0 -DA:109,0 DA:110,0 -DA:112,0 +DA:111,0 DA:113,0 -DA:115,0 +DA:118,0 +DA:120,0 DA:121,0 -DA:123,0 DA:124,0 -DA:127,0 -LF:40 +LF:39 LH:18 end_of_record SF:lib/src/core/services/app_services/snackbar_service/snackbar_service.dart @@ -1705,149 +2049,152 @@ LF:25 LH:25 end_of_record SF:lib/src/features/book_detail/views/book_detail_page.dart -DA:18,1 -DA:23,1 +DA:19,1 DA:24,1 -DA:50,1 -DA:52,1 -DA:54,2 -DA:55,1 +DA:25,1 +DA:51,1 +DA:53,1 +DA:55,2 DA:56,1 -DA:59,3 -DA:60,1 +DA:57,1 +DA:60,3 DA:61,1 -DA:62,3 -DA:67,1 -DA:70,1 -DA:72,3 -DA:73,2 -DA:74,1 -DA:78,0 +DA:62,1 +DA:63,3 +DA:68,1 +DA:71,1 +DA:73,3 +DA:74,2 +DA:75,1 DA:79,0 DA:80,0 -DA:83,0 +DA:81,0 DA:84,0 DA:85,0 -DA:87,0 -DA:89,0 +DA:86,0 +DA:88,0 DA:90,0 -DA:94,1 -DA:99,1 -DA:101,1 -DA:104,1 -DA:106,2 -DA:109,1 -DA:111,1 +DA:91,0 +DA:95,1 +DA:100,1 +DA:102,1 +DA:105,1 +DA:107,2 +DA:110,1 DA:112,1 DA:113,1 DA:114,1 -DA:116,1 -DA:124,1 -DA:127,2 +DA:115,1 +DA:117,1 +DA:125,1 +DA:128,1 DA:129,1 -DA:131,1 -DA:140,1 -DA:141,1 -DA:142,1 -DA:143,1 -DA:144,3 +DA:130,1 +DA:133,1 +DA:135,1 +DA:137,1 +DA:144,1 DA:145,1 -DA:146,0 -DA:147,0 -DA:148,0 -DA:152,3 -DA:156,1 -DA:158,2 -DA:159,1 -DA:160,3 -DA:161,1 -DA:162,1 +DA:146,1 +DA:147,1 +DA:148,3 +DA:149,1 +DA:150,0 +DA:151,0 +DA:152,0 +DA:156,3 +DA:160,1 +DA:162,2 DA:163,1 DA:164,3 DA:165,1 DA:166,1 -DA:168,2 +DA:167,1 +DA:168,3 +DA:169,1 DA:170,1 -DA:171,1 -DA:172,1 -DA:173,1 +DA:172,2 DA:174,1 DA:175,1 +DA:176,1 DA:177,1 DA:178,1 DA:179,1 -DA:180,1 +DA:181,1 +DA:182,1 +DA:183,1 DA:184,1 -DA:185,1 -DA:187,1 -DA:190,1 -DA:195,1 -DA:202,1 -DA:203,1 -DA:204,1 +DA:188,1 +DA:189,1 +DA:191,1 +DA:194,1 +DA:199,1 DA:206,1 DA:207,1 DA:208,1 -DA:210,2 -DA:219,1 -DA:220,1 -DA:222,1 +DA:210,1 +DA:211,1 +DA:212,1 +DA:214,2 +DA:223,1 +DA:224,1 DA:226,1 -DA:228,1 -DA:229,1 -DA:231,4 +DA:230,1 +DA:232,1 DA:233,1 -DA:234,1 -DA:239,1 -DA:241,1 -DA:246,1 -DA:249,1 +DA:235,4 +DA:237,1 +DA:238,1 +DA:243,1 +DA:245,1 DA:250,1 -DA:251,1 DA:253,1 -DA:255,0 -DA:256,0 -DA:260,1 -DA:261,1 +DA:254,1 +DA:255,1 +DA:257,1 +DA:259,0 +DA:260,0 DA:264,1 +DA:265,1 DA:268,1 -DA:269,1 -DA:270,1 -DA:272,2 +DA:272,1 DA:273,1 -DA:280,1 -DA:282,1 +DA:274,1 +DA:276,2 +DA:277,1 DA:284,1 -DA:290,1 -DA:292,0 -DA:293,0 -DA:295,1 -DA:296,1 -DA:297,1 +DA:286,1 +DA:288,1 +DA:294,1 +DA:296,0 +DA:297,0 DA:299,1 -DA:309,1 -DA:312,1 +DA:300,1 +DA:301,1 +DA:303,1 DA:313,1 -DA:314,1 -DA:315,1 +DA:316,1 DA:317,1 +DA:318,1 DA:319,1 -DA:325,1 -DA:327,1 -DA:328,1 -DA:333,1 -DA:334,1 +DA:321,1 +DA:323,1 +DA:329,1 +DA:331,1 +DA:332,1 DA:337,1 DA:338,1 -DA:340,1 +DA:341,1 DA:342,1 -DA:348,1 -DA:350,1 -DA:351,1 -DA:353,1 +DA:344,1 +DA:346,1 +DA:352,1 +DA:354,1 DA:355,1 -LF:141 -LH:125 +DA:357,1 +DA:359,1 +LF:144 +LH:128 end_of_record SF:lib/src/shared/widgets/book_widget/book_widget.dart DA:13,1 @@ -1876,45 +2223,49 @@ LH:9 end_of_record SF:lib/src/features/book_detail/views/widgets/book_description/book_description_widget.dart DA:7,1 -DA:10,1 -DA:12,1 DA:13,1 -DA:14,1 DA:15,1 -DA:18,3 -DA:20,1 -DA:21,1 -DA:22,1 +DA:16,1 +DA:17,1 +DA:18,1 +DA:21,3 DA:23,1 -DA:24,4 +DA:24,1 +DA:25,1 +DA:26,1 +DA:27,4 LF:12 LH:12 end_of_record SF:lib/src/features/book_detail/views/widgets/book_pages_reading_time/widgets/book_pages_reading_time.dart -DA:10,1 -DA:15,1 +DA:11,1 DA:16,1 -DA:22,1 -DA:24,1 -DA:25,3 -DA:26,1 +DA:17,1 +DA:23,1 +DA:25,1 +DA:26,3 DA:27,1 -DA:31,1 -DA:36,1 -DA:38,0 +DA:28,1 +DA:32,1 +DA:37,1 DA:39,0 -DA:41,0 +DA:40,0 DA:42,0 -DA:45,0 +DA:43,0 DA:46,0 -DA:50,0 -DA:54,0 +DA:47,0 +DA:51,0 +DA:52,0 +DA:53,0 DA:55,0 -DA:62,1 -DA:64,1 -DA:65,1 -DA:66,1 -LF:23 +DA:56,0 +DA:59,0 +DA:60,0 +DA:67,1 +DA:69,1 +DA:70,1 +DA:71,1 +LF:27 LH:14 end_of_record SF:lib/src/shared/widgets/center_circular_progress_indicator/center_circular_progress_indicator.dart @@ -2032,119 +2383,86 @@ DA:80,1 LF:36 LH:22 end_of_record -SF:lib/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_event.dart -DA:8,1 -DA:17,1 -LF:2 -LH:2 -end_of_record -SF:lib/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_state.dart -DA:11,1 -DA:22,1 -LF:2 -LH:2 -end_of_record -SF:lib/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_bloc.dart -DA:12,1 -DA:14,2 -DA:15,2 -DA:16,2 -DA:19,1 -DA:24,2 -DA:26,2 -DA:27,1 -DA:30,1 -DA:31,1 -DA:35,1 -DA:36,1 -DA:37,1 -DA:38,2 -DA:40,1 -DA:41,1 -DA:42,2 -DA:47,1 -DA:52,2 -DA:54,2 -DA:55,1 -DA:56,1 -DA:59,1 -DA:60,1 -DA:61,1 -DA:67,2 -DA:68,1 -DA:69,1 -DA:70,1 -DA:71,2 -DA:73,1 -DA:74,1 -DA:75,2 -LF:33 -LH:33 -end_of_record SF:lib/src/features/bookcase/bloc/bookcase_state.dart DA:10,2 -DA:20,2 +DA:21,2 LF:2 LH:2 end_of_record SF:lib/src/features/bookcase/bloc/bookcase_bloc.dart -DA:16,1 -DA:19,2 +DA:17,1 DA:20,2 DA:21,2 DA:22,2 -DA:25,1 -DA:30,2 -DA:32,1 +DA:23,2 +DA:26,1 +DA:31,2 DA:33,1 -DA:34,4 +DA:34,1 DA:35,1 -DA:36,3 -DA:40,1 -DA:45,2 -DA:47,2 -DA:48,1 -DA:49,4 -DA:50,1 -DA:51,3 -DA:55,1 -DA:60,2 +DA:36,1 +DA:37,1 +DA:38,1 +DA:41,1 +DA:42,1 +DA:43,1 +DA:45,1 +DA:51,1 +DA:56,2 +DA:58,2 +DA:59,1 +DA:60,1 +DA:61,1 DA:62,1 -DA:64,2 -DA:65,2 -DA:66,2 -DA:68,2 -DA:69,1 +DA:63,1 +DA:66,1 +DA:67,1 +DA:68,1 DA:70,1 -DA:77,1 -DA:78,1 -DA:79,4 -DA:80,1 -DA:81,3 -DA:85,1 +DA:76,1 +DA:81,2 +DA:83,1 +DA:85,2 DA:86,2 -DA:88,1 -DA:89,2 -DA:93,1 -DA:96,1 -DA:98,2 -DA:100,1 -DA:101,2 +DA:87,2 +DA:90,2 +DA:91,1 +DA:92,1 +DA:95,3 +DA:102,1 +DA:103,1 +DA:104,1 DA:105,1 -DA:108,1 +DA:106,1 +DA:107,1 +DA:110,1 +DA:111,1 DA:112,1 -DA:114,2 -DA:115,1 -DA:116,1 -DA:117,3 -DA:122,2 +DA:114,1 +DA:120,1 +DA:121,2 DA:123,1 -DA:129,2 -DA:132,1 +DA:124,2 +DA:128,1 +DA:131,1 +DA:135,2 DA:137,1 -DA:140,2 -LF:55 -LH:55 +DA:138,2 +DA:142,1 +DA:145,1 +DA:149,1 +DA:151,2 +DA:152,1 +DA:153,1 +DA:154,1 +DA:162,2 +DA:163,1 +DA:169,2 +DA:172,1 +DA:177,1 +DA:180,2 +LF:71 +LH:71 end_of_record SF:lib/src/features/bookcase/bloc/bookcase_event.dart DA:10,1 @@ -2153,7 +2471,7 @@ LF:2 LH:2 end_of_record SF:lib/src/core/dtos/bookcase_dto.dart -DA:7,2 +DA:7,3 DA:12,0 DA:16,0 DA:17,0 @@ -2204,91 +2522,91 @@ LF:5 LH:0 end_of_record SF:lib/src/features/book_on_bookcase_detail/views/book_on_bookcase_detail_page.dart -DA:23,0 -DA:29,0 -DA:31,0 -DA:38,0 -DA:40,0 +DA:24,0 +DA:30,0 +DA:32,0 +DA:39,0 DA:41,0 DA:42,0 DA:43,0 DA:44,0 -DA:47,0 -DA:50,0 -DA:54,0 +DA:45,0 +DA:48,0 +DA:51,0 DA:55,0 DA:56,0 -DA:59,0 -DA:61,0 -DA:65,0 +DA:57,0 +DA:60,0 +DA:62,0 DA:66,0 DA:67,0 DA:68,0 -DA:72,0 +DA:69,0 DA:73,0 DA:74,0 -DA:77,0 -DA:79,0 +DA:75,0 +DA:78,0 +DA:80,0 DA:81,0 -DA:85,0 DA:86,0 DA:87,0 DA:88,0 -DA:95,0 -DA:97,0 -DA:99,0 +DA:89,0 +DA:96,0 +DA:98,0 DA:100,0 DA:101,0 DA:102,0 -DA:104,0 +DA:103,0 DA:105,0 -DA:111,0 +DA:106,0 DA:112,0 DA:113,0 DA:114,0 DA:115,0 DA:116,0 -DA:118,0 +DA:117,0 DA:119,0 -DA:123,0 +DA:120,0 DA:124,0 DA:125,0 DA:126,0 -DA:131,0 -DA:133,0 -DA:135,0 +DA:127,0 +DA:132,0 +DA:134,0 DA:136,0 -DA:141,0 +DA:137,0 DA:142,0 -DA:144,0 +DA:143,0 DA:145,0 -DA:148,0 +DA:146,0 DA:149,0 DA:150,0 -DA:157,0 +DA:151,0 DA:158,0 -DA:165,0 +DA:159,0 DA:166,0 -DA:168,0 +DA:167,0 DA:169,0 -DA:179,0 +DA:170,0 DA:180,0 -DA:182,0 -DA:185,0 +DA:181,0 +DA:183,0 DA:186,0 DA:187,0 DA:188,0 DA:189,0 -DA:194,0 -DA:196,0 +DA:190,0 +DA:195,0 DA:197,0 DA:198,0 -DA:200,0 +DA:199,0 DA:201,0 DA:202,0 DA:203,0 DA:204,0 -DA:207,0 +DA:205,0 +DA:208,0 LF:85 LH:0 end_of_record @@ -2346,49 +2664,52 @@ LF:13 LH:0 end_of_record SF:lib/src/features/bookcase/views/bookcase_page.dart -DA:14,1 -DA:19,1 +DA:15,1 DA:20,1 -DA:26,1 -DA:28,1 -DA:30,5 -DA:33,0 -DA:35,0 +DA:21,1 +DA:27,1 +DA:29,1 +DA:31,5 +DA:34,0 DA:36,0 DA:37,0 -DA:40,0 -DA:45,0 +DA:38,0 +DA:41,0 DA:46,0 -DA:53,0 +DA:47,0 DA:54,0 -DA:57,1 -DA:59,1 -DA:62,2 -DA:63,1 -DA:65,1 -DA:66,0 -DA:69,2 -DA:70,1 -DA:73,1 -DA:74,0 +DA:55,0 +DA:58,1 +DA:60,1 +DA:63,2 +DA:64,1 +DA:66,1 +DA:67,0 +DA:70,2 +DA:71,1 +DA:74,1 DA:75,0 -DA:80,2 -DA:82,1 +DA:76,0 +DA:81,2 DA:83,1 -DA:85,2 +DA:84,1 DA:86,1 -DA:89,1 -DA:94,0 -DA:96,0 -DA:97,0 -DA:102,0 -DA:105,0 -DA:109,1 -DA:111,1 -DA:112,1 +DA:87,1 +DA:88,1 +DA:90,1 +DA:92,1 +DA:93,1 +DA:98,0 +DA:100,0 +DA:101,0 +DA:106,0 +DA:109,0 DA:113,1 -LF:41 -LH:24 +DA:115,1 +DA:116,1 +DA:117,1 +LF:44 +LH:27 end_of_record SF:lib/src/features/bookcase/views/widgets/bookcase_loaded_state_widget/bookcase_loaded_state_widget.dart DA:16,1 @@ -2425,197 +2746,203 @@ DA:88,0 DA:89,0 DA:90,0 DA:94,0 -DA:95,0 -DA:100,0 -DA:103,0 -DA:107,1 -DA:113,3 -DA:114,1 +DA:96,0 +DA:102,0 +DA:105,0 +DA:109,1 +DA:115,3 DA:116,1 -DA:117,1 -DA:118,2 -DA:121,1 -DA:124,1 +DA:118,1 +DA:119,1 +DA:120,2 +DA:123,1 DA:126,1 DA:128,1 -DA:129,0 +DA:130,1 DA:131,0 DA:133,0 -DA:134,0 -DA:139,1 +DA:135,0 +DA:136,0 DA:141,1 -DA:142,0 +DA:143,1 DA:144,0 -DA:146,2 -DA:147,1 -DA:152,1 -DA:154,2 -DA:155,2 -DA:157,1 -DA:158,1 +DA:146,0 +DA:148,2 +DA:149,1 +DA:154,1 +DA:156,2 +DA:157,2 DA:159,1 -DA:160,2 +DA:160,1 DA:161,1 -DA:162,1 -DA:163,2 +DA:162,2 +DA:163,1 DA:164,1 -DA:165,1 -DA:166,0 -DA:167,0 +DA:165,2 +DA:166,1 +DA:167,1 DA:168,0 -DA:169,1 -DA:170,1 +DA:169,0 +DA:170,0 +DA:171,1 DA:172,1 -DA:173,1 -DA:174,0 -DA:175,0 +DA:174,1 +DA:175,1 DA:176,0 -DA:181,1 -DA:182,1 -DA:183,0 -DA:186,1 -DA:187,1 -DA:189,0 -DA:190,1 -DA:194,1 -DA:195,1 +DA:177,0 +DA:178,0 +DA:183,1 +DA:184,1 +DA:185,0 +DA:188,1 +DA:189,1 +DA:191,0 +DA:192,1 DA:196,1 DA:197,1 +DA:198,1 +DA:199,1 LF:90 LH:52 end_of_record SF:lib/src/features/bookcase_insertion/views/bookcase_insertion_page.dart -DA:32,1 -DA:40,1 +DA:33,1 DA:41,1 -DA:54,1 -DA:58,1 -DA:64,1 +DA:42,1 +DA:55,1 +DA:59,1 DA:65,1 -DA:78,1 -DA:80,1 -DA:82,1 -DA:84,3 -DA:86,5 +DA:66,1 +DA:79,1 +DA:81,1 +DA:83,1 +DA:85,3 DA:87,5 -DA:88,4 -DA:91,1 -DA:93,2 +DA:88,5 +DA:89,4 +DA:92,1 DA:94,2 -DA:95,1 -DA:101,0 +DA:95,2 +DA:96,1 DA:102,0 DA:103,0 DA:104,0 -DA:106,0 +DA:105,0 DA:107,0 -DA:123,1 -DA:124,3 -DA:125,2 -DA:128,2 -DA:129,1 -DA:130,3 -DA:131,4 -DA:133,3 -DA:134,1 -DA:138,2 +DA:108,0 +DA:124,1 +DA:125,3 +DA:126,2 +DA:129,2 +DA:130,1 +DA:131,3 +DA:132,4 +DA:134,3 +DA:135,1 DA:139,2 -DA:140,1 +DA:140,2 DA:141,1 -DA:142,3 -DA:143,4 -DA:145,3 -DA:146,1 -DA:150,4 -DA:151,0 +DA:142,1 +DA:143,3 +DA:144,4 +DA:146,3 +DA:147,1 +DA:151,4 DA:152,0 DA:153,0 -DA:155,1 -DA:156,3 +DA:154,0 +DA:156,1 DA:157,3 -DA:158,1 -DA:162,2 -DA:163,1 -DA:168,1 -DA:173,1 -DA:174,0 -DA:176,0 -DA:181,1 -DA:182,1 -DA:184,1 -DA:190,2 -DA:191,1 -DA:192,1 -DA:193,3 +DA:158,3 +DA:159,1 +DA:163,2 +DA:164,1 +DA:169,1 +DA:174,1 +DA:175,0 +DA:177,0 +DA:182,2 +DA:183,1 +DA:186,1 +DA:187,1 +DA:188,1 +DA:189,1 +DA:194,2 DA:195,1 -DA:201,2 -DA:202,1 -DA:208,2 +DA:196,1 +DA:197,3 +DA:199,1 +DA:205,1 +DA:206,1 +DA:207,1 DA:209,1 -DA:210,1 -DA:211,2 -DA:219,1 -DA:221,2 -DA:224,1 -DA:225,1 -DA:227,2 -DA:229,1 -DA:230,1 +DA:211,1 +DA:215,2 +DA:216,1 +DA:217,1 +DA:218,2 +DA:226,1 +DA:228,2 DA:231,1 DA:232,1 -DA:233,1 -DA:235,1 +DA:234,2 +DA:236,1 +DA:237,1 +DA:238,1 DA:239,1 DA:240,1 DA:242,1 -DA:243,1 -DA:248,1 +DA:246,1 +DA:247,1 DA:249,1 -DA:251,1 -DA:252,1 -DA:253,1 -DA:254,1 -DA:257,1 +DA:250,1 +DA:255,1 +DA:256,1 DA:258,1 +DA:259,1 DA:260,1 DA:261,1 -DA:263,1 DA:264,1 DA:265,1 -DA:266,1 +DA:267,1 DA:268,1 DA:270,1 -DA:274,2 -DA:276,1 +DA:271,1 +DA:272,1 +DA:273,1 +DA:275,1 DA:277,1 -DA:281,1 +DA:281,2 DA:283,1 DA:284,1 -DA:285,2 -DA:287,1 DA:288,1 -DA:292,1 -DA:297,0 -DA:298,0 -DA:299,0 -DA:301,0 +DA:290,1 +DA:291,1 +DA:292,2 +DA:294,1 +DA:295,1 +DA:299,1 DA:304,0 -DA:305,1 -DA:306,1 -DA:308,1 -DA:310,1 +DA:305,0 +DA:306,0 +DA:308,0 +DA:311,0 +DA:312,1 DA:313,1 -DA:314,1 -DA:315,2 -DA:316,1 -DA:325,1 -DA:326,1 -DA:327,1 -DA:331,1 +DA:315,1 +DA:317,1 +DA:320,1 +DA:321,1 +DA:322,2 +DA:323,1 +DA:332,1 DA:333,1 DA:334,1 -LF:129 -LH:113 +DA:338,1 +DA:340,1 +DA:341,1 +LF:135 +LH:119 end_of_record SF:lib/src/shared/widgets/item_state_widget/item_empty_state_widget/item_empty_widget.dart DA:7,1 @@ -2655,18 +2982,18 @@ LF:16 LH:15 end_of_record SF:lib/src/features/bookcase_detail/views/bookcase_detail_page.dart -DA:24,0 -DA:29,0 +DA:25,0 DA:30,0 -DA:50,0 -DA:52,0 +DA:31,0 +DA:51,0 DA:53,0 -DA:55,0 -DA:57,0 +DA:54,0 +DA:56,0 DA:58,0 -DA:62,0 -DA:67,0 +DA:59,0 +DA:63,0 DA:68,0 +DA:69,0 DA:70,0 DA:72,0 DA:73,0 @@ -2680,76 +3007,79 @@ DA:82,0 DA:83,0 DA:88,0 DA:89,0 -DA:91,0 -DA:96,0 +DA:90,0 +DA:92,0 +DA:93,0 +DA:94,0 DA:99,0 -DA:100,0 +DA:102,0 DA:103,0 -DA:104,0 -DA:105,0 DA:106,0 -DA:110,0 -DA:111,0 -DA:116,0 -DA:126,0 -DA:128,0 +DA:107,0 +DA:108,0 +DA:109,0 +DA:113,0 +DA:114,0 +DA:119,0 DA:129,0 -DA:130,0 DA:133,0 +DA:134,0 DA:135,0 -DA:139,0 +DA:138,0 DA:140,0 -DA:141,0 -DA:142,0 -DA:149,0 -DA:150,0 -DA:153,0 +DA:144,0 +DA:145,0 +DA:146,0 +DA:147,0 DA:154,0 DA:155,0 DA:158,0 +DA:159,0 DA:161,0 DA:164,0 -DA:165,0 -DA:170,0 +DA:168,0 +DA:171,0 DA:172,0 -DA:173,0 -DA:174,0 -DA:175,0 -DA:176,0 -DA:178,0 -DA:184,0 -DA:186,0 -DA:187,0 -DA:188,0 -DA:189,0 -DA:190,0 -DA:192,0 +DA:177,0 +DA:179,0 +DA:180,0 +DA:181,0 +DA:182,0 +DA:183,0 +DA:185,0 +DA:191,0 DA:193,0 DA:194,0 DA:195,0 DA:196,0 -DA:198,0 +DA:197,0 DA:199,0 DA:200,0 DA:201,0 DA:202,0 DA:203,0 DA:205,0 -DA:211,0 -DA:216,0 +DA:206,0 +DA:207,0 +DA:208,0 +DA:209,0 +DA:210,0 +DA:212,0 DA:218,0 -DA:219,0 -DA:220,0 -DA:221,0 -DA:222,0 DA:223,0 -DA:224,0 DA:225,0 DA:226,0 DA:227,0 +DA:228,0 +DA:229,0 +DA:230,0 +DA:231,0 +DA:232,0 +DA:233,0 DA:234,0 -DA:235,0 -LF:94 +DA:241,0 +DA:242,0 +LF:97 LH:0 end_of_record SF:lib/src/shared/widgets/bookcase_widget/bookcase_widget.dart @@ -2818,41 +3148,42 @@ DA:11,1 DA:20,1 DA:21,1 DA:27,1 -DA:31,1 DA:32,1 -DA:33,0 -DA:36,1 +DA:33,1 +DA:34,0 DA:37,1 -DA:43,1 -DA:45,2 -DA:46,3 -DA:47,2 -DA:48,0 -DA:50,1 -DA:52,1 -DA:53,2 -DA:57,1 +DA:38,1 +DA:44,1 +DA:46,2 +DA:47,3 +DA:48,2 +DA:49,0 +DA:51,1 +DA:53,1 +DA:54,2 DA:58,1 DA:59,1 -DA:60,3 -DA:61,1 -DA:63,1 -DA:67,1 -DA:68,0 +DA:60,1 +DA:61,3 +DA:62,1 +DA:64,1 +DA:68,1 DA:69,0 DA:70,0 DA:71,0 -DA:75,1 -DA:80,1 -DA:82,2 -DA:84,3 -LF:32 -LH:26 +DA:72,0 +DA:76,1 +DA:81,1 +DA:83,2 +DA:84,2 +DA:85,1 +LF:33 +LH:27 end_of_record SF:lib/src/features/bookcase_books_insertion/bloc/bookcase_books_insertion_state.dart -DA:12,1 -DA:21,1 -DA:33,1 +DA:17,1 +DA:26,1 +DA:39,1 LF:3 LH:3 end_of_record @@ -2863,16 +3194,16 @@ LF:2 LH:2 end_of_record SF:lib/src/features/bookcase_books_insertion/bloc/bookcase_books_insertion_bloc.dart -DA:15,1 -DA:18,2 +DA:16,1 DA:19,2 DA:20,2 -DA:23,1 -DA:28,2 -DA:30,2 -DA:32,1 +DA:21,2 +DA:24,1 +DA:29,2 +DA:31,2 DA:33,1 DA:34,1 +DA:35,1 DA:42,1 DA:43,2 DA:46,1 @@ -2883,87 +3214,100 @@ DA:56,1 DA:57,1 DA:58,1 DA:61,1 +DA:65,1 DA:66,1 -DA:67,2 -DA:68,2 +DA:67,1 +DA:68,1 DA:69,1 -DA:70,2 -DA:71,1 -DA:75,1 -DA:80,2 +DA:72,1 +DA:73,1 +DA:74,1 +DA:76,1 DA:82,1 -DA:84,2 -DA:85,2 -DA:86,1 -DA:87,1 -DA:90,1 -DA:91,1 -DA:92,1 -DA:93,2 -DA:100,2 -DA:101,1 -DA:102,2 -DA:103,2 -DA:104,1 -DA:105,2 -DA:106,1 -LF:44 -LH:44 +DA:87,2 +DA:89,1 +DA:91,2 +DA:92,2 +DA:93,1 +DA:94,1 +DA:97,1 +DA:98,1 +DA:99,1 +DA:101,2 +DA:108,2 +DA:109,1 +DA:110,1 +DA:111,1 +DA:112,1 +DA:113,1 +DA:116,1 +DA:117,1 +DA:118,1 +DA:120,1 +LF:50 +LH:50 end_of_record SF:lib/src/features/bookcase_books_insertion/views/bookcase_books_insertion_page.dart -DA:16,0 -DA:21,0 -DA:23,0 -DA:31,0 -DA:33,0 +DA:17,0 +DA:22,0 +DA:24,0 +DA:32,0 DA:34,0 DA:35,0 DA:36,0 -DA:39,0 +DA:37,0 DA:40,0 -DA:43,0 -DA:48,0 +DA:41,0 +DA:44,0 DA:49,0 -DA:51,0 +DA:50,0 DA:52,0 +DA:53,0 +DA:55,0 +DA:56,0 DA:57,0 DA:58,0 -DA:61,0 -DA:62,0 DA:63,0 DA:64,0 +DA:67,0 +DA:68,0 +DA:69,0 DA:70,0 -DA:71,0 -DA:73,0 +DA:76,0 +DA:77,0 DA:78,0 +DA:80,0 +DA:81,0 DA:82,0 -DA:83,0 -DA:84,0 DA:87,0 -DA:89,0 +DA:91,0 +DA:92,0 DA:93,0 -DA:94,0 -DA:95,0 DA:96,0 +DA:98,0 +DA:102,0 DA:103,0 DA:104,0 DA:105,0 -DA:106,0 -DA:111,0 +DA:112,0 DA:113,0 DA:114,0 -DA:116,0 -DA:117,0 -DA:118,0 -DA:119,0 +DA:115,0 DA:120,0 -DA:121,0 +DA:122,0 DA:123,0 -DA:124,0 DA:125,0 +DA:126,0 +DA:127,0 DA:128,0 -DA:131,0 -LF:52 +DA:129,0 +DA:130,0 +DA:132,0 +DA:133,0 +DA:134,0 +DA:137,0 +DA:139,0 +LF:59 LH:0 end_of_record SF:lib/src/features/bookcase_books_insertion/widgets/bookcase_books_insertion_loaded_state_widget/bookcase_books_insertion_loaded_state.dart @@ -3045,64 +3389,70 @@ LF:17 LH:0 end_of_record SF:lib/src/features/bookcase_detail/bloc/bookcase_detail_bloc.dart -DA:16,1 -DA:19,2 +DA:17,1 DA:20,2 DA:21,2 DA:22,2 -DA:25,1 -DA:30,2 -DA:32,2 -DA:33,1 +DA:23,2 +DA:26,1 +DA:31,2 +DA:33,2 DA:34,1 DA:35,1 -DA:36,2 -DA:39,1 -DA:40,1 -DA:41,1 -DA:46,1 -DA:49,2 -DA:52,3 -DA:54,2 -DA:55,2 -DA:60,2 -DA:61,1 -DA:62,1 +DA:36,1 +DA:37,1 +DA:38,1 +DA:42,1 +DA:43,1 +DA:45,1 +DA:51,1 +DA:56,2 +DA:58,2 +DA:59,1 +DA:62,2 DA:63,1 -DA:64,2 -DA:67,1 -DA:68,1 -DA:69,1 +DA:64,1 +DA:72,2 +DA:73,1 DA:74,1 -DA:79,2 +DA:75,1 +DA:77,1 DA:81,1 -DA:83,2 -DA:84,2 -DA:85,2 -DA:87,2 -DA:88,2 -DA:89,2 -DA:94,2 -DA:95,1 -DA:96,1 +DA:82,1 +DA:84,1 +DA:90,1 +DA:95,2 DA:97,1 -DA:98,2 +DA:99,2 +DA:100,2 DA:101,1 DA:102,1 -DA:103,1 -DA:108,1 -DA:112,1 -DA:113,1 -DA:115,1 -DA:116,2 +DA:105,2 +DA:106,1 +DA:107,1 +DA:110,2 +DA:117,2 +DA:118,1 +DA:119,1 DA:120,1 -DA:122,2 -DA:123,2 -DA:124,1 +DA:121,1 +DA:122,1 +DA:126,1 DA:127,1 -DA:130,2 -LF:56 -LH:56 +DA:129,1 +DA:135,1 +DA:139,1 +DA:140,1 +DA:142,1 +DA:143,2 +DA:147,1 +DA:149,2 +DA:150,2 +DA:151,1 +DA:154,1 +DA:157,2 +LF:62 +LH:62 end_of_record SF:lib/src/features/bookcase_detail/bloc/bookcase_detail_event.dart DA:9,1 @@ -3113,7 +3463,7 @@ LH:3 end_of_record SF:lib/src/features/bookcase_detail/bloc/bookcase_detail_state.dart DA:13,1 -DA:21,1 +DA:22,1 LF:2 LH:2 end_of_record @@ -3121,25 +3471,27 @@ SF:lib/src/features/bookcase_detail/widgets/bookcase_description_widget/bookcase DA:11,0 DA:19,0 DA:21,0 +DA:22,0 DA:23,0 -DA:25,0 -DA:27,0 +DA:24,0 +DA:26,0 DA:28,0 -DA:32,0 +DA:29,0 DA:33,0 DA:34,0 DA:35,0 -DA:44,0 +DA:36,0 DA:45,0 -DA:54,0 +DA:46,0 DA:55,0 -DA:58,0 +DA:56,0 DA:59,0 -DA:63,0 +DA:60,0 DA:64,0 DA:65,0 DA:66,0 -LF:21 +DA:67,0 +LF:23 LH:0 end_of_record SF:lib/src/features/bookcase_detail/widgets/bookcase_detail_loaded_state_widget/bookcase_detail_loaded_state_widget.dart @@ -3150,39 +3502,37 @@ DA:36,0 DA:38,0 DA:39,0 DA:42,0 -DA:43,0 -DA:46,0 -DA:48,0 -DA:53,0 -DA:57,0 -DA:58,0 +DA:44,0 +DA:47,0 +DA:49,0 +DA:55,0 DA:59,0 DA:60,0 DA:61,0 DA:62,0 +DA:63,0 DA:64,0 -DA:67,0 -DA:71,0 -DA:72,0 +DA:66,0 +DA:69,0 DA:73,0 DA:74,0 +DA:75,0 DA:76,0 -DA:79,0 -DA:83,0 -DA:84,0 -DA:87,0 -DA:88,0 +DA:78,0 +DA:81,0 +DA:85,0 +DA:86,0 DA:89,0 +DA:90,0 DA:91,0 -DA:97,0 -DA:98,0 +DA:93,0 DA:99,0 DA:100,0 -DA:104,0 +DA:101,0 +DA:102,0 DA:106,0 -DA:107,0 +DA:108,0 DA:109,0 -DA:110,0 DA:111,0 DA:112,0 DA:113,0 @@ -3195,40 +3545,42 @@ DA:119,0 DA:120,0 DA:121,0 DA:122,0 +DA:123,0 DA:124,0 -DA:125,0 DA:126,0 DA:127,0 DA:128,0 -DA:133,0 -DA:134,0 +DA:129,0 +DA:130,0 DA:135,0 -DA:141,0 -DA:142,0 +DA:136,0 +DA:137,0 DA:143,0 DA:144,0 DA:145,0 DA:146,0 -DA:149,0 -DA:150,0 +DA:147,0 +DA:148,0 +DA:151,0 DA:152,0 DA:154,0 -DA:155,0 +DA:156,0 DA:157,0 -DA:158,0 +DA:159,0 DA:160,0 DA:162,0 DA:164,0 -DA:165,0 DA:166,0 DA:167,0 DA:168,0 DA:169,0 DA:170,0 -DA:178,0 -DA:179,0 -DA:182,0 -DA:183,0 +DA:171,0 +DA:172,0 +DA:180,0 +DA:181,0 +DA:184,0 +DA:185,0 LF:86 LH:0 end_of_record @@ -3239,50 +3591,58 @@ LF:2 LH:2 end_of_record SF:lib/src/features/bookcase_insertion/bloc/bookcase_insertion_bloc.dart -DA:14,1 -DA:16,2 +DA:15,1 DA:17,2 DA:18,2 -DA:21,1 -DA:26,2 -DA:28,1 +DA:19,2 +DA:22,1 +DA:27,2 DA:29,1 DA:30,1 DA:31,1 +DA:32,1 DA:35,2 -DA:37,1 -DA:38,2 -DA:43,2 -DA:45,1 -DA:46,2 -DA:47,2 -DA:48,1 -DA:49,2 +DA:39,1 +DA:40,1 +DA:41,1 DA:50,1 -DA:54,1 -DA:59,2 -DA:61,1 +DA:51,1 +DA:55,1 +DA:56,1 +DA:57,1 +DA:59,1 DA:62,1 DA:63,1 DA:64,1 -DA:65,1 -DA:68,2 +DA:66,1 DA:72,1 -DA:73,1 -DA:74,1 -DA:81,2 +DA:77,2 +DA:79,1 +DA:80,1 +DA:81,1 +DA:82,1 DA:83,1 -DA:84,2 -DA:85,2 -DA:86,1 -DA:87,2 -DA:88,1 -LF:38 -LH:38 +DA:86,2 +DA:90,1 +DA:91,1 +DA:92,1 +DA:101,1 +DA:102,1 +DA:106,1 +DA:107,1 +DA:108,1 +DA:109,1 +DA:110,1 +DA:113,1 +DA:114,1 +DA:115,1 +DA:117,1 +LF:46 +LH:46 end_of_record SF:lib/src/features/bookcase_insertion/bloc/bookcase_insertion_state.dart -DA:11,2 -DA:17,2 +DA:16,2 +DA:23,2 LF:2 LH:2 end_of_record @@ -3297,127 +3657,140 @@ LF:1 LH:1 end_of_record SF:lib/src/features/books_picker/views/widgets/book_on_bookcase_picker/bloc/book_on_bookcase_picker_bloc.dart -DA:15,1 -DA:18,2 +DA:16,1 DA:19,2 -DA:22,1 -DA:27,2 -DA:29,1 -DA:30,2 -DA:32,1 -DA:33,2 -DA:37,1 -DA:39,2 +DA:20,2 +DA:23,1 +DA:28,2 +DA:30,1 +DA:31,2 +DA:33,1 +DA:34,2 +DA:38,1 DA:40,2 -DA:41,1 -DA:44,2 -DA:45,1 -DA:49,1 -DA:50,0 -DA:54,2 -DA:55,1 -DA:56,1 -DA:57,1 -DA:58,2 -DA:61,1 -DA:62,1 -DA:63,1 -LF:25 -LH:24 -end_of_record -SF:lib/src/features/books_picker/views/widgets/book_on_bookcase_picker/bloc/book_on_bookcase_picker_state.dart -DA:13,1 -DA:21,1 -LF:2 -LH:2 -end_of_record -SF:lib/src/features/books_picker/views/widgets/bookcase_picker/bloc/bookcase_picker_bloc.dart -DA:16,1 -DA:19,2 -DA:20,2 -DA:23,1 -DA:28,2 -DA:30,2 -DA:32,1 -DA:33,2 -DA:37,1 -DA:39,2 -DA:40,1 -DA:43,1 -DA:44,1 +DA:41,2 +DA:42,1 DA:45,2 -DA:50,2 -DA:57,2 +DA:46,1 +DA:50,1 +DA:51,0 +DA:55,2 +DA:56,1 +DA:57,1 +DA:58,1 +DA:59,1 DA:60,1 +DA:64,1 DA:65,1 -DA:68,1 -DA:69,0 -DA:73,2 -DA:74,1 -DA:75,2 -DA:76,2 -DA:77,1 -DA:78,3 +DA:67,1 LF:26 LH:25 end_of_record -SF:lib/src/features/books_picker/views/widgets/bookcase_picker/bloc/bookcase_picker_state.dart -DA:12,1 -DA:19,1 +SF:lib/src/features/books_picker/views/widgets/book_on_bookcase_picker/bloc/book_on_bookcase_picker_state.dart +DA:13,1 +DA:22,1 LF:2 LH:2 end_of_record SF:lib/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_state.dart DA:12,1 -DA:20,1 +DA:21,1 LF:2 LH:2 end_of_record SF:lib/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_bloc.dart -DA:13,1 -DA:14,2 +DA:14,1 DA:15,2 -DA:18,1 -DA:22,2 +DA:16,2 +DA:19,1 DA:24,2 -DA:26,1 -DA:27,2 -DA:32,5 -DA:34,1 -DA:35,2 -DA:39,2 -DA:40,1 -DA:41,2 +DA:26,2 +DA:28,1 +DA:29,2 +DA:34,4 +DA:35,1 +DA:37,1 +DA:38,2 DA:42,2 DA:43,1 -DA:44,3 -LF:17 -LH:17 +DA:44,1 +DA:45,1 +DA:46,1 +DA:47,1 +DA:50,1 +DA:51,1 +DA:52,1 +DA:54,1 +LF:22 +LH:22 +end_of_record +SF:lib/src/features/books_picker/views/widgets/bookcase_picker/bloc/bookcase_picker_bloc.dart +DA:17,1 +DA:20,2 +DA:21,2 +DA:24,1 +DA:29,2 +DA:31,2 +DA:33,1 +DA:34,2 +DA:38,1 +DA:40,2 +DA:41,1 +DA:44,1 +DA:45,1 +DA:53,2 +DA:60,2 +DA:63,1 +DA:68,1 +DA:71,1 +DA:72,0 +DA:76,2 +DA:77,1 +DA:78,1 +DA:79,1 +DA:80,1 +DA:81,1 +DA:84,1 +DA:85,1 +DA:86,1 +DA:88,1 +LF:29 +LH:28 +end_of_record +SF:lib/src/features/books_picker/views/widgets/bookcase_picker/bloc/bookcase_picker_state.dart +DA:12,1 +DA:19,1 +LF:2 +LH:2 end_of_record SF:lib/src/features/contacts_picker/bloc/contacts_picker_state.dart DA:12,1 -DA:20,1 +DA:21,1 LF:2 LH:2 end_of_record SF:lib/src/features/contacts_picker/bloc/contacts_picker_bloc.dart -DA:12,1 -DA:13,2 -DA:14,2 -DA:17,1 -DA:22,2 +DA:14,1 +DA:15,2 +DA:16,2 +DA:19,1 DA:24,2 -DA:25,1 -DA:26,4 -DA:30,1 +DA:26,2 +DA:27,1 +DA:28,4 DA:31,1 -DA:38,1 -DA:39,2 -DA:43,2 +DA:32,2 +DA:36,2 +DA:37,1 +DA:38,0 +DA:39,0 +DA:40,0 +DA:41,0 +DA:44,1 DA:45,1 DA:46,1 -DA:47,1 -LF:16 +DA:48,1 +LF:20 LH:16 end_of_record SF:lib/src/core/models/contact_model.dart @@ -3441,52 +3814,70 @@ LF:16 LH:1 end_of_record SF:lib/src/features/loan/bloc/loan_bloc.dart -DA:17,1 -DA:21,2 -DA:22,2 +DA:19,1 DA:23,2 -DA:26,1 -DA:31,2 +DA:24,2 +DA:25,2 +DA:28,1 DA:33,2 -DA:35,1 -DA:36,2 -DA:40,1 -DA:41,0 -DA:42,0 +DA:35,2 +DA:37,1 +DA:38,2 +DA:42,1 DA:43,0 DA:44,0 -DA:48,1 -DA:53,2 -DA:55,2 -DA:56,1 -DA:59,1 -DA:60,2 -DA:64,1 -DA:65,1 -DA:66,4 +DA:45,0 +DA:46,0 +DA:47,0 +DA:50,0 +DA:51,0 +DA:52,0 +DA:54,0 +DA:57,0 +DA:58,0 +DA:59,0 +DA:61,0 DA:67,1 -DA:68,3 -DA:72,1 -DA:76,1 -DA:78,2 -DA:79,1 -DA:80,1 -DA:81,3 -DA:86,2 +DA:72,2 +DA:74,2 +DA:75,1 +DA:78,1 +DA:79,2 +DA:83,1 +DA:84,1 +DA:85,1 +DA:86,1 DA:87,1 -DA:90,2 +DA:88,1 DA:91,1 -DA:94,1 -DA:96,1 -DA:97,1 -DA:101,1 -DA:104,2 -LF:40 -LH:36 +DA:92,0 +DA:93,0 +DA:95,0 +DA:98,1 +DA:99,1 +DA:100,1 +DA:102,1 +DA:108,1 +DA:112,1 +DA:114,2 +DA:115,1 +DA:116,1 +DA:117,1 +DA:125,2 +DA:126,1 +DA:129,2 +DA:130,1 +DA:133,1 +DA:135,1 +DA:136,1 +DA:140,1 +DA:143,2 +LF:58 +LH:42 end_of_record SF:lib/src/features/loan/bloc/loan_state.dart DA:14,1 -DA:20,1 +DA:21,1 LF:2 LH:2 end_of_record @@ -3524,7 +3915,7 @@ LH:1 end_of_record SF:lib/src/features/loan_detail/bloc/loan_detail_state.dart DA:10,1 -DA:20,1 +DA:21,1 LF:2 LH:2 end_of_record @@ -3535,131 +3926,157 @@ LF:2 LH:2 end_of_record SF:lib/src/features/loan_detail/bloc/loan_detail_bloc.dart -DA:19,1 -DA:24,2 -DA:25,2 +DA:21,1 DA:26,2 -DA:29,1 -DA:34,2 -DA:36,3 -DA:37,3 -DA:38,3 -DA:40,1 -DA:43,1 -DA:44,1 -DA:47,1 -DA:48,1 -DA:52,1 -DA:53,1 -DA:54,3 +DA:27,2 +DA:28,2 +DA:31,1 +DA:36,2 +DA:38,3 +DA:39,3 +DA:40,3 +DA:42,1 +DA:45,1 +DA:46,1 +DA:49,1 +DA:50,1 +DA:54,1 +DA:55,1 +DA:56,1 DA:57,1 -DA:58,2 -DA:63,1 -DA:68,2 -DA:70,3 -DA:71,2 -DA:72,1 -DA:74,1 -DA:75,1 -DA:76,1 -DA:82,3 -DA:84,1 -DA:85,1 -DA:86,1 -DA:91,2 -DA:92,1 -DA:93,1 -DA:94,3 -DA:97,1 -DA:98,2 -LF:37 -LH:37 -end_of_record -SF:lib/src/core/models/custom_notification_model.dart -DA:5,0 -DA:7,0 -DA:8,0 -DA:12,0 -DA:14,0 -DA:15,0 -DA:19,0 -DA:21,0 -DA:23,0 -DA:28,0 -DA:31,0 -DA:32,0 -DA:45,2 -DA:54,0 +DA:58,1 +DA:61,1 DA:62,0 DA:63,0 -DA:64,0 DA:65,0 -DA:66,0 -DA:67,0 -DA:68,0 -DA:72,0 -DA:74,0 -DA:77,0 -DA:81,0 -DA:82,0 -DA:83,0 -DA:84,0 -DA:85,0 -DA:86,0 -DA:89,0 -DA:91,0 -DA:92,0 -DA:93,0 -DA:94,0 -DA:95,0 -DA:96,0 -LF:37 -LH:1 +DA:69,1 +DA:70,1 +DA:72,1 +DA:78,1 +DA:83,2 +DA:85,3 +DA:86,2 +DA:87,1 +DA:91,1 +DA:92,1 +DA:93,1 +DA:101,3 +DA:103,1 +DA:104,1 +DA:105,1 +DA:113,2 +DA:114,1 +DA:115,1 +DA:116,1 +DA:117,1 +DA:118,1 +DA:121,1 +DA:122,0 +DA:123,0 +DA:125,0 +DA:129,1 +DA:130,1 +DA:132,1 +LF:51 +LH:45 end_of_record SF:lib/src/features/contacts_picker/bloc/contacts_picker_event.dart LF:0 LH:0 end_of_record -SF:lib/src/features/loan_insertion/bloc/loan_insertion_bloc.dart +SF:lib/src/features/my_books/bloc/my_books_state.dart +DA:12,1 +DA:21,1 +LF:2 +LH:2 +end_of_record +SF:lib/src/features/my_books/bloc/my_books_bloc.dart +DA:14,3 +DA:15,2 +DA:16,2 DA:19,1 -DA:23,2 DA:24,2 -DA:27,1 -DA:32,2 -DA:34,2 +DA:26,2 +DA:28,1 +DA:29,2 +DA:33,2 +DA:34,1 DA:35,1 -DA:39,1 -DA:40,1 +DA:36,1 +DA:37,1 +DA:38,1 DA:41,1 -DA:49,1 -DA:50,1 +DA:42,1 +DA:43,1 +DA:45,1 DA:51,1 -DA:52,1 -DA:53,1 -DA:54,1 -DA:57,2 +DA:56,2 +DA:58,2 DA:59,1 -DA:60,1 -DA:61,1 +DA:62,1 +DA:63,2 +DA:67,2 DA:68,1 +DA:69,1 DA:70,1 DA:71,1 DA:72,1 -DA:73,1 +DA:75,1 DA:76,1 DA:77,1 -DA:81,1 -DA:82,2 -DA:83,2 +DA:79,1 +LF:34 +LH:34 +end_of_record +SF:lib/src/features/my_books/bloc/my_books_event.dart +DA:10,1 +LF:1 +LH:1 +end_of_record +SF:lib/src/features/loan_insertion/bloc/loan_insertion_bloc.dart +DA:20,1 +DA:24,2 +DA:25,2 +DA:28,1 +DA:33,2 +DA:35,2 +DA:36,1 +DA:40,1 +DA:41,1 +DA:42,1 +DA:51,1 +DA:52,1 +DA:53,1 +DA:54,1 +DA:55,1 +DA:56,1 +DA:59,2 +DA:63,1 +DA:64,1 +DA:65,1 +DA:74,1 +DA:76,1 +DA:77,1 +DA:78,1 +DA:81,2 +DA:82,1 +DA:83,1 DA:84,1 -DA:85,2 +DA:85,1 DA:86,1 -DA:90,1 +DA:89,1 +DA:90,0 +DA:91,0 +DA:93,0 +DA:96,1 DA:97,1 -DA:101,4 -DA:107,2 -LF:37 -LH:37 +DA:98,1 +DA:100,1 +DA:106,1 +DA:112,1 +DA:121,2 +LF:41 +LH:38 end_of_record SF:lib/src/features/loan_insertion/bloc/loan_insertion_event.dart DA:14,1 @@ -3667,196 +4084,173 @@ LF:1 LH:1 end_of_record SF:lib/src/features/loan_insertion/bloc/loan_insertion_state.dart -DA:10,1 -DA:18,1 -LF:2 -LH:2 -end_of_record -SF:lib/src/features/my_books/bloc/my_books_state.dart -DA:12,1 -DA:20,1 -LF:2 -LH:2 -end_of_record -SF:lib/src/features/my_books/bloc/my_books_bloc.dart -DA:13,3 -DA:14,2 -DA:15,2 -DA:18,1 -DA:23,2 -DA:25,2 -DA:27,1 -DA:28,2 -DA:32,2 -DA:33,1 -DA:34,4 -DA:35,1 -DA:36,3 -DA:40,1 -DA:45,2 -DA:47,3 -DA:49,1 -DA:50,2 -DA:54,2 -DA:55,1 -DA:56,4 -DA:57,1 -DA:58,3 -LF:23 -LH:23 -end_of_record -SF:lib/src/features/my_books/bloc/my_books_event.dart -DA:10,1 +DA:13,1 LF:1 LH:1 end_of_record SF:lib/src/features/home/views/home_page.dart -DA:10,1 -DA:12,1 +DA:11,1 DA:13,1 -DA:21,1 -DA:23,1 -DA:24,2 -DA:25,1 -DA:26,3 -DA:28,3 -DA:29,3 +DA:14,1 +DA:22,1 +DA:24,1 +DA:25,5 +DA:26,2 +DA:27,1 +DA:30,1 +DA:32,2 DA:33,1 -DA:35,2 -DA:36,1 -DA:39,0 -DA:40,0 -DA:41,0 -DA:44,1 -DA:46,1 -DA:49,2 -DA:51,1 -DA:52,1 -DA:53,1 -DA:56,3 -DA:60,3 -DA:62,1 +DA:36,0 +DA:37,0 +DA:38,0 +DA:41,1 +DA:43,1 +DA:46,2 +DA:48,1 +DA:49,1 +DA:50,1 +DA:53,3 +DA:57,1 +DA:58,1 +DA:59,1 +DA:61,1 +DA:63,1 DA:64,1 -DA:70,0 +DA:65,1 DA:71,0 -DA:73,0 +DA:72,0 DA:74,0 -DA:76,0 +DA:75,0 DA:77,0 -DA:79,0 +DA:78,0 DA:80,0 -DA:82,0 +DA:81,0 DA:83,0 -DA:85,0 +DA:84,0 DA:86,0 -DA:92,1 -DA:94,1 -DA:96,1 -DA:97,0 -DA:98,3 -DA:99,1 +DA:87,0 +DA:93,1 +DA:95,1 +DA:97,1 +DA:98,0 +DA:99,3 DA:100,1 DA:101,1 DA:102,1 -DA:104,1 -DA:110,1 -DA:112,1 +DA:103,1 +DA:105,1 +DA:111,1 DA:113,1 -DA:117,1 +DA:114,1 DA:118,1 DA:119,1 -DA:120,0 +DA:120,1 DA:121,0 -DA:123,1 -LF:57 -LH:39 +DA:122,0 +DA:124,1 +LF:59 +LH:41 end_of_record -SF:lib/src/features/home/widgets/animated_search_bar/animated_search_bar.dart +SF:lib/src/core/helpers/error_code/rest_client_error_code/rest_client_error_code_extension.dart +DA:5,1 +DA:9,1 +DA:10,0 +DA:13,1 +DA:14,0 DA:17,1 -DA:23,1 +DA:20,1 +DA:21,0 DA:24,1 -DA:31,0 +DA:27,3 +LF:10 +LH:7 +end_of_record +SF:lib/src/features/home/widgets/animated_search_bar/animated_search_bar.dart +DA:11,1 +DA:17,1 +DA:18,1 +DA:25,0 +DA:26,0 +DA:29,1 +DA:30,1 +DA:31,3 DA:32,0 -DA:35,1 -DA:36,1 -DA:37,3 -DA:38,0 +DA:33,0 +DA:34,0 +DA:36,0 +DA:37,0 DA:39,0 -DA:40,0 -DA:42,0 -DA:43,0 -DA:45,0 -DA:48,4 -DA:51,1 -DA:53,3 -DA:54,1 -DA:56,1 -DA:58,1 -DA:59,1 -DA:61,2 -DA:62,0 +DA:42,4 +DA:45,1 +DA:47,3 +DA:48,1 +DA:50,1 +DA:52,1 +DA:53,1 +DA:55,2 +DA:56,0 +DA:57,0 +DA:58,0 +DA:60,0 +DA:61,0 DA:63,0 -DA:64,0 -DA:66,0 -DA:67,0 -DA:69,0 -DA:73,1 +DA:67,1 +DA:71,1 +DA:72,1 +DA:73,2 +DA:74,1 +DA:75,2 +DA:76,1 DA:77,1 DA:78,1 -DA:79,2 -DA:80,1 -DA:81,2 -DA:82,1 -DA:83,1 -DA:84,1 -DA:88,1 -DA:94,1 -DA:96,1 -DA:97,0 -DA:98,0 -DA:99,0 -DA:100,0 -DA:103,1 +DA:82,1 +DA:88,1 +DA:90,1 +DA:91,0 +DA:92,0 +DA:93,0 +DA:94,0 +DA:97,1 +DA:98,1 +DA:99,1 DA:104,1 -DA:105,1 +DA:108,1 DA:110,1 -DA:114,1 -DA:116,1 -DA:124,1 +DA:118,1 +DA:119,1 +DA:122,1 +DA:123,1 DA:125,1 +DA:127,1 DA:128,1 DA:129,1 -DA:131,1 -DA:133,1 -DA:134,1 +DA:130,2 DA:135,1 -DA:136,2 -DA:141,1 -DA:142,1 +DA:136,1 +DA:138,1 +DA:139,1 +DA:140,1 DA:144,1 -DA:145,1 DA:146,1 -DA:150,1 +DA:147,1 +DA:148,1 DA:152,1 -DA:153,1 DA:154,1 -DA:158,1 +DA:155,1 +DA:156,1 DA:160,1 -DA:161,1 DA:162,1 -DA:166,1 +DA:163,1 +DA:164,1 DA:168,1 -DA:169,1 DA:170,1 -DA:174,1 -DA:176,1 +DA:171,1 +DA:172,1 DA:177,1 -DA:178,1 -DA:183,1 -DA:184,0 -DA:185,0 -DA:186,0 -DA:187,0 +DA:178,0 +DA:179,0 +DA:180,0 +DA:181,0 LF:85 LH:63 end_of_record @@ -3864,9 +4258,9 @@ SF:lib/src/features/home/widgets/book_loaded_state_widget/books_loaded_state_wid DA:9,1 DA:14,1 DA:16,1 -DA:19,1 -DA:21,1 -DA:22,0 +DA:23,1 +DA:25,1 +DA:26,0 LF:6 LH:5 end_of_record @@ -3895,70 +4289,75 @@ LH:18 end_of_record SF:lib/src/features/notifications/bloc/notifications_state.dart DA:12,1 -DA:20,1 +DA:21,1 LF:2 LH:2 end_of_record SF:lib/src/features/notifications/bloc/notifications_bloc.dart -DA:11,1 -DA:13,2 -DA:14,2 -DA:17,1 -DA:22,2 +DA:13,1 +DA:15,2 +DA:16,2 +DA:19,1 DA:24,2 -DA:26,1 -DA:27,2 -DA:31,1 -DA:32,1 -DA:36,1 -DA:37,1 +DA:26,2 +DA:28,1 +DA:29,2 +DA:33,1 +DA:34,1 DA:38,1 -DA:39,2 -LF:14 -LH:14 +DA:39,0 +DA:40,0 +DA:41,0 +DA:42,0 +DA:45,1 +DA:46,1 +DA:47,1 +DA:49,1 +LF:19 +LH:15 end_of_record SF:lib/src/features/profile/bloc/profile_state.dart DA:10,1 -DA:20,1 +DA:21,1 LF:2 LH:2 end_of_record SF:lib/src/features/profile/bloc/profile_bloc.dart -DA:14,1 +DA:13,1 +DA:15,2 +DA:16,2 DA:17,2 -DA:18,2 -DA:19,2 -DA:22,1 +DA:20,1 +DA:25,2 DA:27,2 -DA:29,2 -DA:32,1 -DA:33,1 +DA:30,1 +DA:31,1 DA:40,1 DA:41,1 DA:45,1 -DA:46,2 -DA:47,2 +DA:46,1 +DA:47,1 DA:48,1 DA:49,1 -DA:50,1 -DA:51,1 -DA:57,1 -DA:62,2 -DA:64,2 -DA:65,2 -DA:69,1 -DA:70,1 -DA:77,2 -DA:79,1 -DA:80,1 -DA:81,1 -DA:88,2 -DA:89,1 -DA:90,2 -DA:91,2 +DA:52,1 +DA:53,1 +DA:54,1 +DA:56,1 +DA:62,1 +DA:67,2 +DA:69,2 +DA:70,2 +DA:74,1 +DA:75,1 +DA:83,2 +DA:84,1 +DA:85,1 +DA:86,1 +DA:87,1 +DA:88,1 +DA:91,1 DA:92,1 DA:93,1 -DA:94,1 DA:95,1 LF:36 LH:36 @@ -3969,123 +4368,145 @@ LF:1 LH:1 end_of_record SF:lib/src/features/profile/views/widgets/user_information_row/bloc/user_information_bloc.dart -DA:18,1 -DA:23,2 +DA:19,1 DA:24,2 -DA:27,1 -DA:32,2 -DA:34,2 +DA:25,2 +DA:28,1 +DA:33,2 DA:35,2 DA:36,2 DA:37,2 -DA:39,1 +DA:38,2 DA:40,1 -DA:47,1 +DA:41,1 DA:48,1 DA:49,1 -DA:50,2 +DA:50,1 +DA:51,1 DA:52,1 -DA:53,1 -DA:54,2 -LF:18 -LH:18 +DA:55,1 +DA:56,1 +DA:57,1 +DA:59,1 +LF:20 +LH:20 end_of_record SF:lib/src/features/profile/views/widgets/user_information_row/bloc/user_information_state.dart DA:13,1 -DA:24,1 +DA:25,1 LF:2 LH:2 end_of_record SF:lib/src/features/programming_reading/bloc/programming_reading_state.dart DA:10,1 -DA:23,1 +DA:24,1 LF:2 LH:2 end_of_record SF:lib/src/features/programming_reading/bloc/programming_reading_bloc.dart -DA:17,1 -DA:20,2 -DA:21,2 +DA:19,1 DA:22,2 DA:23,2 -DA:26,1 -DA:31,2 +DA:24,2 +DA:25,2 +DA:28,1 DA:33,2 -DA:35,1 -DA:36,1 -DA:40,1 -DA:41,1 +DA:35,2 +DA:37,1 +DA:38,1 DA:42,1 DA:43,1 +DA:44,1 +DA:45,1 DA:46,1 -DA:47,1 -DA:48,1 DA:49,1 -DA:55,1 -DA:60,2 -DA:62,1 -DA:65,2 +DA:50,1 +DA:51,1 +DA:53,1 +DA:59,1 +DA:64,2 +DA:66,1 +DA:68,1 DA:69,1 -DA:70,1 -DA:71,1 -DA:78,2 -DA:79,1 -DA:82,1 -DA:83,1 -DA:84,2 -DA:85,2 -DA:86,2 +DA:73,1 +DA:74,1 +DA:75,1 +DA:83,2 +DA:84,1 +DA:85,1 +DA:86,1 DA:87,1 DA:88,1 -DA:93,2 -DA:94,1 -DA:95,1 -DA:96,1 -DA:97,1 +DA:89,2 +DA:90,2 +DA:91,2 +DA:92,1 +DA:93,1 +DA:98,2 +DA:99,1 DA:100,1 DA:101,1 DA:102,1 DA:103,1 -DA:109,1 -DA:114,2 -DA:116,2 +DA:106,1 +DA:107,0 +DA:108,0 +DA:110,0 +DA:113,1 +DA:114,1 +DA:115,1 DA:117,1 -DA:120,2 -DA:121,1 -DA:122,1 -DA:123,1 -DA:124,1 -LF:52 -LH:52 +DA:123,1 +DA:128,2 +DA:130,2 +DA:131,1 +DA:134,2 +DA:135,1 +DA:136,0 +DA:137,0 +DA:138,0 +DA:139,0 +DA:142,1 +DA:143,0 +DA:144,0 +DA:146,0 +DA:149,1 +DA:150,1 +DA:151,1 +DA:153,1 +LF:70 +LH:60 end_of_record SF:lib/src/features/programming_reading/bloc/programming_reading_event.dart -DA:10,1 +DA:12,1 LF:1 LH:1 end_of_record SF:lib/src/features/reading_page_timer/bloc/reading_page_timer_bloc.dart -DA:13,1 -DA:15,2 +DA:14,1 DA:16,2 -DA:19,1 -DA:24,2 -DA:26,1 +DA:17,2 +DA:20,1 +DA:25,2 DA:27,1 -DA:31,2 -DA:35,1 +DA:28,1 +DA:31,1 +DA:32,1 DA:36,1 DA:37,1 -DA:44,2 -DA:45,1 -DA:46,1 -DA:47,1 +DA:38,1 +DA:47,2 DA:48,1 +DA:49,1 +DA:50,1 DA:51,1 DA:52,1 -DA:53,1 -DA:54,1 -LF:20 -LH:20 +DA:55,1 +DA:56,1 +DA:57,1 +DA:59,1 +LF:22 +LH:22 end_of_record SF:lib/src/features/reading_page_timer/bloc/reading_page_timer_event.dart DA:8,1 @@ -4093,54 +4514,64 @@ LF:1 LH:1 end_of_record SF:lib/src/features/reading_page_timer/bloc/reading_page_timer_state.dart -DA:12,1 +DA:13,1 LF:1 LH:1 end_of_record SF:lib/src/features/readings/bloc/readings_state.dart DA:14,1 -DA:20,1 +DA:21,1 LF:2 LH:2 end_of_record SF:lib/src/features/readings/bloc/readings_bloc.dart -DA:15,1 -DA:18,2 +DA:16,1 DA:19,2 DA:20,2 -DA:23,1 -DA:28,2 -DA:30,2 -DA:32,1 -DA:33,2 -DA:37,1 +DA:21,2 +DA:24,1 +DA:29,2 +DA:31,2 +DA:33,1 +DA:34,2 DA:38,1 -DA:39,4 +DA:39,1 DA:40,1 -DA:41,3 -DA:45,1 -DA:50,2 -DA:52,2 -DA:53,1 +DA:41,1 +DA:42,1 +DA:43,1 +DA:46,1 +DA:47,1 +DA:48,1 +DA:50,1 DA:56,1 -DA:57,2 -DA:61,1 -DA:62,1 -DA:63,4 +DA:61,2 +DA:63,2 DA:64,1 -DA:65,3 -DA:69,1 +DA:67,1 +DA:68,2 +DA:72,1 DA:73,1 -DA:75,2 +DA:74,1 +DA:75,1 DA:76,1 DA:77,1 -DA:78,3 -DA:82,3 +DA:80,1 +DA:81,1 +DA:82,1 DA:84,1 -DA:89,1 -DA:92,2 -LF:35 -LH:35 +DA:90,1 +DA:94,1 +DA:96,2 +DA:97,1 +DA:98,1 +DA:99,1 +DA:107,3 +DA:109,1 +DA:114,1 +DA:117,2 +LF:45 +LH:45 end_of_record SF:lib/src/features/readings/bloc/readings_event.dart DA:10,1 @@ -4171,52 +4602,54 @@ LF:2 LH:2 end_of_record SF:lib/src/features/readings_detail/bloc/readings_detail_state.dart -DA:14,1 +DA:15,1 LF:1 LH:1 end_of_record SF:lib/src/features/readings_detail/bloc/readings_detail_bloc.dart -DA:16,1 -DA:19,2 +DA:17,1 DA:20,2 DA:21,2 -DA:24,1 -DA:29,2 -DA:31,2 -DA:32,1 -DA:35,1 +DA:22,2 +DA:25,1 +DA:30,2 +DA:32,2 +DA:33,1 DA:36,1 DA:37,1 -DA:42,2 -DA:43,1 -DA:44,1 -DA:45,1 +DA:38,1 DA:46,2 +DA:47,1 +DA:48,1 +DA:49,1 DA:50,1 DA:51,1 -DA:52,1 +DA:55,1 +DA:56,1 DA:58,1 -DA:63,2 -DA:65,2 -DA:66,1 -DA:70,1 -DA:71,1 +DA:64,1 +DA:69,2 +DA:71,2 DA:72,1 -DA:77,2 +DA:76,1 +DA:77,1 DA:78,1 -DA:81,1 -DA:82,1 -DA:83,1 -DA:88,2 -DA:89,1 +DA:86,2 +DA:87,1 DA:90,1 DA:91,1 -DA:92,2 -DA:96,1 -DA:97,1 -DA:98,1 -LF:39 -LH:39 +DA:92,1 +DA:100,2 +DA:101,1 +DA:102,1 +DA:103,1 +DA:104,1 +DA:105,1 +DA:109,1 +DA:110,1 +DA:112,1 +LF:41 +LH:41 end_of_record SF:lib/src/features/readings_insertion/bloc/readings_insertion_event.dart DA:9,1 @@ -4224,70 +4657,74 @@ LF:1 LH:1 end_of_record SF:lib/src/features/readings_insertion/bloc/readings_insertion_state.dart -DA:12,1 +DA:13,1 LF:1 LH:1 end_of_record SF:lib/src/features/readings_insertion/bloc/readings_insertion_bloc.dart -DA:16,1 -DA:19,2 +DA:17,1 DA:20,2 -DA:23,1 -DA:28,2 -DA:30,1 -DA:32,2 -DA:33,1 -DA:37,1 +DA:21,2 +DA:24,1 +DA:29,2 +DA:31,1 +DA:33,2 +DA:34,1 DA:38,1 DA:39,1 -DA:47,2 -DA:48,1 +DA:40,1 +DA:50,2 DA:51,1 -DA:52,1 -DA:53,1 -DA:60,2 -DA:61,1 -DA:63,1 -DA:67,1 +DA:54,1 +DA:55,1 +DA:56,1 +DA:65,2 +DA:66,1 DA:68,1 -DA:69,1 -DA:76,2 -DA:77,1 -DA:78,2 -DA:79,2 -DA:80,1 -DA:81,2 -DA:82,1 -LF:29 -LH:29 +DA:72,1 +DA:73,1 +DA:74,1 +DA:83,2 +DA:84,1 +DA:85,1 +DA:86,1 +DA:87,1 +DA:88,1 +DA:91,1 +DA:92,1 +DA:93,1 +DA:95,1 +LF:32 +LH:32 end_of_record SF:lib/src/features/readings_timer/bloc/readings_timer_state.dart DA:12,1 -DA:20,1 +DA:21,1 LF:2 LH:2 end_of_record SF:lib/src/features/readings_timer/bloc/readings_timer_bloc.dart -DA:11,1 -DA:12,2 +DA:12,1 DA:13,2 -DA:16,1 -DA:21,2 -DA:23,2 -DA:26,2 -DA:30,1 -DA:32,1 +DA:14,2 +DA:17,1 +DA:22,2 +DA:24,2 +DA:27,2 +DA:31,1 DA:33,1 -DA:37,1 +DA:34,1 DA:38,1 DA:39,1 DA:40,1 -DA:43,1 -DA:44,1 +DA:41,1 +DA:42,1 DA:45,1 DA:46,1 -LF:18 -LH:18 +DA:47,1 +DA:49,1 +LF:19 +LH:19 end_of_record SF:lib/src/features/qr_code_scanner/views/qr_code_scanner_page.dart DA:13,1 diff --git a/docs/design/database/E-R Model/Bookify_conceitual.brM3 b/docs/design/database/E-R Model/Bookify_conceitual.brM3 index c015c2ad..07cbad3f 100644 Binary files a/docs/design/database/E-R Model/Bookify_conceitual.brM3 and b/docs/design/database/E-R Model/Bookify_conceitual.brM3 differ diff --git a/lib/src/bookify_app.dart b/lib/src/bookify_app.dart index f97a20fa..54f500d1 100644 --- a/lib/src/bookify_app.dart +++ b/lib/src/bookify_app.dart @@ -1,10 +1,8 @@ -import 'dart:async'; - -import 'package:bookify/src/core/services/app_services/notifications_service/notifications_service.dart'; +import 'package:bookify/src/shared/cubits/user_logged_cubit/user_logged_cubit.dart'; +import 'package:bookify/src/shared/cubits/user_notification_cubit/user_notification_cubit.dart'; import 'package:bookify/src/shared/cubits/user_theme_cubit/user_theme_cubit.dart'; import 'package:bookify/src/shared/routes/routes.dart'; import 'package:bookify/src/shared/theme/app_theme.dart'; -import 'package:firebase_auth/firebase_auth.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_localizations/flutter_localizations.dart'; @@ -20,69 +18,62 @@ class BookifyApp extends StatefulWidget { } class _BookifyAppState extends State { - late final UserThemeCubit _userThemeCubit; - @override void initState() { super.initState(); - _userThemeCubit = context.read()..getTheme(); - WidgetsBinding.instance.addPostFrameCallback( - (_) => _checkForNotificationsOnInitializeApp(), - ); - } + LocalJsonLocalization.delegate.directories = ['assets/lang']; - void _checkForNotificationsOnInitializeApp() { - final notificationService = context.read(); - unawaited(notificationService.checkForNotifications()); + context.read().getTheme(); + context.read().checkAuthStatus(); + context.read().initializeNotifications(); } @override Widget build(BuildContext context) { - LocalJsonLocalization.delegate.directories = ['assets/lang']; + final themeMode = context.select( + (cubit) => switch (cubit.state) { + UserThemeLoadedState(:final themeMode) => themeMode, + _ => ThemeMode.system, + }, + ); - return BlocBuilder( - bloc: _userThemeCubit, - builder: (context, state) { - final themeMode = switch (state) { - UserThemeLoadedState(:final themeMode) => themeMode, - _ => ThemeMode.system, - }; + final isLoggedIn = context.select( + (cubit) => + cubit.state is UserLoggedLoadedState && + (cubit.state as UserLoggedLoadedState).isLoggedIn, + ); - return MaterialApp( - title: 'Bookify', - theme: appLightTheme, - darkTheme: appDarkTheme, - themeMode: themeMode, - navigatorKey: Routes.navigatorKey, - routes: Routes.routes, - initialRoute: Routes.getInitialRoute( - FirebaseAuth.instance.currentUser != null, - ), - localeResolutionCallback: (locale, supportedLocales) { - if (supportedLocales.contains(locale)) { - return locale; - } + return MaterialApp( + title: 'Bookify', + theme: appLightTheme, + darkTheme: appDarkTheme, + themeMode: themeMode, + navigatorKey: Routes.navigatorKey, + routes: Routes.routes, + initialRoute: Routes.getInitialRoute(isLoggedIn), + localeResolutionCallback: (locale, supportedLocales) { + if (supportedLocales.contains(locale)) { + return locale; + } - if (locale?.languageCode == 'pt') { - return Locale('pt', 'BR'); - } + if (locale?.languageCode == 'pt') { + return Locale('pt', 'BR'); + } - return Locale('en', 'US'); - }, - localizationsDelegates: [ - GlobalMaterialLocalizations.delegate, - GlobalWidgetsLocalizations.delegate, - GlobalCupertinoLocalizations.delegate, - LocalJsonLocalization.delegate, - ], - supportedLocales: const [ - Locale('pt', 'BR'), - Locale('en', 'US'), - Locale('it', 'IT'), - ], - ); + return Locale('en', 'US'); }, + localizationsDelegates: [ + GlobalMaterialLocalizations.delegate, + GlobalWidgetsLocalizations.delegate, + GlobalCupertinoLocalizations.delegate, + LocalJsonLocalization.delegate, + ], + supportedLocales: const [ + Locale('pt', 'BR'), + Locale('en', 'US'), + Locale('it', 'IT'), + ], ); } } diff --git a/lib/src/core/adapters/google_books_adapter.dart b/lib/src/core/adapters/google_books_adapter.dart index 2a3c9cfc..7dfe6539 100644 --- a/lib/src/core/adapters/google_books_adapter.dart +++ b/lib/src/core/adapters/google_books_adapter.dart @@ -13,9 +13,7 @@ abstract class GoogleBooksAdapter { if (json['items'] == null) { return []; } - return (json['items'] as List) - .map((bookMap) => fromJson(bookMap)) - .toList(); + return (json['items'] as List).map((bookMap) => fromJson(bookMap)).toList(); } /// This method was extracted from the [BookModel] class in order to ensure that if one were to change the book API, @@ -24,21 +22,21 @@ abstract class GoogleBooksAdapter { return BookModel( id: map['id'], title: map['volumeInfo']['title'], - authors: - List.from(map['volumeInfo']['authors'] ?? ['Unknown Author']) - .map((author) => AuthorModel(name: author)) - .toList(), + authors: List.from( + map['volumeInfo']['authors'] ?? ['Unknown Author'], + ).map((author) => AuthorModel(name: author)).toList(), publisher: map['volumeInfo']['publisher'] ?? 'Unknown Publisher', description: map['volumeInfo']['description'] ?? 'No description available', categories: List.from( - map['volumeInfo']['categories'] ?? ['Unknown category']) - .map((category) => CategoryModel(name: category)) - .toList(), + map['volumeInfo']['categories'] ?? ['Unknown category'], + ).map((category) => CategoryModel(name: category)).toList(), pageCount: map['volumeInfo']['pageCount'] ?? 0, - imageUrl: (map['volumeInfo']['imageLinks']?['thumbnail'] ?? + imageUrl: + (map['volumeInfo']['imageLinks']?['thumbnail'] ?? 'https://books.google.com.br/googlebooks/images/no_cover_thumb.gif'), - buyLink: map['volumeInfo']['infoLink'] ?? + buyLink: + map['volumeInfo']['infoLink'] ?? 'https://play.google.com/store/books?', averageRating: (map['volumeInfo']['averageRating'] ?? 0.0).toDouble(), ratingsCount: map['volumeInfo']['ratingsCount'] ?? 0, diff --git a/lib/src/core/data_sources/remote_books_data_source/google_books_data_source_impl.dart b/lib/src/core/data_sources/remote_books_data_source/google_books_data_source_impl.dart index c5639bd3..28b9a313 100644 --- a/lib/src/core/data_sources/remote_books_data_source/google_books_data_source_impl.dart +++ b/lib/src/core/data_sources/remote_books_data_source/google_books_data_source_impl.dart @@ -1,8 +1,7 @@ -import 'dart:io'; - import 'package:bookify/src/core/adapters/google_books_adapter.dart'; import 'package:bookify/src/core/data_sources/remote_books_data_source/remote_books_data_source.dart'; -import 'package:bookify/src/core/errors/book_exception/book_exception.dart'; +import 'package:bookify/src/shared/enums/rest_client_error_code.dart'; +import 'package:bookify/src/core/errors/rest_client_exception/rest_client_exception.dart'; import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/rest_client/rest_client.dart'; @@ -57,14 +56,13 @@ class GoogleBooksDataSourceImpl implements RemoteBooksDataSource { return books; } on TypeError { return []; - } on BookNotFoundException { - rethrow; - } on BookException { - rethrow; - } on SocketException { + } on RestClientException { rethrow; } catch (e) { - throw Exception(e.toString()); + throw RestClientException( + RestClientErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } } diff --git a/lib/src/core/database/local_database_impl.dart b/lib/src/core/database/local_database_impl.dart index 2e84b518..aa909239 100644 --- a/lib/src/core/database/local_database_impl.dart +++ b/lib/src/core/database/local_database_impl.dart @@ -1,6 +1,7 @@ import 'package:bookify/src/shared/constants/database_scripts/database_scripts.dart'; import 'package:bookify/src/core/database/local_database.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:path/path.dart'; import 'package:sqflite/sqflite.dart'; @@ -29,7 +30,12 @@ class LocalDatabaseImpl implements LocalDatabase { version: 1, ); } on DatabaseException catch (e) { - throw LocalDatabaseException(e.toString()); + throw _toLocalDatabaseMapper(e); + } catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } @@ -65,7 +71,12 @@ class LocalDatabaseImpl implements LocalDatabase { ); return queryItems; } on DatabaseException catch (e) { - throw LocalDatabaseException(e.toString()); + throw _toLocalDatabaseMapper(e); + } catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } @@ -95,7 +106,12 @@ class LocalDatabaseImpl implements LocalDatabase { return queryItems; } on DatabaseException catch (e) { - throw LocalDatabaseException(e.toString()); + throw _toLocalDatabaseMapper(e); + } catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } @@ -115,7 +131,12 @@ class LocalDatabaseImpl implements LocalDatabase { ); return queryItem.first; } on DatabaseException catch (e) { - throw LocalDatabaseException(e.toString()); + throw _toLocalDatabaseMapper(e); + } catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } @@ -142,7 +163,12 @@ class LocalDatabaseImpl implements LocalDatabase { return queryItems; } on DatabaseException catch (e) { - throw LocalDatabaseException(e.toString()); + throw _toLocalDatabaseMapper(e); + } catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } @@ -165,7 +191,12 @@ class LocalDatabaseImpl implements LocalDatabase { return queryItems; } on DatabaseException catch (e) { - throw LocalDatabaseException(e.toString()); + throw _toLocalDatabaseMapper(e); + } catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } @@ -190,7 +221,12 @@ class LocalDatabaseImpl implements LocalDatabase { return queryItems.first; } on DatabaseException catch (e) { - throw LocalDatabaseException(e.toString()); + throw _toLocalDatabaseMapper(e); + } catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } @@ -209,7 +245,12 @@ class LocalDatabaseImpl implements LocalDatabase { return newId; } on DatabaseException catch (e) { - throw LocalDatabaseException(e.toString()); + throw _toLocalDatabaseMapper(e); + } catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } @@ -235,7 +276,12 @@ class LocalDatabaseImpl implements LocalDatabase { return rowUpdated; } on DatabaseException catch (e) { - throw LocalDatabaseException(e.toString()); + throw _toLocalDatabaseMapper(e); + } catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } @@ -247,13 +293,21 @@ class LocalDatabaseImpl implements LocalDatabase { }) async { try { final db = await database; - final queryMap = await db! - .query(table, where: '$column = ?', whereArgs: [columnValue]); + final queryMap = await db!.query( + table, + where: '$column = ?', + whereArgs: [columnValue], + ); final itemFound = queryMap.isNotEmpty; return itemFound; } on DatabaseException catch (e) { - throw LocalDatabaseException(e.toString()); + throw _toLocalDatabaseMapper(e); + } catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } @@ -272,7 +326,12 @@ class LocalDatabaseImpl implements LocalDatabase { return 0; } on DatabaseException catch (e) { - throw LocalDatabaseException(e.toString()); + throw _toLocalDatabaseMapper(e); + } catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } @@ -295,7 +354,12 @@ class LocalDatabaseImpl implements LocalDatabase { return 0; } on DatabaseException catch (e) { - throw LocalDatabaseException(e.toString()); + throw _toLocalDatabaseMapper(e); + } catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } @@ -319,7 +383,12 @@ class LocalDatabaseImpl implements LocalDatabase { return rowCount; } on DatabaseException catch (e) { - throw LocalDatabaseException(e.toString()); + throw _toLocalDatabaseMapper(e); + } catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } @@ -345,7 +414,12 @@ class LocalDatabaseImpl implements LocalDatabase { return rowCount; } on DatabaseException catch (e) { - throw LocalDatabaseException(e.toString()); + throw _toLocalDatabaseMapper(e); + } catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } @@ -355,7 +429,40 @@ class LocalDatabaseImpl implements LocalDatabase { final db = await database; await db!.close(); } on DatabaseException catch (e) { - throw LocalDatabaseException(e.toString()); + throw _toLocalDatabaseMapper(e); + } catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: e.toString(), + ); + } + } + + LocalDatabaseException _toLocalDatabaseMapper(DatabaseException e) { + if (e.isOpenFailedError()) { + return LocalDatabaseException( + LocalDatabaseErrorCode.openFailed, + descriptionMessage: e.toString(), + ); } + + if (e.isUniqueConstraintError()) { + return LocalDatabaseException( + LocalDatabaseErrorCode.uniqueConstraint, + descriptionMessage: e.toString(), + ); + } + + if (e.isNotNullConstraintError()) { + return LocalDatabaseException( + LocalDatabaseErrorCode.notNullConstraint, + descriptionMessage: e.toString(), + ); + } + + return LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } diff --git a/lib/src/core/errors/auth_exception/auth_exception.dart b/lib/src/core/errors/auth_exception/auth_exception.dart index e0f5601c..cd0c1bbf 100644 --- a/lib/src/core/errors/auth_exception/auth_exception.dart +++ b/lib/src/core/errors/auth_exception/auth_exception.dart @@ -1,8 +1,14 @@ +import 'package:bookify/src/shared/enums/auth_error_code.dart'; + class AuthException implements Exception { - final String message; + final AuthErrorCode code; + final String? descriptionMessage; - const AuthException(this.message); + const AuthException( + this.code, { + this.descriptionMessage, + }); @override - String toString() => message; + String toString() => 'AuthException: [$code] $descriptionMessage'; } diff --git a/lib/src/core/errors/book_exception/book_exception.dart b/lib/src/core/errors/book_exception/book_exception.dart deleted file mode 100644 index d03c5e6e..00000000 --- a/lib/src/core/errors/book_exception/book_exception.dart +++ /dev/null @@ -1,19 +0,0 @@ -class BookException implements Exception { - final String message; - - const BookException(this.message); - - @override - String toString() { - return 'Book Exception: $message'; - } -} - -class BookNotFoundException extends BookException { - const BookNotFoundException(super.message); - - @override - String toString() { - return 'BookNotFoundException: $message'; - } -} diff --git a/lib/src/core/errors/local_database_exception/local_database_exception.dart b/lib/src/core/errors/local_database_exception/local_database_exception.dart index 76071d55..6675ddc1 100644 --- a/lib/src/core/errors/local_database_exception/local_database_exception.dart +++ b/lib/src/core/errors/local_database_exception/local_database_exception.dart @@ -1,8 +1,14 @@ +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; + class LocalDatabaseException implements Exception { - final String message; + final LocalDatabaseErrorCode code; + final String? descriptionMessage; - const LocalDatabaseException(this.message); + const LocalDatabaseException( + this.code, { + this.descriptionMessage, + }); @override - String toString() => message; + String toString() => 'LocalDatabaseException: [$code] $descriptionMessage'; } diff --git a/lib/src/core/errors/platform_exception/platform_exception.dart b/lib/src/core/errors/platform_exception/platform_exception.dart new file mode 100644 index 00000000..802c1fe9 --- /dev/null +++ b/lib/src/core/errors/platform_exception/platform_exception.dart @@ -0,0 +1,14 @@ +import 'package:bookify/src/shared/enums/platform_error_code.dart'; + +class PlatformException implements Exception { + final PlatformErrorCode code; + final String? descriptionMessage; + + const PlatformException( + this.code, { + this.descriptionMessage, + }); + + @override + String toString() => 'PlatformException: [$code] $descriptionMessage'; +} diff --git a/lib/src/core/errors/rest_client_exception/rest_client_exception.dart b/lib/src/core/errors/rest_client_exception/rest_client_exception.dart new file mode 100644 index 00000000..7b1a86ef --- /dev/null +++ b/lib/src/core/errors/rest_client_exception/rest_client_exception.dart @@ -0,0 +1,14 @@ +import 'package:bookify/src/shared/enums/rest_client_error_code.dart'; + +class RestClientException implements Exception { + final RestClientErrorCode code; + final String? descriptionMessage; + + const RestClientException( + this.code, { + this.descriptionMessage, + }); + + @override + String toString() => 'RestClientException: [$code] $descriptionMessage'; +} diff --git a/lib/src/core/errors/storage_exception/storage_exception.dart b/lib/src/core/errors/storage_exception/storage_exception.dart index a6f1bb09..1d34df30 100644 --- a/lib/src/core/errors/storage_exception/storage_exception.dart +++ b/lib/src/core/errors/storage_exception/storage_exception.dart @@ -1,8 +1,14 @@ +import 'package:bookify/src/shared/enums/storage_error_code.dart'; + class StorageException implements Exception { - final String message; + final StorageErrorCode code; + final String? descriptionMessage; - const StorageException(this.message); + const StorageException( + this.code, { + this.descriptionMessage, + }); @override - String toString() => message; + String toString() => 'StorageException: [$code] $descriptionMessage'; } diff --git a/lib/src/core/helpers/error_code/auth_error_code/auth_error_code_extension.dart b/lib/src/core/helpers/error_code/auth_error_code/auth_error_code_extension.dart new file mode 100644 index 00000000..0bb5c7a8 --- /dev/null +++ b/lib/src/core/helpers/error_code/auth_error_code/auth_error_code_extension.dart @@ -0,0 +1,34 @@ +import 'package:bookify/src/shared/enums/auth_error_code.dart'; +import 'package:localization/localization.dart'; + +extension AuthErrorCodeExtension on AuthErrorCode { + String toLocalizedMessage(String? descriptionMessage) { + final messageArg = descriptionMessage ?? '---'; + + return switch (this) { + AuthErrorCode.userNotFound => 'error-auth-user-not-found'.i18n([ + messageArg, + ]), + AuthErrorCode.wrongPassword => 'error-auth-wrong-password'.i18n([ + messageArg, + ]), + AuthErrorCode.invalidEmail => 'error-auth-invalid-email'.i18n([ + messageArg, + ]), + AuthErrorCode.accountDisabled => 'error-auth-account-disabled'.i18n([ + messageArg, + ]), + AuthErrorCode.tooManyRequests => 'error-auth-too-many-requests'.i18n([ + messageArg, + ]), + AuthErrorCode.operationNotAllowed => + 'error-auth-operation-not-allowed'.i18n([messageArg]), + AuthErrorCode.networkRequestFailed => + 'error-auth-network-request-failed'.i18n([messageArg]), + AuthErrorCode.internalError => 'error-auth-internal-error'.i18n([ + messageArg, + ]), + AuthErrorCode.unknown => 'error-unknown'.i18n([messageArg]), + }; + } +} diff --git a/lib/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart b/lib/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart new file mode 100644 index 00000000..179bd63c --- /dev/null +++ b/lib/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart @@ -0,0 +1,35 @@ +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; +import 'package:localization/localization.dart'; + +extension LocalDatabaseErrorCodeExtension on LocalDatabaseErrorCode { + String toLocalizedMessage(String? descriptionMessage) { + final messageArg = descriptionMessage ?? '---'; + + return switch (this) { + LocalDatabaseErrorCode.openFailed => + 'error-local-database-open-failed'.i18n([ + messageArg, + ]), + + LocalDatabaseErrorCode.uniqueConstraint => + 'error-local-database-unique-constraint'.i18n([ + messageArg, + ]), + LocalDatabaseErrorCode.notNullConstraint => + 'error-local-database-not-null-constraint'.i18n([ + messageArg, + ]), + LocalDatabaseErrorCode.conversionFailed => + 'error-local-database-conversion-failed'.i18n([ + messageArg, + ]), + LocalDatabaseErrorCode.unknown => 'error-unknown'.i18n([ + messageArg, + ]), + LocalDatabaseErrorCode.operationFailed => + 'error-local-database-operation-failed'.i18n([ + messageArg, + ]), + }; + } +} diff --git a/lib/src/core/helpers/error_code/platform_error_code/platform_error_code_extension.dart b/lib/src/core/helpers/error_code/platform_error_code/platform_error_code_extension.dart new file mode 100644 index 00000000..4a7125ec --- /dev/null +++ b/lib/src/core/helpers/error_code/platform_error_code/platform_error_code_extension.dart @@ -0,0 +1,25 @@ +import 'package:bookify/src/shared/enums/platform_error_code.dart'; // Assicurati che l'import sia corretto +import 'package:localization/localization.dart'; + +extension PlatformErrorCodeExtension on PlatformErrorCode { + String toLocalizedMessage(String? descriptionMessage) { + final messageArg = descriptionMessage ?? '---'; + + return switch (this) { + PlatformErrorCode.permissionDenied => + 'error-platform-permission-denied'.i18n([ + messageArg, + ]), + PlatformErrorCode.permissionPermanentlyDenied => + 'error-platform-permission-permanently-denied'.i18n([ + messageArg, + ]), + PlatformErrorCode.unsupported => 'error-platform-unsupported'.i18n([ + messageArg, + ]), + PlatformErrorCode.unknown => 'error-unknown'.i18n([ + messageArg, + ]), + }; + } +} diff --git a/lib/src/core/helpers/error_code/rest_client_error_code/rest_client_error_code_extension.dart b/lib/src/core/helpers/error_code/rest_client_error_code/rest_client_error_code_extension.dart new file mode 100644 index 00000000..24c47232 --- /dev/null +++ b/lib/src/core/helpers/error_code/rest_client_error_code/rest_client_error_code_extension.dart @@ -0,0 +1,32 @@ +import 'package:bookify/src/shared/enums/rest_client_error_code.dart'; +import 'package:localization/localization.dart'; + +extension RestClientErrorCodeExtension on RestClientErrorCode { + String toLocalizedMessage(String? descriptionMessage) { + final messageArg = descriptionMessage ?? '---'; + + return switch (this) { + RestClientErrorCode.connectionTimeout => + 'error-rest-client-connection-timeout'.i18n([ + messageArg, + ]), + RestClientErrorCode.receiveTimeout => + 'error-rest-client-receive-timeout'.i18n([ + messageArg, + ]), + RestClientErrorCode.notFound => 'error-rest-client-not-found'.i18n([ + messageArg, + ]), + RestClientErrorCode.socketException => + 'error-rest-client-socket-exception'.i18n([ + messageArg, + ]), + RestClientErrorCode.invalidInput => 'error-invalid-isbn'.i18n([ + messageArg, + ]), + RestClientErrorCode.unknown => 'error-unknown'.i18n([ + messageArg, + ]), + }; + } +} diff --git a/lib/src/core/helpers/error_code/storage_error_code/storage_error_code_extension.dart b/lib/src/core/helpers/error_code/storage_error_code/storage_error_code_extension.dart new file mode 100644 index 00000000..8271a78d --- /dev/null +++ b/lib/src/core/helpers/error_code/storage_error_code/storage_error_code_extension.dart @@ -0,0 +1,21 @@ +import 'package:bookify/src/shared/enums/storage_error_code.dart'; +import 'package:localization/localization.dart'; + +extension StorageErrorCodeExtension on StorageErrorCode { + String toLocalizedMessage(String? descriptionMessage) { + final messageArg = descriptionMessage ?? '---'; + + return switch (this) { + StorageErrorCode.invalidValue => 'error-storage-invalid-value'.i18n([ + messageArg, + ]), + StorageErrorCode.writeFailed => 'error-storage-write-failed'.i18n([ + messageArg, + ]), + StorageErrorCode.readFailed => 'error-storage-read-failed'.i18n([ + messageArg, + ]), + StorageErrorCode.unknown => 'error-unknown'.i18n([messageArg]), + }; + } +} diff --git a/lib/src/core/helpers/notification_channel/notification_channel_extension.dart b/lib/src/core/helpers/notification_channel/notification_channel_extension.dart new file mode 100644 index 00000000..92b581c0 --- /dev/null +++ b/lib/src/core/helpers/notification_channel/notification_channel_extension.dart @@ -0,0 +1,22 @@ +import 'package:bookify/src/core/models/custom_notification_model.dart'; +import 'package:localization/localization.dart'; + +extension NotificationChannelExtension on NotificationChannel { + String description() { + return switch (this) { + NotificationChannel.loanChannel => + 'notification-channel-loan-description'.i18n(), + NotificationChannel.readChannel => + 'notification-channel-read-description'.i18n(), + }; + } + + String get label { + return switch (this) { + NotificationChannel.loanChannel => + 'notification-channel-loan-label'.i18n(), + NotificationChannel.readChannel => + 'notification-channel-read-label'.i18n(), + }; + } +} diff --git a/lib/src/core/models/book_model.dart b/lib/src/core/models/book_model.dart index 5b0ffa0c..cc2177e2 100644 --- a/lib/src/core/models/book_model.dart +++ b/lib/src/core/models/book_model.dart @@ -10,7 +10,7 @@ enum BookStatus { return switch (this) { BookStatus.library => 1, BookStatus.reading => 2, - BookStatus.loaned => 3 + BookStatus.loaned => 3, }; } diff --git a/lib/src/core/models/custom_notification_model.dart b/lib/src/core/models/custom_notification_model.dart index 39b2af99..0e8acf8a 100644 --- a/lib/src/core/models/custom_notification_model.dart +++ b/lib/src/core/models/custom_notification_model.dart @@ -15,23 +15,6 @@ enum NotificationChannel { '1' || _ => NotificationChannel.loanChannel, }; } - - String description() { - return switch (this) { - NotificationChannel.loanChannel => - 'Canal que notifica quando é o dia de receber o livro emprestado.', - NotificationChannel.readChannel => - 'Canal que notifica que está na hora da leitura.', - }; - } - - @override - String toString() { - return switch (this) { - NotificationChannel.loanChannel => 'Empréstimos', - NotificationChannel.readChannel => 'Leituras', - }; - } } class CustomNotificationModel { diff --git a/lib/src/core/models/loan_model.dart b/lib/src/core/models/loan_model.dart index 51efb7c4..370647d5 100644 --- a/lib/src/core/models/loan_model.dart +++ b/lib/src/core/models/loan_model.dart @@ -6,7 +6,7 @@ class LoanModel { final String idContact; final String bookId; - const LoanModel({ + const LoanModel({ this.id, this.observation, required this.loanDate, diff --git a/lib/src/core/models/user_hour_time_model.dart b/lib/src/core/models/user_hour_time_model.dart index c28ca455..d545c581 100644 --- a/lib/src/core/models/user_hour_time_model.dart +++ b/lib/src/core/models/user_hour_time_model.dart @@ -1,6 +1,6 @@ import 'dart:convert'; -import 'package:bookify/src/core/enums/repeat_hour_time_type.dart'; +import 'package:bookify/src/shared/enums/repeat_hour_time_type.dart'; class UserHourTimeModel { final RepeatHourTimeType repeatHourTimeType; @@ -23,17 +23,17 @@ class UserHourTimeModel { // Calculate total minutes in starting time int startingTimeInMinutes = (startingHour * 60) + startingMinute; -// Calculate total minutes in ending time + // Calculate total minutes in ending time int endingTimeInMinutes = (endingHour * 60) + endingMinute; -// Calculate the difference in minutes (handling negative values) + // Calculate the difference in minutes (handling negative values) int differenceInMinutes = endingTimeInMinutes - startingTimeInMinutes; if (differenceInMinutes < 0) { // Add a day's worth of minutes if negative differenceInMinutes += 24 * 60; } -// Convert the difference in minutes to seconds + // Convert the difference in minutes to seconds int differenceInSeconds = differenceInMinutes * 60; return differenceInSeconds; } @@ -66,8 +66,9 @@ class UserHourTimeModel { factory UserHourTimeModel.fromMap(Map map) { return UserHourTimeModel( - repeatHourTimeType: - RepeatHourTimeType.toType(map['repeatHourTimeType'] as int), + repeatHourTimeType: RepeatHourTimeType.toType( + map['repeatHourTimeType'] as int, + ), startingHour: map['startingHour'] as int, startingMinute: map['startingMinute'] as int, endingHour: map['endingHour'] as int, diff --git a/lib/src/core/repositories/auth_repository/auth_repository.dart b/lib/src/core/repositories/auth_repository/auth_repository.dart index e6a4a0c5..4590459f 100644 --- a/lib/src/core/repositories/auth_repository/auth_repository.dart +++ b/lib/src/core/repositories/auth_repository/auth_repository.dart @@ -3,4 +3,5 @@ import 'package:bookify/src/core/models/user_model.dart'; abstract interface class AuthRepository { Future getUserModel(); Future setUserModel({required UserModel userModel}); + Future deleteUserModel(); } diff --git a/lib/src/core/repositories/auth_repository/auth_repository_impl.dart b/lib/src/core/repositories/auth_repository/auth_repository_impl.dart index 4a778e69..65f556e4 100644 --- a/lib/src/core/repositories/auth_repository/auth_repository_impl.dart +++ b/lib/src/core/repositories/auth_repository/auth_repository_impl.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/models/user_model.dart'; import 'package:bookify/src/core/repositories/auth_repository/auth_repository.dart'; @@ -14,9 +15,11 @@ class AuthRepositoryImpl implements AuthRepository { @override Future getUserModel() async { try { - final userJson = await _storage.getStorage( - key: _userKey, - ) as String?; + final userJson = + await _storage.getStorage( + key: _userKey, + ) + as String?; if (userJson == null) { return null; @@ -26,7 +29,10 @@ class AuthRepositoryImpl implements AuthRepository { return userModel; } on TypeError { - throw const StorageException('impossível converter o usuário.'); + throw const StorageException( + StorageErrorCode.invalidValue, + descriptionMessage: 'Expected a String value for user data.', + ); } on StorageException { rethrow; } @@ -43,6 +49,25 @@ class AuthRepositoryImpl implements AuthRepository { return (userJsonInserted == 1) ? 1 : 0; } on StorageException { rethrow; + } catch (e) { + throw StorageException( + StorageErrorCode.writeFailed, + descriptionMessage: e.toString(), + ); + } + } + + @override + Future deleteUserModel() async { + try { + return await _storage.deleteStorage(key: _userKey); + } on StorageException { + rethrow; + } catch (e) { + throw StorageException( + StorageErrorCode.writeFailed, + descriptionMessage: e.toString(), + ); } } } diff --git a/lib/src/core/repositories/author_repository/authors_repository_impl.dart b/lib/src/core/repositories/author_repository/authors_repository_impl.dart index e2eb5c36..0619a28f 100644 --- a/lib/src/core/repositories/author_repository/authors_repository_impl.dart +++ b/lib/src/core/repositories/author_repository/authors_repository_impl.dart @@ -3,6 +3,7 @@ import 'package:bookify/src/core/database/local_database.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/models/author_model.dart'; import 'package:bookify/src/core/repositories/author_repository/authors_repository.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; class AuthorsRepositoryImpl implements AuthorsRepository { final LocalDatabase _database; @@ -21,8 +22,11 @@ class AuthorsRepositoryImpl implements AuthorsRepository { final authorModel = AuthorModel.fromMap(authorsMap); return authorModel; - } on TypeError { - throw const LocalDatabaseException('Impossível converter o dado do database'); + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), + ); } on LocalDatabaseException { rethrow; } @@ -45,8 +49,11 @@ class AuthorsRepositoryImpl implements AuthorsRepository { final actualAuthorId = authorMap.last['id'] as int; return actualAuthorId; - } on TypeError { - throw const LocalDatabaseException('Impossível converter o dado do database'); + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), + ); } on LocalDatabaseException { rethrow; } diff --git a/lib/src/core/repositories/book_authors_repository/book_authors_repository_impl.dart b/lib/src/core/repositories/book_authors_repository/book_authors_repository_impl.dart index 0307b847..7accdef0 100644 --- a/lib/src/core/repositories/book_authors_repository/book_authors_repository_impl.dart +++ b/lib/src/core/repositories/book_authors_repository/book_authors_repository_impl.dart @@ -2,6 +2,7 @@ import 'package:bookify/src/shared/constants/database_scripts/database_scripts.d import 'package:bookify/src/core/database/local_database.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/repositories/book_authors_repository/book_authors_repository.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; class BookAuthorsRepositoryImpl implements BookAuthorsRepository { final LocalDatabase _database; @@ -21,23 +22,31 @@ class BookAuthorsRepositoryImpl implements BookAuthorsRepository { ); if (bookAuthorsRelationships.last.isEmpty) { - throw const LocalDatabaseException('Impossível buscar os dados'); + throw const LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: 'Impossible to fetch data', + ); } return bookAuthorsRelationships; - } on LocalDatabaseException { - rethrow; + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), + ); } } @override Future insert({required String bookId, required int authorId}) async { try { - final rowInserted = - await _database.insert(table: _bookAuthorsTableName, values: { - 'bookId': bookId, - 'authorId': authorId, - }); + final rowInserted = await _database.insert( + table: _bookAuthorsTableName, + values: { + 'bookId': bookId, + 'authorId': authorId, + }, + ); return rowInserted; } on LocalDatabaseException { diff --git a/lib/src/core/repositories/book_categories_repository/book_categories_repository.dart b/lib/src/core/repositories/book_categories_repository/book_categories_repository.dart index fad8c1b3..f27a11ca 100644 --- a/lib/src/core/repositories/book_categories_repository/book_categories_repository.dart +++ b/lib/src/core/repositories/book_categories_repository/book_categories_repository.dart @@ -1,6 +1,7 @@ abstract interface class BookCategoriesRepository { - Future>> getRelationshipsById( - {required String bookId}); + Future>> getRelationshipsById({ + required String bookId, + }); Future insert({required String bookId, required int categoryId}); Future delete({required String bookId}); } diff --git a/lib/src/core/repositories/book_categories_repository/book_categories_repository_impl.dart b/lib/src/core/repositories/book_categories_repository/book_categories_repository_impl.dart index a165ce9f..4d4c5931 100644 --- a/lib/src/core/repositories/book_categories_repository/book_categories_repository_impl.dart +++ b/lib/src/core/repositories/book_categories_repository/book_categories_repository_impl.dart @@ -2,6 +2,7 @@ import 'package:bookify/src/shared/constants/database_scripts/database_scripts.d import 'package:bookify/src/core/database/local_database.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/repositories/book_categories_repository/book_categories_repository.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; class BookCategoriesRepositoryImpl implements BookCategoriesRepository { final LocalDatabase _database; @@ -21,23 +22,31 @@ class BookCategoriesRepositoryImpl implements BookCategoriesRepository { ); if (bookCategoriesRelationships.last.isEmpty) { - throw const LocalDatabaseException('Impossível buscar os dados'); + throw const LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: 'Impossible to fetch data', + ); } return bookCategoriesRelationships; - } on LocalDatabaseException { - rethrow; + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), + ); } } @override Future insert({required String bookId, required int categoryId}) async { try { - final rowInserted = - await _database.insert(table: _bookCategoriesTableName, values: { - 'bookId': bookId, - 'categoryId': categoryId, - }); + final rowInserted = await _database.insert( + table: _bookCategoriesTableName, + values: { + 'bookId': bookId, + 'categoryId': categoryId, + }, + ); return rowInserted; } on LocalDatabaseException { diff --git a/lib/src/core/repositories/book_on_case_repository/book_on_case_repository.dart b/lib/src/core/repositories/book_on_case_repository/book_on_case_repository.dart index b83e14bb..b293abeb 100644 --- a/lib/src/core/repositories/book_on_case_repository/book_on_case_repository.dart +++ b/lib/src/core/repositories/book_on_case_repository/book_on_case_repository.dart @@ -1,6 +1,7 @@ abstract interface class BookOnCaseRepository { - Future>> getBooksOnCaseRelationship( - {required int bookcaseId}); + Future>> getBooksOnCaseRelationship({ + required int bookcaseId, + }); Future insert({ required int bookcaseId, required String bookId, diff --git a/lib/src/core/repositories/book_on_case_repository/book_on_case_repository_impl.dart b/lib/src/core/repositories/book_on_case_repository/book_on_case_repository_impl.dart index 5e89d489..39cdd6e3 100644 --- a/lib/src/core/repositories/book_on_case_repository/book_on_case_repository_impl.dart +++ b/lib/src/core/repositories/book_on_case_repository/book_on_case_repository_impl.dart @@ -2,6 +2,7 @@ import 'package:bookify/src/shared/constants/database_scripts/database_scripts.d import 'package:bookify/src/core/database/local_database.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/repositories/book_on_case_repository/book_on_case_repository.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; class BookOnCaseRepositoryImpl implements BookOnCaseRepository { final LocalDatabase _database; @@ -38,8 +39,11 @@ class BookOnCaseRepositoryImpl implements BookOnCaseRepository { final bookId = bookRelationshipMap['bookId'] as String?; return bookId; - } on TypeError { - throw const LocalDatabaseException('Impossível converter o dado do database'); + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), + ); } on LocalDatabaseException { rethrow; } @@ -48,11 +52,13 @@ class BookOnCaseRepositoryImpl implements BookOnCaseRepository { @override Future insert({required int bookcaseId, required String bookId}) async { try { - final rowInserted = - await _database.insert(table: _bookOnCaseTableName, values: { - 'bookId': bookId, - 'bookcaseId': bookcaseId, - }); + final rowInserted = await _database.insert( + table: _bookOnCaseTableName, + values: { + 'bookId': bookId, + 'bookcaseId': bookcaseId, + }, + ); return rowInserted; } on LocalDatabaseException { diff --git a/lib/src/core/repositories/bookcase_repository/bookcase_repository_impl.dart b/lib/src/core/repositories/bookcase_repository/bookcase_repository_impl.dart index 78165af6..4c43268a 100644 --- a/lib/src/core/repositories/bookcase_repository/bookcase_repository_impl.dart +++ b/lib/src/core/repositories/bookcase_repository/bookcase_repository_impl.dart @@ -3,6 +3,7 @@ import 'package:bookify/src/core/database/local_database.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/models/bookcase_model.dart'; import 'package:bookify/src/core/repositories/bookcase_repository/bookcase_repository.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; class BookcaseRepositoryImpl implements BookcaseRepository { final LocalDatabase _database; @@ -17,9 +18,10 @@ class BookcaseRepositoryImpl implements BookcaseRepository { final bookcases = bookcasesMap.map(BookcaseModel.fromMap).toList(); return bookcases; - } on TypeError { - throw const LocalDatabaseException( - 'Impossível encontrar as estantes no database', + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), ); } on LocalDatabaseException { rethrow; @@ -37,9 +39,10 @@ class BookcaseRepositoryImpl implements BookcaseRepository { final bookcases = bookcasesMap.map(BookcaseModel.fromMap).toList(); return bookcases; - } on TypeError { - throw const LocalDatabaseException( - 'Impossível encontrar as estantes no database', + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), ); } on LocalDatabaseException { rethrow; @@ -57,9 +60,10 @@ class BookcaseRepositoryImpl implements BookcaseRepository { final bookcase = BookcaseModel.fromMap(bookcaseMap); return bookcase; - } on TypeError { - throw const LocalDatabaseException( - 'Impossível encontrar a estante no database', + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), ); } on LocalDatabaseException { rethrow; diff --git a/lib/src/core/repositories/books_repository/books_repository.dart b/lib/src/core/repositories/books_repository/books_repository.dart index b29d894a..0ec30444 100644 --- a/lib/src/core/repositories/books_repository/books_repository.dart +++ b/lib/src/core/repositories/books_repository/books_repository.dart @@ -7,8 +7,11 @@ abstract interface class BooksRepository { Future> getBooksByTitle({required String title}); Future insert({required BookModel bookModel}); Future verifyBookIsAlreadyInserted({required String id}); - FuturegetBookStatus({required String id}); - Future updateBookStatus({required String id, required BookStatus status}); + Future getBookStatus({required String id}); + Future updateBookStatus({ + required String id, + required BookStatus status, + }); Future updateBookPageCount({required String id, required int pageCount}); Future countBooks(); Future deleteBookById({required String id}); diff --git a/lib/src/core/repositories/books_repository/books_repository_impl.dart b/lib/src/core/repositories/books_repository/books_repository_impl.dart index bd33506f..892fad5e 100644 --- a/lib/src/core/repositories/books_repository/books_repository_impl.dart +++ b/lib/src/core/repositories/books_repository/books_repository_impl.dart @@ -3,6 +3,7 @@ import 'package:bookify/src/core/database/local_database.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/repositories/books_repository/books_repository.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; class BooksRepositoryImpl implements BooksRepository { final LocalDatabase _database; @@ -16,9 +17,10 @@ class BooksRepositoryImpl implements BooksRepository { final booksMap = await _database.getAll(table: _bookTableName); final booksModel = booksMap.map(BookModel.fromMap).toList(); return booksModel; - } on TypeError { - throw const LocalDatabaseException( - 'Impossível converter o dado do database', + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), ); } on LocalDatabaseException { rethrow; @@ -36,9 +38,10 @@ class BooksRepositoryImpl implements BooksRepository { final bookModel = BookModel.fromMap(bookMap); return bookModel; - } on TypeError { - throw const LocalDatabaseException( - 'Impossível converter o dado do database', + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), ); } on LocalDatabaseException { rethrow; @@ -70,9 +73,10 @@ class BooksRepositoryImpl implements BooksRepository { final bookImage = imageMap['imageUrl'] as String; return bookImage; - } on TypeError { - throw const LocalDatabaseException( - 'Impossível converter o dado do database', + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), ); } on LocalDatabaseException { rethrow; @@ -90,9 +94,10 @@ class BooksRepositoryImpl implements BooksRepository { final books = booksMap.map(BookModel.fromMap).toList(); return books; - } on TypeError { - throw const LocalDatabaseException( - 'Impossível encontrar os livros com esse título no database', + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), ); } on LocalDatabaseException { rethrow; @@ -125,9 +130,10 @@ class BooksRepositoryImpl implements BooksRepository { final bookStatus = BookStatus.fromMap(statusMap['status'] as int); return bookStatus!; - } on TypeError { - throw const LocalDatabaseException( - 'Impossível encontrar o status do livro no database', + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), ); } on LocalDatabaseException { rethrow; @@ -158,9 +164,9 @@ class BooksRepositoryImpl implements BooksRepository { required String id, required int pageCount, }) async { - assert(pageCount > 0, 'pagesCount must be greater than 0'); - try { + assert(pageCount > 0, 'pagesCount must be greater than 0'); + final bookPagesCountUpdate = await _database.update( table: _bookTableName, idColumn: 'id', @@ -171,6 +177,11 @@ class BooksRepositoryImpl implements BooksRepository { return bookPagesCountUpdate; } on LocalDatabaseException { rethrow; + } on AssertionError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), + ); } } diff --git a/lib/src/core/repositories/category_repository/categories_repository.dart b/lib/src/core/repositories/category_repository/categories_repository.dart index 91b0b67e..4f3ead67 100644 --- a/lib/src/core/repositories/category_repository/categories_repository.dart +++ b/lib/src/core/repositories/category_repository/categories_repository.dart @@ -1,8 +1,8 @@ import 'package:bookify/src/core/models/category_model.dart'; abstract interface class CategoriesRepository { - Future getCategoryById({required int id}); + Future getCategoryById({required int id}); Future insert({required CategoryModel categoryModel}); Future getCategoryIdByColumnName({required String categoryName}); Future deleteCategoryById({required int id}); -} \ No newline at end of file +} diff --git a/lib/src/core/repositories/category_repository/categories_repository_impl.dart b/lib/src/core/repositories/category_repository/categories_repository_impl.dart index 70cd2b92..7a404e52 100644 --- a/lib/src/core/repositories/category_repository/categories_repository_impl.dart +++ b/lib/src/core/repositories/category_repository/categories_repository_impl.dart @@ -3,6 +3,7 @@ import 'package:bookify/src/core/database/local_database.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/models/category_model.dart'; import 'package:bookify/src/core/repositories/category_repository/categories_repository.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; class CategoriesRepositoryImpl implements CategoriesRepository { final LocalDatabase _database; @@ -21,8 +22,11 @@ class CategoriesRepositoryImpl implements CategoriesRepository { final categoryModel = CategoryModel.fromMap(categoryMap); return categoryModel; - } on TypeError { - throw const LocalDatabaseException('Impossível converter o dado do database'); + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), + ); } on LocalDatabaseException { rethrow; } @@ -45,8 +49,11 @@ class CategoriesRepositoryImpl implements CategoriesRepository { final actualAuthorId = categoryMap.last['id'] as int; return actualAuthorId; - } on TypeError { - throw const LocalDatabaseException('Impossível converter o dado do database'); + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), + ); } on LocalDatabaseException { rethrow; } diff --git a/lib/src/core/repositories/loan_repository/loan_repository_impl.dart b/lib/src/core/repositories/loan_repository/loan_repository_impl.dart index 50bbe1ba..5f7c5cdc 100644 --- a/lib/src/core/repositories/loan_repository/loan_repository_impl.dart +++ b/lib/src/core/repositories/loan_repository/loan_repository_impl.dart @@ -3,6 +3,7 @@ import 'package:bookify/src/core/database/local_database.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/models/loan_model.dart'; import 'package:bookify/src/core/repositories/loan_repository/loan_repository.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; class LoanRepositoryImpl implements LoanRepository { final LocalDatabase _database; @@ -22,9 +23,10 @@ class LoanRepositoryImpl implements LoanRepository { final loans = loanMap.map(LoanModel.fromMap).toList(); return loans; - } on TypeError { - throw const LocalDatabaseException( - 'Impossível encontrar os empréstimos no database', + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), ); } on LocalDatabaseException { rethrow; @@ -47,9 +49,10 @@ class LoanRepositoryImpl implements LoanRepository { final loans = loanMap.map(LoanModel.fromMap).toList(); return loans; - } on TypeError { - throw const LocalDatabaseException( - 'Impossível encontrar os empréstimos no database', + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), ); } on LocalDatabaseException { rethrow; @@ -67,9 +70,10 @@ class LoanRepositoryImpl implements LoanRepository { final loan = LoanModel.fromMap(loanMap); return loan; - } on TypeError { - throw const LocalDatabaseException( - 'Impossível encontrar o empréstimo no database', + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), ); } on LocalDatabaseException { rethrow; diff --git a/lib/src/core/repositories/reading_repository/reading_repository_impl.dart b/lib/src/core/repositories/reading_repository/reading_repository_impl.dart index 8134c363..518443b3 100644 --- a/lib/src/core/repositories/reading_repository/reading_repository_impl.dart +++ b/lib/src/core/repositories/reading_repository/reading_repository_impl.dart @@ -3,6 +3,7 @@ import 'package:bookify/src/core/database/local_database.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/models/reading_model.dart'; import 'package:bookify/src/core/repositories/reading_repository/reading_repository.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; class ReadingRepositoryImpl implements ReadingRepository { final LocalDatabase _database; @@ -25,9 +26,10 @@ class ReadingRepositoryImpl implements ReadingRepository { final readings = readingMap.map(ReadingModel.fromMap).toList(); return readings; - } on TypeError { - throw const LocalDatabaseException( - 'Impossível encontrar as leituras no database', + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), ); } on LocalDatabaseException { rethrow; @@ -53,9 +55,10 @@ class ReadingRepositoryImpl implements ReadingRepository { final readings = readingMap.map(ReadingModel.fromMap).toList(); return readings; - } on TypeError { - throw const LocalDatabaseException( - 'Impossível encontrar as leituras no database', + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), ); } on LocalDatabaseException { rethrow; @@ -74,9 +77,10 @@ class ReadingRepositoryImpl implements ReadingRepository { final reading = ReadingModel.fromMap(readingMap); return reading; - } on TypeError { - throw const LocalDatabaseException( - 'Impossível encontrar a leitura no database', + } on TypeError catch (e) { + throw LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: e.toString(), ); } on LocalDatabaseException { rethrow; diff --git a/lib/src/core/repositories/remote_books_repository/remote_books_repository_impl.dart b/lib/src/core/repositories/remote_books_repository/remote_books_repository_impl.dart index d01e8cdd..960cfeac 100644 --- a/lib/src/core/repositories/remote_books_repository/remote_books_repository_impl.dart +++ b/lib/src/core/repositories/remote_books_repository/remote_books_repository_impl.dart @@ -1,10 +1,5 @@ -import 'dart:io'; - import 'package:bookify/src/core/data_sources/remote_books_data_source/remote_books_data_source.dart'; -import 'package:bookify/src/core/errors/book_exception/book_exception.dart'; - import 'package:bookify/src/core/models/book_model.dart'; - import 'remote_books_repository.dart'; class RemoteBooksRepositoryImpl implements RemoteBooksRepository { @@ -14,97 +9,35 @@ class RemoteBooksRepositoryImpl implements RemoteBooksRepository { @override Future> findBooksByAuthor({required String author}) async { - try { - final books = await _booksDataSource.findBooksByAuthor( - author: author, - ); - return books; - } on BookNotFoundException { - rethrow; - } on BookException { - rethrow; - } on SocketException { - rethrow; - } + return await _booksDataSource.findBooksByAuthor(author: author); } @override Future> findBooksByIsbn({required String isbn}) async { - try { - final books = await _booksDataSource.findBooksByIsbn( - isbn: isbn, - ); - return books; - } on BookNotFoundException { - rethrow; - } on BookException { - rethrow; - } on SocketException { - rethrow; - } + return await _booksDataSource.findBooksByIsbn(isbn: isbn); } @override - Future> findBooksByPublisher( - {required String publisher}) async { - try { - final books = await _booksDataSource.findBooksByPublisher( - publisher: publisher, - ); - return books; - } on BookNotFoundException { - rethrow; - } on BookException { - rethrow; - } on SocketException { - rethrow; - } + Future> findBooksByPublisher({ + required String publisher, + }) async { + return await _booksDataSource.findBooksByPublisher(publisher: publisher); } @override - Future> findBooksByCategory( - {required String category}) async { - try { - final books = await _booksDataSource.findBooksByCategory( - category: category, - ); - return books; - } on BookNotFoundException { - rethrow; - } on BookException { - rethrow; - } on SocketException { - rethrow; - } + Future> findBooksByCategory({ + required String category, + }) async { + return await _booksDataSource.findBooksByCategory(category: category); } @override Future> findBooksByTitle({required String title}) async { - try { - final books = await _booksDataSource.findBooksByTitle( - title: title, - ); - return books; - } on BookNotFoundException { - rethrow; - } on BookException { - rethrow; - } on SocketException { - rethrow; - } + return await _booksDataSource.findBooksByTitle(title: title); } @override Future> getAllBooks() async { - try { - final books = await _booksDataSource.getAllBooks(); - return books; - } on BookNotFoundException { - rethrow; - } on BookException { - rethrow; - } on SocketException { - rethrow; - } + return await _booksDataSource.getAllBooks(); } } diff --git a/lib/src/core/repositories/user_hour_time_repository/user_hour_time_repository_impl.dart b/lib/src/core/repositories/user_hour_time_repository/user_hour_time_repository_impl.dart index 8ce21bd7..26f8aafe 100644 --- a/lib/src/core/repositories/user_hour_time_repository/user_hour_time_repository_impl.dart +++ b/lib/src/core/repositories/user_hour_time_repository/user_hour_time_repository_impl.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/models/user_hour_time_model.dart'; import 'package:bookify/src/core/repositories/user_hour_time_repository/user_hour_time_repository.dart'; @@ -14,9 +15,11 @@ class UserHourTimeRepositoryImpl implements UserHourTimeRepository { @override Future getUserHourTime() async { try { - final userHourTimeJson = await _storage.getStorage( - key: _userHourTimeKey, - ) as String?; + final userHourTimeJson = + await _storage.getStorage( + key: _userHourTimeKey, + ) + as String?; if (userHourTimeJson == null) { return null; @@ -26,7 +29,10 @@ class UserHourTimeRepositoryImpl implements UserHourTimeRepository { return userReadingTimeModel; } on TypeError { - throw const StorageException('impossível converter a hora de leitura.'); + throw const StorageException( + StorageErrorCode.invalidValue, + descriptionMessage: 'Impossible to convert user reading time.', + ); } on StorageException { rethrow; } @@ -45,6 +51,11 @@ class UserHourTimeRepositoryImpl implements UserHourTimeRepository { return (userHourTimeJsonInserted == 1) ? 1 : 0; } on StorageException { rethrow; + } catch (e) { + throw StorageException( + StorageErrorCode.writeFailed, + descriptionMessage: e.toString(), + ); } } } diff --git a/lib/src/core/repositories/user_page_reading_time_repository/user_page_reading_time_repository_impl.dart b/lib/src/core/repositories/user_page_reading_time_repository/user_page_reading_time_repository_impl.dart index 0f1888cb..dce9b21a 100644 --- a/lib/src/core/repositories/user_page_reading_time_repository/user_page_reading_time_repository_impl.dart +++ b/lib/src/core/repositories/user_page_reading_time_repository/user_page_reading_time_repository_impl.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/models/user_page_reading_time_model.dart'; import 'package:bookify/src/core/repositories/user_page_reading_time_repository/user_page_reading_time_repository.dart'; @@ -15,9 +16,11 @@ class UserPageReadingTimeRepositoryImpl @override Future getUserPageReadingTime() async { try { - final pageReading = await _storage.getStorage( - key: _userPageReadingTimeKey, - ) as int?; + final pageReading = + await _storage.getStorage( + key: _userPageReadingTimeKey, + ) + as int?; final userPageReadingTime = UserPageReadingTimeModel( pageReadingTimeSeconds: pageReading, @@ -26,7 +29,9 @@ class UserPageReadingTimeRepositoryImpl return userPageReadingTime; } on TypeError { throw const StorageException( - 'impossível converter o tempo de leitura da página.'); + StorageErrorCode.invalidValue, + descriptionMessage: 'Impossible to convert user page reading time.', + ); } on StorageException { rethrow; } @@ -36,11 +41,20 @@ class UserPageReadingTimeRepositoryImpl Future setUserPageReadingTime({ required UserPageReadingTimeModel userPageReadingTime, }) async { - final userPageReadingTimeInserted = await _storage.insertStorage( - key: _userPageReadingTimeKey, - value: userPageReadingTime.pageReadingTimeSeconds!, - ); + try { + final userPageReadingTimeInserted = await _storage.insertStorage( + key: _userPageReadingTimeKey, + value: userPageReadingTime.pageReadingTimeSeconds!, + ); - return userPageReadingTimeInserted; + return userPageReadingTimeInserted; + } on StorageException { + rethrow; + } catch (e) { + throw StorageException( + StorageErrorCode.writeFailed, + descriptionMessage: e.toString(), + ); + } } } diff --git a/lib/src/core/repositories/user_theme_repository/user_theme_repository_impl.dart b/lib/src/core/repositories/user_theme_repository/user_theme_repository_impl.dart index d6ff81b6..ea659308 100644 --- a/lib/src/core/repositories/user_theme_repository/user_theme_repository_impl.dart +++ b/lib/src/core/repositories/user_theme_repository/user_theme_repository_impl.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/repositories/user_theme_repository/user_theme_repository.dart'; import 'package:bookify/src/core/storage/storage.dart'; @@ -27,7 +28,10 @@ class UserThemeRepositoryImpl implements UserThemeRepository { return null; } } on TypeError { - throw const StorageException('impossível converter o tema.'); + throw const StorageException( + StorageErrorCode.invalidValue, + descriptionMessage: 'Impossible to convert theme mode.', + ); } on StorageException { rethrow; } @@ -43,6 +47,11 @@ class UserThemeRepositoryImpl implements UserThemeRepository { return themeInserted; } on StorageException { rethrow; + } catch (e) { + throw StorageException( + StorageErrorCode.writeFailed, + descriptionMessage: e.toString(), + ); } } } diff --git a/lib/src/core/rest_client/dio_rest_client_impl.dart b/lib/src/core/rest_client/dio_rest_client_impl.dart index d47ee4f1..e7cf0a28 100644 --- a/lib/src/core/rest_client/dio_rest_client_impl.dart +++ b/lib/src/core/rest_client/dio_rest_client_impl.dart @@ -1,9 +1,8 @@ import 'dart:io'; - +import 'package:bookify/src/shared/enums/rest_client_error_code.dart'; import 'package:dio/dio.dart'; import 'package:dio_cache_interceptor/dio_cache_interceptor.dart'; - -import 'package:bookify/src/core/errors/book_exception/book_exception.dart'; +import 'package:bookify/src/core/errors/rest_client_exception/rest_client_exception.dart'; import 'rest_client.dart'; class DioRestClientImpl implements RestClient { @@ -37,19 +36,36 @@ class DioRestClientImpl implements RestClient { return response.data; } on DioException catch (e) { if (e.response?.statusCode == 404) { - throw BookNotFoundException( - e.response?.statusMessage ?? 'Book not found', + throw RestClientException( + RestClientErrorCode.notFound, + descriptionMessage: e.response?.statusMessage ?? 'Item not found', + ); + } else if (e.type == DioExceptionType.connectionTimeout) { + throw RestClientException( + RestClientErrorCode.connectionTimeout, + descriptionMessage: 'Connection timed out', ); - } else if (e.type == DioExceptionType.connectionTimeout || - e.type == DioExceptionType.receiveTimeout) { - throw BookException( - e.response?.statusMessage ?? 'An error occurred', + } else if (e.type == DioExceptionType.receiveTimeout) { + throw RestClientException( + RestClientErrorCode.receiveTimeout, + descriptionMessage: 'Receive timed out', + ); + } else if (e.error is SocketException) { + throw RestClientException( + RestClientErrorCode.socketException, + descriptionMessage: 'No internet connection', ); } else { - throw SocketException(e.message ?? e.toString()); + throw RestClientException( + RestClientErrorCode.unknown, + descriptionMessage: e.message, + ); } } catch (e) { - throw Exception(e.toString()); + throw RestClientException( + RestClientErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } } diff --git a/lib/src/core/services/app_services/app_version_service/app_version_service_impl.dart b/lib/src/core/services/app_services/app_version_service/app_version_service_impl.dart index 03ef7b6e..5b0ee20d 100644 --- a/lib/src/core/services/app_services/app_version_service/app_version_service_impl.dart +++ b/lib/src/core/services/app_services/app_version_service/app_version_service_impl.dart @@ -1,5 +1,7 @@ +import 'package:bookify/src/core/errors/platform_exception/platform_exception.dart'; import 'package:bookify/src/core/models/app_version_model.dart'; import 'package:bookify/src/core/services/app_services/app_version_service/app_version_service.dart'; +import 'package:bookify/src/shared/enums/platform_error_code.dart'; import 'package:package_info_plus/package_info_plus.dart'; class AppVersionServiceImpl implements AppVersionService { @@ -7,15 +9,24 @@ class AppVersionServiceImpl implements AppVersionService { @override Future getAppVersion() async { - final packageInfo = await PackageInfo.fromPlatform(); + try { + final packageInfo = await PackageInfo.fromPlatform(); - final appVersion = AppVersionModel( - appName: packageInfo.appName, - appPackageName: packageInfo.packageName, - version: packageInfo.version, - buildNumber: packageInfo.buildNumber, - ); + final appVersion = AppVersionModel( + appName: packageInfo.appName, + appPackageName: packageInfo.packageName, + version: packageInfo.version, + buildNumber: packageInfo.buildNumber, + ); - return appVersion; + return appVersion; + } on PlatformException { + rethrow; + } catch (e) { + throw PlatformException( + PlatformErrorCode.unknown, + descriptionMessage: e.toString(), + ); + } } } diff --git a/lib/src/core/services/app_services/contacts_service/contacts_service_impl.dart b/lib/src/core/services/app_services/contacts_service/contacts_service_impl.dart index dcebc4bb..1f6605c7 100644 --- a/lib/src/core/services/app_services/contacts_service/contacts_service_impl.dart +++ b/lib/src/core/services/app_services/contacts_service/contacts_service_impl.dart @@ -1,69 +1,91 @@ +import 'package:bookify/src/core/errors/platform_exception/platform_exception.dart'; import 'package:bookify/src/core/models/contact_model.dart'; import 'package:bookify/src/core/services/app_services/contacts_service/contacts_service.dart'; +import 'package:bookify/src/shared/enums/platform_error_code.dart'; import 'package:permission_handler/permission_handler.dart'; import 'package:fast_contacts/fast_contacts.dart'; class ContactsServiceImpl implements ContactsService { @override Future getContactById({required String id}) async { - final permissionStatus = await Permission.contacts.request(); + try { + final permissionStatus = await Permission.contacts.request(); - if (permissionStatus.isGranted) { - final contact = await FastContacts.getContact( - id, - fields: [ - ContactField.displayName, - ContactField.phoneNumbers, - ], - ); - final photo = await FastContacts.getContactImage(id); - - if (contact != null) { - return ContactModel( - id: contact.id, - name: contact.displayName, - phoneNumber: - (contact.phones.isNotEmpty) ? contact.phones.first.number : null, - photo: photo, + if (permissionStatus.isGranted) { + final contact = await FastContacts.getContact( + id, + fields: [ + ContactField.displayName, + ContactField.phoneNumbers, + ], ); + final photo = await FastContacts.getContactImage(id); + + if (contact != null) { + return ContactModel( + id: contact.id, + name: contact.displayName, + phoneNumber: (contact.phones.isNotEmpty) + ? contact.phones.first.number + : null, + photo: photo, + ); + } + } else if (permissionStatus.isPermanentlyDenied) { + openAppSettings(); } - } else if (permissionStatus.isPermanentlyDenied) { - openAppSettings(); + return null; + } on PlatformException { + rethrow; + } catch (e) { + throw PlatformException( + PlatformErrorCode.unknown, + descriptionMessage: e.toString(), + ); } - return null; } @override Future?> getContacts() async { - final permissionStatus = await Permission.contacts.request(); + try { + final permissionStatus = await Permission.contacts.request(); - if (permissionStatus.isGranted) { - final contacts = await FastContacts.getAllContacts( - fields: [ - ContactField.displayName, - ContactField.phoneNumbers, - ], - ); + if (permissionStatus.isGranted) { + final contacts = await FastContacts.getAllContacts( + fields: [ + ContactField.displayName, + ContactField.phoneNumbers, + ], + ); - final List contactsDto = []; - for (Contact contact in contacts) { - final photo = await FastContacts.getContactImage(contact.id); + final List contactsDto = []; + for (Contact contact in contacts) { + final photo = await FastContacts.getContactImage(contact.id); - final contactDto = ContactModel( - id: contact.id, - name: contact.displayName, - phoneNumber: - (contact.phones.isNotEmpty) ? contact.phones.first.number : null, - photo: photo, - ); + final contactDto = ContactModel( + id: contact.id, + name: contact.displayName, + phoneNumber: (contact.phones.isNotEmpty) + ? contact.phones.first.number + : null, + photo: photo, + ); - contactsDto.add(contactDto); - } + contactsDto.add(contactDto); + } - return contactsDto; - } else if (permissionStatus.isPermanentlyDenied) { - openAppSettings(); + return contactsDto; + } else if (permissionStatus.isPermanentlyDenied) { + openAppSettings(); + } + return null; + } on PlatformException { + rethrow; + } catch (e) { + throw PlatformException( + PlatformErrorCode.unknown, + descriptionMessage: e.toString(), + ); } - return null; } } diff --git a/lib/src/core/services/app_services/launcher_service/launcher_service.dart b/lib/src/core/services/app_services/launcher_service/launcher_service.dart index a5adb337..d620210f 100644 --- a/lib/src/core/services/app_services/launcher_service/launcher_service.dart +++ b/lib/src/core/services/app_services/launcher_service/launcher_service.dart @@ -1,3 +1,5 @@ +import 'package:bookify/src/core/errors/platform_exception/platform_exception.dart'; +import 'package:bookify/src/shared/enums/platform_error_code.dart'; import 'package:url_launcher/url_launcher.dart'; class LauncherService { @@ -11,10 +13,18 @@ class LauncherService { ); if (!urlIsLaunched) { - throw 'Erro ao abrir o link'; + throw const PlatformException( + PlatformErrorCode.unknown, + descriptionMessage: 'Impossible to launch the URL', + ); } + } on PlatformException { + rethrow; } catch (e) { - throw Exception('Ocorreu um erro inesperado: $e'); + throw PlatformException( + PlatformErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } @@ -31,13 +41,24 @@ class LauncherService { ); if (!callIsLaunched) { - throw 'Erro ao efetuar a chamada'; + throw const PlatformException( + PlatformErrorCode.unknown, + descriptionMessage: 'Impossible to launch the call', + ); } } else { - throw 'Não foi possível executar a ação de chamada'; + throw const PlatformException( + PlatformErrorCode.unsupported, + descriptionMessage: 'The phone number format is not supported', + ); } + } on PlatformException { + rethrow; } catch (e) { - throw Exception('Ocorreu um erro inesperado: $e'); + throw PlatformException( + PlatformErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } } diff --git a/lib/src/core/services/app_services/notifications_service/notifications_service.dart b/lib/src/core/services/app_services/notifications_service/notifications_service.dart index 2d76b327..be097f45 100644 --- a/lib/src/core/services/app_services/notifications_service/notifications_service.dart +++ b/lib/src/core/services/app_services/notifications_service/notifications_service.dart @@ -1,4 +1,4 @@ -import 'package:bookify/src/core/enums/repeat_hour_time_type.dart'; +import 'package:bookify/src/shared/enums/repeat_hour_time_type.dart'; import 'package:bookify/src/core/models/custom_notification_model.dart'; abstract interface class NotificationsService { diff --git a/lib/src/core/services/app_services/notifications_service/notifications_service_impl.dart b/lib/src/core/services/app_services/notifications_service/notifications_service_impl.dart index 534661c9..1bc782ce 100644 --- a/lib/src/core/services/app_services/notifications_service/notifications_service_impl.dart +++ b/lib/src/core/services/app_services/notifications_service/notifications_service_impl.dart @@ -1,7 +1,10 @@ import 'dart:io'; -import 'package:bookify/src/core/enums/repeat_hour_time_type.dart'; +import 'package:bookify/src/core/errors/platform_exception/platform_exception.dart'; +import 'package:bookify/src/shared/enums/platform_error_code.dart'; +import 'package:bookify/src/shared/enums/repeat_hour_time_type.dart'; import 'package:bookify/src/core/models/custom_notification_model.dart'; +import 'package:bookify/src/core/helpers/notification_channel/notification_channel_extension.dart'; import 'package:bookify/src/core/services/app_services/notifications_service/notification_navigator.dart'; import 'package:bookify/src/core/services/app_services/notifications_service/notifications_service.dart'; import 'package:bookify/src/shared/theme/colors.dart'; @@ -28,17 +31,20 @@ class NotificationsServiceImpl implements NotificationsService { if (Platform.isAndroid) { await _notifications .resolvePlatformSpecificImplementation< - AndroidFlutterLocalNotificationsPlugin>()! + AndroidFlutterLocalNotificationsPlugin + >()! .requestNotificationsPermission(); await _notifications .resolvePlatformSpecificImplementation< - AndroidFlutterLocalNotificationsPlugin>()! + AndroidFlutterLocalNotificationsPlugin + >()! .requestExactAlarmsPermission(); } else if (Platform.isIOS) { await _notifications .resolvePlatformSpecificImplementation< - IOSFlutterLocalNotificationsPlugin>()! + IOSFlutterLocalNotificationsPlugin + >()! .requestPermissions(); } } @@ -94,7 +100,7 @@ class NotificationsServiceImpl implements NotificationsService { return NotificationDetails( android: AndroidNotificationDetails( channel.channelId(), - channel.toString(), + channel.label, channelDescription: channel.description(), color: AppColor.bookifySecondaryColor, styleInformation: BigTextStyleInformation( @@ -103,7 +109,7 @@ class NotificationsServiceImpl implements NotificationsService { importance: Importance.high, ), iOS: DarwinNotificationDetails( - categoryIdentifier: channel.toString(), + categoryIdentifier: channel.label, ), ); } @@ -112,21 +118,30 @@ class NotificationsServiceImpl implements NotificationsService { Future scheduleNotification( CustomNotificationModel notification, ) async { - await _notifications.zonedSchedule( - id: notification.id, - title: notification.title, - body: notification.body, - scheduledDate: tz.TZDateTime.from( - notification.scheduledDate, - tz.local, - ), - notificationDetails: _getNotificationDetails( - notification.notificationChannel, - notification.body, - ), - payload: notification.payload, - androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, - ); + try { + await _notifications.zonedSchedule( + id: notification.id, + title: notification.title, + body: notification.body, + scheduledDate: tz.TZDateTime.from( + notification.scheduledDate, + tz.local, + ), + notificationDetails: _getNotificationDetails( + notification.notificationChannel, + notification.body, + ), + payload: notification.payload, + androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, + ); + } on PlatformException { + rethrow; + } catch (e) { + throw PlatformException( + PlatformErrorCode.unknown, + descriptionMessage: e.toString(), + ); + } } @override @@ -138,62 +153,96 @@ class NotificationsServiceImpl implements NotificationsService { required DateTime scheduledDate, required NotificationChannel notificationChannel, }) async { - final dateTimeComponents = switch (repeatType) { - RepeatHourTimeType.daily => DateTimeComponents.time, - RepeatHourTimeType.weekly => DateTimeComponents.dayOfWeekAndTime, - }; - - await _notifications.zonedSchedule( - id: id, - title: title, - body: body, - scheduledDate: tz.TZDateTime.from( - scheduledDate, - tz.local, - ), - notificationDetails: _getNotificationDetails( - notificationChannel, - body, - ), - androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, - matchDateTimeComponents: dateTimeComponents, - ); + try { + final dateTimeComponents = switch (repeatType) { + RepeatHourTimeType.daily => DateTimeComponents.time, + RepeatHourTimeType.weekly => DateTimeComponents.dayOfWeekAndTime, + }; + + await _notifications.zonedSchedule( + id: id, + title: title, + body: body, + scheduledDate: tz.TZDateTime.from( + scheduledDate, + tz.local, + ), + notificationDetails: _getNotificationDetails( + notificationChannel, + body, + ), + androidScheduleMode: AndroidScheduleMode.exactAllowWhileIdle, + matchDateTimeComponents: dateTimeComponents, + ); + } on PlatformException { + rethrow; + } catch (e) { + throw PlatformException( + PlatformErrorCode.unknown, + descriptionMessage: e.toString(), + ); + } } @override Future cancelNotificationById({required int id}) async { - await _notifications.cancel(id: id); + try { + await _notifications.cancel(id: id); + } on PlatformException { + rethrow; + } catch (e) { + throw PlatformException( + PlatformErrorCode.unknown, + descriptionMessage: e.toString(), + ); + } } @override Future checkForNotifications() async { - final details = await _notifications.getNotificationAppLaunchDetails(); - if (details != null && details.didNotificationLaunchApp) { - if (details.notificationResponse != null) { - _onTapOnNotification(details.notificationResponse!); + try { + final details = await _notifications.getNotificationAppLaunchDetails(); + if (details != null && details.didNotificationLaunchApp) { + if (details.notificationResponse != null) { + _onTapOnNotification(details.notificationResponse!); + } } + } catch (e) { + throw PlatformException( + PlatformErrorCode.unknown, + descriptionMessage: e.toString(), + ); } } @override Future> getNotifications() async { - final pendingNotifications = - await _notifications.pendingNotificationRequests(); - - final notifications = pendingNotifications - .map( - (notification) => CustomNotificationModel( - id: notification.id, - notificationChannel: notification.payload!.isEmpty - ? NotificationChannel.readChannel - : NotificationChannel.loanChannel, - title: notification.title ?? 'sem título', - body: notification.body ?? 'sem corpo', - scheduledDate: DateTime.now(), - ), - ) - .toList(); - - return notifications; + try { + final pendingNotifications = await _notifications + .pendingNotificationRequests(); + + final notifications = pendingNotifications + .map( + (notification) => CustomNotificationModel( + id: notification.id, + notificationChannel: notification.payload!.isEmpty + ? NotificationChannel.readChannel + : NotificationChannel.loanChannel, + title: notification.title ?? '--', + body: notification.body ?? '--', + scheduledDate: DateTime.now(), + ), + ) + .toList(); + + return notifications; + } on PlatformException { + rethrow; + } catch (e) { + throw PlatformException( + PlatformErrorCode.unknown, + descriptionMessage: e.toString(), + ); + } } } diff --git a/lib/src/core/services/app_services/play_alarm_sound_service/play_alarm_sound_service.dart b/lib/src/core/services/app_services/play_alarm_sound_service/play_alarm_sound_service.dart index 0ea6f20b..26773f1c 100644 --- a/lib/src/core/services/app_services/play_alarm_sound_service/play_alarm_sound_service.dart +++ b/lib/src/core/services/app_services/play_alarm_sound_service/play_alarm_sound_service.dart @@ -1,7 +1,9 @@ import 'dart:async'; +import 'package:bookify/src/core/errors/platform_exception/platform_exception.dart'; import 'package:bookify/src/shared/constants/audios/bookify_audios.dart'; import 'package:audioplayers/audioplayers.dart'; +import 'package:bookify/src/shared/enums/platform_error_code.dart'; class PlayAlarmSoundService { final String assetSound; @@ -34,33 +36,67 @@ class PlayAlarmSoundService { } Future playAlarm() async { - await _playSound(volume); + try { + await _playSound(volume); + } catch (e) { + throw PlatformException( + PlatformErrorCode.unknown, + descriptionMessage: e.toString(), + ); + } } Future stop() async { - await player.stop(); + try { + await player.stop(); + } on PlatformException { + rethrow; + } catch (e) { + throw PlatformException( + PlatformErrorCode.unknown, + descriptionMessage: e.toString(), + ); + } } Future dispose() async { - await player.dispose(); + try { + await player.dispose(); + } on PlatformException { + rethrow; + } catch (e) { + throw PlatformException( + PlatformErrorCode.unknown, + descriptionMessage: e.toString(), + ); + } } Future _playSound(double volume) async { - await player.play( - AssetSource( - assetSound.replaceRange(0, 7, ''), - ), - ctx: AudioContext( - android: const AudioContextAndroid( - usageType: AndroidUsageType.alarm, - stayAwake: true, - audioMode: AndroidAudioMode.ringtone, + try { + await player.play( + AssetSource( + assetSound.replaceRange(0, 7, ''), ), - iOS: AudioContextIOS( - category: AVAudioSessionCategory.ambient, + ctx: AudioContext( + android: const AudioContextAndroid( + usageType: AndroidUsageType.alarm, + stayAwake: true, + audioMode: AndroidAudioMode.ringtone, + ), + iOS: AudioContextIOS( + category: AVAudioSessionCategory.ambient, + ), ), - ), - volume: volume, - ); + volume: volume, + ); + } on PlatformException { + rethrow; + } catch (e) { + throw PlatformException( + PlatformErrorCode.unknown, + descriptionMessage: e.toString(), + ); + } } } diff --git a/lib/src/core/services/app_services/show_dialog_service/show_dialog_service.dart b/lib/src/core/services/app_services/show_dialog_service/show_dialog_service.dart index 695fb40d..61a2cd96 100644 --- a/lib/src/core/services/app_services/show_dialog_service/show_dialog_service.dart +++ b/lib/src/core/services/app_services/show_dialog_service/show_dialog_service.dart @@ -43,7 +43,6 @@ class ShowDialogService { ), ); - // if (_isAndroidPlatform) { await showAdaptiveDialog( context: context, builder: (context) { @@ -61,7 +60,7 @@ class ShowDialogService { key: const Key('ConfirmDialogButton'), onPressed: confirmButtonFunction, child: confirmButtonWidget, - ) + ), ] else ...[ CupertinoDialogAction( onPressed: @@ -105,31 +104,28 @@ class ShowDialogService { await showDialog( context: context, - builder: (context) { - if (_isAndroidPlatform) { - return SimpleDialog( - title: titleWidget, - children: [ - SimpleDialogOption( - key: const Key('OkDialogButton'), - onPressed: () => Navigator.pop(context), - child: okButtonWidget, - ), - ], - ); - } - return CupertinoAlertDialog( - title: titleWidget, - actions: [ - CupertinoDialogAction( - key: const Key('OkDialogButton'), - isDefaultAction: true, - onPressed: () => Navigator.pop(context), - child: okButtonWidget, + builder: (context) => (_isAndroidPlatform) + ? SimpleDialog( + title: titleWidget, + children: [ + SimpleDialogOption( + key: const Key('OkDialogButton'), + onPressed: () => Navigator.pop(context), + child: okButtonWidget, + ), + ], + ) + : CupertinoAlertDialog( + title: titleWidget, + actions: [ + CupertinoDialogAction( + key: const Key('OkDialogButton'), + isDefaultAction: true, + onPressed: () => Navigator.pop(context), + child: okButtonWidget, + ), + ], ), - ], - ); - }, ); } } diff --git a/lib/src/core/services/app_services/time_picker_dialog_service.dart/time_picker_dialog_service.dart b/lib/src/core/services/app_services/time_picker_dialog_service.dart/time_picker_dialog_service.dart index 6a5aaf2b..89ab53b2 100644 --- a/lib/src/core/services/app_services/time_picker_dialog_service.dart/time_picker_dialog_service.dart +++ b/lib/src/core/services/app_services/time_picker_dialog_service.dart/time_picker_dialog_service.dart @@ -34,8 +34,9 @@ class TimePickerDialogService { context: context, builder: (context) { return CupertinoTimerPicker( - backgroundColor: - CupertinoColors.systemBackground.resolveFrom(context), + backgroundColor: CupertinoColors.systemBackground.resolveFrom( + context, + ), mode: CupertinoTimerPickerMode.hm, initialTimerDuration: initialTimerDuration, onTimerDurationChanged: (duration) { diff --git a/lib/src/core/services/auth_service/auth_service.dart b/lib/src/core/services/auth_service/auth_service.dart index f11b468d..5715e455 100644 --- a/lib/src/core/services/auth_service/auth_service.dart +++ b/lib/src/core/services/auth_service/auth_service.dart @@ -5,4 +5,5 @@ abstract interface class AuthService { Future signIn({required SignInType signInType}); Future signOut({required SignInType signInType}); Future getUserModel(); + Future userIsLoggedIn(); } diff --git a/lib/src/core/services/auth_service/auth_service_impl.dart b/lib/src/core/services/auth_service/auth_service_impl.dart index 534158bb..31c04e99 100644 --- a/lib/src/core/services/auth_service/auth_service_impl.dart +++ b/lib/src/core/services/auth_service/auth_service_impl.dart @@ -1,8 +1,10 @@ +import 'package:bookify/src/shared/enums/auth_error_code.dart'; import 'package:bookify/src/core/errors/auth_exception/auth_exception.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/models/user_model.dart'; import 'package:bookify/src/core/repositories/auth_repository/auth_repository.dart'; import 'package:bookify/src/shared/enums/sign_in_type.dart'; +import 'package:firebase_auth/firebase_auth.dart'; import 'auth_service.dart'; import 'auth_strategy/auth_strategy_factory.dart'; @@ -14,8 +16,19 @@ class AuthServiceImpl implements AuthService { const AuthServiceImpl({ required AuthRepository authRepository, required AuthStrategyFactory authStrategyFactory, - }) : _authRepository = authRepository, - _authStrategyFactory = authStrategyFactory; + }) : _authRepository = authRepository, + _authStrategyFactory = authStrategyFactory; + + @override + Future userIsLoggedIn() async { + final userIsLoggedIn = FirebaseAuth.instance.currentUser != null; + + if (!userIsLoggedIn) { + await _authRepository.deleteUserModel(); + return false; + } + return true; + } @override Future signIn({required SignInType signInType}) async { @@ -31,9 +44,15 @@ class AuthServiceImpl implements AuthService { } on AuthException { rethrow; } on StorageException catch (e) { - throw AuthException(e.message); + throw AuthException( + AuthErrorCode.internalError, + descriptionMessage: e.descriptionMessage, + ); } on Exception catch (e) { - throw AuthException(e.toString()); + throw AuthException( + AuthErrorCode.internalError, + descriptionMessage: e.toString(), + ); } } @@ -41,11 +60,24 @@ class AuthServiceImpl implements AuthService { Future signOut({required SignInType signInType}) async { try { final authStrategy = _authStrategyFactory.create(signInType); - return await authStrategy.signOut(); + final strategyResult = await authStrategy.signOut(); + + if (strategyResult) { + await _authRepository.deleteUserModel(); + } + return strategyResult; } on AuthException { rethrow; + } on StorageException catch (e) { + throw AuthException( + AuthErrorCode.internalError, + descriptionMessage: e.descriptionMessage, + ); } on Exception catch (e) { - throw AuthException(e.toString()); + throw AuthException( + AuthErrorCode.internalError, + descriptionMessage: e.toString(), + ); } } @@ -55,9 +87,15 @@ class AuthServiceImpl implements AuthService { final user = await _authRepository.getUserModel(); return user; } on StorageException catch (e) { - throw AuthException(e.message); + throw AuthException( + AuthErrorCode.internalError, + descriptionMessage: e.descriptionMessage, + ); } on Exception catch (e) { - throw AuthException(e.toString()); + throw AuthException( + AuthErrorCode.internalError, + descriptionMessage: e.toString(), + ); } } } diff --git a/lib/src/core/services/auth_service/auth_strategy/apple_auth_strategy.dart b/lib/src/core/services/auth_service/auth_strategy/apple_auth_strategy.dart index 908f1cf2..130cea2c 100644 --- a/lib/src/core/services/auth_service/auth_strategy/apple_auth_strategy.dart +++ b/lib/src/core/services/auth_service/auth_strategy/apple_auth_strategy.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:math'; +import 'package:bookify/src/shared/enums/auth_error_code.dart'; import 'package:bookify/src/core/errors/auth_exception/auth_exception.dart'; import 'package:bookify/src/core/models/user_model.dart'; import 'package:bookify/src/shared/enums/sign_in_type.dart'; @@ -21,8 +22,10 @@ class AppleAuthStrategy implements AuthStrategy { '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._'; final random = Random.secure(); - return List.generate(length, (_) => charset[random.nextInt(charset.length)]) - .join(); + return List.generate( + length, + (_) => charset[random.nextInt(charset.length)], + ).join(); } String _sha256ofString(String input) { @@ -60,10 +63,28 @@ class AppleAuthStrategy implements AuthStrategy { ); return userModel; - } on FirebaseException catch (e) { - throw AuthException(e.message ?? 'With no message'); + } on FirebaseAuthException catch (e) { + final errorCode = switch (e.code) { + 'user-not-found' => AuthErrorCode.userNotFound, + 'wrong-password' => AuthErrorCode.wrongPassword, + 'invalid-email' => AuthErrorCode.invalidEmail, + 'account-disabled' => AuthErrorCode.accountDisabled, + 'too-many-requests' => AuthErrorCode.tooManyRequests, + 'operation-not-allowed' => AuthErrorCode.operationNotAllowed, + 'network-request-failed' => AuthErrorCode.networkRequestFailed, + _ => AuthErrorCode.internalError, + }; + throw AuthException( + errorCode, + descriptionMessage: e.message, + ); + } on AuthException { + rethrow; } on Exception catch (e) { - throw AuthException(e.toString()); + throw AuthException( + AuthErrorCode.internalError, + descriptionMessage: e.toString(), + ); } } @@ -72,10 +93,26 @@ class AppleAuthStrategy implements AuthStrategy { try { await _firebaseAuth.signOut(); return true; - } on FirebaseException catch (e) { - throw AuthException(e.message ?? 'With no message'); + } on FirebaseAuthException catch (e) { + final errorCode = switch (e.code) { + 'user-not-found' => AuthErrorCode.userNotFound, + 'wrong-password' => AuthErrorCode.wrongPassword, + 'invalid-email' => AuthErrorCode.invalidEmail, + 'account-disabled' => AuthErrorCode.accountDisabled, + 'too-many-requests' => AuthErrorCode.tooManyRequests, + 'operation-not-allowed' => AuthErrorCode.operationNotAllowed, + 'network-request-failed' => AuthErrorCode.networkRequestFailed, + _ => AuthErrorCode.internalError, + }; + throw AuthException( + errorCode, + descriptionMessage: e.message, + ); } on Exception catch (e) { - throw AuthException(e.toString()); + throw AuthException( + AuthErrorCode.internalError, + descriptionMessage: e.toString(), + ); } } } diff --git a/lib/src/core/services/auth_service/auth_strategy/auth_strategy_factory.dart b/lib/src/core/services/auth_service/auth_strategy/auth_strategy_factory.dart index 51bcbb44..d21d2899 100644 --- a/lib/src/core/services/auth_service/auth_strategy/auth_strategy_factory.dart +++ b/lib/src/core/services/auth_service/auth_strategy/auth_strategy_factory.dart @@ -12,16 +12,16 @@ class AuthStrategyFactory { AuthStrategy create(SignInType signInType) { return switch (signInType) { SignInType.google => GoogleAuthStrategy( - googleSignIn: GoogleSignIn.instance, - firebaseAuth: FirebaseAuth.instance, - ), + googleSignIn: GoogleSignIn.instance, + firebaseAuth: FirebaseAuth.instance, + ), SignInType.apple => AppleAuthStrategy( - firebaseAuth: FirebaseAuth.instance, - ), + firebaseAuth: FirebaseAuth.instance, + ), SignInType.facebook => FacebookAuthStrategy( - facebookAuth: FacebookAuth.instance, - firebaseAuth: FirebaseAuth.instance, - ), + facebookAuth: FacebookAuth.instance, + firebaseAuth: FirebaseAuth.instance, + ), }; } } diff --git a/lib/src/core/services/auth_service/auth_strategy/facebook_auth_strategy.dart b/lib/src/core/services/auth_service/auth_strategy/facebook_auth_strategy.dart index dd6d9b29..4179bf6e 100644 --- a/lib/src/core/services/auth_service/auth_strategy/facebook_auth_strategy.dart +++ b/lib/src/core/services/auth_service/auth_strategy/facebook_auth_strategy.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:math'; +import 'package:bookify/src/shared/enums/auth_error_code.dart'; import 'package:bookify/src/core/errors/auth_exception/auth_exception.dart'; import 'package:bookify/src/core/models/user_model.dart'; import 'package:bookify/src/shared/enums/sign_in_type.dart'; @@ -16,16 +17,18 @@ class FacebookAuthStrategy implements AuthStrategy { FacebookAuthStrategy({ required FacebookAuth facebookAuth, required FirebaseAuth firebaseAuth, - }) : _facebookAuth = facebookAuth, - _firebaseAuth = firebaseAuth; + }) : _facebookAuth = facebookAuth, + _firebaseAuth = firebaseAuth; String _generateNonce([int length = 32]) { const charset = '0123456789ABCDEFGHIJKLMNOPQRSTUVXYZabcdefghijklmnopqrstuvwxyz-._'; final random = Random.secure(); - return List.generate(length, (_) => charset[random.nextInt(charset.length)]) - .join(); + return List.generate( + length, + (_) => charset[random.nextInt(charset.length)], + ).join(); } String _sha256ofString(String input) { @@ -71,11 +74,33 @@ class FacebookAuthStrategy implements AuthStrategy { return userModel; } - throw const AuthException('O usuário não autorizou a autentificação'); - } on FirebaseException catch (e) { - throw AuthException(e.message ?? 'With no message'); + throw AuthException( + AuthErrorCode.internalError, + descriptionMessage: loginResult.message, + ); + } on FirebaseAuthException catch (e) { + final errorCode = switch (e.code) { + 'user-not-found' => AuthErrorCode.userNotFound, + 'wrong-password' => AuthErrorCode.wrongPassword, + 'invalid-email' => AuthErrorCode.invalidEmail, + 'account-disabled' => AuthErrorCode.accountDisabled, + 'too-many-requests' => AuthErrorCode.tooManyRequests, + 'operation-not-allowed' => AuthErrorCode.operationNotAllowed, + 'network-request-failed' => AuthErrorCode.networkRequestFailed, + _ => AuthErrorCode.internalError, + }; + + throw AuthException( + errorCode, + descriptionMessage: e.message, + ); + } on AuthException { + rethrow; } on Exception catch (e) { - throw AuthException(e.toString()); + throw AuthException( + AuthErrorCode.internalError, + descriptionMessage: e.toString(), + ); } } @@ -85,10 +110,26 @@ class FacebookAuthStrategy implements AuthStrategy { await _facebookAuth.logOut(); await _firebaseAuth.signOut(); return true; - } on FirebaseException catch (e) { - throw AuthException(e.message ?? 'With no message'); + } on FirebaseAuthException catch (e) { + final errorCode = switch (e.code) { + 'user-not-found' => AuthErrorCode.userNotFound, + 'wrong-password' => AuthErrorCode.wrongPassword, + 'invalid-email' => AuthErrorCode.invalidEmail, + 'account-disabled' => AuthErrorCode.accountDisabled, + 'too-many-requests' => AuthErrorCode.tooManyRequests, + 'operation-not-allowed' => AuthErrorCode.operationNotAllowed, + 'network-request-failed' => AuthErrorCode.networkRequestFailed, + _ => AuthErrorCode.internalError, + }; + throw AuthException( + errorCode, + descriptionMessage: e.message, + ); } on Exception catch (e) { - throw AuthException(e.toString()); + throw AuthException( + AuthErrorCode.internalError, + descriptionMessage: e.toString(), + ); } } } diff --git a/lib/src/core/services/auth_service/auth_strategy/google_auth_strategy.dart b/lib/src/core/services/auth_service/auth_strategy/google_auth_strategy.dart index b2587803..8ab5ea61 100644 --- a/lib/src/core/services/auth_service/auth_strategy/google_auth_strategy.dart +++ b/lib/src/core/services/auth_service/auth_strategy/google_auth_strategy.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/shared/enums/auth_error_code.dart'; import 'package:bookify/src/core/errors/auth_exception/auth_exception.dart'; import 'package:bookify/src/core/models/user_model.dart'; import 'package:bookify/src/core/services/auth_service/auth_strategy/auth_strategy.dart'; @@ -12,21 +13,24 @@ class GoogleAuthStrategy implements AuthStrategy { GoogleAuthStrategy({ required GoogleSignIn googleSignIn, required FirebaseAuth firebaseAuth, - }) : _googleSignIn = googleSignIn, - _firebaseAuth = firebaseAuth; + }) : _googleSignIn = googleSignIn, + _firebaseAuth = firebaseAuth; @override Future signIn() async { try { await _googleSignIn.initialize().onError( - (error, _) => throw AuthException(error.toString()), - ); + (error, _) => throw AuthException( + AuthErrorCode.operationNotAllowed, + descriptionMessage: error.toString(), + ), + ); const scopes = ['https://www.googleapis.com/auth/contacts.readonly']; final googleAuth = await _googleSignIn.authenticate(); - final authorization = - await googleAuth.authorizationClient.authorizationForScopes(scopes); + final authorization = await googleAuth.authorizationClient + .authorizationForScopes(scopes); final credential = GoogleAuthProvider.credential( accessToken: authorization?.accessToken, @@ -44,10 +48,29 @@ class GoogleAuthStrategy implements AuthStrategy { ); return userModel; - } on FirebaseException catch (e) { - throw AuthException(e.message ?? 'With no message'); + } on FirebaseAuthException catch (e) { + final errorCode = switch (e.code) { + 'user-not-found' => AuthErrorCode.userNotFound, + 'wrong-password' => AuthErrorCode.wrongPassword, + 'invalid-email' => AuthErrorCode.invalidEmail, + 'account-disabled' => AuthErrorCode.accountDisabled, + 'too-many-requests' => AuthErrorCode.tooManyRequests, + 'operation-not-allowed' => AuthErrorCode.operationNotAllowed, + 'network-request-failed' => AuthErrorCode.networkRequestFailed, + _ => AuthErrorCode.internalError, + }; + + throw AuthException( + errorCode, + descriptionMessage: e.message, + ); + } on AuthException { + rethrow; } on Exception catch (e) { - throw AuthException(e.toString()); + throw AuthException( + AuthErrorCode.internalError, + descriptionMessage: e.toString(), + ); } } @@ -57,10 +80,26 @@ class GoogleAuthStrategy implements AuthStrategy { await _googleSignIn.signOut(); await _firebaseAuth.signOut(); return true; - } on FirebaseException catch (e) { - throw AuthException(e.message ?? 'With no message'); + } on FirebaseAuthException catch (e) { + final errorCode = switch (e.code) { + 'user-not-found' => AuthErrorCode.userNotFound, + 'wrong-password' => AuthErrorCode.wrongPassword, + 'invalid-email' => AuthErrorCode.invalidEmail, + 'account-disabled' => AuthErrorCode.accountDisabled, + 'too-many-requests' => AuthErrorCode.tooManyRequests, + 'operation-not-allowed' => AuthErrorCode.operationNotAllowed, + 'network-request-failed' => AuthErrorCode.networkRequestFailed, + _ => AuthErrorCode.internalError, + }; + throw AuthException( + errorCode, + descriptionMessage: e.message, + ); } on Exception catch (e) { - throw AuthException(e.toString()); + throw AuthException( + AuthErrorCode.internalError, + descriptionMessage: e.toString(), + ); } } } diff --git a/lib/src/core/services/book_service/book_service_impl.dart b/lib/src/core/services/book_service/book_service_impl.dart index b965b62d..4f6e9bcf 100644 --- a/lib/src/core/services/book_service/book_service_impl.dart +++ b/lib/src/core/services/book_service/book_service_impl.dart @@ -24,11 +24,11 @@ class BookServiceImpl implements BookService { required CategoriesRepository categoriesRepository, required BookAuthorsRepository bookAuthorsRepository, required BookCategoriesRepository bookCategoriesRepository, - }) : _booksRepository = booksRepository, - _authorsRepository = authorsRepository, - _categoriesRepository = categoriesRepository, - _bookAuthorsRepository = bookAuthorsRepository, - _bookCategoriesRepository = bookCategoriesRepository; + }) : _booksRepository = booksRepository, + _authorsRepository = authorsRepository, + _categoriesRepository = categoriesRepository, + _bookAuthorsRepository = bookAuthorsRepository, + _bookCategoriesRepository = bookCategoriesRepository; @override Future> getAllBook() async { @@ -36,8 +36,9 @@ class BookServiceImpl implements BookService { final booksModel = await _booksRepository.getAll(); for (var index = 0; index < booksModel.length; index++) { - final (authors, categories) = - await _getBookComponents(booksModel[index].id); + final (authors, categories) = await _getBookComponents( + booksModel[index].id, + ); booksModel[index] = booksModel[index].copyWith( authors: authors, categories: categories, @@ -74,8 +75,9 @@ class BookServiceImpl implements BookService { final booksModel = await _booksRepository.getBooksByTitle(title: title); for (var index = 0; index < booksModel.length; index++) { - final (authors, categories) = - await _getBookComponents(booksModel[index].id); + final (authors, categories) = await _getBookComponents( + booksModel[index].id, + ); booksModel[index] = booksModel[index].copyWith( authors: authors, categories: categories, @@ -118,8 +120,9 @@ class BookServiceImpl implements BookService { ); if (categoryId == -1) { - categoryId = - await _categoriesRepository.insert(categoryModel: category); + categoryId = await _categoriesRepository.insert( + categoryModel: category, + ); } await _bookCategoriesRepository.insert( @@ -137,8 +140,9 @@ class BookServiceImpl implements BookService { @override Future verifyBookIsAlreadyInserted({required String id}) async { try { - final isInserted = - await _booksRepository.verifyBookIsAlreadyInserted(id: id); + final isInserted = await _booksRepository.verifyBookIsAlreadyInserted( + id: id, + ); return isInserted; } on LocalDatabaseException { rethrow; @@ -218,8 +222,8 @@ class BookServiceImpl implements BookService { } Future _getBookComponents(String bookId) async { - final bookAuthorsRelationShip = - await _bookAuthorsRepository.getRelationshipsById(bookId: bookId); + final bookAuthorsRelationShip = await _bookAuthorsRepository + .getRelationshipsById(bookId: bookId); final authorsId = bookAuthorsRelationShip .map((relationship) => relationship['authorId'] as int) @@ -231,8 +235,8 @@ class BookServiceImpl implements BookService { authors.add(author); } - final bookCategoriesRelationShip = - await _bookCategoriesRepository.getRelationshipsById(bookId: bookId); + final bookCategoriesRelationShip = await _bookCategoriesRepository + .getRelationshipsById(bookId: bookId); final categoriesId = bookCategoriesRelationShip .map((relationship) => relationship['categoryId'] as int) diff --git a/lib/src/core/services/bookcase_service/bookcase_service_impl.dart b/lib/src/core/services/bookcase_service/bookcase_service_impl.dart index fd9271f5..7c81ebb9 100644 --- a/lib/src/core/services/bookcase_service/bookcase_service_impl.dart +++ b/lib/src/core/services/bookcase_service/bookcase_service_impl.dart @@ -11,8 +11,8 @@ class BookcaseServiceImpl implements BookcaseService { BookcaseServiceImpl({ required BookcaseRepository bookcaseRepository, required BookOnCaseRepository bookOnCaseRepository, - }) : _bookcaseRepository = bookcaseRepository, - _bookOnCaseRepository = bookOnCaseRepository; + }) : _bookcaseRepository = bookcaseRepository, + _bookOnCaseRepository = bookOnCaseRepository; @override Future> getAllBookcases() async { @@ -37,8 +37,9 @@ class BookcaseServiceImpl implements BookcaseService { } @override - Future>> getAllBookcaseRelationships( - {required int bookcaseId}) async { + Future>> getAllBookcaseRelationships({ + required int bookcaseId, + }) async { try { final bookcasesRelationships = await _bookOnCaseRepository .getBooksOnCaseRelationship(bookcaseId: bookcaseId); @@ -49,14 +50,16 @@ class BookcaseServiceImpl implements BookcaseService { } @override - Future deleteBookcaseRelationship( - {required int bookcaseId, required String bookId}) async { + Future deleteBookcaseRelationship({ + required int bookcaseId, + required String bookId, + }) async { try { - final bookcaseRelationshipRowDeleted = - await _bookOnCaseRepository.deleteBookcaseRelationship( - bookcaseId: bookcaseId, - bookId: bookId, - ); + final bookcaseRelationshipRowDeleted = await _bookOnCaseRepository + .deleteBookcaseRelationship( + bookcaseId: bookcaseId, + bookId: bookId, + ); return bookcaseRelationshipRowDeleted; } on LocalDatabaseException { rethrow; @@ -78,8 +81,9 @@ class BookcaseServiceImpl implements BookcaseService { @override Future getBookcaseById({required int bookcaseId}) async { try { - final bookcaseModel = - await _bookcaseRepository.getById(bookcaseId: bookcaseId); + final bookcaseModel = await _bookcaseRepository.getById( + bookcaseId: bookcaseId, + ); return bookcaseModel; } on LocalDatabaseException { rethrow; @@ -89,8 +93,9 @@ class BookcaseServiceImpl implements BookcaseService { @override Future insertBookcase({required BookcaseModel bookcaseModel}) async { try { - final newBookcaseId = - _bookcaseRepository.insert(bookcaseModel: bookcaseModel); + final newBookcaseId = _bookcaseRepository.insert( + bookcaseModel: bookcaseModel, + ); return newBookcaseId; } on LocalDatabaseException { rethrow; diff --git a/lib/src/core/services/storage_services/storage_services.dart b/lib/src/core/services/storage_services/storage_services.dart index c8c89662..1f17f5b8 100644 --- a/lib/src/core/services/storage_services/storage_services.dart +++ b/lib/src/core/services/storage_services/storage_services.dart @@ -1,3 +1,3 @@ abstract interface class StorageServices { Future clearStorage(); -} \ No newline at end of file +} diff --git a/lib/src/core/storage/shared_preference_storage.dart b/lib/src/core/storage/shared_preference_storage.dart index de84b542..fbb07e47 100644 --- a/lib/src/core/storage/shared_preference_storage.dart +++ b/lib/src/core/storage/shared_preference_storage.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:shared_preferences/shared_preferences.dart'; @@ -11,8 +12,13 @@ class SharedPreferencesStorage implements Storage { final storageValue = sharedPreferences.get(key); return storageValue; + } on StorageException { + rethrow; } catch (e) { - throw StorageException(e.toString()); + throw StorageException( + StorageErrorCode.readFailed, + descriptionMessage: e.toString(), + ); } } @@ -26,33 +32,39 @@ class SharedPreferencesStorage implements Storage { final storageInserted = switch (value.runtimeType) { const (int) => await sharedPreferences.setInt( - key, - value as int, - ), + key, + value as int, + ), const (String) => await sharedPreferences.setString( - key, - value as String, - ), + key, + value as String, + ), const (bool) => await sharedPreferences.setBool( - key, - value as bool, - ), + key, + value as bool, + ), const (double) => await sharedPreferences.setDouble( - key, - value as double, - ), + key, + value as double, + ), const (List) => await sharedPreferences.setStringList( - key, - value as List, - ), + key, + value as List, + ), _ => throw StorageException( - 'Type of value not valid: ${value.runtimeType}', - ), + StorageErrorCode.invalidValue, + descriptionMessage: 'Unsupported type: ${value.runtimeType}', + ), }; return storageInserted == true ? 1 : 0; } catch (e) { - throw StorageException(e.toString()); + if (e is StorageException) rethrow; + + throw StorageException( + StorageErrorCode.writeFailed, + descriptionMessage: e.toString(), + ); } } @@ -76,7 +88,10 @@ class SharedPreferencesStorage implements Storage { final deletedStorage = await sharedPreferences.remove(key); return deletedStorage == true ? 1 : 0; } catch (e) { - throw StorageException(e.toString()); + throw StorageException( + StorageErrorCode.writeFailed, + descriptionMessage: e.toString(), + ); } } @@ -88,7 +103,10 @@ class SharedPreferencesStorage implements Storage { final clearStorage = await sharedPreferences.clear(); return clearStorage == true ? 1 : 0; } catch (e) { - throw StorageException(e.toString()); + throw StorageException( + StorageErrorCode.writeFailed, + descriptionMessage: e.toString(), + ); } } } diff --git a/lib/src/core/utils/input_formatter/isbn_input_formatter.dart b/lib/src/core/utils/input_formatter/isbn_input_formatter.dart index 140a2761..fef34bb9 100644 --- a/lib/src/core/utils/input_formatter/isbn_input_formatter.dart +++ b/lib/src/core/utils/input_formatter/isbn_input_formatter.dart @@ -15,13 +15,13 @@ class IsbnMaskTextInputFormatter extends MaskTextInputFormatter { /// /// Initializes the formatter with the ISBN-10 mask and a filter for digits and 'X'. IsbnMaskTextInputFormatter() - : super( - mask: _maskIsbn10, - filter: { - '#': RegExp(r'[0-9]'), // Matches any digit. - 'S': RegExp(r'[xX0-9]'), // Matches 'X', 'x', or any digit. - }, - ); + : super( + mask: _maskIsbn10, + filter: { + '#': RegExp(r'[0-9]'), // Matches any digit. + 'S': RegExp(r'[xX0-9]'), // Matches 'X', 'x', or any digit. + }, + ); @override TextEditingValue formatEditUpdate( diff --git a/lib/src/core/utils/verifier/isbn_verifier.dart b/lib/src/core/utils/verifier/isbn_verifier.dart index 5ff7c362..3665f84a 100644 --- a/lib/src/core/utils/verifier/isbn_verifier.dart +++ b/lib/src/core/utils/verifier/isbn_verifier.dart @@ -9,7 +9,8 @@ class IsbnVerifier { // This regex ensures the ISBN code contains only digits, 'X', or '-', and follows the structure of ISBN codes. // It checks for the presence of 9 digits followed by an 'X' or a digit, and optionally 3 more digits. static final _isbnRegExp = RegExp( - r'^(?=(?:[^0-9]*[0-9]){9}[^0-9xX]*[0-9xX](?:(?:[^0-9]*[0-9]){3})?$)[\dXx-]+$'); + r'^(?=(?:[^0-9]*[0-9]){9}[^0-9xX]*[0-9xX](?:(?:[^0-9]*[0-9]){3})?$)[\dXx-]+$', + ); /// Getter for the ISBN format regular expression. /// This regex is used to validate if a given string is in a valid ISBN format. diff --git a/lib/src/features/about/bloc/about_bloc.dart b/lib/src/features/about/bloc/about_bloc.dart index 3cecc694..f03a3936 100644 --- a/lib/src/features/about/bloc/about_bloc.dart +++ b/lib/src/features/about/bloc/about_bloc.dart @@ -1,5 +1,7 @@ +import 'package:bookify/src/core/errors/platform_exception/platform_exception.dart'; import 'package:bookify/src/core/models/app_version_model.dart'; import 'package:bookify/src/core/services/app_services/app_version_service/app_version_service.dart'; +import 'package:bookify/src/shared/enums/platform_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'about_event.dart'; @@ -20,10 +22,18 @@ class AboutBloc extends Bloc { emit(AboutLoadingState()); final appVersion = await _appVersionService.getAppVersion(); emit(AboutLoadedState(appVersionModel: appVersion)); - } catch (e) { + } on PlatformException catch (e) { emit( AboutErrorState( - errorMessage: 'Erro ao buscar a versão: ${e.toString()}', + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); + } on Exception catch (e) { + emit( + AboutErrorState( + errorCode: PlatformErrorCode.unknown, + errorDescriptionMessage: e.toString(), ), ); } diff --git a/lib/src/features/about/bloc/about_state.dart b/lib/src/features/about/bloc/about_state.dart index 912686d1..ba8f09a0 100644 --- a/lib/src/features/about/bloc/about_state.dart +++ b/lib/src/features/about/bloc/about_state.dart @@ -13,9 +13,11 @@ final class AboutLoadedState extends AboutState { } final class AboutErrorState extends AboutState { - final String errorMessage; + final PlatformErrorCode errorCode; + final String? errorDescriptionMessage; AboutErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/about/views/about_page.dart b/lib/src/features/about/views/about_page.dart index 4e024545..71e85c18 100644 --- a/lib/src/features/about/views/about_page.dart +++ b/lib/src/features/about/views/about_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/platform_error_code/platform_error_code_extension.dart'; import 'package:bookify/src/features/about/bloc/about_bloc.dart'; import 'package:bookify/src/features/about/views/widgets/about_loaded_state_widget.dart'; import 'package:bookify/src/shared/widgets/center_circular_progress_indicator/center_circular_progress_indicator.dart'; @@ -30,9 +31,12 @@ class _AboutPageState extends State { AboutLoadingState() => const CenterCircularProgressIndicator(), AboutLoadedState(appVersionModel: final appVersion) => AboutLoadedStateWidget(appVersionModel: appVersion), - AboutErrorState(:final errorMessage) => + AboutErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => InfoItemStateWidget.withErrorState( - message: errorMessage, + message: errorCode.toLocalizedMessage(errorDescriptionMessage), onPressed: _refreshPage, ), }; diff --git a/lib/src/features/auth/bloc/auth_bloc.dart b/lib/src/features/auth/bloc/auth_bloc.dart index 57d596c8..f7779b73 100644 --- a/lib/src/features/auth/bloc/auth_bloc.dart +++ b/lib/src/features/auth/bloc/auth_bloc.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/shared/enums/auth_error_code.dart'; import 'package:bookify/src/core/errors/auth_exception/auth_exception.dart'; import 'package:bookify/src/core/services/auth_service/auth_service.dart'; import 'package:bookify/src/shared/enums/sign_in_type.dart'; @@ -27,7 +28,9 @@ class AuthBloc extends Bloc { if (authSignedIn == 0) { emit( AuthErrorState( - errorMessage: 'Impossível efetuar a autentificação', + errorCode: AuthErrorCode.internalError, + errorDescriptionMessage: + 'Failed to save user data. Please try again.', ), ); return; @@ -37,13 +40,15 @@ class AuthBloc extends Bloc { } on AuthException catch (e) { emit( AuthErrorState( - errorMessage: 'Erro na autentificação: ${e.message}', + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, ), ); } on Exception catch (e) { emit( AuthErrorState( - errorMessage: 'Erro inesperado: $e', + errorCode: AuthErrorCode.internalError, + errorDescriptionMessage: e.toString(), ), ); } diff --git a/lib/src/features/auth/bloc/auth_state.dart b/lib/src/features/auth/bloc/auth_state.dart index d76dcb19..013e529f 100644 --- a/lib/src/features/auth/bloc/auth_state.dart +++ b/lib/src/features/auth/bloc/auth_state.dart @@ -9,9 +9,11 @@ final class AuthLoadingState extends AuthState {} final class AuthSignedState extends AuthState {} final class AuthErrorState extends AuthState { - final String errorMessage; + final AuthErrorCode errorCode; + final String? errorDescriptionMessage; AuthErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/auth/views/auth_page.dart b/lib/src/features/auth/views/auth_page.dart index 517cd249..af2fb2f8 100644 --- a/lib/src/features/auth/views/auth_page.dart +++ b/lib/src/features/auth/views/auth_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/auth_error_code/auth_error_code_extension.dart'; import 'package:bookify/src/features/auth/bloc/auth_bloc.dart'; import 'package:bookify/src/features/auth/widgets/platform_sign_in_buttons.dart'; import 'package:bookify/src/features/auth/widgets/terms_information.dart'; @@ -77,10 +78,13 @@ class _AuthPageState extends State { }, ); break; - case AuthErrorState(): + case AuthErrorState( + :final errorCode, + :final errorDescriptionMessage, + ): SnackbarService.showSnackBar( context, - state.errorMessage, + errorCode.toLocalizedMessage(errorDescriptionMessage), SnackBarType.error, ); break; diff --git a/lib/src/features/book_detail/bloc/book_detail_bloc.dart b/lib/src/features/book_detail/bloc/book_detail_bloc.dart index 5934ec4f..c09d5ce6 100644 --- a/lib/src/features/book_detail/bloc/book_detail_bloc.dart +++ b/lib/src/features/book_detail/bloc/book_detail_bloc.dart @@ -1,6 +1,7 @@ import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/helpers/book_status/book_status_extension.dart'; import 'package:bookify/src/core/models/book_model.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; @@ -34,13 +35,15 @@ class BookDetailBloc extends Bloc { } on LocalDatabaseException catch (e) { emit( BookDetailErrorState( - errorMessage: 'Ocorreu um erro no database: ${e.toString()}', + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, ), ); } catch (e) { emit( BookDetailErrorState( - errorMessage: 'Ocorreu um erro não esperado: ${e.toString()}', + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), ), ); } @@ -59,7 +62,10 @@ class BookDetailBloc extends Bloc { if (bookInserted != 1) { emit( - BookDetailErrorState(errorMessage: 'Erro no inserimento do livro'), + BookDetailErrorState( + errorCode: LocalDatabaseErrorCode.operationFailed, + errorDescriptionMessage: 'Error on insert book', + ), ); return; } @@ -68,13 +74,15 @@ class BookDetailBloc extends Bloc { } on LocalDatabaseException catch (e) { emit( BookDetailErrorState( - errorMessage: 'Ocorreu um erro no database: ${e.toString()}', + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, ), ); } catch (e) { emit( BookDetailErrorState( - errorMessage: 'Ocorreu um erro não esperado: ${e.toString()}', + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), ), ); } @@ -92,8 +100,9 @@ class BookDetailBloc extends Bloc { if (bookStatus != BookStatus.library) { emit( BookDetailErrorState( - errorMessage: - 'Impossível remover o livro porque está ${bookStatus.label}.', + errorCode: LocalDatabaseErrorCode.operationFailed, + errorDescriptionMessage: + 'Impossible to remove this book because is: ${bookStatus.label}.', ), ); return; @@ -103,7 +112,8 @@ class BookDetailBloc extends Bloc { if (bookRemoved != 1) { emit( BookDetailErrorState( - errorMessage: 'Erro ao remover o livro', + errorCode: LocalDatabaseErrorCode.operationFailed, + errorDescriptionMessage: 'Error on remove book', ), ); return; @@ -113,13 +123,15 @@ class BookDetailBloc extends Bloc { } on LocalDatabaseException catch (e) { emit( BookDetailErrorState( - errorMessage: 'Ocorreu um erro no database: ${e.toString()}', + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, ), ); } catch (e) { emit( BookDetailErrorState( - errorMessage: 'Ocorreu um erro não esperado: ${e.toString()}', + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), ), ); } diff --git a/lib/src/features/book_detail/bloc/book_detail_state.dart b/lib/src/features/book_detail/bloc/book_detail_state.dart index a3d08164..f474bacc 100644 --- a/lib/src/features/book_detail/bloc/book_detail_state.dart +++ b/lib/src/features/book_detail/bloc/book_detail_state.dart @@ -13,9 +13,11 @@ final class BookDetailLoadedState extends BookDetailState { } final class BookDetailErrorState extends BookDetailState { - final String errorMessage; + final LocalDatabaseErrorCode errorCode; + final String? errorDescriptionMessage; BookDetailErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/book_detail/views/book_detail_page.dart b/lib/src/features/book_detail/views/book_detail_page.dart index 8e885d23..757ab50b 100644 --- a/lib/src/features/book_detail/views/book_detail_page.dart +++ b/lib/src/features/book_detail/views/book_detail_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart'; import 'package:bookify/src/features/book_detail/bloc/book_detail_bloc.dart'; import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/services/app_services/launcher_service/launcher_service.dart'; @@ -124,13 +125,16 @@ class _BookDetailPageState extends State { _isCallVerifyBookEvent = false; break; - case BookDetailErrorState(errorMessage: final message): + case BookDetailErrorState( + :final errorCode, + :final errorDescriptionMessage, + ): // enable the click on ElevatedButton. _canClickToInsertOrRemoveButton = true; SnackbarService.showSnackBar( context, - message, + errorCode.toLocalizedMessage(errorDescriptionMessage), SnackBarType.error, ); break; diff --git a/lib/src/features/book_detail/views/widgets/book_description/book_description_widget.dart b/lib/src/features/book_detail/views/widgets/book_description/book_description_widget.dart index 185c3563..d7743ac4 100644 --- a/lib/src/features/book_detail/views/widgets/book_description/book_description_widget.dart +++ b/lib/src/features/book_detail/views/widgets/book_description/book_description_widget.dart @@ -4,8 +4,11 @@ class BookDescriptionWidget extends StatelessWidget { final String title; final String content; - const BookDescriptionWidget( - {super.key, required this.title, required this.content}); + const BookDescriptionWidget({ + super.key, + required this.title, + required this.content, + }); @override Widget build(BuildContext context) { diff --git a/lib/src/features/book_detail/views/widgets/book_pages_reading_time/bloc/book_pages_reading_time_bloc.dart b/lib/src/features/book_detail/views/widgets/book_pages_reading_time/bloc/book_pages_reading_time_bloc.dart index ed4f56e3..4cb8e693 100644 --- a/lib/src/features/book_detail/views/widgets/book_pages_reading_time/bloc/book_pages_reading_time_bloc.dart +++ b/lib/src/features/book_detail/views/widgets/book_pages_reading_time/bloc/book_pages_reading_time_bloc.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/models/user_page_reading_time_model.dart'; import 'package:bookify/src/core/repositories/user_page_reading_time_repository/user_page_reading_time_repository.dart'; @@ -23,8 +24,8 @@ class BookPagesReadingTimeBloc try { emit(BookPagesReadingTimeLoadingState()); - final userPageReadingTime = - await _userPageReadingTimeRepository.getUserPageReadingTime(); + final userPageReadingTime = await _userPageReadingTimeRepository + .getUserPageReadingTime(); emit( BookPagesReadingTimeLoadedState( @@ -34,13 +35,15 @@ class BookPagesReadingTimeBloc } on StorageException catch (e) { emit( BookPagesReadingTimeErrorState( - errorMessage: 'Erro ao buscar o tempo de leitura da página: $e', + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, ), ); } on Exception catch (e) { emit( BookPagesReadingTimeErrorState( - errorMessage: 'Erro inesperado: $e', + errorCode: StorageErrorCode.unknown, + errorDescriptionMessage: e.toString(), ), ); } diff --git a/lib/src/features/book_detail/views/widgets/book_pages_reading_time/bloc/book_pages_reading_time_state.dart b/lib/src/features/book_detail/views/widgets/book_pages_reading_time/bloc/book_pages_reading_time_state.dart index 9b0cc424..ecc6c580 100644 --- a/lib/src/features/book_detail/views/widgets/book_pages_reading_time/bloc/book_pages_reading_time_state.dart +++ b/lib/src/features/book_detail/views/widgets/book_pages_reading_time/bloc/book_pages_reading_time_state.dart @@ -14,9 +14,11 @@ final class BookPagesReadingTimeLoadedState extends BookPagesReadingTimeState { } final class BookPagesReadingTimeErrorState extends BookPagesReadingTimeState { - final String errorMessage; + final StorageErrorCode errorCode; + final String? errorDescriptionMessage; BookPagesReadingTimeErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/book_detail/views/widgets/book_pages_reading_time/widgets/book_pages_reading_time.dart b/lib/src/features/book_detail/views/widgets/book_pages_reading_time/widgets/book_pages_reading_time.dart index 6e5f4cd3..690c56b8 100644 --- a/lib/src/features/book_detail/views/widgets/book_pages_reading_time/widgets/book_pages_reading_time.dart +++ b/lib/src/features/book_detail/views/widgets/book_pages_reading_time/widgets/book_pages_reading_time.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/storage_error_code/storage_error_code_extension.dart'; import 'package:bookify/src/features/book_detail/views/widgets/book_pages_reading_time/bloc/book_pages_reading_time_bloc.dart'; import 'package:bookify/src/shared/widgets/center_circular_progress_indicator/center_circular_progress_indicator.dart'; import 'package:flutter/material.dart'; @@ -36,19 +37,23 @@ class _BookPagesReadingTimeState extends State { BookPagesReadingTimeLoadingState() => const CenterCircularProgressIndicator(), BookPagesReadingTimeLoadedState(:final userPageReadingTime) => Text( - 'hours-to-read-label'.i18n([ - userPageReadingTime - .readingTimeForTotalBookPage(widget.pagesCount) - .toString() - ]), - textScaler: TextScaler.noScaling, - style: TextStyle( - color: Theme.of(context).colorScheme.primary, - fontSize: 14, - ), + 'hours-to-read-label'.i18n([ + userPageReadingTime + .readingTimeForTotalBookPage(widget.pagesCount) + .toString(), + ]), + textScaler: TextScaler.noScaling, + style: TextStyle( + color: Theme.of(context).colorScheme.primary, + fontSize: 14, ), - BookPagesReadingTimeErrorState(:final errorMessage) => Text( - errorMessage, + ), + BookPagesReadingTimeErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => + Text( + errorCode.toLocalizedMessage(errorDescriptionMessage), overflow: TextOverflow.ellipsis, textScaler: TextScaler.noScaling, style: TextStyle( diff --git a/lib/src/features/book_detail/views/widgets/widgets.dart b/lib/src/features/book_detail/views/widgets/widgets.dart index d7fd0035..0f7bb8e3 100644 --- a/lib/src/features/book_detail/views/widgets/widgets.dart +++ b/lib/src/features/book_detail/views/widgets/widgets.dart @@ -1,3 +1,3 @@ export 'book_description/book_description_widget.dart'; export 'book_rating/book_rating.dart'; -export 'book_pages_reading_time/widgets/book_pages_reading_time.dart'; \ No newline at end of file +export 'book_pages_reading_time/widgets/book_pages_reading_time.dart'; diff --git a/lib/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_bloc.dart b/lib/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_bloc.dart index 2286e9d5..6544bf1d 100644 --- a/lib/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_bloc.dart +++ b/lib/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_bloc.dart @@ -1,5 +1,6 @@ import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/services/bookcase_service/bookcase_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'book_on_bookcase_detail_event.dart'; @@ -35,11 +36,16 @@ class BookOnBookcaseDetailBloc } on LocalDatabaseException catch (e) { emit( BookOnBookcaseDetailErrorState( - errorMessage: 'Erro no database: ${e.message}'), + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), ); } on Exception catch (e) { emit( - BookOnBookcaseDetailErrorState(errorMessage: 'Erro inesperado: $e'), + BookOnBookcaseDetailErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), ); } } @@ -59,7 +65,10 @@ class BookOnBookcaseDetailBloc if (deletedBook != 1) { emit( BookOnBookcaseDetailErrorState( - errorMessage: 'Erro ao deletar o livro'), + errorCode: LocalDatabaseErrorCode.operationFailed, + errorDescriptionMessage: + 'Failed to delete the book from the bookcase. Please try again.', + ), ); return; } @@ -68,11 +77,16 @@ class BookOnBookcaseDetailBloc } on LocalDatabaseException catch (e) { emit( BookOnBookcaseDetailErrorState( - errorMessage: 'Erro no database: ${e.message}'), + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), ); } on Exception catch (e) { emit( - BookOnBookcaseDetailErrorState(errorMessage: 'Erro inesperado: $e'), + BookOnBookcaseDetailErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), ); } } diff --git a/lib/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_state.dart b/lib/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_state.dart index acb384fe..3e501611 100644 --- a/lib/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_state.dart +++ b/lib/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_state.dart @@ -17,9 +17,11 @@ final class BookOnBookcaseDetailDeletedState extends BookOnBookcaseDetailState {} final class BookOnBookcaseDetailErrorState extends BookOnBookcaseDetailState { - final String errorMessage; + final LocalDatabaseErrorCode errorCode; + final String? errorDescriptionMessage; BookOnBookcaseDetailErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/book_on_bookcase_detail/views/book_on_bookcase_detail_page.dart b/lib/src/features/book_on_bookcase_detail/views/book_on_bookcase_detail_page.dart index ff636f4f..54cf07d5 100644 --- a/lib/src/features/book_on_bookcase_detail/views/book_on_bookcase_detail_page.dart +++ b/lib/src/features/book_on_bookcase_detail/views/book_on_bookcase_detail_page.dart @@ -1,4 +1,5 @@ import 'package:bookify/src/core/helpers/book_status/book_status_extension.dart'; +import 'package:bookify/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart'; import 'package:bookify/src/features/book_detail/views/book_detail_page.dart'; import 'package:bookify/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_bloc.dart'; import 'package:bookify/src/features/book_on_bookcase_detail/views/widgets/widgets.dart'; @@ -74,11 +75,11 @@ class _BookOnBookcaseDetailPageState extends State { _canPopPage = false; }); - final errorMessage = state.errorMessage; - SnackbarService.showSnackBar( context, - 'error-snackbar'.i18n([errorMessage]), + 'error-snackbar'.i18n([ + state.errorCode.toLocalizedMessage(state.errorDescriptionMessage), + ]), SnackBarType.error, ); diff --git a/lib/src/features/book_on_bookcase_detail/views/widgets/widgets.dart b/lib/src/features/book_on_bookcase_detail/views/widgets/widgets.dart index f12bd1bd..b5b013ee 100644 --- a/lib/src/features/book_on_bookcase_detail/views/widgets/widgets.dart +++ b/lib/src/features/book_on_bookcase_detail/views/widgets/widgets.dart @@ -1,2 +1,2 @@ export 'package:bookify/src/features/book_on_bookcase_detail/views/widgets/book_state_widget.dart'; -export 'package:bookify/src/features/book_on_bookcase_detail/views/widgets/bookcases_count_widget.dart'; \ No newline at end of file +export 'package:bookify/src/features/book_on_bookcase_detail/views/widgets/bookcases_count_widget.dart'; diff --git a/lib/src/features/bookcase/bloc/bookcase_bloc.dart b/lib/src/features/bookcase/bloc/bookcase_bloc.dart index 2952d329..fbc7b45f 100644 --- a/lib/src/features/bookcase/bloc/bookcase_bloc.dart +++ b/lib/src/features/bookcase/bloc/bookcase_bloc.dart @@ -1,6 +1,7 @@ import 'package:bookify/src/core/dtos/bookcase_dto.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/models/bookcase_model.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; @@ -31,9 +32,19 @@ class BookcaseBloc extends Bloc { await _getAllBookcases(emit); } on LocalDatabaseException catch (e) { - emit(BookcaseErrorState(errorMessage: 'Erro no database: ${e.message}')); + emit( + BookcaseErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { - emit(BookcaseErrorState(errorMessage: 'Erro inesperado: $e')); + emit( + BookcaseErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } @@ -46,9 +57,19 @@ class BookcaseBloc extends Bloc { await _findBookcaseByName(emit, event.searchQueryName); } on LocalDatabaseException catch (e) { - emit(BookcaseErrorState(errorMessage: 'Erro no database: ${e.message}')); + emit( + BookcaseErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { - emit(BookcaseErrorState(errorMessage: 'Erro inesperado: $e')); + emit( + BookcaseErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } @@ -63,12 +84,16 @@ class BookcaseBloc extends Bloc { for (var bookcaseDto in selectedList) { int bookcaseDeletedRow = await _bookcaseService.deleteBookcase( - bookcaseId: bookcaseDto.bookcase.id!); + bookcaseId: bookcaseDto.bookcase.id!, + ); if (bookcaseDeletedRow == -1) { emit( BookcaseErrorState( - errorMessage: 'Não foi possível deletar a estante'), + errorCode: LocalDatabaseErrorCode.operationFailed, + errorDescriptionMessage: + 'Failed to delete the bookcase ${bookcaseDto.bookcase.name}.', + ), ); return; } @@ -76,9 +101,19 @@ class BookcaseBloc extends Bloc { await _getAllBookcases(emit); } on LocalDatabaseException catch (e) { - emit(BookcaseErrorState(errorMessage: 'Erro no database: ${e.message}')); + emit( + BookcaseErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { - emit(BookcaseErrorState(errorMessage: 'Erro inesperado: $e')); + emit( + BookcaseErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } @@ -94,7 +129,9 @@ class BookcaseBloc extends Bloc { } Future _findBookcaseByName( - Emitter emit, String name) async { + Emitter emit, + String name, + ) async { final bookcases = await _bookcaseService.getBookcasesByName(name: name); if (bookcases.isEmpty) { @@ -114,7 +151,10 @@ class BookcaseBloc extends Bloc { for (BookcaseModel bookcase in bookcases) { if (bookcase.id == null) { emit( - BookcaseErrorState(errorMessage: 'Erro inesperado: ${bookcase.id}'), + BookcaseErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: 'Bookcase with null ID found.', + ), ); return; } diff --git a/lib/src/features/bookcase/bloc/bookcase_state.dart b/lib/src/features/bookcase/bloc/bookcase_state.dart index 101a8c43..1a7ea2cd 100644 --- a/lib/src/features/bookcase/bloc/bookcase_state.dart +++ b/lib/src/features/bookcase/bloc/bookcase_state.dart @@ -15,9 +15,11 @@ final class BookcaseEmptyState extends BookcaseState {} final class BookcaseNotFoundState extends BookcaseState {} final class BookcaseErrorState extends BookcaseState { - final String errorMessage; + final LocalDatabaseErrorCode errorCode; + final String? errorDescriptionMessage; BookcaseErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/bookcase/views/bookcase_page.dart b/lib/src/features/bookcase/views/bookcase_page.dart index 81f9ecc2..8286191f 100644 --- a/lib/src/features/bookcase/views/bookcase_page.dart +++ b/lib/src/features/bookcase/views/bookcase_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart'; import 'package:bookify/src/features/bookcase/views/widgets/bookcase_loaded_state_widget/bookcase_loaded_state_widget.dart'; import 'package:bookify/src/features/bookcase_insertion/views/bookcase_insertion_page.dart'; import 'package:bookify/src/shared/widgets/center_circular_progress_indicator/center_circular_progress_indicator.dart'; @@ -82,10 +83,13 @@ class _BookcasePageState extends State { message: 'bookcase-not-found-whit-this-terms'.i18n(), onPressed: _refreshPage, ), - BookcaseErrorState(errorMessage: final message) => + BookcaseErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => InfoItemStateWidget.withErrorState( key: const Key('BookcaseErrorStateWidget'), - message: message, + message: errorCode.toLocalizedMessage(errorDescriptionMessage), onPressed: _refreshPage, ), }; diff --git a/lib/src/features/bookcase/views/widgets/bookcase_loaded_state_widget/bookcase_loaded_state_widget.dart b/lib/src/features/bookcase/views/widgets/bookcase_loaded_state_widget/bookcase_loaded_state_widget.dart index 23c2542c..c8603fe3 100644 --- a/lib/src/features/bookcase/views/widgets/bookcase_loaded_state_widget/bookcase_loaded_state_widget.dart +++ b/lib/src/features/bookcase/views/widgets/bookcase_loaded_state_widget/bookcase_loaded_state_widget.dart @@ -92,10 +92,12 @@ class _BookcaseLoadedStateWidgetState extends State { } Future _onAddNewBookcase(BuildContext context) async { - var bookcaseInsertionList = await Navigator.pushNamed( - context, - BookcaseInsertionPage.routeName, - ) as List?; + var bookcaseInsertionList = + await Navigator.pushNamed( + context, + BookcaseInsertionPage.routeName, + ) + as List?; final isInserted = bookcaseInsertionList?[0] as bool?; diff --git a/lib/src/features/bookcase_books_insertion/bloc/bookcase_books_insertion_bloc.dart b/lib/src/features/bookcase_books_insertion/bloc/bookcase_books_insertion_bloc.dart index e743aa42..e33b51f5 100644 --- a/lib/src/features/bookcase_books_insertion/bloc/bookcase_books_insertion_bloc.dart +++ b/lib/src/features/bookcase_books_insertion/bloc/bookcase_books_insertion_bloc.dart @@ -2,6 +2,7 @@ import 'package:bookify/src/core/errors/local_database_exception/local_database_ import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/bookcase_service/bookcase_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'bookcase_books_insertion_event.dart'; @@ -32,8 +33,7 @@ class BookcaseBooksInsertionBloc if (booksList.isEmpty) { emit( BookcaseBooksInsertionEmptyState( - message: - 'Nenhum livro cadastrado. Volte à Página início para cadastrar.', + reason: BookcaseBooksEmptyReason.noBooksRegistered, ), ); return; @@ -59,16 +59,23 @@ class BookcaseBooksInsertionBloc books: booksList, ) : BookcaseBooksInsertionEmptyState( - message: - 'Todos os livros cadastrados já foram adicionados nessa estante.', + reason: BookcaseBooksEmptyReason.allBooksAlreadyInserted, ), ); } on LocalDatabaseException catch (e) { - emit(BookcaseBooksInsertionErrorState( - errorMessage: 'Erro no database: ${e.message}')); + emit( + BookcaseBooksInsertionErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { - emit(BookcaseBooksInsertionErrorState( - errorMessage: 'Erro inesperado: $e')); + emit( + BookcaseBooksInsertionErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } @@ -90,7 +97,8 @@ class BookcaseBooksInsertionBloc if (insertedRow == 0) { emit( BookcaseBooksInsertionErrorState( - errorMessage: 'Erro ao inserir o livro ${book.title}', + errorCode: LocalDatabaseErrorCode.operationFailed, + errorDescriptionMessage: 'Error on insert book: ${book.title}', ), ); return; @@ -99,11 +107,19 @@ class BookcaseBooksInsertionBloc emit(BookcaseBooksInsertionInsertedState()); } on LocalDatabaseException catch (e) { - emit(BookcaseBooksInsertionErrorState( - errorMessage: 'Erro no database: ${e.message}')); + emit( + BookcaseBooksInsertionErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { - emit(BookcaseBooksInsertionErrorState( - errorMessage: 'Erro inesperado: $e')); + emit( + BookcaseBooksInsertionErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } } diff --git a/lib/src/features/bookcase_books_insertion/bloc/bookcase_books_insertion_state.dart b/lib/src/features/bookcase_books_insertion/bloc/bookcase_books_insertion_state.dart index b0f07fb6..9614b0d1 100644 --- a/lib/src/features/bookcase_books_insertion/bloc/bookcase_books_insertion_state.dart +++ b/lib/src/features/bookcase_books_insertion/bloc/bookcase_books_insertion_state.dart @@ -1,5 +1,10 @@ part of 'bookcase_books_insertion_bloc.dart'; +enum BookcaseBooksEmptyReason { + noBooksRegistered, + allBooksAlreadyInserted, +} + sealed class BookcaseBooksInsertionState {} final class BookcaseBooksInsertionLoadingState @@ -7,10 +12,10 @@ final class BookcaseBooksInsertionLoadingState final class BookcaseBooksInsertionEmptyState extends BookcaseBooksInsertionState { - final String message; + final BookcaseBooksEmptyReason reason; BookcaseBooksInsertionEmptyState({ - required this.message, + required this.reason, }); } @@ -28,9 +33,11 @@ final class BookcaseBooksInsertionInsertedState final class BookcaseBooksInsertionErrorState extends BookcaseBooksInsertionState { - final String errorMessage; + final LocalDatabaseErrorCode errorCode; + final String? errorDescriptionMessage; BookcaseBooksInsertionErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/bookcase_books_insertion/views/bookcase_books_insertion_page.dart b/lib/src/features/bookcase_books_insertion/views/bookcase_books_insertion_page.dart index 21f3635d..f6898bd4 100644 --- a/lib/src/features/bookcase_books_insertion/views/bookcase_books_insertion_page.dart +++ b/lib/src/features/bookcase_books_insertion/views/bookcase_books_insertion_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart'; import 'package:bookify/src/features/bookcase_books_insertion/widgets/bookcase_books_insertion_loaded_state_widget/bookcase_books_insertion_loaded_state.dart'; import 'package:bookify/src/core/services/app_services/snackbar_service/snackbar_service.dart'; import 'package:bookify/src/shared/widgets/center_circular_progress_indicator/center_circular_progress_indicator.dart'; @@ -48,12 +49,17 @@ class _BookcaseBooksInsertionPageState BookcaseBooksInsertionLoadingState() || BookcaseBooksInsertionInsertedState() => const CenterCircularProgressIndicator(), - BookcaseBooksInsertionEmptyState(:final message) => Center( - child: Text( - message, - textAlign: TextAlign.center, - ), + BookcaseBooksInsertionEmptyState(:final reason) => Center( + child: Text( + switch (reason) { + BookcaseBooksEmptyReason.noBooksRegistered => + 'no-books-registered'.i18n(), + BookcaseBooksEmptyReason.allBooksAlreadyInserted => + 'all-books-already-inserted'.i18n(), + }, + textAlign: TextAlign.center, ), + ), BookcaseBooksInsertionLoadedState(:final books) => BookcaseBooksInsertionLoadedStateWidget( key: const Key('BookcaseBooksInsertionLoadedStateWidget'), @@ -67,9 +73,12 @@ class _BookcaseBooksInsertionPageState ); }, ), - BookcaseBooksInsertionErrorState(:final errorMessage) => + BookcaseBooksInsertionErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => InfoItemStateWidget.withErrorState( - message: errorMessage, + message: errorCode.toLocalizedMessage(errorDescriptionMessage), onPressed: _refreshPage, ), }; @@ -114,24 +123,27 @@ class _BookcaseBooksInsertionPageState canPop: _canPop, child: BlocConsumer( - bloc: _bloc, - listener: _handleBookcaseInsertionState, - builder: (context, state) { - return Scaffold( - appBar: AppBar( - centerTitle: true, - title: Text( - 'select-books-title'.i18n(), - style: TextStyle(fontSize: 16), - ), + bloc: _bloc, + listener: _handleBookcaseInsertionState, + builder: (context, state) { + return Scaffold( + appBar: AppBar( + centerTitle: true, + title: Text( + 'select-books-title'.i18n(), + style: TextStyle(fontSize: 16), ), - body: Padding( - padding: const EdgeInsets.all(16.0), - child: - _getWidgetOnBookcaseBooksInsertionState(context, state), + ), + body: Padding( + padding: const EdgeInsets.all(16.0), + child: _getWidgetOnBookcaseBooksInsertionState( + context, + state, ), - ); - }), + ), + ); + }, + ), ); } } diff --git a/lib/src/features/bookcase_books_insertion/widgets/widgets.dart b/lib/src/features/bookcase_books_insertion/widgets/widgets.dart index 79a40f66..9431419d 100644 --- a/lib/src/features/bookcase_books_insertion/widgets/widgets.dart +++ b/lib/src/features/bookcase_books_insertion/widgets/widgets.dart @@ -1 +1 @@ -export 'bookcase_books_insertion_loaded_state_widget/bookcase_books_insertion_loaded_state.dart'; \ No newline at end of file +export 'bookcase_books_insertion_loaded_state_widget/bookcase_books_insertion_loaded_state.dart'; diff --git a/lib/src/features/bookcase_detail/bloc/bookcase_detail_bloc.dart b/lib/src/features/bookcase_detail/bloc/bookcase_detail_bloc.dart index 10a4f73a..19ced350 100644 --- a/lib/src/features/bookcase_detail/bloc/bookcase_detail_bloc.dart +++ b/lib/src/features/bookcase_detail/bloc/bookcase_detail_bloc.dart @@ -2,6 +2,7 @@ import 'package:bookify/src/core/errors/local_database_exception/local_database_ import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/bookcase_service/bookcase_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter/foundation.dart'; @@ -33,27 +34,38 @@ class BookcaseDetailBloc } on LocalDatabaseException catch (e) { emit( BookcaseDetailErrorState( - errorMessage: 'Erro no database: ${e.message}'), + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), ); } catch (e) { emit( BookcaseDetailErrorState( - errorMessage: 'Ocorreu um erro não esperado: $e'), + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), ); } } Future _deletedBookcase( - DeletedBookcaseEvent event, Emitter emit) async { + DeletedBookcaseEvent event, + Emitter emit, + ) async { try { emit(BookcaseDetailLoadingState()); - final bookcaseDeletedRow = - await _bookcaseService.deleteBookcase(bookcaseId: event.bookcaseId); + final bookcaseDeletedRow = await _bookcaseService.deleteBookcase( + bookcaseId: event.bookcaseId, + ); if (bookcaseDeletedRow == -1) { - emit(BookcaseDetailErrorState( - errorMessage: 'Impossível deletar a estante')); + emit( + BookcaseDetailErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: 'Impossible delete the bookcase', + ), + ); return; } @@ -61,12 +73,16 @@ class BookcaseDetailBloc } on LocalDatabaseException catch (e) { emit( BookcaseDetailErrorState( - errorMessage: 'Erro no database: ${e.message}'), + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.descriptionMessage, + ), ); } catch (e) { emit( BookcaseDetailErrorState( - errorMessage: 'Ocorreu um erro não esperado: $e'), + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), ); } } @@ -82,11 +98,18 @@ class BookcaseDetailBloc for (var book in books) { final rowDeleted = await _bookcaseService.deleteBookcaseRelationship( - bookcaseId: event.bookcaseId, bookId: book.id); + bookcaseId: event.bookcaseId, + bookId: book.id, + ); if (rowDeleted == -1) { - emit(BookcaseDetailErrorState( - errorMessage: 'Impossível deletar o livro: ${book.title}')); + emit( + BookcaseDetailErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: + 'Impossible delete the book: ${book.title}', + ), + ); return; } } @@ -95,12 +118,16 @@ class BookcaseDetailBloc } on LocalDatabaseException catch (e) { emit( BookcaseDetailErrorState( - errorMessage: 'Erro no database: ${e.message}'), + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), ); } catch (e) { emit( BookcaseDetailErrorState( - errorMessage: 'Ocorreu um erro não esperado: $e'), + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), ); } } diff --git a/lib/src/features/bookcase_detail/bloc/bookcase_detail_state.dart b/lib/src/features/bookcase_detail/bloc/bookcase_detail_state.dart index 67bddff8..81f88807 100644 --- a/lib/src/features/bookcase_detail/bloc/bookcase_detail_state.dart +++ b/lib/src/features/bookcase_detail/bloc/bookcase_detail_state.dart @@ -16,9 +16,11 @@ final class BookcaseDetailBooksLoadedState extends BookcaseDetailState { final class BookcaseDetailDeletedState extends BookcaseDetailState {} final class BookcaseDetailErrorState extends BookcaseDetailState { - final String errorMessage; + final LocalDatabaseErrorCode errorCode; + final String? errorDescriptionMessage; BookcaseDetailErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/bookcase_detail/views/bookcase_detail_page.dart b/lib/src/features/bookcase_detail/views/bookcase_detail_page.dart index b44f47da..09990401 100644 --- a/lib/src/features/bookcase_detail/views/bookcase_detail_page.dart +++ b/lib/src/features/bookcase_detail/views/bookcase_detail_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart'; import 'package:bookify/src/features/bookcase_books_insertion/views/bookcase_books_insertion_page.dart'; import 'package:bookify/src/features/bookcase_detail/bloc/bookcase_detail_bloc.dart'; import 'package:bookify/src/features/bookcase_detail/widgets/widgets.dart'; @@ -65,13 +66,12 @@ class _BookcaseDetailPageState extends State { ) { return switch (state) { BookcaseDetailLoadingState() || - BookcaseDetailDeletedState() => - const CenterCircularProgressIndicator(), + BookcaseDetailDeletedState() => const CenterCircularProgressIndicator(), BookcaseDetailBooksEmptyState() => ItemEmptyStateWidget( - key: const Key('BookcaseDetailBooksEmptyState'), - label: 'add-new-books-button'.i18n(), - onTap: () async => await _addNewBooksBottomSheet(), - ), + key: const Key('BookcaseDetailBooksEmptyState'), + label: 'add-new-books-button'.i18n(), + onTap: () async => await _addNewBooksBottomSheet(), + ), BookcaseDetailBooksLoadedState(:final books) => BookcaseDetailLoadedStateWidget( books: books, @@ -85,9 +85,12 @@ class _BookcaseDetailPageState extends State { ), ), ), - BookcaseDetailErrorState(:final errorMessage) => + BookcaseDetailErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => InfoItemStateWidget.withErrorState( - message: errorMessage, + message: errorCode.toLocalizedMessage(errorDescriptionMessage), onPressed: _refreshPage, ), }; @@ -124,7 +127,9 @@ class _BookcaseDetailPageState extends State { /// /// **Note**: If there is an error removing the [_bookcase], the state will always be [BookcaseDetailErrorState]. Future _handleBookcaseDetailsStateListener( - BookcaseDetailState state, BuildContext context) async { + BookcaseDetailState state, + BuildContext context, + ) async { if (state is BookcaseDetailDeletedState) { setState(() { _canPopPage = false; @@ -152,11 +157,13 @@ class _BookcaseDetailPageState extends State { Future _popupMenuOnSelected(String value, BuildContext context) async { if (value == _popupMenuItemsSet.first) { - final result = await Navigator.pushNamed( - context, - BookcaseInsertionPage.routeName, - arguments: _actualBookcase, - ) as List?; + final result = + await Navigator.pushNamed( + context, + BookcaseInsertionPage.routeName, + arguments: _actualBookcase, + ) + as List?; final bookcaseUpdated = result?[1] as BookcaseModel?; diff --git a/lib/src/features/bookcase_detail/widgets/bookcase_description_widget/bookcase_description_widget.dart b/lib/src/features/bookcase_detail/widgets/bookcase_description_widget/bookcase_description_widget.dart index 025bcc7e..baa95e4b 100644 --- a/lib/src/features/bookcase_detail/widgets/bookcase_description_widget/bookcase_description_widget.dart +++ b/lib/src/features/bookcase_detail/widgets/bookcase_description_widget/bookcase_description_widget.dart @@ -19,8 +19,9 @@ class BookcaseDescriptionWidget extends StatelessWidget { @override Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; - final bookTextQuantity = - (booksQuantity == 1) ? 'book-label'.i18n() : 'books-label'.i18n(); + final bookTextQuantity = (booksQuantity == 1) + ? 'book-label'.i18n() + : 'books-label'.i18n(); return Column( crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/src/features/bookcase_detail/widgets/bookcase_detail_loaded_state_widget/bookcase_detail_loaded_state_widget.dart b/lib/src/features/bookcase_detail/widgets/bookcase_detail_loaded_state_widget/bookcase_detail_loaded_state_widget.dart index 232ea90a..5612f97d 100644 --- a/lib/src/features/bookcase_detail/widgets/bookcase_detail_loaded_state_widget/bookcase_detail_loaded_state_widget.dart +++ b/lib/src/features/bookcase_detail/widgets/bookcase_detail_loaded_state_widget/bookcase_detail_loaded_state_widget.dart @@ -40,14 +40,16 @@ class _BookcaseDetailLoadedStateWidgetState } Future _normalOnTap(BuildContext context, BookModel book) async { - final bookIsChanged = await Navigator.pushNamed( - context, - BookOnBookcaseDetailPage.routeName, - arguments: [ - book, - widget.bookcaseId, - ], - ) as bool?; + final bookIsChanged = + await Navigator.pushNamed( + context, + BookOnBookcaseDetailPage.routeName, + arguments: [ + book, + widget.bookcaseId, + ], + ) + as bool?; if (bookIsChanged != null && bookIsChanged) { widget.refreshPage(); diff --git a/lib/src/features/bookcase_detail/widgets/widgets.dart b/lib/src/features/bookcase_detail/widgets/widgets.dart index 2fd3b09c..deceb737 100644 --- a/lib/src/features/bookcase_detail/widgets/widgets.dart +++ b/lib/src/features/bookcase_detail/widgets/widgets.dart @@ -1,2 +1,2 @@ export 'bookcase_detail_loaded_state_widget/bookcase_detail_loaded_state_widget.dart'; -export 'bookcase_description_widget/bookcase_description_widget.dart'; \ No newline at end of file +export 'bookcase_description_widget/bookcase_description_widget.dart'; diff --git a/lib/src/features/bookcase_insertion/bloc/bookcase_insertion_bloc.dart b/lib/src/features/bookcase_insertion/bloc/bookcase_insertion_bloc.dart index bf593ba0..b4b9ee34 100644 --- a/lib/src/features/bookcase_insertion/bloc/bookcase_insertion_bloc.dart +++ b/lib/src/features/bookcase_insertion/bloc/bookcase_insertion_bloc.dart @@ -1,6 +1,7 @@ import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/models/bookcase_model.dart'; import 'package:bookify/src/core/services/bookcase_service/bookcase_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -31,23 +32,40 @@ class BookcaseInsertionBloc color: event.color, ); - final newBookcaseId = - await _bookcaseService.insertBookcase(bookcaseModel: bookcaseModel); + final newBookcaseId = await _bookcaseService.insertBookcase( + bookcaseModel: bookcaseModel, + ); if (newBookcaseId == 0) { - emit(BookcaseInsertionErrorState( - errorMessage: 'Ocorreu um erro ao inserir a estante')); + emit( + BookcaseInsertionErrorState( + errorCode: LocalDatabaseErrorCode.operationFailed, + errorDescriptionMessage: + 'An error occurred while inserting the bookcase', + ), + ); return; } - emit(BookcaseInsertionInsertedState( - bookcaseInsertionMessage: 'Estante inserida com sucesso')); + emit( + BookcaseInsertionInsertedState( + reason: BookcaseInsertionSuccessReason.inserted, + ), + ); } on LocalDatabaseException catch (e) { - emit(BookcaseInsertionErrorState( - errorMessage: 'Ocorreu um erro no database: ${e.message}')); + emit( + BookcaseInsertionErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { - emit(BookcaseInsertionErrorState( - errorMessage: 'Ocorreu um erro não esperado: $e')); + emit( + BookcaseInsertionErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } @@ -72,20 +90,33 @@ class BookcaseInsertionBloc if (bookcaseRowUpdated < 1) { emit( BookcaseInsertionErrorState( - errorMessage: 'Ocorreu um erro ao atualizar a estante', + errorCode: LocalDatabaseErrorCode.operationFailed, + errorDescriptionMessage: + 'An error occurred while updating the bookcase', ), ); return; } - emit(BookcaseInsertionInsertedState( - bookcaseInsertionMessage: 'Estante atualizada com sucesso')); + emit( + BookcaseInsertionInsertedState( + reason: BookcaseInsertionSuccessReason.updated, + ), + ); } on LocalDatabaseException catch (e) { - emit(BookcaseInsertionErrorState( - errorMessage: 'Ocorreu um erro no database: ${e.message}')); + emit( + BookcaseInsertionErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { - emit(BookcaseInsertionErrorState( - errorMessage: 'Ocorreu um erro não esperado: $e')); + emit( + BookcaseInsertionErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } } diff --git a/lib/src/features/bookcase_insertion/bloc/bookcase_insertion_state.dart b/lib/src/features/bookcase_insertion/bloc/bookcase_insertion_state.dart index 460c2396..abc3854a 100644 --- a/lib/src/features/bookcase_insertion/bloc/bookcase_insertion_state.dart +++ b/lib/src/features/bookcase_insertion/bloc/bookcase_insertion_state.dart @@ -1,20 +1,27 @@ part of 'bookcase_insertion_bloc.dart'; +enum BookcaseInsertionSuccessReason { + inserted, + updated, +} + @immutable sealed class BookcaseInsertionState {} final class BookcaseInsertionLoadingState extends BookcaseInsertionState {} final class BookcaseInsertionInsertedState extends BookcaseInsertionState { - final String bookcaseInsertionMessage; + final BookcaseInsertionSuccessReason reason; - BookcaseInsertionInsertedState({required this.bookcaseInsertionMessage}); + BookcaseInsertionInsertedState({required this.reason}); } final class BookcaseInsertionErrorState extends BookcaseInsertionState { - final String errorMessage; + final LocalDatabaseErrorCode errorCode; + final String? errorDescriptionMessage; BookcaseInsertionErrorState({ - required this.errorMessage, + required this.errorCode, + required this.errorDescriptionMessage, }); } diff --git a/lib/src/features/bookcase_insertion/views/bookcase_insertion_page.dart b/lib/src/features/bookcase_insertion/views/bookcase_insertion_page.dart index 491673b2..947907d8 100644 --- a/lib/src/features/bookcase_insertion/views/bookcase_insertion_page.dart +++ b/lib/src/features/bookcase_insertion/views/bookcase_insertion_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart'; import 'package:bookify/src/features/bookcase_insertion/bloc/bookcase_insertion_bloc.dart'; import 'package:bookify/src/core/helpers/textfield_unfocus/textfield_unfocus_extension.dart'; import 'package:bookify/src/core/models/bookcase_model.dart'; @@ -178,12 +179,15 @@ class _BookcaseInsertionPageState extends State { ); break; - case BookcaseInsertionInsertedState( - bookcaseInsertionMessage: final successMessage, - ): + case BookcaseInsertionInsertedState(:final reason): SnackbarService.showSnackBar( context, - successMessage, + switch (reason) { + BookcaseInsertionSuccessReason.inserted => + 'bookcase-inserted-success-snackbar'.i18n(), + BookcaseInsertionSuccessReason.updated => + 'bookcase-updated-success-snackbar'.i18n(), + }, SnackBarType.success, ); @@ -198,10 +202,13 @@ class _BookcaseInsertionPageState extends State { }, ); break; - case BookcaseInsertionErrorState(:final errorMessage): + case BookcaseInsertionErrorState( + :final errorCode, + :final errorDescriptionMessage, + ): SnackbarService.showSnackBar( context, - errorMessage, + errorCode.toLocalizedMessage(errorDescriptionMessage), SnackBarType.error, ); diff --git a/lib/src/features/bookcase_tab_view/views/pages/pages.dart b/lib/src/features/bookcase_tab_view/views/pages/pages.dart index 0f3b3c11..e4b9fda4 100644 --- a/lib/src/features/bookcase_tab_view/views/pages/pages.dart +++ b/lib/src/features/bookcase_tab_view/views/pages/pages.dart @@ -1,3 +1,3 @@ export 'package:bookify/src/features/bookcase/views/bookcase_page.dart'; export 'package:bookify/src/features/loan/views/loan_page.dart'; -export 'package:bookify/src/features/my_books/views/my_books_page.dart'; \ No newline at end of file +export 'package:bookify/src/features/my_books/views/my_books_page.dart'; diff --git a/lib/src/features/books_picker/views/books_picker_page.dart b/lib/src/features/books_picker/views/books_picker_page.dart index f2502dcd..fedd4bf6 100644 --- a/lib/src/features/books_picker/views/books_picker_page.dart +++ b/lib/src/features/books_picker/views/books_picker_page.dart @@ -79,7 +79,7 @@ class _BooksPickerPageState extends State { }, ), ), - ) + ), ], ), body: !isSelectionBook diff --git a/lib/src/features/books_picker/views/widgets/book_on_bookcase_picker/bloc/book_on_bookcase_picker_bloc.dart b/lib/src/features/books_picker/views/widgets/book_on_bookcase_picker/bloc/book_on_bookcase_picker_bloc.dart index 71310d8f..1f28ddb2 100644 --- a/lib/src/features/books_picker/views/widgets/book_on_bookcase_picker/bloc/book_on_bookcase_picker_bloc.dart +++ b/lib/src/features/books_picker/views/widgets/book_on_bookcase_picker/bloc/book_on_bookcase_picker_bloc.dart @@ -2,6 +2,7 @@ import 'package:bookify/src/core/errors/local_database_exception/local_database_ import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/bookcase_service/bookcase_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'book_on_bookcase_picker_event.dart'; @@ -55,12 +56,16 @@ class BookOnBookcasePickerBloc } on LocalDatabaseException catch (e) { emit( BookOnBookcasePickerErrorState( - errorMessage: 'Erro no database: ${e.message}'), + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), ); } catch (e) { emit( BookOnBookcasePickerErrorState( - errorMessage: 'Ocorreu um erro não esperado: $e'), + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), ); } } diff --git a/lib/src/features/books_picker/views/widgets/book_on_bookcase_picker/bloc/book_on_bookcase_picker_state.dart b/lib/src/features/books_picker/views/widgets/book_on_bookcase_picker/bloc/book_on_bookcase_picker_state.dart index 9e0ee6f5..6f0fa56c 100644 --- a/lib/src/features/books_picker/views/widgets/book_on_bookcase_picker/bloc/book_on_bookcase_picker_state.dart +++ b/lib/src/features/books_picker/views/widgets/book_on_bookcase_picker/bloc/book_on_bookcase_picker_state.dart @@ -16,9 +16,11 @@ final class BookOnBookcasePickerLoadedState extends BookOnBookcasePickerState { } final class BookOnBookcasePickerErrorState extends BookOnBookcasePickerState { - final String errorMessage; + final LocalDatabaseErrorCode errorCode; + final String? errorDescriptionMessage; BookOnBookcasePickerErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/books_picker/views/widgets/book_on_bookcase_picker/views/book_on_bookcase_widget.dart b/lib/src/features/books_picker/views/widgets/book_on_bookcase_picker/views/book_on_bookcase_widget.dart index 738b6006..96038346 100644 --- a/lib/src/features/books_picker/views/widgets/book_on_bookcase_picker/views/book_on_bookcase_widget.dart +++ b/lib/src/features/books_picker/views/widgets/book_on_bookcase_picker/views/book_on_bookcase_widget.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart'; import 'package:bookify/src/features/books_picker/views/widgets/book_on_bookcase_picker/bloc/book_on_bookcase_picker_bloc.dart'; import 'package:bookify/src/features/books_picker/views/widgets/book_selector_widget/book_selector_widget.dart'; import 'package:bookify/src/shared/widgets/center_circular_progress_indicator/center_circular_progress_indicator.dart'; @@ -41,23 +42,28 @@ class _BookOnBookcaseWidgetState extends State { } Widget _getWidgetOnBookOnBookcasePickerState( - BuildContext context, BookOnBookcasePickerState state) { + BuildContext context, + BookOnBookcasePickerState state, + ) { return switch (state) { BookOnBookcasePickerLoadingState() => const CenterCircularProgressIndicator(), BookOnBookcasePickerEmptyState() => Center( - child: Text( - 'empty-bookcase-or-not-contains-books-message'.i18n(), - textAlign: TextAlign.center, - ), + child: Text( + 'empty-bookcase-or-not-contains-books-message'.i18n(), + textAlign: TextAlign.center, ), + ), BookOnBookcasePickerLoadedState(:final books) => BookSelectorWidget( - books: books, - onSelectBook: (book) => Navigator.pop(context, book), - ), - BookOnBookcasePickerErrorState(:final errorMessage) => + books: books, + onSelectBook: (book) => Navigator.pop(context, book), + ), + BookOnBookcasePickerErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => InfoItemStateWidget.withErrorState( - message: errorMessage, + message: errorCode.toLocalizedMessage(errorDescriptionMessage), onPressed: _refreshPage, ), }; diff --git a/lib/src/features/books_picker/views/widgets/book_selector_widget/book_selector_widget.dart b/lib/src/features/books_picker/views/widgets/book_selector_widget/book_selector_widget.dart index 7fac5587..79e37308 100644 --- a/lib/src/features/books_picker/views/widgets/book_selector_widget/book_selector_widget.dart +++ b/lib/src/features/books_picker/views/widgets/book_selector_widget/book_selector_widget.dart @@ -68,54 +68,57 @@ class _BookSelectorWidgetState extends State { Expanded( child: GestureDetector( onTap: () => selectedBook != null ? _clearData() : null, - child: LayoutBuilder(builder: (context, constraints) { - return GridView.builder( - keyboardDismissBehavior: - ScrollViewKeyboardDismissBehavior.onDrag, - itemCount: widget.books.length, - gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( - childAspectRatio: .7, - crossAxisCount: constraints.maxWidth > 500 ? 6 : 3, - ), - itemBuilder: (context, index) { - return Padding( - padding: const EdgeInsets.all(4.0), - child: Tooltip( - message: widget.books[index].title, - child: Material( - child: InkWell( - splashColor: Colors.transparent, - onTap: () => - _clickOnBook(widget.books[index], index), - child: (selectedBook == widget.books[index]) - ? Container( - decoration: BoxDecoration( - color: colorScheme.secondary, - border: Border.all( - color: Colors.transparent, + child: LayoutBuilder( + builder: (context, constraints) { + return GridView.builder( + keyboardDismissBehavior: + ScrollViewKeyboardDismissBehavior.onDrag, + itemCount: widget.books.length, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + childAspectRatio: .7, + crossAxisCount: constraints.maxWidth > 500 ? 6 : 3, + ), + itemBuilder: (context, index) { + return Padding( + padding: const EdgeInsets.all(4.0), + child: Tooltip( + message: widget.books[index].title, + child: Material( + child: InkWell( + splashColor: Colors.transparent, + onTap: () => + _clickOnBook(widget.books[index], index), + child: (selectedBook == widget.books[index]) + ? Container( + decoration: BoxDecoration( + color: colorScheme.secondary, + border: Border.all( + color: Colors.transparent, + ), + borderRadius: const BorderRadius.all( + Radius.circular(15), + ), ), - borderRadius: const BorderRadius.all( - Radius.circular(15), + padding: const EdgeInsets.all(4.0), + child: BookWidget( + key: const Key('SelectedBookWidget'), + bookImageUrl: + widget.books[index].imageUrl, ), - ), - padding: const EdgeInsets.all(4.0), - child: BookWidget( - key: const Key('SelectedBookWidget'), + ) + : BookWidget( + key: const Key('BookWidget'), bookImageUrl: widget.books[index].imageUrl, ), - ) - : BookWidget( - key: const Key('BookWidget'), - bookImageUrl: widget.books[index].imageUrl, - ), + ), ), ), - ), - ); - }, - ); - }), + ); + }, + ); + }, + ), ), ), ], diff --git a/lib/src/features/books_picker/views/widgets/bookcase_picker/bloc/bookcase_picker_bloc.dart b/lib/src/features/books_picker/views/widgets/bookcase_picker/bloc/bookcase_picker_bloc.dart index e6f818b9..61cf4fd4 100644 --- a/lib/src/features/books_picker/views/widgets/bookcase_picker/bloc/bookcase_picker_bloc.dart +++ b/lib/src/features/books_picker/views/widgets/bookcase_picker/bloc/bookcase_picker_bloc.dart @@ -3,6 +3,7 @@ import 'package:bookify/src/core/errors/local_database_exception/local_database_ import 'package:bookify/src/core/models/bookcase_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/bookcase_service/bookcase_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'bookcase_picker_event.dart'; @@ -42,7 +43,9 @@ class BookcasePickerBloc if (bookcaseId == null) { emit( BookcasePickerErrorState( - errorMessage: 'Erro inesperado: ${bookcase.id}'), + errorCode: LocalDatabaseErrorCode.conversionFailed, + errorDescriptionMessage: 'Error: Bookcase not found', + ), ); return; } @@ -72,10 +75,19 @@ class BookcasePickerBloc emit(BookcasePickerLoadedState(bookcasesDto: bookcasesDto)); } on LocalDatabaseException catch (e) { - emit(BookcasePickerErrorState( - errorMessage: 'Erro no database: ${e.message}')); + emit( + BookcasePickerErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { - emit(BookcasePickerErrorState(errorMessage: 'Erro inesperado: $e')); + emit( + BookcasePickerErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } } diff --git a/lib/src/features/books_picker/views/widgets/bookcase_picker/bloc/bookcase_picker_state.dart b/lib/src/features/books_picker/views/widgets/bookcase_picker/bloc/bookcase_picker_state.dart index 970ab5d0..ab2a1f7c 100644 --- a/lib/src/features/books_picker/views/widgets/bookcase_picker/bloc/bookcase_picker_state.dart +++ b/lib/src/features/books_picker/views/widgets/bookcase_picker/bloc/bookcase_picker_state.dart @@ -7,14 +7,17 @@ final class BookcasePickerLoadingState extends BookcasePickerState {} final class BookcasePickerEmptyState extends BookcasePickerState {} final class BookcasePickerLoadedState extends BookcasePickerState { - final List bookcasesDto; + final List bookcasesDto; BookcasePickerLoadedState({required this.bookcasesDto}); - } final class BookcasePickerErrorState extends BookcasePickerState { - final String errorMessage; + final LocalDatabaseErrorCode errorCode; + final String? errorDescriptionMessage; - BookcasePickerErrorState({required this.errorMessage}); + BookcasePickerErrorState({ + required this.errorCode, + this.errorDescriptionMessage, + }); } diff --git a/lib/src/features/books_picker/views/widgets/bookcase_picker/views/bookcase_picker_widget.dart b/lib/src/features/books_picker/views/widgets/bookcase_picker/views/bookcase_picker_widget.dart index 90ebfe89..5c8f122c 100644 --- a/lib/src/features/books_picker/views/widgets/bookcase_picker/views/bookcase_picker_widget.dart +++ b/lib/src/features/books_picker/views/widgets/bookcase_picker/views/bookcase_picker_widget.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart'; import 'package:bookify/src/features/books_picker/views/widgets/bookcase_picker/bloc/bookcase_picker_bloc.dart'; import 'package:bookify/src/features/books_picker/views/widgets/bookcase_picker/views/widgets/bookcase_picker_loaded_state_widget/bookcase_picker_loaded_state_widget.dart'; import 'package:bookify/src/core/models/book_model.dart'; @@ -34,23 +35,28 @@ class _BookcasePickerWidgetState extends State { } Widget _getWidgetOnBookcasePickerState( - BuildContext context, BookcasePickerState state) { + BuildContext context, + BookcasePickerState state, + ) { return switch (state) { BookcasePickerLoadingState() => const CenterCircularProgressIndicator(), BookcasePickerEmptyState() => Center( - child: Text( - 'no-bookcases-to-add-message'.i18n(), - textAlign: TextAlign.center, - ), + child: Text( + 'no-bookcases-to-add-message'.i18n(), + textAlign: TextAlign.center, ), + ), BookcasePickerLoadedState(:final bookcasesDto) => BookcasePickerLoadedStateWidget( bookcasesDto: bookcasesDto, onSelectBookModel: widget.onSelectBookModel, ), - BookcasePickerErrorState(:final errorMessage) => + BookcasePickerErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => InfoItemStateWidget.withErrorState( - message: errorMessage, + message: errorCode.toLocalizedMessage(errorDescriptionMessage), onPressed: _refreshPage, ), }; diff --git a/lib/src/features/books_picker/views/widgets/bookcase_picker/views/widgets/bookcase_picker_loaded_state_widget/bookcase_picker_loaded_state_widget.dart b/lib/src/features/books_picker/views/widgets/bookcase_picker/views/widgets/bookcase_picker_loaded_state_widget/bookcase_picker_loaded_state_widget.dart index efc81d10..896cfb8c 100644 --- a/lib/src/features/books_picker/views/widgets/bookcase_picker/views/widgets/bookcase_picker_loaded_state_widget/bookcase_picker_loaded_state_widget.dart +++ b/lib/src/features/books_picker/views/widgets/bookcase_picker/views/widgets/bookcase_picker_loaded_state_widget/bookcase_picker_loaded_state_widget.dart @@ -26,20 +26,22 @@ class BookcasePickerLoadedStateWidget extends StatelessWidget { return BookcaseWidget( bookcaseDto: bookcasesDto[index], onTap: () async { - final book = await showModalBottomSheet( - context: context, - constraints: BoxConstraints.loose( - Size( - MediaQuery.of(context).size.width, - MediaQuery.of(context).size.height * 0.75, - ), - ), - isScrollControlled: true, - showDragHandle: true, - builder: (context) => BookOnBookcaseWidget( - bookcaseId: bookcasesDto[index].bookcase.id!, - ), - ) as BookModel?; + final book = + await showModalBottomSheet( + context: context, + constraints: BoxConstraints.loose( + Size( + MediaQuery.of(context).size.width, + MediaQuery.of(context).size.height * 0.75, + ), + ), + isScrollControlled: true, + showDragHandle: true, + builder: (context) => BookOnBookcaseWidget( + bookcaseId: bookcasesDto[index].bookcase.id!, + ), + ) + as BookModel?; if (book != null) { onSelectBookModel(book); diff --git a/lib/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_bloc.dart b/lib/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_bloc.dart index 2e8028db..94edad19 100644 --- a/lib/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_bloc.dart +++ b/lib/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_bloc.dart @@ -1,6 +1,7 @@ import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'separate_books_picker_event.dart'; @@ -11,13 +12,14 @@ class SeparateBooksPickerBloc final BookService _bookService; SeparateBooksPickerBloc(this._bookService) - : super(SeparateBooksPickerLoadingState()) { + : super(SeparateBooksPickerLoadingState()) { on(_gotAllSeparatedBooksPickerEvent); } Future _gotAllSeparatedBooksPickerEvent( - GotAllSeparatedBooksPickerEvent event, - Emitter emit) async { + GotAllSeparatedBooksPickerEvent event, + Emitter emit, + ) async { try { emit(SeparateBooksPickerLoadingState()); @@ -28,8 +30,9 @@ class SeparateBooksPickerBloc return; } - final bookForPicker = - books.where((book) => book.status == BookStatus.library).toList(); + final bookForPicker = books + .where((book) => book.status == BookStatus.library) + .toList(); if (bookForPicker.isEmpty) { emit(SeparateBooksPickerEmptyState()); @@ -38,10 +41,19 @@ class SeparateBooksPickerBloc emit(SeparateBooksPickerLoadedState(books: bookForPicker)); } on LocalDatabaseException catch (e) { - emit(SeparateBooksPickerErrorState( - errorMessage: 'Erro no database: ${e.message}')); + emit( + SeparateBooksPickerErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { - emit(SeparateBooksPickerErrorState(errorMessage: 'Erro inesperado: $e')); + emit( + SeparateBooksPickerErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } } diff --git a/lib/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_event.dart b/lib/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_event.dart index 81257fdd..b4a40631 100644 --- a/lib/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_event.dart +++ b/lib/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_event.dart @@ -2,4 +2,4 @@ part of 'separate_books_picker_bloc.dart'; sealed class SeparateBooksPickerEvent {} -final class GotAllSeparatedBooksPickerEvent extends SeparateBooksPickerEvent{} +final class GotAllSeparatedBooksPickerEvent extends SeparateBooksPickerEvent {} diff --git a/lib/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_state.dart b/lib/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_state.dart index 0e5cc02c..dfc9dc6f 100644 --- a/lib/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_state.dart +++ b/lib/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_state.dart @@ -15,9 +15,11 @@ final class SeparateBooksPickerLoadedState extends SeparateBooksPickerState { } final class SeparateBooksPickerErrorState extends SeparateBooksPickerState { - final String errorMessage; + final LocalDatabaseErrorCode errorCode; + final String? errorDescriptionMessage; SeparateBooksPickerErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/books_picker/views/widgets/separate_books_picker/views/separate_books_picker_widget.dart b/lib/src/features/books_picker/views/widgets/separate_books_picker/views/separate_books_picker_widget.dart index c6a64e39..02e60588 100644 --- a/lib/src/features/books_picker/views/widgets/separate_books_picker/views/separate_books_picker_widget.dart +++ b/lib/src/features/books_picker/views/widgets/separate_books_picker/views/separate_books_picker_widget.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart'; import 'package:bookify/src/features/books_picker/views/widgets/book_selector_widget/book_selector_widget.dart'; import 'package:bookify/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_bloc.dart'; import 'package:bookify/src/core/models/book_model.dart'; @@ -37,27 +38,32 @@ class _SeparateBooksPickerWidgetState extends State { } Widget _getWidgetOnBookcasePickerState( - BuildContext context, SeparateBooksPickerState state) { + BuildContext context, + SeparateBooksPickerState state, + ) { return switch (state) { SeparateBooksPickerLoadingState() => const CenterCircularProgressIndicator(), SeparateBooksPickerEmptyState() => Center( - child: Padding( - padding: EdgeInsets.all(8.0), - child: Text( - 'no-books-to-add-message'.i18n(), - textAlign: TextAlign.center, - ), + child: Padding( + padding: EdgeInsets.all(8.0), + child: Text( + 'no-books-to-add-message'.i18n(), + textAlign: TextAlign.center, ), ), + ), SeparateBooksPickerLoadedState(:final books) => BookSelectorWidget( - key: const Key('BookSelectorWidget'), - books: books, - onSelectBook: (book) => Navigator.pop(context, book), - ), - SeparateBooksPickerErrorState(:final errorMessage) => + key: const Key('BookSelectorWidget'), + books: books, + onSelectBook: (book) => Navigator.pop(context, book), + ), + SeparateBooksPickerErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => InfoItemStateWidget.withErrorState( - message: errorMessage, + message: errorCode.toLocalizedMessage(errorDescriptionMessage), onPressed: _refreshPage, ), }; diff --git a/lib/src/features/contacts_picker/bloc/contacts_picker_bloc.dart b/lib/src/features/contacts_picker/bloc/contacts_picker_bloc.dart index b3261d22..0ba01f39 100644 --- a/lib/src/features/contacts_picker/bloc/contacts_picker_bloc.dart +++ b/lib/src/features/contacts_picker/bloc/contacts_picker_bloc.dart @@ -1,5 +1,7 @@ +import 'package:bookify/src/core/errors/platform_exception/platform_exception.dart'; import 'package:bookify/src/core/models/contact_model.dart'; import 'package:bookify/src/core/services/app_services/contacts_service/contacts_service.dart'; +import 'package:bookify/src/shared/enums/platform_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'contacts_picker_event.dart'; @@ -10,7 +12,7 @@ class ContactsPickerBloc final ContactsService _contactsService; ContactsPickerBloc(this._contactsService) - : super(ContactsPickerLoadingState()) { + : super(ContactsPickerLoadingState()) { on(_gotContactsPicker); } @@ -26,25 +28,24 @@ class ContactsPickerBloc (a, b) => a.name.compareTo(b.name), ); - if (contacts == null) { - emit( - ContactsPickerErrorState( - errorMessage: 'Aconteceu um problema ao carregar os contatos.', - ), - ); - return; - } - - if (contacts.isEmpty) { + if (contacts == null || contacts.isEmpty) { emit(ContactsPickerEmptyState()); return; } emit(ContactsPickerLoadedState(contacts: contacts)); - } catch (e) { + } on PlatformException catch (e) { + emit( + ContactsPickerErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); + } on Exception catch (e) { emit( ContactsPickerErrorState( - errorMessage: 'Erro inesperado: $e', + errorCode: PlatformErrorCode.unknown, + errorDescriptionMessage: e.toString(), ), ); } diff --git a/lib/src/features/contacts_picker/bloc/contacts_picker_state.dart b/lib/src/features/contacts_picker/bloc/contacts_picker_state.dart index b21dd75d..7cdc4e39 100644 --- a/lib/src/features/contacts_picker/bloc/contacts_picker_state.dart +++ b/lib/src/features/contacts_picker/bloc/contacts_picker_state.dart @@ -15,9 +15,11 @@ final class ContactsPickerLoadedState extends ContactsPickerState { } final class ContactsPickerErrorState extends ContactsPickerState { - final String errorMessage; + final PlatformErrorCode errorCode; + final String? errorDescriptionMessage; ContactsPickerErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/contacts_picker/views/contacts_picker_page.dart b/lib/src/features/contacts_picker/views/contacts_picker_page.dart index d8bd3249..275e45af 100644 --- a/lib/src/features/contacts_picker/views/contacts_picker_page.dart +++ b/lib/src/features/contacts_picker/views/contacts_picker_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/platform_error_code/platform_error_code_extension.dart'; import 'package:bookify/src/features/contacts_picker/bloc/contacts_picker_bloc.dart'; import 'package:bookify/src/features/contacts_picker/views/widgets/contacts_picker_loaded_state_widget.dart'; import 'package:bookify/src/shared/widgets/center_circular_progress_indicator/center_circular_progress_indicator.dart'; @@ -36,20 +37,24 @@ class _ContactsPickerPageState extends State { return switch (state) { ContactsPickerLoadingState() => const CenterCircularProgressIndicator(), ContactsPickerEmptyState() => Center( - child: InfoItemStateWidget.withNotFoundState( - message: 'no-contacts-found'.i18n(), - onPressed: _onRefresh, - ), + child: InfoItemStateWidget.withNotFoundState( + message: 'no-contacts-found'.i18n(), + onPressed: _onRefresh, ), + ), ContactsPickerLoadedState(:final contacts) => ContactsPickerLoadedStateWidget( key: const Key('ContactsPickerLoadedStateWidget'), contacts: contacts, onSelectedContact: (contactDto) => Navigator.pop(context, contactDto), ), - ContactsPickerErrorState(:final errorMessage) => Center( + ContactsPickerErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => + Center( child: InfoItemStateWidget.withErrorState( - message: errorMessage, + message: errorCode.toLocalizedMessage(errorDescriptionMessage), onPressed: _onRefresh, ), ), diff --git a/lib/src/features/contacts_picker/views/widgets/widgets.dart b/lib/src/features/contacts_picker/views/widgets/widgets.dart index 4d86ba94..2454c855 100644 --- a/lib/src/features/contacts_picker/views/widgets/widgets.dart +++ b/lib/src/features/contacts_picker/views/widgets/widgets.dart @@ -1,2 +1,2 @@ export 'package:bookify/src/features/contacts_picker/views/widgets/contact_selected_row.dart'; -export 'package:bookify/src/features/contacts_picker/views/widgets/contact_widget.dart'; \ No newline at end of file +export 'package:bookify/src/features/contacts_picker/views/widgets/contact_widget.dart'; diff --git a/lib/src/features/home/views/home_page.dart b/lib/src/features/home/views/home_page.dart index 9b73985a..d89684c5 100644 --- a/lib/src/features/home/views/home_page.dart +++ b/lib/src/features/home/views/home_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/rest_client_error_code/rest_client_error_code_extension.dart'; import 'package:bookify/src/shared/blocs/book_bloc/book_bloc.dart'; import 'package:bookify/src/shared/widgets/center_circular_progress_indicator/center_circular_progress_indicator.dart'; import 'package:bookify/src/shared/widgets/item_state_widget/info_item_state_widget/info_item_state_widget.dart'; @@ -21,13 +22,9 @@ class _HomePageState extends State { @override void initState() { super.initState(); + _bookBloc = context.read()..add(GotAllBooksEvent()); _searchEC = TextEditingController(); _isSearchBarVisible = false; - _bookBloc = context.read(); - - WidgetsBinding.instance.addPostFrameCallback((_) { - _bookBloc.add(GotAllBooksEvent()); - }); } @override @@ -44,23 +41,27 @@ class _HomePageState extends State { Widget _getBookStateWidget(BuildContext context, BookState state) { return switch (state) { BooksLoadingState() => const CenterCircularProgressIndicator( - key: Key('BooksLoadingStateWidget'), - ), + key: Key('BooksLoadingStateWidget'), + ), BookEmptyState() => Center( - key: const Key('BookEmptyStateWidget'), - child: InfoItemStateWidget.withNotFoundState( - message: 'no-books-found-with-terms'.i18n(), - onPressed: _refreshPage, - ), + key: const Key('BookEmptyStateWidget'), + child: InfoItemStateWidget.withNotFoundState( + message: 'no-books-found-with-terms'.i18n(), + onPressed: _refreshPage, ), + ), BooksLoadedState(:final books) => BooksLoadedStateWidget( - key: const Key('BooksLoadedStateWidget'), - books: books, - ), - BookErrorSate(errorMessage: final message) => Center( + key: const Key('BooksLoadedStateWidget'), + books: books, + ), + BookErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => + Center( key: const Key('BookErrorSateWidget'), child: InfoItemStateWidget.withErrorState( - message: message, + message: errorCode.toLocalizedMessage(errorDescriptionMessage), onPressed: _refreshPage, ), ), diff --git a/lib/src/features/home/widgets/animated_search_bar/animated_search_bar.dart b/lib/src/features/home/widgets/animated_search_bar/animated_search_bar.dart index 0fd843bf..ce955050 100644 --- a/lib/src/features/home/widgets/animated_search_bar/animated_search_bar.dart +++ b/lib/src/features/home/widgets/animated_search_bar/animated_search_bar.dart @@ -2,13 +2,7 @@ import 'package:bookify/src/shared/constants/icons/bookify_icons.dart'; import 'package:flutter/material.dart'; import 'package:localization/localization.dart'; -enum SearchType { - title, - author, - category, - publisher, - isbn; -} +enum SearchType { title, author, category, publisher, isbn } class AnimatedSearchBar extends StatefulWidget { final TextEditingController searchEC; @@ -37,11 +31,11 @@ class _AnimatedSearchBarState extends State { SearchType.title => {'enter-title-label'.i18n(): Icons.menu_book_rounded}, SearchType.author => {'enter-author-label'.i18n(): Icons.person_rounded}, SearchType.category => { - 'enter-category-label'.i18n(): Icons.category_rounded - }, + 'enter-category-label'.i18n(): Icons.category_rounded, + }, SearchType.publisher => { - 'enter-publisher-label'.i18n(): Icons.publish_rounded - }, + 'enter-publisher-label'.i18n(): Icons.publish_rounded, + }, SearchType.isbn => {'enter-isbn-label'.i18n(): BookifyIcons.isbn}, }; diff --git a/lib/src/features/home/widgets/book_loaded_state_widget/books_loaded_state_widget.dart b/lib/src/features/home/widgets/book_loaded_state_widget/books_loaded_state_widget.dart index 91e4836b..25b704c6 100644 --- a/lib/src/features/home/widgets/book_loaded_state_widget/books_loaded_state_widget.dart +++ b/lib/src/features/home/widgets/book_loaded_state_widget/books_loaded_state_widget.dart @@ -15,7 +15,11 @@ class BooksLoadedStateWidget extends StatelessWidget { Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.only( - top: 8.0, right: 16.0, left: 16.0, bottom: 16.0), + top: 8.0, + right: 16.0, + left: 16.0, + bottom: 16.0, + ), child: BooksGridView( key: const Key('BooksGridView'), books: books, diff --git a/lib/src/features/home/widgets/widgets.dart b/lib/src/features/home/widgets/widgets.dart index a1357b65..648a3aa8 100644 --- a/lib/src/features/home/widgets/widgets.dart +++ b/lib/src/features/home/widgets/widgets.dart @@ -1,2 +1,2 @@ export 'animated_search_bar/animated_search_bar.dart'; -export 'book_loaded_state_widget/books_loaded_state_widget.dart'; \ No newline at end of file +export 'book_loaded_state_widget/books_loaded_state_widget.dart'; diff --git a/lib/src/features/loan/bloc/loan_bloc.dart b/lib/src/features/loan/bloc/loan_bloc.dart index 57d70a38..668c2b28 100644 --- a/lib/src/features/loan/bloc/loan_bloc.dart +++ b/lib/src/features/loan/bloc/loan_bloc.dart @@ -1,9 +1,11 @@ import 'package:bookify/src/core/dtos/loan_dto.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; +import 'package:bookify/src/core/errors/platform_exception/platform_exception.dart'; import 'package:bookify/src/core/models/loan_model.dart'; import 'package:bookify/src/core/services/app_services/contacts_service/contacts_service.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/loan_services/loan_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'loan_event.dart'; @@ -39,9 +41,26 @@ class LoanBloc extends Bloc { await _mountLoanDto(loans, emit); } on LocalDatabaseException catch (e) { - emit(LoanErrorState(errorMessage: 'Erro no database: ${e.message}')); + emit( + LoanErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); + } on PlatformException catch (e) { + emit( + LoanErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { - emit(LoanErrorState(errorMessage: 'Erro inesperado: $e')); + emit( + LoanErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } @@ -63,9 +82,26 @@ class LoanBloc extends Bloc { await _mountLoanDto(loans, emit); } on LocalDatabaseException catch (e) { - emit(LoanErrorState(errorMessage: 'Erro no database: ${e.message}')); + emit( + LoanErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); + } on PlatformException catch (e) { + emit( + LoanErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { - emit(LoanErrorState(errorMessage: 'Erro inesperado: $e')); + emit( + LoanErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } @@ -78,7 +114,10 @@ class LoanBloc extends Bloc { for (LoanModel loan in loans) { if (loan.id == null) { emit( - LoanErrorState(errorMessage: 'Erro inesperado: ${loan.id}'), + LoanErrorState( + errorCode: LocalDatabaseErrorCode.conversionFailed, + errorDescriptionMessage: 'Error: Loan not found', + ), ); return; } diff --git a/lib/src/features/loan/bloc/loan_state.dart b/lib/src/features/loan/bloc/loan_state.dart index 1bc22d41..e7ff8235 100644 --- a/lib/src/features/loan/bloc/loan_state.dart +++ b/lib/src/features/loan/bloc/loan_state.dart @@ -15,7 +15,11 @@ final class LoanLoadedState extends LoanState { } final class LoanErrorState extends LoanState { - final String errorMessage; + final LocalDatabaseErrorCode errorCode; + final String? errorDescriptionMessage; - LoanErrorState({required this.errorMessage}); + LoanErrorState({ + required this.errorCode, + this.errorDescriptionMessage, + }); } diff --git a/lib/src/features/loan/views/loan_page.dart b/lib/src/features/loan/views/loan_page.dart index 57eeb970..738a7675 100644 --- a/lib/src/features/loan/views/loan_page.dart +++ b/lib/src/features/loan/views/loan_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart'; import 'package:bookify/src/features/loan/bloc/loan_bloc.dart'; import 'package:bookify/src/features/loan/widgets/loan_loaded_state_widget/loan_loaded_state_widget.dart'; import 'package:bookify/src/features/loan_insertion/views/loan_insertion_page.dart'; @@ -57,33 +58,39 @@ class _LoanPageState extends State { return switch (state) { LoanLoadingState() => const CenterCircularProgressIndicator(), LoanEmptyState() => Center( - child: ItemEmptyStateWidget( - key: const Key('LoanEmptyState'), - label: 'create-new-loan-button'.i18n(), - onTap: () async { - final loanInserted = await Navigator.pushNamed( - context, - LoanInsertionPage.routeName, - ) as bool?; + child: ItemEmptyStateWidget( + key: const Key('LoanEmptyState'), + label: 'create-new-loan-button'.i18n(), + onTap: () async { + final loanInserted = + await Navigator.pushNamed( + context, + LoanInsertionPage.routeName, + ) + as bool?; - if (loanInserted != null && loanInserted) { - _refreshPage(); - } - }, - ), + if (loanInserted != null && loanInserted) { + _refreshPage(); + } + }, ), + ), LoanLoadedState(:final loansDto) => LoanLoadedStateWidget( - key: const Key('LoanLoadedState'), - loansDto: loansDto, - refreshPage: _refreshPage, - ), + key: const Key('LoanLoadedState'), + loansDto: loansDto, + refreshPage: _refreshPage, + ), LoanNotFoundState() => InfoItemStateWidget.withNotFoundState( - message: 'no-loans-found-with-terms'.i18n(), - onPressed: _refreshPage, - ), - LoanErrorState(:final errorMessage) => Center( + message: 'no-loans-found-with-terms'.i18n(), + onPressed: _refreshPage, + ), + LoanErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => + Center( child: InfoItemStateWidget.withErrorState( - message: errorMessage, + message: errorCode.toLocalizedMessage(errorDescriptionMessage), onPressed: _refreshPage, ), ), diff --git a/lib/src/features/loan/widgets/loan_loaded_state_widget/loan_loaded_state_widget.dart b/lib/src/features/loan/widgets/loan_loaded_state_widget/loan_loaded_state_widget.dart index 9cf05c75..eb64b557 100644 --- a/lib/src/features/loan/widgets/loan_loaded_state_widget/loan_loaded_state_widget.dart +++ b/lib/src/features/loan/widgets/loan_loaded_state_widget/loan_loaded_state_widget.dart @@ -25,10 +25,12 @@ class LoanLoadedStateWidget extends StatelessWidget { child: AddNewItemTextButton( label: 'loan-book-label'.i18n(), onPressed: () async { - final loanInserted = await Navigator.pushNamed( - context, - LoanInsertionPage.routeName, - ) as bool?; + final loanInserted = + await Navigator.pushNamed( + context, + LoanInsertionPage.routeName, + ) + as bool?; if (loanInserted != null && loanInserted) { refreshPage(); @@ -49,11 +51,13 @@ class LoanLoadedStateWidget extends StatelessWidget { key: const Key('LoanWidget'), loan: loansDto[index], onTap: () async { - final loanChanged = await Navigator.pushNamed( - context, - LoanDetailPage.routeName, - arguments: loansDto[index].loanModel.id!, - ) as bool?; + final loanChanged = + await Navigator.pushNamed( + context, + LoanDetailPage.routeName, + arguments: loansDto[index].loanModel.id!, + ) + as bool?; if (loanChanged != null && loanChanged) { refreshPage(); diff --git a/lib/src/features/loan/widgets/loan_widget/loan_widget.dart b/lib/src/features/loan/widgets/loan_widget/loan_widget.dart index 4a7fdc66..64cf01db 100644 --- a/lib/src/features/loan/widgets/loan_widget/loan_widget.dart +++ b/lib/src/features/loan/widgets/loan_widget/loan_widget.dart @@ -78,7 +78,8 @@ class LoanWidget extends StatelessWidget { top: -3, right: -3, child: ContactCircleAvatar( - name: loan.contactModel?.name ?? + name: + loan.contactModel?.name ?? 'no-name-label'.i18n(), photo: loan.contactModel?.photo, ), @@ -114,13 +115,15 @@ class LoanWidget extends StatelessWidget { ContactInformationWidget( iconData: Icons.person_outlined, title: 'name-label'.i18n(), - content: loan.contactModel?.name ?? + content: + loan.contactModel?.name ?? 'no-name-label'.i18n(), ), ContactInformationWidget( iconData: Icons.smartphone_outlined, title: 'contact-label'.i18n(), - content: loan.contactModel?.phoneNumber ?? + content: + loan.contactModel?.phoneNumber ?? 'no-contact-number-label'.i18n(), ), ], @@ -137,8 +140,8 @@ class LoanWidget extends StatelessWidget { ContactInformationWidget( iconData: Icons.calendar_month_outlined, title: 'loan-label'.i18n(), - content: - loan.loanModel.loanDate.toFormattedDate(), + content: loan.loanModel.loanDate + .toFormattedDate(), ), ContactInformationWidget( iconData: Icons.calendar_month_outlined, diff --git a/lib/src/features/loan_detail/bloc/loan_detail_bloc.dart b/lib/src/features/loan_detail/bloc/loan_detail_bloc.dart index 87ff081f..e4b4947c 100644 --- a/lib/src/features/loan_detail/bloc/loan_detail_bloc.dart +++ b/lib/src/features/loan_detail/bloc/loan_detail_bloc.dart @@ -1,10 +1,12 @@ import 'package:bookify/src/core/dtos/loan_dto.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; +import 'package:bookify/src/core/errors/platform_exception/platform_exception.dart'; import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/services/app_services/contacts_service/contacts_service.dart'; import 'package:bookify/src/core/services/app_services/notifications_service/notifications_service.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/loan_services/loan_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'loan_detail_event.dart'; @@ -51,11 +53,24 @@ class LoanDetailBloc extends Bloc { ); } on LocalDatabaseException catch (e) { emit( - LoanDetailErrorState(errorMessage: 'Erro no database: ${e.message}'), + LoanDetailErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); + } on PlatformException catch (e) { + emit( + LoanDetailErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.descriptionMessage, + ), ); } catch (e) { emit( - LoanDetailErrorState(errorMessage: 'Ocorreu um erro não esperado: $e'), + LoanDetailErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), ); } } @@ -69,12 +84,16 @@ class LoanDetailBloc extends Bloc { await _notificationsService.cancelNotificationById(id: event.loanId); final bookStatusUpdated = await _bookService.updateStatus( - id: event.bookId, status: BookStatus.library); + id: event.bookId, + status: BookStatus.library, + ); if (bookStatusUpdated != 1) { emit( LoanDetailErrorState( - errorMessage: 'Impossível remover o livro do empréstimo'), + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: 'Impossible to remove the book status', + ), ); return; } @@ -83,7 +102,10 @@ class LoanDetailBloc extends Bloc { if (loanRemovedRow != 1) { emit( - LoanDetailErrorState(errorMessage: 'Impossível remover o empréstimo'), + LoanDetailErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: 'Impossible to remove the loan', + ), ); return; } @@ -91,11 +113,24 @@ class LoanDetailBloc extends Bloc { emit(LoanDetailFinishedState()); } on LocalDatabaseException catch (e) { emit( - LoanDetailErrorState(errorMessage: 'Erro no database: ${e.message}'), + LoanDetailErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); + } on PlatformException catch (e) { + emit( + LoanDetailErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.descriptionMessage, + ), ); } catch (e) { emit( - LoanDetailErrorState(errorMessage: 'Ocorreu um erro não esperado: $e'), + LoanDetailErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), ); } } diff --git a/lib/src/features/loan_detail/bloc/loan_detail_state.dart b/lib/src/features/loan_detail/bloc/loan_detail_state.dart index 09d92892..aab1fae5 100644 --- a/lib/src/features/loan_detail/bloc/loan_detail_state.dart +++ b/lib/src/features/loan_detail/bloc/loan_detail_state.dart @@ -15,7 +15,11 @@ final class LoanDetailLoadedState extends LoanDetailState { final class LoanDetailFinishedState extends LoanDetailState {} final class LoanDetailErrorState extends LoanDetailState { - final String errorMessage; + final LocalDatabaseErrorCode errorCode; + final String? errorDescriptionMessage; - LoanDetailErrorState({required this.errorMessage}); + LoanDetailErrorState({ + required this.errorCode, + this.errorDescriptionMessage, + }); } diff --git a/lib/src/features/loan_detail/views/loan_detail_page.dart b/lib/src/features/loan_detail/views/loan_detail_page.dart index 176f14ac..2a08e039 100644 --- a/lib/src/features/loan_detail/views/loan_detail_page.dart +++ b/lib/src/features/loan_detail/views/loan_detail_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart'; import 'package:bookify/src/features/loan_detail/bloc/loan_detail_bloc.dart'; import 'package:bookify/src/features/loan_detail/views/widgets/loan_detail_loaded_widget.dart'; import 'package:bookify/src/core/services/app_services/show_dialog_service/show_dialog_service.dart'; @@ -46,31 +47,33 @@ class _LoanDetailPageState extends State { ) { return switch (state) { LoanDetailLoadingState() || - LoanDetailFinishedState() => - const CenterCircularProgressIndicator(), + LoanDetailFinishedState() => const CenterCircularProgressIndicator(), LoanDetailLoadedState(:final loanDto) => LoanDetailLoadedWidget( - key: const Key('LoanDetailLoadedState'), - loanDto: loanDto, - onPressedButton: () async { - await ShowDialogService.showAlertDialog( - context: context, - title: 'finish-loan-title'.i18n(), - content: 'finish-loan-description'.i18n(), - confirmButtonFunction: () { - _bloc.add( - FinishedLoanDetailEvent( - loanId: loanDto.loanModel.id!, - bookId: loanDto.loanModel.bookId, - ), - ); - Navigator.of(context).pop(); - }, - ); - }, - ), - LoanDetailErrorState(:final errorMessage) => + key: const Key('LoanDetailLoadedState'), + loanDto: loanDto, + onPressedButton: () async { + await ShowDialogService.showAlertDialog( + context: context, + title: 'finish-loan-title'.i18n(), + content: 'finish-loan-description'.i18n(), + confirmButtonFunction: () { + _bloc.add( + FinishedLoanDetailEvent( + loanId: loanDto.loanModel.id!, + bookId: loanDto.loanModel.bookId, + ), + ); + Navigator.of(context).pop(); + }, + ); + }, + ), + LoanDetailErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => InfoItemStateWidget.withErrorState( - message: errorMessage, + message: errorCode.toLocalizedMessage(errorDescriptionMessage), onPressed: _refreshPage, ), }; diff --git a/lib/src/features/loan_detail/views/widgets/book_card.dart b/lib/src/features/loan_detail/views/widgets/book_card.dart index 8187385f..b52b3650 100644 --- a/lib/src/features/loan_detail/views/widgets/book_card.dart +++ b/lib/src/features/loan_detail/views/widgets/book_card.dart @@ -81,7 +81,7 @@ class BookCard extends StatelessWidget { content: devolutionDate, ), ], - ) + ), ], ), ), diff --git a/lib/src/features/loan_detail/views/widgets/contact_card.dart b/lib/src/features/loan_detail/views/widgets/contact_card.dart index 03ef15e8..872550a5 100644 --- a/lib/src/features/loan_detail/views/widgets/contact_card.dart +++ b/lib/src/features/loan_detail/views/widgets/contact_card.dart @@ -68,7 +68,7 @@ class ContactCard extends StatelessWidget { ), ), ], - ) + ), ], ), ); diff --git a/lib/src/features/loan_detail/views/widgets/loan_detail_loaded_widget.dart b/lib/src/features/loan_detail/views/widgets/loan_detail_loaded_widget.dart index e6d96409..10d16318 100644 --- a/lib/src/features/loan_detail/views/widgets/loan_detail_loaded_widget.dart +++ b/lib/src/features/loan_detail/views/widgets/loan_detail_loaded_widget.dart @@ -52,8 +52,8 @@ class LoanDetailLoadedWidget extends StatelessWidget { bookTitle: loanDto.bookTitlePreview, observation: loanDto.loanModel.observation, loanDate: loanDto.loanModel.loanDate.toFormattedDate(), - devolutionDate: - loanDto.loanModel.devolutionDate.toFormattedDate(), + devolutionDate: loanDto.loanModel.devolutionDate + .toFormattedDate(), ), const SizedBox( height: 20, diff --git a/lib/src/features/loan_detail/views/widgets/loan_is_late_widget.dart b/lib/src/features/loan_detail/views/widgets/loan_is_late_widget.dart index ef6c0b7d..5aec4527 100644 --- a/lib/src/features/loan_detail/views/widgets/loan_is_late_widget.dart +++ b/lib/src/features/loan_detail/views/widgets/loan_is_late_widget.dart @@ -31,7 +31,7 @@ class LoanIsLateWidget extends StatelessWidget { fontSize: 12, fontWeight: FontWeight.bold, ), - ) + ), ], ), ); diff --git a/lib/src/features/loan_insertion/bloc/loan_insertion_bloc.dart b/lib/src/features/loan_insertion/bloc/loan_insertion_bloc.dart index 75171cbf..4dc898be 100644 --- a/lib/src/features/loan_insertion/bloc/loan_insertion_bloc.dart +++ b/lib/src/features/loan_insertion/bloc/loan_insertion_bloc.dart @@ -1,11 +1,12 @@ import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; -import 'package:bookify/src/core/helpers/date_time_format/date_time_format_extension.dart'; +import 'package:bookify/src/core/errors/platform_exception/platform_exception.dart'; import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/models/loan_model.dart'; import 'package:bookify/src/core/models/custom_notification_model.dart'; import 'package:bookify/src/core/services/app_services/notifications_service/notifications_service.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/loan_services/loan_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'loan_insertion_event.dart'; @@ -39,8 +40,9 @@ class LoanInsertionBloc extends Bloc { if (bookUpdatedStatus < 1) { emit( LoanInsertionErrorState( - errorMessage: - 'Ocorreu um erro ao adicionar o livro ao empréstimo. Verifique se o livro já não foi emprestado ou em lista de leitura', + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: + 'An error occurred while updating the book status to loaned. Verify is already loaned or if the book exists.', ), ); return; @@ -54,12 +56,16 @@ class LoanInsertionBloc extends Bloc { idContact: event.idContact, ); - final loanId = await _loanService.insert(loanModel: loanModel); + final loanId = await _loanService.insert( + loanModel: loanModel, + ); if (loanId < 1) { emit( LoanInsertionErrorState( - errorMessage: 'Ocorreu um erro ao criar o empréstimo', + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: + 'An error occurred while creating the loan', ), ); return; @@ -67,38 +73,46 @@ class LoanInsertionBloc extends Bloc { await _createNotification( loanId, - event.contactName, - event.bookTitle, - event.loanDate, event.devolutionDate, + event.notificationTitle, + event.notificationBody, ); + emit(LoanInsertionInsertedState()); + } on LocalDatabaseException catch (e) { emit( - LoanInsertionInsertedState( - loanInsertionMessage: 'Empréstimo inserido com sucesso', + LoanInsertionErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); + } on PlatformException catch (e) { + emit( + LoanInsertionErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.descriptionMessage, ), ); - } on LocalDatabaseException catch (e) { - emit(LoanInsertionErrorState( - errorMessage: 'Ocorreu um erro no database: ${e.message}')); } on Exception catch (e) { - emit(LoanInsertionErrorState( - errorMessage: 'Ocorreu um erro não esperado: $e')); + emit( + LoanInsertionErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } Future _createNotification( int loanId, - String contactName, - String bookTitle, - DateTime loanDate, DateTime devolutionDate, + String title, + String body, ) async { final customNotification = CustomNotificationModel( id: loanId, - title: 'Ei, seu livro tá voltando!', - body: - 'Olá! Só passando pra lembrar que tá na hora de ${contactName.toUpperCase()} devolver o ${bookTitle.toUpperCase()} que você emprestou no dia ${loanDate.toFormattedDate()}.', + title: title, + body: body, notificationChannel: NotificationChannel.loanChannel, scheduledDate: devolutionDate, payload: '/loan_detail', diff --git a/lib/src/features/loan_insertion/bloc/loan_insertion_event.dart b/lib/src/features/loan_insertion/bloc/loan_insertion_event.dart index bc72895b..5a29b561 100644 --- a/lib/src/features/loan_insertion/bloc/loan_insertion_event.dart +++ b/lib/src/features/loan_insertion/bloc/loan_insertion_event.dart @@ -7,17 +7,17 @@ final class InsertedLoanInsertionEvent extends LoanInsertionEvent { final DateTime loanDate; final DateTime devolutionDate; final String idContact; - final String contactName; final String bookId; - final String bookTitle; + final String notificationTitle; + final String notificationBody; InsertedLoanInsertionEvent({ this.observation, required this.loanDate, required this.devolutionDate, - required this.contactName, required this.idContact, required this.bookId, - required this.bookTitle, + required this.notificationTitle, + required this.notificationBody, }); } diff --git a/lib/src/features/loan_insertion/bloc/loan_insertion_state.dart b/lib/src/features/loan_insertion/bloc/loan_insertion_state.dart index 300ec540..cf33e7d1 100644 --- a/lib/src/features/loan_insertion/bloc/loan_insertion_state.dart +++ b/lib/src/features/loan_insertion/bloc/loan_insertion_state.dart @@ -4,18 +4,14 @@ sealed class LoanInsertionState {} final class LoanInsertionLoadingState extends LoanInsertionState {} -final class LoanInsertionInsertedState extends LoanInsertionState { - final String loanInsertionMessage; - - LoanInsertionInsertedState({ - required this.loanInsertionMessage, - }); -} +final class LoanInsertionInsertedState extends LoanInsertionState {} final class LoanInsertionErrorState extends LoanInsertionState { - final String errorMessage; + final LocalDatabaseErrorCode errorCode; + final String? errorDescriptionMessage; LoanInsertionErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/loan_insertion/views/loan_insertion_page.dart b/lib/src/features/loan_insertion/views/loan_insertion_page.dart index d0bde1b2..b77b888d 100644 --- a/lib/src/features/loan_insertion/views/loan_insertion_page.dart +++ b/lib/src/features/loan_insertion/views/loan_insertion_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart'; import 'package:bookify/src/features/books_picker/views/books_picker_page.dart'; import 'package:bookify/src/features/contacts_picker/views/contacts_picker_page.dart'; import 'package:bookify/src/features/loan_insertion/bloc/loan_insertion_bloc.dart'; @@ -186,15 +187,25 @@ class _LoanInsertionPageState extends State { ), ); + final formattedLoanDate = _loanDateEC.text; + final contactNameUpper = _contactNameEC.text.toUpperCase(); + final bookTitleUpper = _bookModel!.title.toUpperCase(); + _bloc.add( InsertedLoanInsertionEvent( idContact: _contact!.id, bookId: _bookModel!.id, - bookTitle: _bookModel!.title, - contactName: _contactNameEC.text, observation: _observationEC.text.isEmpty ? null : _observationEC.text, - loanDate: _loanDateEC.text.parseFormattedDate(), + loanDate: formattedLoanDate.parseFormattedDate(), devolutionDate: devolutionDateWithHours, + notificationTitle: 'loan-notification-title'.i18n(), + notificationBody: 'loan-notification-body'.i18n( + [ + contactNameUpper, + bookTitleUpper, + formattedLoanDate, + ], + ), ), ); @@ -240,12 +251,10 @@ class _LoanInsertionPageState extends State { break; - case LoanInsertionInsertedState( - loanInsertionMessage: final successMessage, - ): + case LoanInsertionInsertedState(): SnackbarService.showSnackBar( context, - successMessage, + 'loan-insertion-success-snackbar'.i18n(), SnackBarType.success, ); @@ -257,10 +266,13 @@ class _LoanInsertionPageState extends State { }, ); break; - case LoanInsertionErrorState(:final errorMessage): + case LoanInsertionErrorState( + :final errorCode, + :final errorDescriptionMessage, + ): SnackbarService.showSnackBar( context, - errorMessage, + errorCode.toLocalizedMessage(errorDescriptionMessage), SnackBarType.error, ); diff --git a/lib/src/features/loan_insertion/views/widgets/empty_book_button_widget.dart b/lib/src/features/loan_insertion/views/widgets/empty_book_button_widget.dart index b31ec828..de8cfe9d 100644 --- a/lib/src/features/loan_insertion/views/widgets/empty_book_button_widget.dart +++ b/lib/src/features/loan_insertion/views/widgets/empty_book_button_widget.dart @@ -19,7 +19,6 @@ class EmptyBookButtonWidget extends StatelessWidget { final colorScheme = Theme.of(context).colorScheme; final colorBorder = bookIsValid ? Colors.grey[300]! : colorScheme.error; - return GestureDetector( onTap: onTap, child: Container( diff --git a/lib/src/features/loan_insertion/views/widgets/empty_contact_button_widget.dart b/lib/src/features/loan_insertion/views/widgets/empty_contact_button_widget.dart index 1d86b5bd..86b6ed86 100644 --- a/lib/src/features/loan_insertion/views/widgets/empty_contact_button_widget.dart +++ b/lib/src/features/loan_insertion/views/widgets/empty_contact_button_widget.dart @@ -18,7 +18,6 @@ class EmptyContactButtonWidget extends StatelessWidget { Widget build(BuildContext context) { final colorScheme = Theme.of(context).colorScheme; - final borderColor = contactIsValid ? Colors.grey[300]! : colorScheme.error; return GestureDetector( diff --git a/lib/src/features/my_books/bloc/my_books_bloc.dart b/lib/src/features/my_books/bloc/my_books_bloc.dart index 10a64e04..66761b90 100644 --- a/lib/src/features/my_books/bloc/my_books_bloc.dart +++ b/lib/src/features/my_books/bloc/my_books_bloc.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'my_books_event.dart'; @@ -31,9 +32,19 @@ class MyBooksBloc extends Bloc { emit(MyBooksLoadedState(books: books)); } on LocalDatabaseException catch (e) { - emit(MyBooksErrorState(errorMessage: 'Erro no database: ${e.message}')); + emit( + MyBooksErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { - emit(MyBooksErrorState(errorMessage: 'Erro inesperado: $e')); + emit( + MyBooksErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } @@ -44,7 +55,9 @@ class MyBooksBloc extends Bloc { try { emit(MyBooksLoadingState()); - final books = await _bookService.getBooksByTitle(title: event.searchQuery); + final books = await _bookService.getBooksByTitle( + title: event.searchQuery, + ); if (books.isEmpty) { emit(MyBooksNotFoundState()); @@ -53,9 +66,19 @@ class MyBooksBloc extends Bloc { emit(MyBooksLoadedState(books: books)); } on LocalDatabaseException catch (e) { - emit(MyBooksErrorState(errorMessage: 'Erro no database: ${e.message}')); + emit( + MyBooksErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { - emit(MyBooksErrorState(errorMessage: 'Erro inesperado: $e')); + emit( + MyBooksErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } } diff --git a/lib/src/features/my_books/bloc/my_books_event.dart b/lib/src/features/my_books/bloc/my_books_event.dart index 881165fa..1fa34f62 100644 --- a/lib/src/features/my_books/bloc/my_books_event.dart +++ b/lib/src/features/my_books/bloc/my_books_event.dart @@ -4,7 +4,7 @@ sealed class MyBooksEvent {} final class GotAllBooksEvent extends MyBooksEvent {} -final class SearchedBooksEvent extends MyBooksEvent{ +final class SearchedBooksEvent extends MyBooksEvent { final String searchQuery; SearchedBooksEvent({required this.searchQuery}); diff --git a/lib/src/features/my_books/bloc/my_books_state.dart b/lib/src/features/my_books/bloc/my_books_state.dart index 333b6987..9e91093d 100644 --- a/lib/src/features/my_books/bloc/my_books_state.dart +++ b/lib/src/features/my_books/bloc/my_books_state.dart @@ -15,7 +15,11 @@ final class MyBooksLoadedState extends MyBooksState { final class MyBooksNotFoundState extends MyBooksState {} final class MyBooksErrorState extends MyBooksState { - final String errorMessage; + final LocalDatabaseErrorCode errorCode; + final String? errorDescriptionMessage; - MyBooksErrorState({required this.errorMessage}); + MyBooksErrorState({ + required this.errorCode, + required this.errorDescriptionMessage, + }); } diff --git a/lib/src/features/my_books/views/my_books_page.dart b/lib/src/features/my_books/views/my_books_page.dart index e6cfb5f6..9ac55d7a 100644 --- a/lib/src/features/my_books/views/my_books_page.dart +++ b/lib/src/features/my_books/views/my_books_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart'; import 'package:bookify/src/features/book_detail/views/book_detail_page.dart'; import 'package:bookify/src/features/my_books/bloc/my_books_bloc.dart'; import 'package:bookify/src/shared/widgets/center_circular_progress_indicator/center_circular_progress_indicator.dart'; @@ -52,28 +53,31 @@ class _MyBooksPageState extends State { return switch (state) { MyBooksLoadingState() => const CenterCircularProgressIndicator(), MyBooksEmptyState() => Center( - child: SizedBox( - child: Text('no-books-saved-message'.i18n()), - ), + child: SizedBox( + child: Text('no-books-saved-message'.i18n()), ), + ), MyBooksLoadedState(:final books) => BooksGridView( - books: books, - onTap: (book) async { - await Navigator.pushNamed( - context, - BookDetailPage.routeName, - arguments: book, - ); - _refreshPage(); - }, - ), + books: books, + onTap: (book) async { + await Navigator.pushNamed( + context, + BookDetailPage.routeName, + arguments: book, + ); + _refreshPage(); + }, + ), MyBooksNotFoundState() => InfoItemStateWidget.withNotFoundState( - message: 'no-books-found-with-terms'.i18n(), - onPressed: _refreshPage, - ), - MyBooksErrorState(:final errorMessage) => + message: 'no-books-found-with-terms'.i18n(), + onPressed: _refreshPage, + ), + MyBooksErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => InfoItemStateWidget.withErrorState( - message: errorMessage, + message: errorCode.toLocalizedMessage(errorDescriptionMessage), onPressed: _refreshPage, ), }; diff --git a/lib/src/features/notifications/bloc/notifications_bloc.dart b/lib/src/features/notifications/bloc/notifications_bloc.dart index 10ef1b6d..9222f8a4 100644 --- a/lib/src/features/notifications/bloc/notifications_bloc.dart +++ b/lib/src/features/notifications/bloc/notifications_bloc.dart @@ -1,5 +1,7 @@ +import 'package:bookify/src/core/errors/platform_exception/platform_exception.dart'; import 'package:bookify/src/core/models/custom_notification_model.dart'; import 'package:bookify/src/core/services/app_services/notifications_service/notifications_service.dart'; +import 'package:bookify/src/shared/enums/platform_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'notifications_event.dart'; @@ -33,10 +35,19 @@ class NotificationsBloc extends Bloc { notifications: notifications, ), ); + } on PlatformException catch (e) { + emit( + NotificationErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { emit( NotificationErrorState( - errorMessage: 'Erro inesperado: ${e.toString()}'), + errorCode: PlatformErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), ); } } diff --git a/lib/src/features/notifications/bloc/notifications_state.dart b/lib/src/features/notifications/bloc/notifications_state.dart index 5e143ab8..6da08d2f 100644 --- a/lib/src/features/notifications/bloc/notifications_state.dart +++ b/lib/src/features/notifications/bloc/notifications_state.dart @@ -15,9 +15,11 @@ final class NotificationsLoadedState extends NotificationsState { } final class NotificationErrorState extends NotificationsState { - final String errorMessage; + final PlatformErrorCode errorCode; + final String? errorDescriptionMessage; NotificationErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/notifications/views/notifications_page.dart b/lib/src/features/notifications/views/notifications_page.dart index 229adc92..aa2e7301 100644 --- a/lib/src/features/notifications/views/notifications_page.dart +++ b/lib/src/features/notifications/views/notifications_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/platform_error_code/platform_error_code_extension.dart'; import 'package:bookify/src/features/notifications/bloc/notifications_bloc.dart'; import 'package:bookify/src/features/notifications/views/widgets/notifications_loaded_state_widget.dart'; import 'package:bookify/src/shared/widgets/center_circular_progress_indicator/center_circular_progress_indicator.dart'; @@ -35,21 +36,24 @@ class _NotificationsPageState extends State { return switch (state) { NotificationsLoadingState() => const CenterCircularProgressIndicator(), NotificationEmptyState() => Center( - child: Padding( - padding: EdgeInsets.all(16.0), - child: Text( - 'no-notifications-found'.i18n(), - textAlign: TextAlign.center, - ), + child: Padding( + padding: EdgeInsets.all(16.0), + child: Text( + 'no-notifications-found'.i18n(), + textAlign: TextAlign.center, ), ), + ), NotificationsLoadedState(:final notifications) => NotificationsLoadedStateWidget( notifications: notifications, ), - NotificationErrorState(:final errorMessage) => + NotificationErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => InfoItemStateWidget.withErrorState( - message: errorMessage, + message: errorCode.toLocalizedMessage(errorDescriptionMessage), onPressed: _onRefreshPage, ), }; diff --git a/lib/src/features/notifications/views/widgets/notification_widget.dart b/lib/src/features/notifications/views/widgets/notification_widget.dart index 2b974d3d..dcb0b521 100644 --- a/lib/src/features/notifications/views/widgets/notification_widget.dart +++ b/lib/src/features/notifications/views/widgets/notification_widget.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/notification_channel/notification_channel_extension.dart'; import 'package:bookify/src/core/models/custom_notification_model.dart'; import 'package:flutter/material.dart'; @@ -63,7 +64,7 @@ class NotificationWidget extends StatelessWidget { ), ), Text( - 'channel: ${notification.notificationChannel.channelId()}', + notification.notificationChannel.label, textScaler: TextScaler.noScaling, style: TextStyle( fontSize: 14, @@ -71,7 +72,7 @@ class NotificationWidget extends StatelessWidget { ), ), ], - ) + ), ], ), ), diff --git a/lib/src/features/on_boarding/pages/pages.dart b/lib/src/features/on_boarding/pages/pages.dart index f96ffe94..ff2751f8 100644 --- a/lib/src/features/on_boarding/pages/pages.dart +++ b/lib/src/features/on_boarding/pages/pages.dart @@ -1,4 +1,4 @@ export 'package:bookify/src/features/on_boarding/pages/illustration_1_page.dart'; export 'package:bookify/src/features/on_boarding/pages/illustration_2_page.dart'; export 'package:bookify/src/features/on_boarding/pages/illustration_3_page.dart'; -export 'package:bookify/src/features/on_boarding/pages/illustration_4_page.dart'; \ No newline at end of file +export 'package:bookify/src/features/on_boarding/pages/illustration_4_page.dart'; diff --git a/lib/src/features/on_boarding/views/on_boarding_page.dart b/lib/src/features/on_boarding/views/on_boarding_page.dart index aaaa641c..fb4fb8c8 100644 --- a/lib/src/features/on_boarding/views/on_boarding_page.dart +++ b/lib/src/features/on_boarding/views/on_boarding_page.dart @@ -135,7 +135,7 @@ class _OnBoardingPageState extends State { ), ), ], - ) + ), ], ), ), diff --git a/lib/src/features/profile/bloc/profile_bloc.dart b/lib/src/features/profile/bloc/profile_bloc.dart index 9758ee42..54443a04 100644 --- a/lib/src/features/profile/bloc/profile_bloc.dart +++ b/lib/src/features/profile/bloc/profile_bloc.dart @@ -1,7 +1,7 @@ +import 'package:bookify/src/shared/enums/auth_error_code.dart'; import 'package:bookify/src/core/errors/auth_exception/auth_exception.dart'; import 'package:bookify/src/core/models/user_model.dart'; import 'package:bookify/src/core/services/auth_service/auth_service.dart'; -import 'package:bookify/src/core/services/storage_services/storage_services.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'profile_event.dart'; @@ -9,11 +9,9 @@ part 'profile_state.dart'; class ProfileBloc extends Bloc { final AuthService _authService; - final StorageServices _storageServices; ProfileBloc( this._authService, - this._storageServices, ) : super(ProfileLoadingState()) { on(_gotUserProfileEvent); on(_userLoggedOutEvent); @@ -31,7 +29,9 @@ class ProfileBloc extends Bloc { if (userModel == null) { emit( ProfileErrorState( - errorMessage: 'Erro ao buscar o usuário', + errorCode: AuthErrorCode.internalError, + errorDescriptionMessage: + 'Failed to save user data. Please try again.', ), ); return; @@ -43,12 +43,17 @@ class ProfileBloc extends Bloc { ), ); } on AuthException catch (e) { - emit(ProfileErrorState( - errorMessage: 'Erro ao buscar o usuário: ${e.message}')); + emit( + ProfileErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { emit( ProfileErrorState( - errorMessage: 'Erro inesperado: $e', + errorCode: AuthErrorCode.internalError, + errorDescriptionMessage: e.toString(), ), ); } @@ -68,18 +73,8 @@ class ProfileBloc extends Bloc { if (!userLoggedOut) { emit( ProfileErrorState( - errorMessage: 'Erro ao fazer o logout do usuário', - ), - ); - return; - } - - final storageRemoved = await _storageServices.clearStorage(); - - if (storageRemoved == 0) { - emit( - ProfileErrorState( - errorMessage: 'Erro ao limpar as configurações do usuário', + errorCode: AuthErrorCode.internalError, + errorDescriptionMessage: 'Failed to logout', ), ); return; @@ -87,12 +82,17 @@ class ProfileBloc extends Bloc { emit(ProfileLogOutState()); } on AuthException catch (e) { - emit(ProfileErrorState( - errorMessage: 'Erro em fazer o logout do usuário: ${e.message}')); + emit( + ProfileErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { emit( ProfileErrorState( - errorMessage: 'Erro inesperado: $e', + errorCode: AuthErrorCode.internalError, + errorDescriptionMessage: e.toString(), ), ); } diff --git a/lib/src/features/profile/bloc/profile_state.dart b/lib/src/features/profile/bloc/profile_state.dart index a43eb98c..fc14acd2 100644 --- a/lib/src/features/profile/bloc/profile_state.dart +++ b/lib/src/features/profile/bloc/profile_state.dart @@ -15,9 +15,11 @@ final class ProfileLoadedState extends ProfileState { final class ProfileLogOutState extends ProfileState {} final class ProfileErrorState extends ProfileState { - final String errorMessage; + final AuthErrorCode errorCode; + final String? errorDescriptionMessage; ProfileErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/profile/views/profile_page.dart b/lib/src/features/profile/views/profile_page.dart index 4e5f5621..d9931c40 100644 --- a/lib/src/features/profile/views/profile_page.dart +++ b/lib/src/features/profile/views/profile_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/auth_error_code/auth_error_code_extension.dart'; import 'package:bookify/src/features/auth/views/auth_page.dart'; import 'package:bookify/src/features/profile/bloc/profile_bloc.dart'; import 'package:bookify/src/features/profile/views/widgets/profile_loaded_state_widget.dart'; @@ -28,19 +29,23 @@ class _ProfilePageState extends State { Widget _getWidgetOnProfileState(BuildContext context, ProfileState state) { return switch (state) { ProfileLoadingState() || - ProfileLogOutState() => - const CenterCircularProgressIndicator(), + ProfileLogOutState() => const CenterCircularProgressIndicator(), ProfileLoadedState(:final userModel) => ProfileLoadedStateWidget( - userModel: userModel, - onPressedLogOut: () => _bloc.add( - UserLoggedOutEvent( - userModel: userModel, - ), + userModel: userModel, + onPressedLogOut: () => _bloc.add( + UserLoggedOutEvent( + userModel: userModel, ), ), - ProfileErrorState(:final errorMessage) => Center( + ), + ProfileErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => + Center( + key: const Key('BookErrorSateWidget'), child: InfoItemStateWidget.withErrorState( - message: errorMessage, + message: errorCode.toLocalizedMessage(errorDescriptionMessage), onPressed: _refreshPage, ), ), diff --git a/lib/src/features/profile/views/widgets/user_information_row/bloc/user_information_bloc.dart b/lib/src/features/profile/views/widgets/user_information_row/bloc/user_information_bloc.dart index 8bb7e1ed..353821b8 100644 --- a/lib/src/features/profile/views/widgets/user_information_row/bloc/user_information_bloc.dart +++ b/lib/src/features/profile/views/widgets/user_information_row/bloc/user_information_bloc.dart @@ -3,6 +3,7 @@ import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/bookcase_service/bookcase_service.dart'; import 'package:bookify/src/core/services/loan_services/loan_service.dart'; import 'package:bookify/src/core/services/reading_services/reading_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'user_information_event.dart'; @@ -47,11 +48,16 @@ class UserInformationBloc } on LocalDatabaseException catch (e) { emit( UserInformationErrorState( - errorMessage: 'Erro no database: ${e.message}'), + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), ); } on Exception catch (e) { emit( - UserInformationErrorState(errorMessage: 'Erro inesperado: $e'), + UserInformationErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), ); } } diff --git a/lib/src/features/profile/views/widgets/user_information_row/bloc/user_information_event.dart b/lib/src/features/profile/views/widgets/user_information_row/bloc/user_information_event.dart index c8e67c18..2b58978f 100644 --- a/lib/src/features/profile/views/widgets/user_information_row/bloc/user_information_event.dart +++ b/lib/src/features/profile/views/widgets/user_information_row/bloc/user_information_event.dart @@ -2,4 +2,4 @@ part of 'user_information_bloc.dart'; sealed class UserInformationEvent {} -final class GotUserInformationEvent extends UserInformationEvent{} +final class GotUserInformationEvent extends UserInformationEvent {} diff --git a/lib/src/features/profile/views/widgets/user_information_row/bloc/user_information_state.dart b/lib/src/features/profile/views/widgets/user_information_row/bloc/user_information_state.dart index dd2aa1da..a4aaa58d 100644 --- a/lib/src/features/profile/views/widgets/user_information_row/bloc/user_information_state.dart +++ b/lib/src/features/profile/views/widgets/user_information_row/bloc/user_information_state.dart @@ -19,9 +19,11 @@ final class UserInformationLoadedState extends UserInformationState { } final class UserInformationErrorState extends UserInformationState { - final String errorMessage; + final LocalDatabaseErrorCode errorCode; + final String? errorDescriptionMessage; UserInformationErrorState({ - required this.errorMessage, + required this.errorCode, + required this.errorDescriptionMessage, }); } diff --git a/lib/src/features/profile/views/widgets/user_information_row/user_information_row.dart b/lib/src/features/profile/views/widgets/user_information_row/user_information_row.dart index 43351961..cacf889b 100644 --- a/lib/src/features/profile/views/widgets/user_information_row/user_information_row.dart +++ b/lib/src/features/profile/views/widgets/user_information_row/user_information_row.dart @@ -54,16 +54,18 @@ class _UserInformationRowState extends State { ), ItemStatusColumn( quantity: bookCount, - label: - bookCount == 1 ? 'book-label'.i18n() : 'books-label'.i18n(), + label: bookCount == 1 + ? 'book-label'.i18n() + : 'books-label'.i18n(), ), const SizedBox( width: 5, ), ItemStatusColumn( quantity: loansCount, - label: - loansCount == 1 ? 'loan-label'.i18n() : 'loans-label'.i18n(), + label: loansCount == 1 + ? 'loan-label'.i18n() + : 'loans-label'.i18n(), ), const SizedBox( width: 5, @@ -77,13 +79,13 @@ class _UserInformationRowState extends State { ], ), UserInformationErrorState() => Center( - child: Text( - 'error-on-loading-data'.i18n(), - style: TextStyle( - fontSize: 10, - ), + child: Text( + 'error-on-loading-data'.i18n(), + style: TextStyle( + fontSize: 10, ), ), + ), }; } diff --git a/lib/src/features/programming_reading/bloc/programming_reading_bloc.dart b/lib/src/features/programming_reading/bloc/programming_reading_bloc.dart index 1943d9ad..56757e56 100644 --- a/lib/src/features/programming_reading/bloc/programming_reading_bloc.dart +++ b/lib/src/features/programming_reading/bloc/programming_reading_bloc.dart @@ -1,3 +1,5 @@ +import 'package:bookify/src/core/errors/platform_exception/platform_exception.dart'; +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/models/user_hour_time_model.dart'; import 'package:bookify/src/core/repositories/user_hour_time_repository/user_hour_time_repository.dart'; @@ -40,13 +42,15 @@ class ProgrammingReadingBloc } on StorageException catch (e) { emit( ProgrammingReadingErrorState( - errorMessage: 'Erro ao buscar a hora para leitura: $e', + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, ), ); } on Exception catch (e) { emit( ProgrammingReadingErrorState( - errorMessage: 'Erro inesperado: $e', + errorCode: StorageErrorCode.unknown, + errorDescriptionMessage: e.toString(), ), ); } @@ -61,15 +65,16 @@ class ProgrammingReadingBloc final userHourTime = event.userHourTimeModel; - final userHourTimeInserted = - await _userHourTimeRepository.setUserHourTime( - userHourTime: userHourTime, - ); + final userHourTimeInserted = await _userHourTimeRepository + .setUserHourTime( + userHourTime: userHourTime, + ); if (userHourTimeInserted == 0) { emit( ProgrammingReadingErrorState( - errorMessage: 'Erro ao inserir buscar a hora de leitura', + errorCode: StorageErrorCode.writeFailed, + errorDescriptionMessage: 'Failed to insert reading hour time', ), ); return; @@ -77,8 +82,8 @@ class ProgrammingReadingBloc await _notificationsService.periodicallyShowNotificationWithSpecificDate( id: _readingNotificationId, - title: 'A hora da leitura chegou!', - body: 'A história está esperando a gente!', + title: event.readingTimeNotificationTitle, + body: event.readingTimeNotificationBody, repeatType: userHourTime.repeatHourTimeType, scheduledDate: DateTime( DateTime.now().year, @@ -94,13 +99,22 @@ class ProgrammingReadingBloc } on StorageException catch (e) { emit( ProgrammingReadingErrorState( - errorMessage: 'Erro ao inserir a hora de leitura: $e', + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); + } on PlatformException catch (e) { + emit( + ProgrammingReadingErrorState( + errorCode: StorageErrorCode.unknown, + errorDescriptionMessage: e.descriptionMessage, ), ); } on Exception catch (e) { emit( ProgrammingReadingErrorState( - errorMessage: 'Erro inesperado: $e', + errorCode: StorageErrorCode.unknown, + errorDescriptionMessage: e.toString(), ), ); } @@ -118,10 +132,25 @@ class ProgrammingReadingBloc ); emit(ProgrammingReadingRemovedNotificationState()); + } on StorageException catch (e) { + emit( + ProgrammingReadingErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); + } on PlatformException catch (e) { + emit( + ProgrammingReadingErrorState( + errorCode: StorageErrorCode.unknown, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { emit( ProgrammingReadingErrorState( - errorMessage: 'Erro inesperado: $e', + errorCode: StorageErrorCode.unknown, + errorDescriptionMessage: e.toString(), ), ); } diff --git a/lib/src/features/programming_reading/bloc/programming_reading_event.dart b/lib/src/features/programming_reading/bloc/programming_reading_event.dart index b6b2d681..ec001763 100644 --- a/lib/src/features/programming_reading/bloc/programming_reading_event.dart +++ b/lib/src/features/programming_reading/bloc/programming_reading_event.dart @@ -6,9 +6,13 @@ final class GotHourTimeEvent extends ProgrammingReadingEvent {} final class InsertedHourTimeEvent extends ProgrammingReadingEvent { final UserHourTimeModel userHourTimeModel; + final String readingTimeNotificationTitle; + final String readingTimeNotificationBody; InsertedHourTimeEvent({ required this.userHourTimeModel, + required this.readingTimeNotificationTitle, + required this.readingTimeNotificationBody, }); } diff --git a/lib/src/features/programming_reading/bloc/programming_reading_state.dart b/lib/src/features/programming_reading/bloc/programming_reading_state.dart index 6af117c9..2120c3af 100644 --- a/lib/src/features/programming_reading/bloc/programming_reading_state.dart +++ b/lib/src/features/programming_reading/bloc/programming_reading_state.dart @@ -18,9 +18,11 @@ final class ProgrammingReadingRemovedNotificationState extends ProgrammingReadingState {} final class ProgrammingReadingErrorState extends ProgrammingReadingState { - final String errorMessage; + final StorageErrorCode errorCode; + final String? errorDescriptionMessage; ProgrammingReadingErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/programming_reading/views/programming_reading_page.dart b/lib/src/features/programming_reading/views/programming_reading_page.dart index 33b24b6a..103151a9 100644 --- a/lib/src/features/programming_reading/views/programming_reading_page.dart +++ b/lib/src/features/programming_reading/views/programming_reading_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/storage_error_code/storage_error_code_extension.dart'; import 'package:bookify/src/core/models/user_hour_time_model.dart'; import 'package:bookify/src/core/services/app_services/snackbar_service/snackbar_service.dart'; import 'package:bookify/src/features/programming_reading/bloc/programming_reading_bloc.dart'; @@ -43,6 +44,10 @@ class _ProgrammingHourState extends State { _bloc.add( InsertedHourTimeEvent( userHourTimeModel: userHourTimeModel, + readingTimeNotificationTitle: 'reading-time-notification-title' + .i18n(), + readingTimeNotificationBody: 'reading-time-notification-body' + .i18n(), ), ); }, @@ -50,9 +55,13 @@ class _ProgrammingHourState extends State { RemovedNotificationHourTimeEvent(), ), ), - ProgrammingReadingErrorState(:final errorMessage) => Center( + ProgrammingReadingErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => + Center( child: InfoItemStateWidget.withErrorState( - message: errorMessage, + message: errorCode.toLocalizedMessage(errorDescriptionMessage), onPressed: _onRefreshPage, ), ), diff --git a/lib/src/features/programming_reading/views/widgets/hour_time_selected_widget.dart b/lib/src/features/programming_reading/views/widgets/hour_time_selected_widget.dart index f5e00383..1c5e3b31 100644 --- a/lib/src/features/programming_reading/views/widgets/hour_time_selected_widget.dart +++ b/lib/src/features/programming_reading/views/widgets/hour_time_selected_widget.dart @@ -6,7 +6,7 @@ import 'package:localization/localization.dart'; class HourTimeSelectedWidget extends StatefulWidget { final void Function(TimeOfDay startingTime, TimeOfDay endingTime) - onSelectedTimes; + onSelectedTimes; final UserHourTimeModel? userHourTimeModel; const HourTimeSelectedWidget({ @@ -45,10 +45,12 @@ class _HourTimeSelectedWidgetState extends State { return Material( child: InkWell( onTap: () async { - final times = await Navigator.of(context).pushNamed( - TimePickerPage.routeName, - arguments: widget.userHourTimeModel, - ) as List?; + final times = + await Navigator.of(context).pushNamed( + TimePickerPage.routeName, + arguments: widget.userHourTimeModel, + ) + as List?; if (times != null) { setState(() { diff --git a/lib/src/features/programming_reading/views/widgets/programming_hour_loading_state_widget.dart b/lib/src/features/programming_reading/views/widgets/programming_hour_loading_state_widget.dart index e3531b56..c55cd478 100644 --- a/lib/src/features/programming_reading/views/widgets/programming_hour_loading_state_widget.dart +++ b/lib/src/features/programming_reading/views/widgets/programming_hour_loading_state_widget.dart @@ -1,4 +1,4 @@ -import 'package:bookify/src/core/enums/repeat_hour_time_type.dart'; +import 'package:bookify/src/shared/enums/repeat_hour_time_type.dart'; import 'package:bookify/src/core/helpers/size/size_for_small_device_extension.dart'; import 'package:bookify/src/core/models/user_hour_time_model.dart'; import 'package:bookify/src/features/programming_reading/views/widgets/hour_time_selected_widget.dart'; @@ -33,7 +33,8 @@ class _ProgrammingHourLoadingStateWidgetState void initState() { super.initState(); userHourTimeModel = UserHourTimeModel( - repeatHourTimeType: widget.initialUserHourTimeModel?.repeatHourTimeType ?? + repeatHourTimeType: + widget.initialUserHourTimeModel?.repeatHourTimeType ?? RepeatHourTimeType.daily, startingHour: widget.initialUserHourTimeModel?.startingHour ?? 7, startingMinute: widget.initialUserHourTimeModel?.startingMinute ?? 0, @@ -74,8 +75,9 @@ class _ProgrammingHourLoadingStateWidgetState height: 10, ), RepeatTimeWidget( - initialRepeatTimeSelected: - userHourTimeModel.repeatHourTimeType.toIntValue(), + initialRepeatTimeSelected: userHourTimeModel + .repeatHourTimeType + .toIntValue(), onSelectedRepeatTime: (int selectedRepeatTime) { setState(() { userHourTimeModel = userHourTimeModel.copyWith( @@ -91,19 +93,20 @@ class _ProgrammingHourLoadingStateWidgetState ), HourTimeSelectedWidget( userHourTimeModel: userHourTimeModel, - onSelectedTimes: ( - TimeOfDay startingTime, - TimeOfDay endingTime, - ) { - setState(() { - userHourTimeModel = userHourTimeModel.copyWith( - startingHour: startingTime.hour, - startingMinute: startingTime.minute, - endingHour: endingTime.hour, - endingMinute: endingTime.minute, - ); - }); - }, + onSelectedTimes: + ( + TimeOfDay startingTime, + TimeOfDay endingTime, + ) { + setState(() { + userHourTimeModel = userHourTimeModel.copyWith( + startingHour: startingTime.hour, + startingMinute: startingTime.minute, + endingHour: endingTime.hour, + endingMinute: endingTime.minute, + ); + }); + }, ), const Spacer(), BookifyOutlinedButton.expanded( diff --git a/lib/src/features/reading_page_time_calculator/views/reading_page_time_calculator_page.dart b/lib/src/features/reading_page_time_calculator/views/reading_page_time_calculator_page.dart index a3cb7e9d..d05acb39 100644 --- a/lib/src/features/reading_page_time_calculator/views/reading_page_time_calculator_page.dart +++ b/lib/src/features/reading_page_time_calculator/views/reading_page_time_calculator_page.dart @@ -38,7 +38,7 @@ class ReadingPageTimeCalculatorPage extends StatelessWidget { child: BookifyElevatedButton.expanded( text: 'calculate-time-button'.i18n(), onPressed: () async { - await Navigator.pushNamed( + await Navigator.pushNamed( context, ReadingPageTimerPage.routeName, ); diff --git a/lib/src/features/reading_page_timer/bloc/reading_page_timer_bloc.dart b/lib/src/features/reading_page_timer/bloc/reading_page_timer_bloc.dart index 1568e3aa..72017375 100644 --- a/lib/src/features/reading_page_timer/bloc/reading_page_timer_bloc.dart +++ b/lib/src/features/reading_page_timer/bloc/reading_page_timer_bloc.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/models/user_page_reading_time_model.dart'; import 'package:bookify/src/core/repositories/user_page_reading_time_repository/user_page_reading_time_repository.dart'; @@ -27,15 +28,17 @@ class ReadingPageTimerBloc pageReadingTimeSeconds: event.readingPageTime, ); - final userPageReadingTimeInserted = - await _userPageReadingTimeRepository.setUserPageReadingTime( - userPageReadingTime: userPageReading, - ); + final userPageReadingTimeInserted = await _userPageReadingTimeRepository + .setUserPageReadingTime( + userPageReadingTime: userPageReading, + ); if (userPageReadingTimeInserted == 0) { emit( ReadingPageTimerErrorState( - errorMessage: 'Erro ao inserir o tempo de leitura da página', + errorCode: StorageErrorCode.writeFailed, + errorDescriptionMessage: + 'Failed to save page reading time. Please try again.', ), ); return; @@ -45,13 +48,15 @@ class ReadingPageTimerBloc } on StorageException catch (e) { emit( ReadingPageTimerErrorState( - errorMessage: 'Erro ao inserir o tempo de leitura da página: $e', + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, ), ); } on Exception catch (e) { emit( ReadingPageTimerErrorState( - errorMessage: 'Erro inesperado: $e', + errorCode: StorageErrorCode.unknown, + errorDescriptionMessage: e.toString(), ), ); } diff --git a/lib/src/features/reading_page_timer/bloc/reading_page_timer_state.dart b/lib/src/features/reading_page_timer/bloc/reading_page_timer_state.dart index 7b3b2581..9c359374 100644 --- a/lib/src/features/reading_page_timer/bloc/reading_page_timer_state.dart +++ b/lib/src/features/reading_page_timer/bloc/reading_page_timer_state.dart @@ -7,9 +7,11 @@ final class ReadingPageTimerLoadingState extends ReadingPageTimerState {} final class ReadingPageTimerInsertedState extends ReadingPageTimerState {} final class ReadingPageTimerErrorState extends ReadingPageTimerState { - final String errorMessage; + final StorageErrorCode errorCode; + final String? errorDescriptionMessage; ReadingPageTimerErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/reading_page_timer/views/reading_page_timer_page.dart b/lib/src/features/reading_page_timer/views/reading_page_timer_page.dart index 3b09750b..8b16776a 100644 --- a/lib/src/features/reading_page_timer/views/reading_page_timer_page.dart +++ b/lib/src/features/reading_page_timer/views/reading_page_timer_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/storage_error_code/storage_error_code_extension.dart'; import 'package:bookify/src/core/services/app_services/snackbar_service/snackbar_service.dart'; import 'package:bookify/src/features/reading_page_timer/bloc/reading_page_timer_bloc.dart'; import 'widgets/reading_page_timer_loaded_state_widget.dart'; @@ -49,10 +50,13 @@ class _ReadingPageTimerPageState extends State { Navigator.of(context).pop, ); break; - case ReadingPageTimerErrorState(:final errorMessage): + case ReadingPageTimerErrorState( + :final errorCode, + :final errorDescriptionMessage, + ): SnackbarService.showSnackBar( context, - errorMessage, + errorCode.toLocalizedMessage(errorDescriptionMessage), SnackBarType.error, ); break; diff --git a/lib/src/features/reading_page_timer/views/widgets/reading_page_timer_loaded_state_widget.dart b/lib/src/features/reading_page_timer/views/widgets/reading_page_timer_loaded_state_widget.dart index 71ddbe98..971e3333 100644 --- a/lib/src/features/reading_page_timer/views/widgets/reading_page_timer_loaded_state_widget.dart +++ b/lib/src/features/reading_page_timer/views/widgets/reading_page_timer_loaded_state_widget.dart @@ -57,8 +57,13 @@ class _ReadingPageTimerLoadedStateWidgetState } @override - Future dispose() async { + Future deactivate() async { await _stopWatchTimer.dispose(); + super.deactivate(); + } + + @override + void dispose() { _isTimerRunningNotifier.dispose(); WidgetsBinding.instance.removeObserver(this); super.dispose(); diff --git a/lib/src/features/readings/bloc/readings_bloc.dart b/lib/src/features/readings/bloc/readings_bloc.dart index 10a141af..c215f614 100644 --- a/lib/src/features/readings/bloc/readings_bloc.dart +++ b/lib/src/features/readings/bloc/readings_bloc.dart @@ -3,6 +3,7 @@ import 'package:bookify/src/core/errors/local_database_exception/local_database_ import 'package:bookify/src/core/models/reading_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/reading_services/reading_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'readings_event.dart'; @@ -36,9 +37,19 @@ class ReadingsBloc extends Bloc { await _mountReadingsDto(readings, emit); } on LocalDatabaseException catch (e) { - emit(ReadingsErrorState(errorMessage: 'Erro no database: ${e.message}')); + emit( + ReadingsErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { - emit(ReadingsErrorState(errorMessage: 'Erro inesperado: $e')); + emit( + ReadingsErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } @@ -60,9 +71,19 @@ class ReadingsBloc extends Bloc { await _mountReadingsDto(readings, emit); } on LocalDatabaseException catch (e) { - emit(ReadingsErrorState(errorMessage: 'Erro no database: ${e.message}')); + emit( + ReadingsErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { - emit(ReadingsErrorState(errorMessage: 'Erro inesperado: $e')); + emit( + ReadingsErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } @@ -75,7 +96,11 @@ class ReadingsBloc extends Bloc { for (ReadingModel reading in readings) { if (reading.id == null) { emit( - ReadingsErrorState(errorMessage: 'Erro inesperado: ${reading.id}')); + ReadingsErrorState( + errorCode: LocalDatabaseErrorCode.conversionFailed, + errorDescriptionMessage: 'Reading not found', + ), + ); return; } diff --git a/lib/src/features/readings/bloc/readings_state.dart b/lib/src/features/readings/bloc/readings_state.dart index 68a2df07..6290d6fb 100644 --- a/lib/src/features/readings/bloc/readings_state.dart +++ b/lib/src/features/readings/bloc/readings_state.dart @@ -15,7 +15,11 @@ final class ReadingsLoadedState extends ReadingsState { } final class ReadingsErrorState extends ReadingsState { - final String errorMessage; + final LocalDatabaseErrorCode errorCode; + final String? errorDescriptionMessage; - ReadingsErrorState({required this.errorMessage}); + ReadingsErrorState({ + required this.errorCode, + this.errorDescriptionMessage, + }); } diff --git a/lib/src/features/readings/views/readings_page.dart b/lib/src/features/readings/views/readings_page.dart index 0d037eb2..b23a9fab 100644 --- a/lib/src/features/readings/views/readings_page.dart +++ b/lib/src/features/readings/views/readings_page.dart @@ -1,5 +1,6 @@ import 'dart:async'; +import 'package:bookify/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart'; import 'package:bookify/src/features/books_picker/views/books_picker_page.dart'; import 'package:bookify/src/features/readings/bloc/readings_bloc.dart'; import 'package:bookify/src/features/readings/views/widgets/readings_loaded_state_widget.dart'; @@ -74,31 +75,35 @@ class _ReadingsPageState extends State { return switch (state) { ReadingsLoadingState() => const CenterCircularProgressIndicator(), ReadingsEmptyState() => Center( - key: const Key('ReadingsEmptyState'), - child: ItemEmptyStateWidget( - label: 'start-new-reading-title'.i18n(), - onTap: () => _insertNewReading(context), - ), + key: const Key('ReadingsEmptyState'), + child: ItemEmptyStateWidget( + label: 'start-new-reading-title'.i18n(), + onTap: () => _insertNewReading(context), ), + ), ReadingsNotFoundState() => Center( - child: InfoItemStateWidget.withNotFoundState( - message: 'no-readings-found-with-terms'.i18n(), - onPressed: () { - _searchController.clear(); - _toggleSearchBarVisible(); - _refreshPage(); - }, - ), + child: InfoItemStateWidget.withNotFoundState( + message: 'no-readings-found-with-terms'.i18n(), + onPressed: () { + _searchController.clear(); + _toggleSearchBarVisible(); + _refreshPage(); + }, ), + ), ReadingsLoadedState(:final readingsDto) => ReadingsLoadedStateWidget( - key: const Key('ReadingsLoadedState'), - readingsDto: readingsDto, - onNewReading: () => _insertNewReading(context), - onRefreshPage: _refreshPage, - ), - ReadingsErrorState(:final errorMessage) => Center( + key: const Key('ReadingsLoadedState'), + readingsDto: readingsDto, + onNewReading: () => _insertNewReading(context), + onRefreshPage: _refreshPage, + ), + ReadingsErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => + Center( child: InfoItemStateWidget.withErrorState( - message: errorMessage, + message: errorCode.toLocalizedMessage(errorDescriptionMessage), onPressed: _refreshPage, ), ), diff --git a/lib/src/features/readings/views/widgets/reading_widget.dart b/lib/src/features/readings/views/widgets/reading_widget.dart index 93fe807e..2c40bd00 100644 --- a/lib/src/features/readings/views/widgets/reading_widget.dart +++ b/lib/src/features/readings/views/widgets/reading_widget.dart @@ -148,10 +148,10 @@ class ReadingWidget extends StatelessWidget { ), ), ], - ) + ), ], ), - ) + ), ], ), ), diff --git a/lib/src/features/readings/views/widgets/readings_loaded_state_widget.dart b/lib/src/features/readings/views/widgets/readings_loaded_state_widget.dart index ca28dde5..3dec794a 100644 --- a/lib/src/features/readings/views/widgets/readings_loaded_state_widget.dart +++ b/lib/src/features/readings/views/widgets/readings_loaded_state_widget.dart @@ -43,9 +43,10 @@ class ReadingsLoadedStateWidget extends StatelessWidget { onTap: () async { final readingIsChanged = await Navigator.of(context).pushNamed( - ReadingsDetailPage.routeName, - arguments: readingsDto[index], - ) as bool?; + ReadingsDetailPage.routeName, + arguments: readingsDto[index], + ) + as bool?; if (readingIsChanged != null && readingIsChanged) { onRefreshPage(); diff --git a/lib/src/features/readings_detail/bloc/readings_detail_bloc.dart b/lib/src/features/readings_detail/bloc/readings_detail_bloc.dart index 6f336cd2..0cb040aa 100644 --- a/lib/src/features/readings_detail/bloc/readings_detail_bloc.dart +++ b/lib/src/features/readings_detail/bloc/readings_detail_bloc.dart @@ -3,6 +3,7 @@ import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/models/reading_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/reading_services/reading_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'readings_detail_event.dart'; @@ -34,7 +35,10 @@ class ReadingsDetailBloc if (readingUpdatedRow != 1) { emit( - ReadingsDetailErrorState(errorMessage: 'Erro ao atualizar a leitura'), + ReadingsDetailErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: 'Error on updating reading', + ), ); return; } @@ -43,13 +47,15 @@ class ReadingsDetailBloc } on LocalDatabaseException catch (e) { emit( ReadingsDetailErrorState( - errorMessage: 'Erro no database: ${e.message}', + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, ), ); } catch (e) { emit( ReadingsDetailErrorState( - errorMessage: 'Ocorreu um erro não esperado: $e', + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), ), ); } @@ -69,7 +75,10 @@ class ReadingsDetailBloc if (bookUpdatedStatusRow != 1) { emit( - ReadingsDetailErrorState(errorMessage: 'Erro ao atualizar o livro'), + ReadingsDetailErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: 'Error on updating book status', + ), ); return; } @@ -80,7 +89,10 @@ class ReadingsDetailBloc if (readingDeletedRow != 1) { emit( - ReadingsDetailErrorState(errorMessage: 'Erro ao finalizar a leitura'), + ReadingsDetailErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: 'Error on deleting reading', + ), ); return; } @@ -89,13 +101,15 @@ class ReadingsDetailBloc } on LocalDatabaseException catch (e) { emit( ReadingsDetailErrorState( - errorMessage: 'Erro no database: ${e.message}', + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, ), ); } catch (e) { emit( ReadingsDetailErrorState( - errorMessage: 'Ocorreu um erro não esperado: $e', + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), ), ); } diff --git a/lib/src/features/readings_detail/bloc/readings_detail_state.dart b/lib/src/features/readings_detail/bloc/readings_detail_state.dart index 88506115..71631755 100644 --- a/lib/src/features/readings_detail/bloc/readings_detail_state.dart +++ b/lib/src/features/readings_detail/bloc/readings_detail_state.dart @@ -9,9 +9,11 @@ final class ReadingsDetailUpdatedState extends ReadingsDetailState {} final class ReadingsDetailFinishedState extends ReadingsDetailState {} final class ReadingsDetailErrorState extends ReadingsDetailState { - final String errorMessage; + final LocalDatabaseErrorCode errorCode; + final String? errorDescriptionMessage; ReadingsDetailErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/readings_detail/views/readings_detail_page.dart b/lib/src/features/readings_detail/views/readings_detail_page.dart index f69388c6..525a393b 100644 --- a/lib/src/features/readings_detail/views/readings_detail_page.dart +++ b/lib/src/features/readings_detail/views/readings_detail_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart'; import 'package:bookify/src/features/readings_detail/bloc/readings_detail_bloc.dart'; import 'package:bookify/src/features/readings_timer/views/readings_timer.page.dart'; import 'package:bookify/src/core/dtos/reading_dto.dart'; @@ -84,10 +85,13 @@ class _ReadingsDetailPageState extends State { ); break; - case ReadingsDetailErrorState(:final errorMessage): + case ReadingsDetailErrorState( + :final errorCode, + :final errorDescriptionMessage, + ): SnackbarService.showSnackBar( context, - errorMessage, + errorCode.toLocalizedMessage(errorDescriptionMessage), SnackBarType.error, ); @@ -201,7 +205,7 @@ class _ReadingsDetailPageState extends State { fontSize: 14, fontWeight: FontWeight.normal, ), - ) + ), ], ), ), @@ -278,7 +282,7 @@ class _ReadingsDetailPageState extends State { await _updateReadingOnPressedButton(); } }, - ) + ), ], ), ), diff --git a/lib/src/features/readings_insertion/bloc/readings_insertion_bloc.dart b/lib/src/features/readings_insertion/bloc/readings_insertion_bloc.dart index 8dd5f653..3fac7f61 100644 --- a/lib/src/features/readings_insertion/bloc/readings_insertion_bloc.dart +++ b/lib/src/features/readings_insertion/bloc/readings_insertion_bloc.dart @@ -3,6 +3,7 @@ import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/models/reading_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/reading_services/reading_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'readings_insertion_event.dart'; @@ -37,7 +38,9 @@ class ReadingsInsertionBloc if (bookPageCountUpdated != 1) { emit( ReadingsInsertionErrorState( - errorMessage: 'Ocorreu um erro ao atualizar as páginas do livro.', + errorCode: LocalDatabaseErrorCode.operationFailed, + errorDescriptionMessage: + 'An error occurred while updating the book page count.', ), ); return; @@ -51,7 +54,9 @@ class ReadingsInsertionBloc if (bookStatusUpdated != 1) { emit( ReadingsInsertionErrorState( - errorMessage: 'Ocorreu um erro ao atualizar o livro.', + errorCode: LocalDatabaseErrorCode.operationFailed, + errorDescriptionMessage: + 'An error occurred while updating the book status.', ), ); return; @@ -67,19 +72,29 @@ class ReadingsInsertionBloc if (newReadingId < 1) { emit( ReadingsInsertionErrorState( - errorMessage: 'Ocorreu um erro ao inserir a leitura.', + errorCode: LocalDatabaseErrorCode.operationFailed, + errorDescriptionMessage: + 'An error occurred while inserting the reading.', ), ); return; } - emit(ReadingsInsertionInsertedState()); + emit(ReadingsInsertionInsertedState()); } on LocalDatabaseException catch (e) { - emit(ReadingsInsertionErrorState( - errorMessage: 'Ocorreu um erro no database: ${e.message}')); + emit( + ReadingsInsertionErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); } on Exception catch (e) { - emit(ReadingsInsertionErrorState( - errorMessage: 'Ocorreu um erro não esperado: $e')); + emit( + ReadingsInsertionErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } } diff --git a/lib/src/features/readings_insertion/bloc/readings_insertion_state.dart b/lib/src/features/readings_insertion/bloc/readings_insertion_state.dart index bfe7b09a..da94519e 100644 --- a/lib/src/features/readings_insertion/bloc/readings_insertion_state.dart +++ b/lib/src/features/readings_insertion/bloc/readings_insertion_state.dart @@ -7,9 +7,11 @@ final class ReadingsInsertionLoadingState extends ReadingsInsertionState {} final class ReadingsInsertionInsertedState extends ReadingsInsertionState {} final class ReadingsInsertionErrorState extends ReadingsInsertionState { - final String errorMessage; + final LocalDatabaseErrorCode errorCode; + final String? errorDescriptionMessage; ReadingsInsertionErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/readings_insertion/views/readings_insertion_page.dart b/lib/src/features/readings_insertion/views/readings_insertion_page.dart index 1319f304..60ba1d89 100644 --- a/lib/src/features/readings_insertion/views/readings_insertion_page.dart +++ b/lib/src/features/readings_insertion/views/readings_insertion_page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/local_database_error_code/local_database_error_code_extension.dart'; import 'package:bookify/src/features/readings_insertion/bloc/readings_insertion_bloc.dart'; import 'package:bookify/src/core/helpers/textfield_unfocus/textfield_unfocus_extension.dart'; import 'package:bookify/src/core/models/book_model.dart'; @@ -82,10 +83,13 @@ class _ReadingsInsertionPageState extends State { }, ); break; - case ReadingsInsertionErrorState(:final errorMessage): + case ReadingsInsertionErrorState( + :final errorCode, + :final errorDescriptionMessage, + ): SnackbarService.showSnackBar( context, - errorMessage, + errorCode.toLocalizedMessage(errorDescriptionMessage), SnackBarType.error, ); @@ -167,7 +171,7 @@ class _ReadingsInsertionPageState extends State { 1, 2000, 'enter-pages-between-1-and-2000'.i18n(), - ) + ), ], ), onTapOutside: (_) => context.unfocus(), diff --git a/lib/src/features/readings_timer/bloc/readings_timer_bloc.dart b/lib/src/features/readings_timer/bloc/readings_timer_bloc.dart index 79c011b8..b1619517 100644 --- a/lib/src/features/readings_timer/bloc/readings_timer_bloc.dart +++ b/lib/src/features/readings_timer/bloc/readings_timer_bloc.dart @@ -1,5 +1,6 @@ import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/repositories/user_hour_time_repository/user_hour_time_repository.dart'; +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; part 'readings_timer_event.dart'; @@ -9,7 +10,7 @@ class ReadingsTimerBloc extends Bloc { final UserHourTimeRepository _userHourTimeRepository; ReadingsTimerBloc(this._userHourTimeRepository) - : super(ReadingsTimerLoadingState()) { + : super(ReadingsTimerLoadingState()) { on(_gotReadingsUserTimerEvent); } @@ -37,13 +38,15 @@ class ReadingsTimerBloc extends Bloc { } on StorageException catch (e) { emit( ReadingsTimerErrorState( - errorMessage: 'Erro ao buscar a hora do timer: $e', + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, ), ); } on Exception catch (e) { emit( ReadingsTimerErrorState( - errorMessage: 'Erro inesperado: $e', + errorCode: StorageErrorCode.unknown, + errorDescriptionMessage: e.toString(), ), ); } diff --git a/lib/src/features/readings_timer/bloc/readings_timer_state.dart b/lib/src/features/readings_timer/bloc/readings_timer_state.dart index 04d2e4a0..b6aaea85 100644 --- a/lib/src/features/readings_timer/bloc/readings_timer_state.dart +++ b/lib/src/features/readings_timer/bloc/readings_timer_state.dart @@ -15,9 +15,11 @@ final class ReadingsTimerLoadedState extends ReadingsTimerState { } final class ReadingsTimerErrorState extends ReadingsTimerState { - final String errorMessage; + final StorageErrorCode errorCode; + final String? errorDescriptionMessage; ReadingsTimerErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/features/readings_timer/views/readings_timer.page.dart b/lib/src/features/readings_timer/views/readings_timer.page.dart index a8eb08f1..f33f6bb4 100644 --- a/lib/src/features/readings_timer/views/readings_timer.page.dart +++ b/lib/src/features/readings_timer/views/readings_timer.page.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/storage_error_code/storage_error_code_extension.dart'; import 'package:bookify/src/features/readings_timer/bloc/readings_timer_bloc.dart'; import 'package:bookify/src/core/dtos/reading_dto.dart'; import 'package:bookify/src/features/readings_timer/views/widgets/readings_timer_widget.dart'; @@ -39,16 +40,18 @@ class _ReadingsTimerPageState extends State { return switch (state) { ReadingsTimerLoadingState() => const CenterCircularProgressIndicator(), ReadingsTimerEmptyState() || - ReadingsTimerLoadedState() => - ReadingsTimerWidget( - readingDto: widget.readingDto, - timerDurationInSeconds: state is ReadingsTimerLoadedState - ? state.initialUserTimerInSeconds - : 300, - ), - ReadingsTimerErrorState(:final errorMessage) => + ReadingsTimerLoadedState() => ReadingsTimerWidget( + readingDto: widget.readingDto, + timerDurationInSeconds: state is ReadingsTimerLoadedState + ? state.initialUserTimerInSeconds + : 300, + ), + ReadingsTimerErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => InfoItemStateWidget.withErrorState( - message: errorMessage, + message: errorCode.toLocalizedMessage(errorDescriptionMessage), onPressed: _onRefreshPage, ), }; diff --git a/lib/src/features/root/views/root_page.dart b/lib/src/features/root/views/root_page.dart index 51b55b59..876e1c7d 100644 --- a/lib/src/features/root/views/root_page.dart +++ b/lib/src/features/root/views/root_page.dart @@ -76,10 +76,12 @@ class _RootPageState extends State { } Future _scanAndGetIsbnCode(BuildContext context) async { - final isbn = await Navigator.pushNamed( - context, - QrCodeScannerPage.routeName, - ) as String?; + final isbn = + await Navigator.pushNamed( + context, + QrCodeScannerPage.routeName, + ) + as String?; if (isbn != null) { _bookBloc.add(FoundBooksByIsbnEvent(isbn: isbn)); diff --git a/lib/src/features/settings/views/widgets/theme_settings.dart b/lib/src/features/settings/views/widgets/theme_settings.dart index 1336979a..44bf6bce 100644 --- a/lib/src/features/settings/views/widgets/theme_settings.dart +++ b/lib/src/features/settings/views/widgets/theme_settings.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/core/helpers/error_code/storage_error_code/storage_error_code_extension.dart'; import 'package:bookify/src/features/settings/views/widgets/settings_container.dart'; import 'package:bookify/src/shared/cubits/user_theme_cubit/user_theme_cubit.dart'; import 'package:bookify/src/shared/widgets/center_circular_progress_indicator/center_circular_progress_indicator.dart'; @@ -25,55 +26,59 @@ class _ThemeSettingsState extends State { return switch (state) { UserThemeLoadingState() => const CenterCircularProgressIndicator(), UserThemeLoadedState(:final themeMode) => SingleChildScrollView( - scrollDirection: Axis.horizontal, - child: RadioGroup( - groupValue: themeMode, - onChanged: _onChangedRadioButton, - child: Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Text( - 'light-theme-label'.i18n(), - overflow: TextOverflow.ellipsis, - textScaler: TextScaler.noScaling, - style: TextStyle( - fontSize: 10, - color: Theme.of(context).colorScheme.primary, - ), + scrollDirection: Axis.horizontal, + child: RadioGroup( + groupValue: themeMode, + onChanged: _onChangedRadioButton, + child: Row( + mainAxisAlignment: MainAxisAlignment.center, + children: [ + Text( + 'light-theme-label'.i18n(), + overflow: TextOverflow.ellipsis, + textScaler: TextScaler.noScaling, + style: TextStyle( + fontSize: 10, + color: Theme.of(context).colorScheme.primary, ), - Radio.adaptive( - value: ThemeMode.light, + ), + Radio.adaptive( + value: ThemeMode.light, + ), + Text( + 'dark-theme-label'.i18n(), + overflow: TextOverflow.ellipsis, + textScaler: TextScaler.noScaling, + style: TextStyle( + fontSize: 10, + color: Theme.of(context).colorScheme.primary, ), - Text( - 'dark-theme-label'.i18n(), - overflow: TextOverflow.ellipsis, - textScaler: TextScaler.noScaling, - style: TextStyle( - fontSize: 10, - color: Theme.of(context).colorScheme.primary, - ), + ), + Radio.adaptive( + value: ThemeMode.dark, + ), + Text( + 'system-theme-label'.i18n(), + overflow: TextOverflow.ellipsis, + textScaler: TextScaler.noScaling, + style: TextStyle( + fontSize: 10, + color: Theme.of(context).colorScheme.primary, ), - Radio.adaptive( - value: ThemeMode.dark, - ), - Text( - 'system-theme-label'.i18n(), - overflow: TextOverflow.ellipsis, - textScaler: TextScaler.noScaling, - style: TextStyle( - fontSize: 10, - color: Theme.of(context).colorScheme.primary, - ), - ), - Radio.adaptive( - value: ThemeMode.system, - ), - ], - ), + ), + Radio.adaptive( + value: ThemeMode.system, + ), + ], ), ), - UserThemeErrorState(:final errorMessage) => Text( - errorMessage, + ), + UserThemeErrorState( + :final errorCode, + :final errorDescriptionMessage, + ) => + Text( + errorCode.toLocalizedMessage(errorDescriptionMessage), style: const TextStyle( fontSize: 14, ), diff --git a/lib/src/features/settings/views/widgets/widgets.dart b/lib/src/features/settings/views/widgets/widgets.dart index cfd89194..18378688 100644 --- a/lib/src/features/settings/views/widgets/widgets.dart +++ b/lib/src/features/settings/views/widgets/widgets.dart @@ -1,3 +1,3 @@ export 'package:bookify/src/features/settings/views/widgets/theme_settings.dart'; export 'package:bookify/src/features/settings/views/widgets/time_reading_settings.dart'; -export 'package:bookify/src/features/settings/views/widgets/hour_reading_settings.dart'; \ No newline at end of file +export 'package:bookify/src/features/settings/views/widgets/hour_reading_settings.dart'; diff --git a/lib/src/features/time_picker/views/time_picker_page.dart b/lib/src/features/time_picker/views/time_picker_page.dart index 39082d69..50522448 100644 --- a/lib/src/features/time_picker/views/time_picker_page.dart +++ b/lib/src/features/time_picker/views/time_picker_page.dart @@ -80,56 +80,58 @@ class _TimePickerPageState extends State { Widget build(BuildContext context) { return Scaffold( appBar: AppBar(), - body: LayoutBuilder(builder: (context, constraints) { - final isSmallDevice = constraints.biggest.isSmallDevice(); + body: LayoutBuilder( + builder: (context, constraints) { + final isSmallDevice = constraints.biggest.isSmallDevice(); - return SingleChildScrollView( - child: SizedBox( - height: isSmallDevice - ? MediaQuery.sizeOf(context).height - : constraints.biggest.height, - child: Padding( - padding: const EdgeInsets.symmetric( - vertical: 16.0, - horizontal: 30.0, - ), - child: Column( - children: [ - const SizedBox( - height: 10, - ), - TimePickerWidget( - onTimeSelected: (TimeOfDay time) { - setState(() { - startingTime = time; - }); - }, - hour: startingTime.hour, - minute: startingTime.minute, - ), - const Text('|'), - Text('to-time'.i18n()), - const Text('|'), - TimePickerWidget( - onTimeSelected: (TimeOfDay time) { - setState(() { - endingTime = time; - }); - }, - hour: endingTime.hour, - minute: endingTime.minute, - ), - const Spacer(), - BookifyOutlinedButton.expanded( - text: 'define-return-button'.i18n(), - onPressed: _defineTimer, - ) - ], + return SingleChildScrollView( + child: SizedBox( + height: isSmallDevice + ? MediaQuery.sizeOf(context).height + : constraints.biggest.height, + child: Padding( + padding: const EdgeInsets.symmetric( + vertical: 16.0, + horizontal: 30.0, + ), + child: Column( + children: [ + const SizedBox( + height: 10, + ), + TimePickerWidget( + onTimeSelected: (TimeOfDay time) { + setState(() { + startingTime = time; + }); + }, + hour: startingTime.hour, + minute: startingTime.minute, + ), + const Text('|'), + Text('to-time'.i18n()), + const Text('|'), + TimePickerWidget( + onTimeSelected: (TimeOfDay time) { + setState(() { + endingTime = time; + }); + }, + hour: endingTime.hour, + minute: endingTime.minute, + ), + const Spacer(), + BookifyOutlinedButton.expanded( + text: 'define-return-button'.i18n(), + onPressed: _defineTimer, + ), + ], + ), ), ), - ), - ); - }), + ); + }, + ), ); } } diff --git a/lib/src/features/time_picker/views/widgets/time_picker_widget.dart b/lib/src/features/time_picker/views/widgets/time_picker_widget.dart index fc8cce3f..97af8531 100644 --- a/lib/src/features/time_picker/views/widgets/time_picker_widget.dart +++ b/lib/src/features/time_picker/views/widgets/time_picker_widget.dart @@ -118,7 +118,7 @@ class TimePickerWidget extends StatelessWidget { ), ), ], - ) + ), ], ), ), diff --git a/lib/src/shared/blocs/book_bloc/book_bloc.dart b/lib/src/shared/blocs/book_bloc/book_bloc.dart index d998af52..3ed1b9f0 100644 --- a/lib/src/shared/blocs/book_bloc/book_bloc.dart +++ b/lib/src/shared/blocs/book_bloc/book_bloc.dart @@ -1,5 +1,5 @@ -import 'dart:io'; - +import 'package:bookify/src/shared/enums/rest_client_error_code.dart'; +import 'package:bookify/src/core/errors/rest_client_exception/rest_client_exception.dart'; import 'package:bookify/src/core/repositories/remote_books_repository/remote_books_repository.dart'; import 'package:bookify/src/core/utils/verifier/isbn_verifier.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; @@ -36,10 +36,20 @@ class BookBloc extends Bloc { } emit(BooksLoadedState(books: books)); - } on SocketException catch (socketException) { - emit(BookErrorSate(errorMessage: socketException.message)); - } on Exception catch (e) { - emit(BookErrorSate(errorMessage: e.toString())); + } on RestClientException catch (e) { + emit( + BookErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); + } catch (e) { + emit( + BookErrorState( + errorCode: RestClientErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } @@ -57,10 +67,20 @@ class BookBloc extends Bloc { return; } emit(BooksLoadedState(books: books)); - } on SocketException catch (socketException) { - emit(BookErrorSate(errorMessage: socketException.message)); - } on Exception catch (e) { - emit(BookErrorSate(errorMessage: e.toString())); + } on RestClientException catch (e) { + emit( + BookErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); + } catch (e) { + emit( + BookErrorState( + errorCode: RestClientErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } @@ -71,8 +91,9 @@ class BookBloc extends Bloc { try { emit(BooksLoadingState()); - final books = - await _booksRepository.findBooksByAuthor(author: event.author); + final books = await _booksRepository.findBooksByAuthor( + author: event.author, + ); if (books.isEmpty) { emit(BookEmptyState()); @@ -80,10 +101,20 @@ class BookBloc extends Bloc { } emit(BooksLoadedState(books: books)); - } on SocketException catch (socketException) { - emit(BookErrorSate(errorMessage: socketException.message)); - } on Exception catch (e) { - emit(BookErrorSate(errorMessage: e.toString())); + } on RestClientException catch (e) { + emit( + BookErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); + } catch (e) { + emit( + BookErrorState( + errorCode: RestClientErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } @@ -94,8 +125,9 @@ class BookBloc extends Bloc { try { emit(BooksLoadingState()); - final books = - await _booksRepository.findBooksByCategory(category: event.category); + final books = await _booksRepository.findBooksByCategory( + category: event.category, + ); if (books.isEmpty) { emit(BookEmptyState()); @@ -103,10 +135,20 @@ class BookBloc extends Bloc { } emit(BooksLoadedState(books: books)); - } on SocketException catch (socketException) { - emit(BookErrorSate(errorMessage: socketException.message)); - } on Exception catch (e) { - emit(BookErrorSate(errorMessage: e.toString())); + } on RestClientException catch (e) { + emit( + BookErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); + } catch (e) { + emit( + BookErrorState( + errorCode: RestClientErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } @@ -118,7 +160,8 @@ class BookBloc extends Bloc { emit(BooksLoadingState()); final books = await _booksRepository.findBooksByPublisher( - publisher: event.publisher); + publisher: event.publisher, + ); if (books.isEmpty) { emit(BookEmptyState()); @@ -126,10 +169,20 @@ class BookBloc extends Bloc { } emit(BooksLoadedState(books: books)); - } on SocketException catch (socketException) { - emit(BookErrorSate(errorMessage: socketException.message)); - } on Exception catch (e) { - emit(BookErrorSate(errorMessage: e.toString())); + } on RestClientException catch (e) { + emit( + BookErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); + } catch (e) { + emit( + BookErrorState( + errorCode: RestClientErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } @@ -143,7 +196,12 @@ class BookBloc extends Bloc { final verifier = IsbnVerifier(); String? isbn = verifier.verifyIsbn(event.isbn); if (isbn == null) { - emit(BookErrorSate(errorMessage: 'Digite um ISBN Válido')); + emit( + BookErrorState( + errorCode: RestClientErrorCode.invalidInput, + errorDescriptionMessage: 'Invalid ISBN provided', + ), + ); return; } @@ -155,10 +213,20 @@ class BookBloc extends Bloc { } emit(BooksLoadedState(books: books)); - } on SocketException catch (socketException) { - emit(BookErrorSate(errorMessage: socketException.message)); - } on Exception catch (e) { - emit(BookErrorSate(errorMessage: e.toString())); + } on RestClientException catch (e) { + emit( + BookErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); + } catch (e) { + emit( + BookErrorState( + errorCode: RestClientErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); } } } diff --git a/lib/src/shared/blocs/book_bloc/book_state.dart b/lib/src/shared/blocs/book_bloc/book_state.dart index a2aa32ce..5067d9cd 100644 --- a/lib/src/shared/blocs/book_bloc/book_state.dart +++ b/lib/src/shared/blocs/book_bloc/book_state.dart @@ -14,10 +14,12 @@ final class BooksLoadedState extends BookState { }); } -final class BookErrorSate extends BookState { - final String errorMessage; +final class BookErrorState extends BookState { + final RestClientErrorCode errorCode; + final String? errorDescriptionMessage; - BookErrorSate({ - required this.errorMessage, + BookErrorState({ + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/shared/constants/audios/bookify_audios.dart b/lib/src/shared/constants/audios/bookify_audios.dart index dc108ae8..fcc9b460 100644 --- a/lib/src/shared/constants/audios/bookify_audios.dart +++ b/lib/src/shared/constants/audios/bookify_audios.dart @@ -1,7 +1,6 @@ - class BookifyAudios { BookifyAudios._(); /// Audio for timer ![](bookify/assets/audios/timer.mp3) static const timerAudio = 'assets/audios/timer.mp3'; -} \ No newline at end of file +} diff --git a/lib/src/shared/constants/database_scripts/database_scripts.dart b/lib/src/shared/constants/database_scripts/database_scripts.dart index 2c07e8c6..7da40777 100644 --- a/lib/src/shared/constants/database_scripts/database_scripts.dart +++ b/lib/src/shared/constants/database_scripts/database_scripts.dart @@ -2,7 +2,7 @@ class DatabaseScripts { ///Get the name of database : bookify.db String get databaseName => _databaseName; -//Table Names Getters + //Table Names Getters String get bookTableName => _bookTableName; String get authorTableName => _authorTableName; String get categoryTableName => _categoryTableName; @@ -13,7 +13,7 @@ class DatabaseScripts { String get bookcaseTableName => _bookcaseTableName; String get bookOnCaseTableName => _bookOnCaseTableName; -//Tables Scripts Getters + //Tables Scripts Getters /// Create a table for [BookModel] String get bookScript => _bookScript; @@ -58,7 +58,8 @@ class DatabaseScripts { static const String _bookcaseTableName = 'bookcase'; static const String _bookOnCaseTableName = 'bookOnCase'; - static const String _bookScript = ''' + static const String _bookScript = + ''' CREATE TABLE $_bookTableName ( id TEXT UNIQUE NOT NULL PRIMARY KEY, title TEXT NOT NULL, @@ -73,21 +74,24 @@ class DatabaseScripts { ) '''; - static const String _authorScript = ''' + static const String _authorScript = + ''' CREATE TABLE $_authorTableName ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE NOT NULL ) '''; - static const String _categoryScript = ''' + static const String _categoryScript = + ''' CREATE TABLE $_categoryTableName ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE NOT NULL ) '''; - static const String _bookAuthorsScript = ''' + static const String _bookAuthorsScript = + ''' CREATE TABLE $_bookAuthorsTableName ( bookId TEXT NOT NULL, authorId INTEGER NOT NULL, @@ -97,7 +101,8 @@ class DatabaseScripts { ) '''; - static const String _bookCategoriesScript = ''' + static const String _bookCategoriesScript = + ''' CREATE TABLE $_bookCategoriesTableName ( bookId TEXT NOT NULL, categoryId INTEGER NOT NULL, @@ -107,7 +112,8 @@ class DatabaseScripts { ) '''; - static const String _bookReadingScript = ''' + static const String _bookReadingScript = + ''' CREATE TABLE $_bookReadingTableName ( id INTEGER PRIMARY KEY AUTOINCREMENT, pagesReaded INTEGER NOT NULL, @@ -117,7 +123,8 @@ class DatabaseScripts { ) '''; - static const String _loanScript = ''' + static const String _loanScript = + ''' CREATE TABLE $_loanTableName ( id INTEGER PRIMARY KEY AUTOINCREMENT, observation TEXT, @@ -129,7 +136,8 @@ class DatabaseScripts { ) '''; - static const String _bookCaseScript = ''' + static const String _bookCaseScript = + ''' CREATE TABLE $_bookcaseTableName ( id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT UNIQUE NOT NULL, @@ -138,7 +146,8 @@ class DatabaseScripts { ) '''; - static const String _bookOnCaseScript = ''' + static const String _bookOnCaseScript = + ''' CREATE TABLE $_bookOnCaseTableName ( bookId TEXT NOT NULL, bookcaseId INTEGER NOT NULL, diff --git a/lib/src/shared/constants/icons/bookify_icons.dart b/lib/src/shared/constants/icons/bookify_icons.dart index 10c7c55b..9b367083 100644 --- a/lib/src/shared/constants/icons/bookify_icons.dart +++ b/lib/src/shared/constants/icons/bookify_icons.dart @@ -14,12 +14,24 @@ class BookifyIcons { static const _kFontFam = 'BookifyIcons'; static const String? _kFontPkg = null; - static const IconData qr_code = - IconData(0xe800, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData bookcase = - IconData(0xe801, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData bookcase_outlined = - IconData(0xe802, fontFamily: _kFontFam, fontPackage: _kFontPkg); - static const IconData isbn = - IconData(0xe803, fontFamily: _kFontFam, fontPackage: _kFontPkg); + static const IconData qr_code = IconData( + 0xe800, + fontFamily: _kFontFam, + fontPackage: _kFontPkg, + ); + static const IconData bookcase = IconData( + 0xe801, + fontFamily: _kFontFam, + fontPackage: _kFontPkg, + ); + static const IconData bookcase_outlined = IconData( + 0xe802, + fontFamily: _kFontFam, + fontPackage: _kFontPkg, + ); + static const IconData isbn = IconData( + 0xe803, + fontFamily: _kFontFam, + fontPackage: _kFontPkg, + ); } diff --git a/lib/src/shared/cubits/user_logged_cubit/user_logged_cubit.dart b/lib/src/shared/cubits/user_logged_cubit/user_logged_cubit.dart new file mode 100644 index 00000000..ef16581a --- /dev/null +++ b/lib/src/shared/cubits/user_logged_cubit/user_logged_cubit.dart @@ -0,0 +1,41 @@ +import 'package:bookify/src/shared/enums/auth_error_code.dart'; +import 'package:bookify/src/core/errors/auth_exception/auth_exception.dart'; +import 'package:bookify/src/core/services/auth_service/auth_service.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +part 'user_logged_state.dart'; + +class UserLoggedCubit extends Cubit { + final AuthService _authService; + + UserLoggedCubit( + this._authService, + ) : super(UserLoggedLoadingState()); + + Future checkAuthStatus() async { + try { + emit(UserLoggedLoadingState()); + + final isLoggedIn = await _authService.userIsLoggedIn(); + + emit( + UserLoggedLoadedState(isLoggedIn: isLoggedIn), + ); + } on AuthException catch (e) { + emit( + UserLoggedErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); + } on Exception catch (e) { + emit( + UserLoggedErrorState( + errorCode: AuthErrorCode.internalError, + errorDescriptionMessage: e.toString(), + ), + ); + } + } +} diff --git a/lib/src/shared/cubits/user_logged_cubit/user_logged_state.dart b/lib/src/shared/cubits/user_logged_cubit/user_logged_state.dart new file mode 100644 index 00000000..490c0bc6 --- /dev/null +++ b/lib/src/shared/cubits/user_logged_cubit/user_logged_state.dart @@ -0,0 +1,24 @@ +part of 'user_logged_cubit.dart'; + +@immutable +sealed class UserLoggedState {} + +final class UserLoggedLoadingState extends UserLoggedState {} + +final class UserLoggedLoadedState extends UserLoggedState { + final bool isLoggedIn; + + UserLoggedLoadedState({ + required this.isLoggedIn, + }); +} + +final class UserLoggedErrorState extends UserLoggedState { + final AuthErrorCode errorCode; + final String? errorDescriptionMessage; + + UserLoggedErrorState({ + required this.errorCode, + this.errorDescriptionMessage, + }); +} diff --git a/lib/src/shared/cubits/user_notification_cubit/user_notification_cubit.dart b/lib/src/shared/cubits/user_notification_cubit/user_notification_cubit.dart new file mode 100644 index 00000000..802bdce5 --- /dev/null +++ b/lib/src/shared/cubits/user_notification_cubit/user_notification_cubit.dart @@ -0,0 +1,39 @@ +import 'package:bookify/src/core/errors/platform_exception/platform_exception.dart'; +import 'package:bookify/src/core/services/app_services/notifications_service/notifications_service.dart'; +import 'package:bookify/src/shared/enums/platform_error_code.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +part 'user_notification_state.dart'; + +class UserNotificationCubit extends Cubit { + final NotificationsService _notificationsService; + + UserNotificationCubit( + this._notificationsService, + ) : super(UserNotificationLoadingState()); + + Future initializeNotifications() async { + try { + emit(UserNotificationLoadingState()); + + await _notificationsService.checkForNotifications(); + + emit(UserNotificationLoadedState()); + } on PlatformException catch (e) { + emit( + UserNotificationErrorState( + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, + ), + ); + } on Exception catch (e) { + emit( + UserNotificationErrorState( + errorCode: PlatformErrorCode.unknown, + errorDescriptionMessage: e.toString(), + ), + ); + } + } +} diff --git a/lib/src/shared/cubits/user_notification_cubit/user_notification_state.dart b/lib/src/shared/cubits/user_notification_cubit/user_notification_state.dart new file mode 100644 index 00000000..8ca85705 --- /dev/null +++ b/lib/src/shared/cubits/user_notification_cubit/user_notification_state.dart @@ -0,0 +1,18 @@ +part of 'user_notification_cubit.dart'; + +@immutable +sealed class UserNotificationState {} + +final class UserNotificationLoadingState extends UserNotificationState {} + +final class UserNotificationLoadedState extends UserNotificationState {} + +final class UserNotificationErrorState extends UserNotificationState { + final PlatformErrorCode errorCode; + final String? errorDescriptionMessage; + + UserNotificationErrorState({ + required this.errorCode, + this.errorDescriptionMessage, + }); +} diff --git a/lib/src/shared/cubits/user_theme_cubit/user_theme_cubit.dart b/lib/src/shared/cubits/user_theme_cubit/user_theme_cubit.dart index e8c5608b..c550e9a0 100644 --- a/lib/src/shared/cubits/user_theme_cubit/user_theme_cubit.dart +++ b/lib/src/shared/cubits/user_theme_cubit/user_theme_cubit.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/repositories/user_theme_repository/user_theme_repository.dart'; import 'package:flutter/material.dart'; @@ -34,13 +35,15 @@ class UserThemeCubit extends Cubit { } on StorageException catch (e) { emit( UserThemeErrorState( - errorMessage: 'erro ao buscar o tema: $e', + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, ), ); } on Exception catch (e) { emit( UserThemeErrorState( - errorMessage: 'Erro inesperado: $e', + errorCode: StorageErrorCode.unknown, + errorDescriptionMessage: e.toString(), ), ); } @@ -57,7 +60,8 @@ class UserThemeCubit extends Cubit { if (themeInserted == 0) { emit( UserThemeErrorState( - errorMessage: 'erro ao inserir o tema', + errorCode: StorageErrorCode.writeFailed, + errorDescriptionMessage: 'Failed to save theme. Please try again.', ), ); return; @@ -69,13 +73,15 @@ class UserThemeCubit extends Cubit { } on StorageException catch (e) { emit( UserThemeErrorState( - errorMessage: 'erro ao inserir o tema: $e', + errorCode: e.code, + errorDescriptionMessage: e.descriptionMessage, ), ); } on Exception catch (e) { emit( UserThemeErrorState( - errorMessage: 'Erro inesperado: $e', + errorCode: StorageErrorCode.unknown, + errorDescriptionMessage: e.toString(), ), ); } diff --git a/lib/src/shared/cubits/user_theme_cubit/user_theme_state.dart b/lib/src/shared/cubits/user_theme_cubit/user_theme_state.dart index bfdef307..9f3423a1 100644 --- a/lib/src/shared/cubits/user_theme_cubit/user_theme_state.dart +++ b/lib/src/shared/cubits/user_theme_cubit/user_theme_state.dart @@ -14,9 +14,11 @@ final class UserThemeLoadedState extends UserThemeState { } final class UserThemeErrorState extends UserThemeState { - final String errorMessage; + final StorageErrorCode errorCode; + final String? errorDescriptionMessage; UserThemeErrorState({ - required this.errorMessage, + required this.errorCode, + this.errorDescriptionMessage, }); } diff --git a/lib/src/shared/enums/auth_error_code.dart b/lib/src/shared/enums/auth_error_code.dart new file mode 100644 index 00000000..d9450e3e --- /dev/null +++ b/lib/src/shared/enums/auth_error_code.dart @@ -0,0 +1,11 @@ +enum AuthErrorCode { + userNotFound, + wrongPassword, + invalidEmail, + accountDisabled, + tooManyRequests, + operationNotAllowed, + networkRequestFailed, + internalError, + unknown, +} diff --git a/lib/src/shared/enums/local_database_error_code.dart b/lib/src/shared/enums/local_database_error_code.dart new file mode 100644 index 00000000..8abb8f08 --- /dev/null +++ b/lib/src/shared/enums/local_database_error_code.dart @@ -0,0 +1,8 @@ +enum LocalDatabaseErrorCode { + uniqueConstraint, + notNullConstraint, + openFailed, + conversionFailed, + operationFailed, + unknown, +} diff --git a/lib/src/shared/enums/platform_error_code.dart b/lib/src/shared/enums/platform_error_code.dart new file mode 100644 index 00000000..8afe7a7c --- /dev/null +++ b/lib/src/shared/enums/platform_error_code.dart @@ -0,0 +1,6 @@ +enum PlatformErrorCode { + permissionDenied, + permissionPermanentlyDenied, + unsupported, + unknown, +} diff --git a/lib/src/core/enums/repeat_hour_time_type.dart b/lib/src/shared/enums/repeat_hour_time_type.dart similarity index 100% rename from lib/src/core/enums/repeat_hour_time_type.dart rename to lib/src/shared/enums/repeat_hour_time_type.dart diff --git a/lib/src/shared/enums/rest_client_error_code.dart b/lib/src/shared/enums/rest_client_error_code.dart new file mode 100644 index 00000000..4cd4a0b0 --- /dev/null +++ b/lib/src/shared/enums/rest_client_error_code.dart @@ -0,0 +1,8 @@ +enum RestClientErrorCode { + connectionTimeout, + receiveTimeout, + notFound, + invalidInput, + socketException, + unknown, +} diff --git a/lib/src/shared/enums/sign_in_type.dart b/lib/src/shared/enums/sign_in_type.dart index b0b7a562..6dc02a07 100644 --- a/lib/src/shared/enums/sign_in_type.dart +++ b/lib/src/shared/enums/sign_in_type.dart @@ -1,8 +1,7 @@ enum SignInType { google, apple, - facebook - ; + facebook; static SignInType toType(int value) { return switch (value) { diff --git a/lib/src/shared/enums/storage_error_code.dart b/lib/src/shared/enums/storage_error_code.dart new file mode 100644 index 00000000..8662ddc3 --- /dev/null +++ b/lib/src/shared/enums/storage_error_code.dart @@ -0,0 +1,6 @@ +enum StorageErrorCode { + invalidValue, + writeFailed, + readFailed, + unknown, +} diff --git a/lib/src/shared/providers/blocs/blocs_providers.dart b/lib/src/shared/providers/blocs/blocs_providers.dart index 70ba153b..13531df9 100644 --- a/lib/src/shared/providers/blocs/blocs_providers.dart +++ b/lib/src/shared/providers/blocs/blocs_providers.dart @@ -1,4 +1,6 @@ -export 'package:bookify/src/shared/providers/blocs/user_theme_bloc_providers.dart'; +export 'package:bookify/src/shared/providers/blocs/user_theme_cubit_providers.dart'; +export 'package:bookify/src/shared/providers/blocs/user_logged_cubit_providers.dart'; +export 'package:bookify/src/shared/providers/blocs/user_notification_cubit_providers.dart'; export 'package:bookify/src/shared/providers/blocs/user_information_bloc_providers.dart'; export 'package:bookify/src/shared/providers/blocs/auth_bloc_providers.dart'; export 'package:bookify/src/shared/providers/blocs/about_bloc_providers.dart'; diff --git a/lib/src/shared/providers/blocs/books_picker_bloc_providers.dart b/lib/src/shared/providers/blocs/books_picker_bloc_providers.dart index 38d1138d..690141f9 100644 --- a/lib/src/shared/providers/blocs/books_picker_bloc_providers.dart +++ b/lib/src/shared/providers/blocs/books_picker_bloc_providers.dart @@ -20,5 +20,5 @@ final booksPickerBlocProviders = [ create: (context) => SeparateBooksPickerBloc( context.read(), ), - ) + ), ]; diff --git a/lib/src/shared/providers/blocs/loan_bloc_providers.dart b/lib/src/shared/providers/blocs/loan_bloc_providers.dart index 3cae9be8..597838f3 100644 --- a/lib/src/shared/providers/blocs/loan_bloc_providers.dart +++ b/lib/src/shared/providers/blocs/loan_bloc_providers.dart @@ -9,4 +9,4 @@ final loanBlocProviders = [ context.read(), ), ), -]; \ No newline at end of file +]; diff --git a/lib/src/shared/providers/blocs/profile_bloc_providers.dart b/lib/src/shared/providers/blocs/profile_bloc_providers.dart index d65eb408..5fc12940 100644 --- a/lib/src/shared/providers/blocs/profile_bloc_providers.dart +++ b/lib/src/shared/providers/blocs/profile_bloc_providers.dart @@ -5,7 +5,6 @@ final profileBlocProviders = [ BlocProvider( create: (context) => ProfileBloc( context.read(), - context.read(), ), ), ]; diff --git a/lib/src/shared/providers/blocs/user_information_bloc_providers.dart b/lib/src/shared/providers/blocs/user_information_bloc_providers.dart index 6caa86a3..2f5f9591 100644 --- a/lib/src/shared/providers/blocs/user_information_bloc_providers.dart +++ b/lib/src/shared/providers/blocs/user_information_bloc_providers.dart @@ -10,4 +10,4 @@ final userInformationBlocProviders = [ context.read(), ), ), -]; \ No newline at end of file +]; diff --git a/lib/src/shared/providers/blocs/user_logged_cubit_providers.dart b/lib/src/shared/providers/blocs/user_logged_cubit_providers.dart new file mode 100644 index 00000000..e053e3e9 --- /dev/null +++ b/lib/src/shared/providers/blocs/user_logged_cubit_providers.dart @@ -0,0 +1,10 @@ +import 'package:bookify/src/shared/cubits/user_logged_cubit/user_logged_cubit.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +final userLoggedCubitProviders = [ + BlocProvider( + create: (context) => UserLoggedCubit( + context.read(), + ), + ), +]; diff --git a/lib/src/shared/providers/blocs/user_notification_cubit_providers.dart b/lib/src/shared/providers/blocs/user_notification_cubit_providers.dart new file mode 100644 index 00000000..aeb33e21 --- /dev/null +++ b/lib/src/shared/providers/blocs/user_notification_cubit_providers.dart @@ -0,0 +1,10 @@ +import 'package:bookify/src/shared/cubits/user_notification_cubit/user_notification_cubit.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +final userNotificationCubitProviders = [ + BlocProvider( + create: (context) => UserNotificationCubit( + context.read(), + ), + ), +]; diff --git a/lib/src/shared/providers/blocs/user_theme_bloc_providers.dart b/lib/src/shared/providers/blocs/user_theme_cubit_providers.dart similarity index 87% rename from lib/src/shared/providers/blocs/user_theme_bloc_providers.dart rename to lib/src/shared/providers/blocs/user_theme_cubit_providers.dart index 4adab0c7..3a11f7a4 100644 --- a/lib/src/shared/providers/blocs/user_theme_bloc_providers.dart +++ b/lib/src/shared/providers/blocs/user_theme_cubit_providers.dart @@ -1,7 +1,7 @@ import 'package:bookify/src/shared/cubits/user_theme_cubit/user_theme_cubit.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; -final userThemeBlocProviders = [ +final userThemeCubitProviders = [ BlocProvider( create: (context) => UserThemeCubit( context.read(), diff --git a/lib/src/shared/providers/providers.dart b/lib/src/shared/providers/providers.dart index 07d0e230..be7ba7d6 100644 --- a/lib/src/shared/providers/providers.dart +++ b/lib/src/shared/providers/providers.dart @@ -14,7 +14,9 @@ abstract class Providers { ...appServicesProviders, ...userSettingsServicesProviders, ...servicesProviders, - ...userThemeBlocProviders, + ...userThemeCubitProviders, + ...userLoggedCubitProviders, + ...userNotificationCubitProviders, ...userInformationBlocProviders, ...authBlocProviders, ...readingPageTimerBlocProviders, diff --git a/lib/src/shared/routes/routes.dart b/lib/src/shared/routes/routes.dart index 324c878b..3796f63f 100644 --- a/lib/src/shared/routes/routes.dart +++ b/lib/src/shared/routes/routes.dart @@ -45,19 +45,19 @@ abstract class Routes { ProgrammingReadingPage.routeName: (context) => const ProgrammingReadingPage(), TimePickerPage.routeName: (context) => TimePickerPage( - userHourTimeModel: - ModalRoute.of(context)!.settings.arguments as UserHourTimeModel?, - ), + userHourTimeModel: + ModalRoute.of(context)!.settings.arguments as UserHourTimeModel?, + ), NotificationsPage.routeName: (context) => const NotificationsPage(), RootPage.routeName: (context) => const RootPage(), BookDetailPage.routeName: (context) => BookDetailPage( - bookModel: ModalRoute.of(context)!.settings.arguments as BookModel, - ), + bookModel: ModalRoute.of(context)!.settings.arguments as BookModel, + ), QrCodeScannerPage.routeName: (context) => const QrCodeScannerPage(), BookcaseDetailPage.routeName: (context) => BookcaseDetailPage( - bookcaseModel: - ModalRoute.of(context)!.settings.arguments as BookcaseModel, - ), + bookcaseModel: + ModalRoute.of(context)!.settings.arguments as BookcaseModel, + ), BookOnBookcaseDetailPage.routeName: (context) { final arguments = ModalRoute.of(context)!.settings.arguments as List; @@ -82,17 +82,17 @@ abstract class Routes { ), LoanInsertionPage.routeName: (context) => const LoanInsertionPage(), LoanDetailPage.routeName: (context) => LoanDetailPage( - loanId: ModalRoute.of(context)!.settings.arguments as int, - ), + loanId: ModalRoute.of(context)!.settings.arguments as int, + ), ReadingsInsertionPage.routeName: (context) => ReadingsInsertionPage( - book: ModalRoute.of(context)!.settings.arguments as BookModel, - ), + book: ModalRoute.of(context)!.settings.arguments as BookModel, + ), ReadingsDetailPage.routeName: (context) => ReadingsDetailPage( - readingDto: ModalRoute.of(context)!.settings.arguments as ReadingDto, - ), + readingDto: ModalRoute.of(context)!.settings.arguments as ReadingDto, + ), ReadingsTimerPage.routeName: (context) => ReadingsTimerPage( - readingDto: ModalRoute.of(context)!.settings.arguments as ReadingDto, - ), + readingDto: ModalRoute.of(context)!.settings.arguments as ReadingDto, + ), ContactsPickerPage.routeName: (context) => const ContactsPickerPage(), BooksPickerPage.routeName: (context) => const BooksPickerPage(), SettingsPage.routeName: (context) => const SettingsPage(), diff --git a/lib/src/shared/theme/app_theme.dart b/lib/src/shared/theme/app_theme.dart index 7afd9d48..64f665b2 100644 --- a/lib/src/shared/theme/app_theme.dart +++ b/lib/src/shared/theme/app_theme.dart @@ -229,7 +229,8 @@ const _segmentedButtonTheme = SegmentedButtonThemeData( ), ), side: WidgetStatePropertyAll( - BorderSide(color: AppColor.bookifySecondaryColor)), + BorderSide(color: AppColor.bookifySecondaryColor), + ), iconColor: WidgetStatePropertyAll(AppColor.bookifySecondaryColor), ), ); @@ -258,12 +259,13 @@ final _sliderTheme = SliderThemeData( ); const _radioTheme = RadioThemeData( - fillColor: WidgetStatePropertyAll( - AppColor.bookifySecondaryColor, - ), - overlayColor: WidgetStatePropertyAll( - AppColor.bookifySecondaryColor, - )); + fillColor: WidgetStatePropertyAll( + AppColor.bookifySecondaryColor, + ), + overlayColor: WidgetStatePropertyAll( + AppColor.bookifySecondaryColor, + ), +); const _textButtonTheme = TextButtonThemeData( style: ButtonStyle( diff --git a/lib/src/shared/widgets/book_with_detail_widget/book_with_detail_widget.dart b/lib/src/shared/widgets/book_with_detail_widget/book_with_detail_widget.dart index 7f1a0a62..476755ad 100644 --- a/lib/src/shared/widgets/book_with_detail_widget/book_with_detail_widget.dart +++ b/lib/src/shared/widgets/book_with_detail_widget/book_with_detail_widget.dart @@ -31,7 +31,7 @@ class BookWithDetailWidget extends StatelessWidget { ), BookifyRatingWidget( averageRating: bookAverageRating, - ) + ), ], ), const SizedBox( diff --git a/lib/src/shared/widgets/bookcase_widget/bookcase_widget.dart b/lib/src/shared/widgets/bookcase_widget/bookcase_widget.dart index e2baf151..97521387 100644 --- a/lib/src/shared/widgets/bookcase_widget/bookcase_widget.dart +++ b/lib/src/shared/widgets/bookcase_widget/bookcase_widget.dart @@ -128,7 +128,7 @@ class BookcaseWidget extends StatelessWidget { style: const TextStyle(fontSize: 14), ), ), - ) + ), ], ), ), diff --git a/lib/src/shared/widgets/buttons/buttons.dart b/lib/src/shared/widgets/buttons/buttons.dart index 0a98c61b..1e94e883 100644 --- a/lib/src/shared/widgets/buttons/buttons.dart +++ b/lib/src/shared/widgets/buttons/buttons.dart @@ -1,2 +1,2 @@ export 'bookify_outlined_button.dart'; -export 'bookify_elevated_button.dart'; \ No newline at end of file +export 'bookify_elevated_button.dart'; diff --git a/lib/src/shared/widgets/floating_action_button/rectangle_floating_action_button.dart b/lib/src/shared/widgets/floating_action_button/rectangle_floating_action_button.dart index 5fa30d92..497a29a9 100644 --- a/lib/src/shared/widgets/floating_action_button/rectangle_floating_action_button.dart +++ b/lib/src/shared/widgets/floating_action_button/rectangle_floating_action_button.dart @@ -6,7 +6,8 @@ class _FloatingActionButtonAlignedCenterDockerLocation @override Offset getOffset(ScaffoldPrelayoutGeometry scaffoldGeometry) { - final double centerWidth = (scaffoldGeometry.scaffoldSize.width - + final double centerWidth = + (scaffoldGeometry.scaffoldSize.width - scaffoldGeometry.floatingActionButtonSize.width) / 2.0; diff --git a/lib/src/shared/widgets/list/selected_item_row/selected_item_row.dart b/lib/src/shared/widgets/list/selected_item_row/selected_item_row.dart index 2fdf545c..b952ee6a 100644 --- a/lib/src/shared/widgets/list/selected_item_row/selected_item_row.dart +++ b/lib/src/shared/widgets/list/selected_item_row/selected_item_row.dart @@ -27,16 +27,17 @@ class _SelectedItemRowState extends State { ( String selectedAllText, IconData selectedAllIcon, - ) _getAllIconButtonProperties() { + ) + _getAllIconButtonProperties() { return switch (_isSelectedAll) { true => ( - 'deselect-all-button'.i18n(), - Icons.deselect_rounded, - ), + 'deselect-all-button'.i18n(), + Icons.deselect_rounded, + ), false => ( - 'select-all-button'.i18n(), - Icons.select_all_rounded, - ), + 'select-all-button'.i18n(), + Icons.select_all_rounded, + ), }; } @@ -80,8 +81,9 @@ class _SelectedItemRowState extends State { IconButton( key: const Key('DeleteSelectedItemsButton'), onPressed: widget.onPressedDeleteButton, - tooltip: - 'delete-item-button-tooltip'.i18n([itemText.toLowerCase()]), + tooltip: 'delete-item-button-tooltip'.i18n([ + itemText.toLowerCase(), + ]), icon: const Icon(Icons.delete_rounded), ), ], diff --git a/pubspec.lock b/pubspec.lock index 2b4b5769..788129e3 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1057,26 +1057,26 @@ packages: dependency: "direct dev" description: name: patrol - sha256: "7825a6e96a8f0755f68eec600a91a08b19bd0975488a70885b3696f6b65ffc0f" + sha256: baebcc5e7dbd22ac6838512b7efdd432f33188ad5f3c4b3bfe00680c1bbef453 url: "https://pub.dev" source: hosted - version: "4.5.0" + version: "4.6.0" patrol_finders: dependency: transitive description: name: patrol_finders - sha256: "9970eac0669a90b20ec7e1bcaabd0475655655998068ca656f4df9f6ec84f336" + sha256: "915da1e63fe7fd024418ab30b2394b1c8d6e812ce25be7d0b11634202521f0a9" url: "https://pub.dev" source: hosted - version: "3.2.0" + version: "3.4.0" patrol_log: dependency: transitive description: name: patrol_log - sha256: a2360db165c34692665c0de146e5157887d6b584fdccca8f141f947a5acf1b2e + sha256: "16ab747b28621640115d9493138eae82a1d410a613857cb0caf9000ce62fc546" url: "https://pub.dev" source: hosted - version: "0.8.0" + version: "0.9.0" permission_handler: dependency: "direct main" description: diff --git a/pubspec.yaml b/pubspec.yaml index f528998a..7b371c09 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -3,7 +3,7 @@ description: A Flutter project that helps you search for books, add them to your publish_to: "none" -version: 2.10.9 +version: 2.11.15 environment: sdk: ">=3.10.0 <4.0.0" @@ -64,7 +64,7 @@ dev_dependencies: mocktail: ^1.0.5 bloc_test: ^10.0.0 sqflite_common_ffi: ^2.4.0+3 - patrol: ^4.5.0 + patrol: ^4.6.0 envied_generator: ^1.3.5 build_runner: ^2.15.0 diff --git a/test/src/core/data_sources/remote_book_data_source/remote_book_data_source_impl_test.dart b/test/src/core/data_sources/remote_book_data_source/remote_book_data_source_impl_test.dart index f0de3f1b..ce943bde 100644 --- a/test/src/core/data_sources/remote_book_data_source/remote_book_data_source_impl_test.dart +++ b/test/src/core/data_sources/remote_book_data_source/remote_book_data_source_impl_test.dart @@ -1,7 +1,6 @@ -import 'dart:io'; - import 'package:bookify/src/core/data_sources/remote_books_data_source/google_books_data_source_impl.dart'; -import 'package:bookify/src/core/errors/book_exception/book_exception.dart'; +import 'package:bookify/src/shared/enums/rest_client_error_code.dart'; +import 'package:bookify/src/core/errors/rest_client_exception/rest_client_exception.dart'; import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/rest_client/rest_client.dart'; import 'package:dio/dio.dart'; @@ -13,11 +12,16 @@ import '../../../mocks/json/books_json_mock.dart'; class RestClientMock extends Mock implements RestClient {} void main() { - final restClient = RestClientMock(); - final bookDataSource = GoogleBooksDataSourceImpl( - restClient, - 'test_api_key_12345', - ); + late RestClientMock restClient; + late GoogleBooksDataSourceImpl bookDataSource; + + setUp(() { + restClient = RestClientMock(); + bookDataSource = GoogleBooksDataSourceImpl( + restClient, + 'test_api_key_12345', + ); + }); group('Test all methods of RemoteBookDataSourceImpl:', () { test('Get a List of books by author', () async { @@ -151,57 +155,128 @@ void main() { } }); - test('test a BookException', () async { + test('test a RestClientException with NotFound code', () async { when( () => restClient.get( baseUrl: any(named: 'baseUrl'), queryParameters: any(named: 'queryParameters'), ), - ).thenThrow(const BookException('')); - expect(bookDataSource.getAllBooks(), throwsA(isA())); + ).thenThrow( + const RestClientException(RestClientErrorCode.notFound), + ); + + expect( + bookDataSource.getAllBooks(), + throwsA( + isA().having( + (e) => e.code, + 'code', + RestClientErrorCode.notFound, + ), + ), + ); }); - test('test a BookNotFoundException', () async { + test('test a Connection Timeout Exception', () async { when( () => restClient.get( baseUrl: any(named: 'baseUrl'), queryParameters: any(named: 'queryParameters'), ), - ).thenThrow(const BookNotFoundException('BookNotFoundException')); + ).thenThrow( + const RestClientException(RestClientErrorCode.connectionTimeout), + ); + expect( bookDataSource.getAllBooks(), - throwsA(isA()), + throwsA( + isA().having( + (e) => e.code, + 'code', + RestClientErrorCode.connectionTimeout, + ), + ), ); }); - test('test a SocketException', () async { + test('test a Receive Timeout Exception', () async { when( () => restClient.get( baseUrl: any(named: 'baseUrl'), queryParameters: any(named: 'queryParameters'), ), - ).thenThrow(const SocketException('message')); - expect(bookDataSource.getAllBooks(), throwsA(isA())); + ).thenThrow( + const RestClientException(RestClientErrorCode.receiveTimeout), + ); + + expect( + bookDataSource.getAllBooks(), + throwsA( + isA().having( + (e) => e.code, + 'code', + RestClientErrorCode.receiveTimeout, + ), + ), + ); }); - test('test a TypeError expecting an empty list of books', () async { + test('test a RestClientException with SocketException code', () async { when( () => restClient.get( baseUrl: any(named: 'baseUrl'), queryParameters: any(named: 'queryParameters'), ), - ).thenThrow(TypeError()); - expect(await bookDataSource.getAllBooks(), []); + ).thenThrow( + const RestClientException(RestClientErrorCode.socketException), + ); + + expect( + bookDataSource.getAllBooks(), + throwsA( + isA().having( + (e) => e.code, + 'code', + RestClientErrorCode.socketException, + ), + ), + ); }); - test('test a generic Exception', () async { + test('test a TypeError expecting an empty list of books', () async { when( () => restClient.get( baseUrl: any(named: 'baseUrl'), queryParameters: any(named: 'queryParameters'), ), - ).thenThrow(Exception()); - expect(bookDataSource.getAllBooks(), throwsA(isA())); + ).thenThrow(TypeError()); + + final result = await bookDataSource.getAllBooks(); + expect(result, isA>()); + expect(result, isEmpty); }); + + test( + 'test a generic Exception should be wrapped in RestClientException unknown', + () async { + when( + () => restClient.get( + baseUrl: any(named: 'baseUrl'), + queryParameters: any(named: 'queryParameters'), + ), + ).thenThrow(Exception('Generic Error')); + + expect( + bookDataSource.getAllBooks(), + throwsA( + isA().having( + (e) => e.code, + 'code', + RestClientErrorCode.unknown, + ), + ), + ); + }, + ); }); } diff --git a/test/src/core/database/sqllite_database_test.dart b/test/src/core/database/sqllite_database_test.dart index 01ef2bad..5c336838 100644 --- a/test/src/core/database/sqllite_database_test.dart +++ b/test/src/core/database/sqllite_database_test.dart @@ -86,21 +86,27 @@ void main() { final categories = [ ...booksModel[0].categories, - CategoryModel(name: 'category2') + CategoryModel(name: 'category2'), ]; // TEST insertion of book int bookRowsInserted = 0; for (var book in booksModel) { - bookRowsInserted = - await _insertOnDatabase(database, bookTableName, book.toMap()); + bookRowsInserted = await _insertOnDatabase( + database, + bookTableName, + book.toMap(), + ); } expect(bookRowsInserted, equals(2)); // TEST insertion of authors and retrive id for (var author in authors) { - author.id = - await _insertOnDatabase(database, authorTableName, author.toMap()); + author.id = await _insertOnDatabase( + database, + authorTableName, + author.toMap(), + ); } expect(authors[0].id, equals(1)); expect(authors[1].id, equals(2)); @@ -110,22 +116,35 @@ void main() { //TEST insertion of categories and retrive id for (var category in categories) { category.id = await _insertOnDatabase( - database, categoryTableName, category.toMap()); + database, + categoryTableName, + category.toMap(), + ); } expect(categories[0].id, equals(1)); expect(categories[1].id, equals(2)); // Insertion of relationship between books and authors - await _insertOnDatabase(database, bookAuthorsTableName, - {'bookId': booksModel[0].id, 'authorId': authors[0].id}); - await _insertOnDatabase(database, bookAuthorsTableName, - {'bookId': booksModel[0].id, 'authorId': authors[1].id}); - await _insertOnDatabase(database, bookAuthorsTableName, - {'bookId': booksModel[1].id, 'authorId': authors[0].id}); - await _insertOnDatabase(database, bookAuthorsTableName, - {'bookId': booksModel[1].id, 'authorId': authors[2].id}); - await _insertOnDatabase(database, bookAuthorsTableName, - {'bookId': booksModel[1].id, 'authorId': authors[3].id}); + await _insertOnDatabase(database, bookAuthorsTableName, { + 'bookId': booksModel[0].id, + 'authorId': authors[0].id, + }); + await _insertOnDatabase(database, bookAuthorsTableName, { + 'bookId': booksModel[0].id, + 'authorId': authors[1].id, + }); + await _insertOnDatabase(database, bookAuthorsTableName, { + 'bookId': booksModel[1].id, + 'authorId': authors[0].id, + }); + await _insertOnDatabase(database, bookAuthorsTableName, { + 'bookId': booksModel[1].id, + 'authorId': authors[2].id, + }); + await _insertOnDatabase(database, bookAuthorsTableName, { + 'bookId': booksModel[1].id, + 'authorId': authors[3].id, + }); final bookAuthorsList = await _queryOnDatabaseWhenId( database, @@ -139,15 +158,25 @@ void main() { expect(bookAuthorsList[2]['bookId'], equals('2')); // Insertion of relationship between books and categories - await _insertOnDatabase(database, bookCategoriesTableName, - {'bookId': booksModel[0].id, 'categoryId': categories[0].id}); - await _insertOnDatabase(database, bookCategoriesTableName, - {'bookId': booksModel[0].id, 'categoryId': categories[1].id}); - await _insertOnDatabase(database, bookCategoriesTableName, - {'bookId': booksModel[1].id, 'categoryId': categories[1].id}); + await _insertOnDatabase(database, bookCategoriesTableName, { + 'bookId': booksModel[0].id, + 'categoryId': categories[0].id, + }); + await _insertOnDatabase(database, bookCategoriesTableName, { + 'bookId': booksModel[0].id, + 'categoryId': categories[1].id, + }); + await _insertOnDatabase(database, bookCategoriesTableName, { + 'bookId': booksModel[1].id, + 'categoryId': categories[1].id, + }); final bookCategoriesList = await _queryOnDatabaseWhenId( - database, bookCategoriesTableName, 'bookId', [booksModel[0].id]); + database, + bookCategoriesTableName, + 'bookId', + [booksModel[0].id], + ); expect(bookCategoriesList[0]['bookId'], equals('1')); expect(bookCategoriesList[1]['bookId'], equals('1')); @@ -235,8 +264,11 @@ void main() { // TEST insertion of book int bookRowsInserted = 0; for (var book in booksModel) { - bookRowsInserted = - await _insertOnDatabase(database, bookTableName, book.toMap()); + bookRowsInserted = await _insertOnDatabase( + database, + bookTableName, + book.toMap(), + ); } expect(bookRowsInserted, equals(2)); @@ -248,11 +280,15 @@ void main() { }); // UPDATE book with status "reading" = 2 - await _updateRowWhenId(database, bookTableName, 'id', [ - booksModel[0].id - ], { - 'status': BookStatus.reading.statusNumber, - }); + await _updateRowWhenId( + database, + bookTableName, + 'id', + [booksModel[0].id], + { + 'status': BookStatus.reading.statusNumber, + }, + ); await _insertOnDatabase(database, readingTableName, { 'pagesReaded': 75, @@ -261,26 +297,40 @@ void main() { }); // UPDATE book with status "reading" = 2 - await _updateRowWhenId(database, bookTableName, 'id', [ - booksModel[1].id - ], { - 'status': BookStatus.reading.statusNumber, - }); + await _updateRowWhenId( + database, + bookTableName, + 'id', + [booksModel[1].id], + { + 'status': BookStatus.reading.statusNumber, + }, + ); // VERiFY that there are two books with the status "reading" = 2 - final booksUpdated = await database - .query(bookTableName, where: 'status = ?', whereArgs: ['2']); + final booksUpdated = await database.query( + bookTableName, + where: 'status = ?', + whereArgs: ['2'], + ); expect(booksUpdated.length, equals(2)); - final readingsListMap = await database.query(readingTableName, - orderBy: 'lastReadingDate DESC'); + final readingsListMap = await database.query( + readingTableName, + orderBy: 'lastReadingDate DESC', + ); expect(readingsListMap[0]['id'], equals(2)); expect(readingsListMap[1]['id'], equals(1)); //TEST UPDATE reading with id 2 final readingRowChanges = await _updateRowWhenId( - database, readingTableName, 'id', [1], {'pagesReaded': 55}); + database, + readingTableName, + 'id', + [1], + {'pagesReaded': 55}, + ); expect(readingRowChanges, equals(1)); final newReadingMap = await _queryOnDatabaseWhenId( @@ -315,7 +365,10 @@ void main() { // TEST insertion of book final bookRowInserted = await _insertOnDatabase( - database, bookTableName, booksModel[0].toMap()); + database, + bookTableName, + booksModel[0].toMap(), + ); expect(bookRowInserted, equals(1)); @@ -332,25 +385,34 @@ void main() { expect(loanId, equals(1)); //TEST UPDATE loan - final updateLoanRow = - await _updateRowWhenId(database, loanTableName, 'id', [ - loanId - ], { - 'devolutionDate': DateTime(2023, 06, 20).millisecondsSinceEpoch, - }); + final updateLoanRow = await _updateRowWhenId( + database, + loanTableName, + 'id', + [loanId], + { + 'devolutionDate': DateTime(2023, 06, 20).millisecondsSinceEpoch, + }, + ); expect(updateLoanRow, equals(1)); - final newLoanMap = - await _queryOnDatabaseWhenId(database, loanTableName, 'id', [loanId]); + final newLoanMap = await _queryOnDatabaseWhenId( + database, + loanTableName, + 'id', + [loanId], + ); expect(newLoanMap.first['id'], equals(1)); expect( DateTime.fromMillisecondsSinceEpoch( - newLoanMap.first['loanDate'] as int), + newLoanMap.first['loanDate'] as int, + ), equals(DateTime(2023, 05, 23)), ); expect( DateTime.fromMillisecondsSinceEpoch( - newLoanMap.first['devolutionDate'] as int), + newLoanMap.first['devolutionDate'] as int, + ), equals(DateTime(2023, 06, 20)), ); expect(newLoanMap.first['idContact'], equals('idContact')); @@ -358,11 +420,19 @@ void main() { //TEST DELETE book and expect its relations to be deleted. final bookDeletedRow = await _deleteRowWhenId( - database, bookTableName, 'id', [booksModel[0].id]); + database, + bookTableName, + 'id', + [booksModel[0].id], + ); expect(bookDeletedRow, equals(1)); - final deletedLoanRelationship = - await _queryOnDatabaseWhenId(database, loanTableName, 'id', [loanId]); + final deletedLoanRelationship = await _queryOnDatabaseWhenId( + database, + loanTableName, + 'id', + [loanId], + ); expect(deletedLoanRelationship, isEmpty); }); @@ -374,8 +444,11 @@ void main() { // TEST insertion of book int bookRowsInserted = 0; for (var book in booksModel) { - bookRowsInserted = - await _insertOnDatabase(database, bookTableName, book.toMap()); + bookRowsInserted = await _insertOnDatabase( + database, + bookTableName, + book.toMap(), + ); } expect(bookRowsInserted, equals(2)); @@ -432,7 +505,9 @@ void main() { ); expect(newBookcase.last['name'], equals('Tecnologia')); expect( - newBookcase.last['description'], equals('Meus livros de tecnologia')); + newBookcase.last['description'], + equals('Meus livros de tecnologia'), + ); //TEST DELETE bookcase and expect its relations to be deleted. final bookcaseRowDeleted = await _deleteRowWhenId( @@ -464,7 +539,10 @@ void main() { } Future _insertOnDatabase( - Database db, String table, Map values) async { + Database db, + String table, + Map values, +) async { return await db.insert(table, values); } diff --git a/test/src/core/helpers/locale_decimal_format/locale_decimal_format_extension_test.dart b/test/src/core/helpers/locale_decimal_format/locale_decimal_format_extension_test.dart index c3a14ee9..c96792e1 100644 --- a/test/src/core/helpers/locale_decimal_format/locale_decimal_format_extension_test.dart +++ b/test/src/core/helpers/locale_decimal_format/locale_decimal_format_extension_test.dart @@ -13,12 +13,14 @@ void main() { }); group('Test double to locale-specific String conversion ||', () { - test('should format number for pt_BR locale with default decimal digits', - () { - Intl.defaultLocale = 'pt_BR'; - final formattedNumber = number.toLocaleDecimalFormat(); - expect(formattedNumber, '1.234,56'); - }); + test( + 'should format number for pt_BR locale with default decimal digits', + () { + Intl.defaultLocale = 'pt_BR'; + final formattedNumber = number.toLocaleDecimalFormat(); + expect(formattedNumber, '1.234,56'); + }, + ); test('should format number for it_IT locale with 2 decimal digits', () { final formattedNumber = number.toLocaleDecimalFormat( diff --git a/test/src/core/models/book_model_test.dart b/test/src/core/models/book_model_test.dart index dbf2d32f..5998312f 100644 --- a/test/src/core/models/book_model_test.dart +++ b/test/src/core/models/book_model_test.dart @@ -33,15 +33,17 @@ void main() { ); test( - 'should return false when comparing instances with different properties', - () { - expect(book1 == book2, false); - }); + 'should return false when comparing instances with different properties', + () { + expect(book1 == book2, false); + }, + ); test( - 'should return a different hashCode for instances with different properties', - () { - expect(book1.hashCode != book2.hashCode, true); - }); + 'should return a different hashCode for instances with different properties', + () { + expect(book1.hashCode != book2.hashCode, true); + }, + ); }); } diff --git a/test/src/core/repositories/auth_repository/auth_repository_impl_test.dart b/test/src/core/repositories/auth_repository/auth_repository_impl_test.dart index 050c47bd..f2df8114 100644 --- a/test/src/core/repositories/auth_repository/auth_repository_impl_test.dart +++ b/test/src/core/repositories/auth_repository/auth_repository_impl_test.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/models/user_model.dart'; import 'package:bookify/src/core/repositories/auth_repository/auth_repository_impl.dart'; @@ -64,6 +65,19 @@ void main() { expect(userModelInserted, equals(1)); }); + + test('Test delete UserModel', () async { + when( + () => storage.deleteStorage( + key: any(named: 'key'), + ), + ).thenAnswer( + (_) async => 1, + ); + final userModelDeleted = await authRepository.deleteUserModel(); + + expect(userModelDeleted, equals(1)); + }); }); group('Test normal crud with error', () { @@ -78,9 +92,12 @@ void main() { expect( () async => await authRepository.getUserModel(), - throwsA((Exception e) => - e is StorageException && - e.message == 'impossível converter o usuário.'), + throwsA( + (Exception e) => + e is StorageException && + e.code == StorageErrorCode.invalidValue && + e.descriptionMessage == 'Expected a String value for user data.', + ), ); }); @@ -89,12 +106,21 @@ void main() { () => storage.getStorage( key: 'user', ), - ).thenThrow(const StorageException('Storage error')); + ).thenThrow( + StorageException( + StorageErrorCode.writeFailed, + descriptionMessage: 'Storage error', + ), + ); expect( () async => await authRepository.getUserModel(), - throwsA((Exception e) => - e is StorageException && e.message == 'Storage error'), + throwsA( + (Exception e) => + e is StorageException && + e.code == StorageErrorCode.writeFailed && + e.descriptionMessage == 'Storage error', + ), ); }); @@ -104,14 +130,46 @@ void main() { key: 'user', value: any(named: 'value'), ), - ).thenThrow(const StorageException('Storage error')); + ).thenThrow( + StorageException( + StorageErrorCode.writeFailed, + descriptionMessage: 'Storage error', + ), + ); expect( () async => await authRepository.setUserModel( userModel: userModel, ), - throwsA((Exception e) => - e is StorageException && e.message == 'Storage error'), + throwsA( + (Exception e) => + e is StorageException && + e.code == StorageErrorCode.writeFailed && + e.descriptionMessage == 'Storage error', + ), + ); + }); + + test('Test delete UserModel with Storage Exception', () async { + when( + () => storage.deleteStorage( + key: any(named: 'key'), + ), + ).thenThrow( + StorageException( + StorageErrorCode.writeFailed, + descriptionMessage: 'Storage error', + ), + ); + + expect( + () async => await authRepository.deleteUserModel(), + throwsA( + (Exception e) => + e is StorageException && + e.code == StorageErrorCode.writeFailed && + e.descriptionMessage == 'Storage error', + ), ); }); }); diff --git a/test/src/core/repositories/author_repository/authors_repository_impl_test.dart b/test/src/core/repositories/author_repository/authors_repository_impl_test.dart index 20b03d2e..e49aaa92 100644 --- a/test/src/core/repositories/author_repository/authors_repository_impl_test.dart +++ b/test/src/core/repositories/author_repository/authors_repository_impl_test.dart @@ -2,6 +2,7 @@ import 'package:bookify/src/core/database/local_database.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/models/author_model.dart'; import 'package:bookify/src/core/repositories/author_repository/authors_repository_impl.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -13,10 +14,12 @@ void main() { group('Test normal CRUD author without error ||', () { test('insert a new author', () async { - when(() => localDatabase.insert( - table: any(named: 'table'), - values: any(named: 'values'), - )).thenAnswer((_) async => 1); + when( + () => localDatabase.insert( + table: any(named: 'table'), + values: any(named: 'values'), + ), + ).thenAnswer((_) async => 1); final authorId = await authorsRepository.insert( authorModel: AuthorModel(name: 'Machado de Assis'), @@ -26,13 +29,17 @@ void main() { }); test('get actual author id by name', () async { - when(() => localDatabase.getItemsByColumn( - table: any(named: 'table'), - column: any(named: 'column'), - columnValues: any(named: 'columnValues'), - )).thenAnswer((_) async => [ - {'id': 1, 'name': 'Machado de Assis'} - ]); + when( + () => localDatabase.getItemsByColumn( + table: any(named: 'table'), + column: any(named: 'column'), + columnValues: any(named: 'columnValues'), + ), + ).thenAnswer( + (_) async => [ + {'id': 1, 'name': 'Machado de Assis'}, + ], + ); final authorId = await authorsRepository.getAuthorIdByColumnName( authorName: 'Machado de Assis', @@ -42,11 +49,13 @@ void main() { }); test('get -1 when is a empty list', () async { - when(() => localDatabase.getItemsByColumn( - table: any(named: 'table'), - column: any(named: 'column'), - columnValues: any(named: 'columnValues'), - )).thenAnswer((_) async => []); + when( + () => localDatabase.getItemsByColumn( + table: any(named: 'table'), + column: any(named: 'column'), + columnValues: any(named: 'columnValues'), + ), + ).thenAnswer((_) async => []); final authorId = await authorsRepository.getAuthorIdByColumnName( authorName: 'Machado de Assis', @@ -56,11 +65,13 @@ void main() { }); test('get author by Id', () async { - when(() => localDatabase.getItemById( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenAnswer((_) async => {'id': 1, 'name': 'Machado de Assis'}); + when( + () => localDatabase.getItemById( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenAnswer((_) async => {'id': 1, 'name': 'Machado de Assis'}); final authorModel = await authorsRepository.getAuthorById(id: 1); @@ -69,11 +80,13 @@ void main() { }); test('delete author by Id', () async { - when(() => localDatabase.delete( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenAnswer((_) async => 1); + when( + () => localDatabase.delete( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenAnswer((_) async => 1); final rowDeleted = await authorsRepository.deleteAuthorById(id: 1); expect(rowDeleted, equals(1)); @@ -82,65 +95,113 @@ void main() { group('Test normal CRUD author with error ||', () { test('insert a new author', () async { - when(() => localDatabase.insert( - table: any(named: 'table'), - values: any(named: 'values'), - )).thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.insert( + table: any(named: 'table'), + values: any(named: 'values'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await authorsRepository.insert( authorModel: AuthorModel(name: 'Machado de Assis'), ), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('get actual author id by name', () async { - when(() => localDatabase.getItemsByColumn( - table: any(named: 'table'), - column: any(named: 'column'), - columnValues: any(named: 'columnValues'), - )).thenAnswer((_) async => [{}]); + when( + () => localDatabase.getItemsByColumn( + table: any(named: 'table'), + column: any(named: 'column'), + columnValues: any(named: 'columnValues'), + ), + ).thenAnswer((_) async => [{}]); expect( () async => await authorsRepository.getAuthorIdByColumnName( authorName: 'Machado de Assis', ), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível converter o dado do database'), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), ); }); test('get author by Id', () async { - when(() => localDatabase.getItemById( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenAnswer((_) async => {'id': '1'}); + when( + () => localDatabase.getItemById( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenAnswer((_) async => {'id': '1'}); expect( () async => await authorsRepository.getAuthorById(id: 1), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível converter o dado do database'), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), ); }); test('delete author by Id', () async { - when(() => localDatabase.delete( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.delete( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await authorsRepository.deleteAuthorById( id: 1, ), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); }); diff --git a/test/src/core/repositories/book_authors_repository/book_authors_repository_impl_test.dart b/test/src/core/repositories/book_authors_repository/book_authors_repository_impl_test.dart index c0b9dbb6..3ed70709 100644 --- a/test/src/core/repositories/book_authors_repository/book_authors_repository_impl_test.dart +++ b/test/src/core/repositories/book_authors_repository/book_authors_repository_impl_test.dart @@ -1,6 +1,7 @@ import 'package:bookify/src/core/database/local_database.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/repositories/book_authors_repository/book_authors_repository_impl.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -12,10 +13,12 @@ void main() { group('Test normal CRUD book/authors without error ||', () { test('insert book/authors relationship', () async { - when(() => localDatabase.insert( - table: any(named: 'table'), - values: any(named: 'values'), - )).thenAnswer((_) async => 1); + when( + () => localDatabase.insert( + table: any(named: 'table'), + values: any(named: 'values'), + ), + ).thenAnswer((_) async => 1); final bookAuthorsRelationship = await bookAuthorsRepository.insert( bookId: '1', @@ -26,30 +29,37 @@ void main() { }); test('get book/authors relationship', () async { - when(() => - localDatabase.getItemsByColumn( - table: any(named: 'table'), - column: any(named: 'column'), - columnValues: any(named: 'columnValues'))) - .thenAnswer((_) async => [ - {'bookId': '1', 'authorId': 1}, - ]); - - final bookAuthorsRelationshipMap = - await bookAuthorsRepository.getRelationshipsById(bookId: '1'); + when( + () => localDatabase.getItemsByColumn( + table: any(named: 'table'), + column: any(named: 'column'), + columnValues: any(named: 'columnValues'), + ), + ).thenAnswer( + (_) async => [ + {'bookId': '1', 'authorId': 1}, + ], + ); + + final bookAuthorsRelationshipMap = await bookAuthorsRepository + .getRelationshipsById(bookId: '1'); expect(bookAuthorsRelationshipMap.last['bookId'], equals('1')); expect(bookAuthorsRelationshipMap.last['authorId'], equals(1)); }); test('delete book/authors relationship', () async { - when(() => localDatabase.delete( + when( + () => localDatabase.delete( table: any(named: 'table'), idColumn: any(named: 'idColumn'), - id: any(named: 'id'))).thenAnswer((_) async => 1); + id: any(named: 'id'), + ), + ).thenAnswer((_) async => 1); - final deletedRelationshipRow = - await bookAuthorsRepository.delete(bookId: '1'); + final deletedRelationshipRow = await bookAuthorsRepository.delete( + bookId: '1', + ); expect(deletedRelationshipRow, equals(1)); }); @@ -57,48 +67,90 @@ void main() { group('Test normal CRUD book/authors with error ||', () { test('insert book/authors relationship', () async { - when(() => localDatabase.insert( - table: any(named: 'table'), - values: any(named: 'values'), - )).thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.insert( + table: any(named: 'table'), + values: any(named: 'values'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookAuthorsRepository.insert( bookId: '1', authorId: 1, ), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('get book/authors relationship', () async { - when(() => localDatabase.getItemsByColumn( - table: any(named: 'table'), - column: any(named: 'column'), - columnValues: any(named: 'columnValues'))) - .thenAnswer((_) async => [{}]); + when( + () => localDatabase.getItemsByColumn( + table: any(named: 'table'), + column: any(named: 'column'), + columnValues: any(named: 'columnValues'), + ), + ).thenAnswer((_) async => [{}]); expect( () async => await bookAuthorsRepository.getRelationshipsById(bookId: '1'), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível buscar os dados'), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), ); }); test('delete book/authors relationship', () async { - when(() => localDatabase.delete( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.delete( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookAuthorsRepository.delete(bookId: '1'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); }); diff --git a/test/src/core/repositories/book_categories_repository/book_categories_repository_impl_test.dart b/test/src/core/repositories/book_categories_repository/book_categories_repository_impl_test.dart index 9b52ae37..b89c3952 100644 --- a/test/src/core/repositories/book_categories_repository/book_categories_repository_impl_test.dart +++ b/test/src/core/repositories/book_categories_repository/book_categories_repository_impl_test.dart @@ -1,6 +1,7 @@ import 'package:bookify/src/core/database/local_database.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/repositories/book_categories_repository/book_categories_repository_impl.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -11,10 +12,12 @@ void main() { final bookCategoriesRepository = BookCategoriesRepositoryImpl(localDatabase); group('Test normal CRUD of book/categories without error ||', () { test('insert book/categories relationship', () async { - when(() => localDatabase.insert( - table: any(named: 'table'), - values: any(named: 'values'), - )).thenAnswer((_) async => 1); + when( + () => localDatabase.insert( + table: any(named: 'table'), + values: any(named: 'values'), + ), + ).thenAnswer((_) async => 1); final bookAuthorsRelationship = await bookCategoriesRepository.insert( bookId: '1', @@ -25,30 +28,37 @@ void main() { }); test('get book/categories relationship', () async { - when(() => - localDatabase.getItemsByColumn( - table: any(named: 'table'), - column: any(named: 'column'), - columnValues: any(named: 'columnValues'))) - .thenAnswer((_) async => [ - {'bookId': '1', 'categoryId': 1}, - ]); - - final bookAuthorsRelationshipMap = - await bookCategoriesRepository.getRelationshipsById(bookId: '1'); + when( + () => localDatabase.getItemsByColumn( + table: any(named: 'table'), + column: any(named: 'column'), + columnValues: any(named: 'columnValues'), + ), + ).thenAnswer( + (_) async => [ + {'bookId': '1', 'categoryId': 1}, + ], + ); + + final bookAuthorsRelationshipMap = await bookCategoriesRepository + .getRelationshipsById(bookId: '1'); expect(bookAuthorsRelationshipMap.last['bookId'], equals('1')); expect(bookAuthorsRelationshipMap.last['categoryId'], equals(1)); }); test('delete book/categories relationship', () async { - when(() => localDatabase.delete( + when( + () => localDatabase.delete( table: any(named: 'table'), idColumn: any(named: 'idColumn'), - id: any(named: 'id'))).thenAnswer((_) async => 1); + id: any(named: 'id'), + ), + ).thenAnswer((_) async => 1); - final deletedRelationshipRow = - await bookCategoriesRepository.delete(bookId: '1'); + final deletedRelationshipRow = await bookCategoriesRepository.delete( + bookId: '1', + ); expect(deletedRelationshipRow, equals(1)); }); @@ -56,48 +66,90 @@ void main() { group('Test normal CRUD of book/categories with error ||', () { test('insert book/categories relationship', () async { - when(() => localDatabase.insert( - table: any(named: 'table'), - values: any(named: 'values'), - )).thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.insert( + table: any(named: 'table'), + values: any(named: 'values'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookCategoriesRepository.insert( bookId: '1', categoryId: 1, ), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('get book/categories relationship', () async { - when(() => localDatabase.getItemsByColumn( - table: any(named: 'table'), - column: any(named: 'column'), - columnValues: any(named: 'columnValues'))) - .thenAnswer((_) async => [{}]); + when( + () => localDatabase.getItemsByColumn( + table: any(named: 'table'), + column: any(named: 'column'), + columnValues: any(named: 'columnValues'), + ), + ).thenAnswer((_) async => [{}]); expect( () async => await bookCategoriesRepository.getRelationshipsById(bookId: '1'), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível buscar os dados'), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), ); }); test('delete book/categories relationship', () async { - when(() => localDatabase.delete( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.delete( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookCategoriesRepository.delete(bookId: '1'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); }); diff --git a/test/src/core/repositories/book_on_case_repository/book_on_case_repository_impl_test.dart b/test/src/core/repositories/book_on_case_repository/book_on_case_repository_impl_test.dart index 85c69f9d..72f406c1 100644 --- a/test/src/core/repositories/book_on_case_repository/book_on_case_repository_impl_test.dart +++ b/test/src/core/repositories/book_on_case_repository/book_on_case_repository_impl_test.dart @@ -1,6 +1,7 @@ import 'package:bookify/src/core/database/local_database.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/repositories/book_on_case_repository/book_on_case_repository_impl.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -12,18 +13,21 @@ void main() { group('Test normal CRUD of bookcase/book without error ||', () { test('get bookcase/book relationships', () async { - when(() => localDatabase.getItemsByColumn( + when( + () => localDatabase.getItemsByColumn( table: any(named: 'table'), column: any(named: 'column'), - columnValues: any(named: 'columnValues'))).thenAnswer( + columnValues: any(named: 'columnValues'), + ), + ).thenAnswer( (_) async => [ {'bookId': '1', 'bookcaseId': 1}, {'bookId': '2', 'bookcaseId': 1}, ], ); - final bookOnCaseRelationship = - await bookOnCaseRepository.getBooksOnCaseRelationship(bookcaseId: 1); + final bookOnCaseRelationship = await bookOnCaseRepository + .getBooksOnCaseRelationship(bookcaseId: 1); expect(bookOnCaseRelationship[0]['bookId'], equals('1')); expect(bookOnCaseRelationship[0]['bookcaseId'], equals(1)); @@ -32,39 +36,49 @@ void main() { }); test('getBookIdForImagePreview when bookId is null', () async { - when(() => localDatabase.getColumnsById( - table: any(named: 'table'), - columns: any(named: 'columns'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenAnswer((_) async => {}); - - final bookId = - await bookOnCaseRepository.getBookIdForImagePreview(bookcaseId: 3); + when( + () => localDatabase.getColumnsById( + table: any(named: 'table'), + columns: any(named: 'columns'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenAnswer((_) async => {}); + + final bookId = await bookOnCaseRepository.getBookIdForImagePreview( + bookcaseId: 3, + ); expect(bookId, equals(null)); }); test('getBookIdForImagePreview', () async { - when(() => localDatabase.getColumnsById( - table: any(named: 'table'), - columns: any(named: 'columns'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenAnswer((_) async => {'bookId': '1'}); - - final bookId = - await bookOnCaseRepository.getBookIdForImagePreview(bookcaseId: 3); + when( + () => localDatabase.getColumnsById( + table: any(named: 'table'), + columns: any(named: 'columns'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenAnswer((_) async => {'bookId': '1'}); + + final bookId = await bookOnCaseRepository.getBookIdForImagePreview( + bookcaseId: 3, + ); expect(bookId, equals('1')); }); test('insert relationship', () async { when( () => localDatabase.insert( - table: any(named: 'table'), values: any(named: 'values')), + table: any(named: 'table'), + values: any(named: 'values'), + ), ).thenAnswer((invocation) async => 1); - final relationshipRowInserted = - await bookOnCaseRepository.insert(bookcaseId: 1, bookId: '1'); + final relationshipRowInserted = await bookOnCaseRepository.insert( + bookcaseId: 1, + bookId: '1', + ); expect(relationshipRowInserted, equals(1)); }); @@ -77,8 +91,9 @@ void main() { ), ).thenAnswer((_) async => 2); - final bookcasesCount = - await bookOnCaseRepository.countBookcasesByBook(bookId: 'bookId'); + final bookcasesCount = await bookOnCaseRepository.countBookcasesByBook( + bookId: 'bookId', + ); expect(bookcasesCount, equals(2)); }); @@ -86,11 +101,12 @@ void main() { test('delete relationship', () async { when( () => localDatabase.deleteWithAnotherColumn( - table: any(named: 'table'), - otherColumn: any(named: 'otherColumn'), - value: any(named: 'value'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id')), + table: any(named: 'table'), + otherColumn: any(named: 'otherColumn'), + value: any(named: 'value'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), ).thenAnswer((invocation) async => 1); final relationshipRowDeleted = await bookOnCaseRepository @@ -101,64 +117,125 @@ void main() { group('Test normal CRUD of bookcase/book with error ||', () { test('get bookcase/book relationships -- LocalDatabaseException', () async { - when(() => localDatabase.getItemsByColumn( - table: any(named: 'table'), - column: any(named: 'column'), - columnValues: any(named: 'columnValues'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.getItemsByColumn( + table: any(named: 'table'), + column: any(named: 'column'), + columnValues: any(named: 'columnValues'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookOnCaseRepository.getBooksOnCaseRelationship( - bookcaseId: 1), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + bookcaseId: 1, + ), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('getBookIdForImagePreview -- LocalDatabaseException', () async { - when(() => localDatabase.getColumnsById( - table: any(named: 'table'), - columns: any(named: 'columns'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.getColumnsById( + table: any(named: 'table'), + columns: any(named: 'columns'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookOnCaseRepository.getBookIdForImagePreview(bookcaseId: 3), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('getBookIdForImagePreview -- TypeError', () async { - when(() => localDatabase.getColumnsById( - table: any(named: 'table'), - columns: any(named: 'columns'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenAnswer((_) async => {'bookId': 1}); + when( + () => localDatabase.getColumnsById( + table: any(named: 'table'), + columns: any(named: 'columns'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenAnswer((_) async => {'bookId': 1}); expect( () async => await bookOnCaseRepository.getBookIdForImagePreview(bookcaseId: 3), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível converter o dado do database'), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), ); }); test('insert relationship', () async { when( () => localDatabase.insert( - table: any(named: 'table'), values: any(named: 'values')), - ).thenThrow(const LocalDatabaseException('Error on database')); + table: any(named: 'table'), + values: any(named: 'values'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookOnCaseRepository.insert(bookcaseId: 1, bookId: '1'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); @@ -169,33 +246,66 @@ void main() { idColumn: any(named: 'idColumn'), id: any(named: 'id'), ), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookOnCaseRepository.countBookcasesByBook(bookId: '1'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('delete relationship', () async { when( () => localDatabase.deleteWithAnotherColumn( - table: any(named: 'table'), - otherColumn: any(named: 'otherColumn'), - value: any(named: 'value'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id')), - ).thenThrow(const LocalDatabaseException('Error on database')); + table: any(named: 'table'), + otherColumn: any(named: 'otherColumn'), + value: any(named: 'value'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookOnCaseRepository.deleteBookcaseRelationship( bookcaseId: 1, bookId: '1', ), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); }); diff --git a/test/src/core/repositories/bookcase_repository/bookcase_repository_impl_test.dart b/test/src/core/repositories/bookcase_repository/bookcase_repository_impl_test.dart index cd1144a2..7beb547c 100644 --- a/test/src/core/repositories/bookcase_repository/bookcase_repository_impl_test.dart +++ b/test/src/core/repositories/bookcase_repository/bookcase_repository_impl_test.dart @@ -3,6 +3,7 @@ import 'package:bookify/src/core/errors/local_database_exception/local_database_ import 'package:bookify/src/core/helpers/color_to_int/color_to_int_extension.dart'; import 'package:bookify/src/core/models/bookcase_model.dart'; import 'package:bookify/src/core/repositories/bookcase_repository/bookcase_repository_impl.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -36,8 +37,9 @@ void main() { group('Test normal CRUD bookcase without error ||', () { test('getAll()', () async { - when(() => localDatabase.getAll(table: any(named: 'table'))) - .thenAnswer((_) async => bookcasesMap); + when( + () => localDatabase.getAll(table: any(named: 'table')), + ).thenAnswer((_) async => bookcasesMap); final bookcasesModel = await bookcaseRepository.getAll(); @@ -63,14 +65,17 @@ void main() { }); test('get by name()', () async { - when(() => localDatabase.researchBy( - table: any(named: 'table'), - column: any(named: 'column'), - columnValues: any(named: 'columnValues'))) - .thenAnswer((_) async => [bookcasesMap[0]]); + when( + () => localDatabase.researchBy( + table: any(named: 'table'), + column: any(named: 'column'), + columnValues: any(named: 'columnValues'), + ), + ).thenAnswer((_) async => [bookcasesMap[0]]); - final bookcaseModelByName = - await bookcaseRepository.getBookcasesByName(name: 'Fantasia'); + final bookcaseModelByName = await bookcaseRepository.getBookcasesByName( + name: 'Fantasia', + ); expect(bookcaseModelByName[0].id, equals(1)); expect(bookcaseModelByName[0].name, 'Fantasia'); @@ -84,10 +89,13 @@ void main() { }); test('getById()', () async { - when(() => localDatabase.getItemById( + when( + () => localDatabase.getItemById( table: any(named: 'table'), idColumn: any(named: 'idColumn'), - id: any(named: 'id'))).thenAnswer((_) async => bookcasesMap[0]); + id: any(named: 'id'), + ), + ).thenAnswer((_) async => bookcasesMap[0]); final bookcasesModel = await bookcaseRepository.getById(bookcaseId: 1); @@ -117,25 +125,33 @@ void main() { }); test('insert()', () async { - when(() => localDatabase.insert( + when( + () => localDatabase.insert( table: any(named: 'table'), - values: any(named: 'values'))).thenAnswer((_) async => 3); + values: any(named: 'values'), + ), + ).thenAnswer((_) async => 3); - final bookcaseInsertedId = - await bookcaseRepository.insert(bookcaseModel: bookcaseModel); + final bookcaseInsertedId = await bookcaseRepository.insert( + bookcaseModel: bookcaseModel, + ); expect(bookcaseInsertedId, equals(3)); }); test('update()', () async { - when(() => localDatabase.update( + when( + () => localDatabase.update( table: any(named: 'table'), values: any(named: 'values'), idColumn: any(named: 'idColumn'), - id: any(named: 'id'))).thenAnswer((_) async => 1); + id: any(named: 'id'), + ), + ).thenAnswer((_) async => 1); final bookcaseUpdatedRow = await bookcaseRepository.update( - bookcaseModel: bookcaseModel.copyWith(color: Colors.blue)); + bookcaseModel: bookcaseModel.copyWith(color: Colors.blue), + ); expect(bookcaseUpdatedRow, equals(1)); }); @@ -156,83 +172,158 @@ void main() { group('Test normal CRUD bookcase with error ||', () { test('getAll() -- LocalDatabaseException', () async { - when(() => localDatabase.getAll(table: any(named: 'table'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.getAll(table: any(named: 'table')), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( - () async => await bookcaseRepository.getAll(), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database')); + () async => await bookcaseRepository.getAll(), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), + ); }); test('getAll() -- TypeError', () async { - when(() => localDatabase.getAll(table: any(named: 'table'))) - .thenAnswer((_) async => [ - {'id': 1} - ]); + when(() => localDatabase.getAll(table: any(named: 'table'))).thenAnswer( + (_) async => [ + {'id': 1}, + ], + ); expect( () async => await bookcaseRepository.getAll(), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível encontrar as estantes no database'), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), ); }); test('get by name() -- LocalDatabaseException', () async { - when(() => localDatabase.researchBy( - table: any(named: 'table'), - column: any(named: 'column'), - columnValues: any(named: 'columnValues'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.researchBy( + table: any(named: 'table'), + column: any(named: 'column'), + columnValues: any(named: 'columnValues'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( - () async => - await bookcaseRepository.getBookcasesByName(name: 'Fantasia'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database')); + () async => + await bookcaseRepository.getBookcasesByName(name: 'Fantasia'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), + ); }); }); test('get by name() -- TypeError', () async { - when(() => localDatabase.researchBy( - table: any(named: 'table'), - column: any(named: 'column'), - columnValues: any(named: 'columnValues'))) - .thenAnswer((_) async => [{}]); + when( + () => localDatabase.researchBy( + table: any(named: 'table'), + column: any(named: 'column'), + columnValues: any(named: 'columnValues'), + ), + ).thenAnswer((_) async => [{}]); expect( - () async => - await bookcaseRepository.getBookcasesByName(name: 'Fantasia'), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível encontrar as estantes no database')); + () async => await bookcaseRepository.getBookcasesByName(name: 'Fantasia'), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), + ); }); test('getById() -- LocalDatabaseException', () async { - when(() => localDatabase.getItemById( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.getItemById( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( - () async => await bookcaseRepository.getById(bookcaseId: 1), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database')); + () async => await bookcaseRepository.getById(bookcaseId: 1), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), + ); }); test('getById() -- TypeError', () async { - when(() => localDatabase.getItemById( + when( + () => localDatabase.getItemById( table: any(named: 'table'), idColumn: any(named: 'idColumn'), - id: any(named: 'id'))).thenAnswer((_) async => {'id': 1}); + id: any(named: 'id'), + ), + ).thenAnswer((_) async => {'id': 1}); expect( - () async => await bookcaseRepository.getById(bookcaseId: 1), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível encontrar a estante no database')); + () async => await bookcaseRepository.getById(bookcaseId: 1), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), + ); }); test('countBookcases() -- LocalDatabaseException', () async { @@ -240,52 +331,126 @@ void main() { () => localDatabase.countItems( table: any(named: 'table'), ), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookcaseRepository.countBookcases(), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('insert() -- LocalDatabaseException', () async { - when(() => localDatabase.insert( - table: any(named: 'table'), values: any(named: 'values'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.insert( + table: any(named: 'table'), + values: any(named: 'values'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( - () async => - await bookcaseRepository.insert(bookcaseModel: bookcaseModel), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database')); + () async => await bookcaseRepository.insert(bookcaseModel: bookcaseModel), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), + ); }); test('update() -- LocalDatabaseException', () async { - when(() => localDatabase.update( - table: any(named: 'table'), - values: any(named: 'values'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.update( + table: any(named: 'table'), + values: any(named: 'values'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( - () async => await bookcaseRepository.update( - bookcaseModel: bookcaseModel.copyWith(color: Colors.blue)), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database')); + () async => await bookcaseRepository.update( + bookcaseModel: bookcaseModel.copyWith(color: Colors.blue), + ), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), + ); }); test('delete() -- LocalDatabaseException', () async { - when(() => localDatabase.delete( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.delete( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( - () async => await bookcaseRepository.delete(bookcaseId: 1), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database')); + () async => await bookcaseRepository.delete(bookcaseId: 1), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), + ); }); } diff --git a/test/src/core/repositories/books_repository/books_repository_impl_test.dart b/test/src/core/repositories/books_repository/books_repository_impl_test.dart index 26c6d2ec..186e6f33 100644 --- a/test/src/core/repositories/books_repository/books_repository_impl_test.dart +++ b/test/src/core/repositories/books_repository/books_repository_impl_test.dart @@ -2,6 +2,7 @@ import 'package:bookify/src/core/database/local_database.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/repositories/books_repository/books_repository_impl.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -16,36 +17,44 @@ void main() { group('Test normal CRUD book without error ||', () { test('insert book', () async { - when(() => localDatabase.insert( - table: any(named: 'table'), - values: any(named: 'values'), - )).thenAnswer((_) async => 1); + when( + () => localDatabase.insert( + table: any(named: 'table'), + values: any(named: 'values'), + ), + ).thenAnswer((_) async => 1); final bookInsertedRow = await bookRepository.insert(bookModel: bookModel); expect(bookInsertedRow, equals(1)); }); test('delete book', () async { - when(() => localDatabase.delete( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenAnswer((_) async => 1); - - final bookRemovedRow = - await bookRepository.deleteBookById(id: bookModel.id); + when( + () => localDatabase.delete( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenAnswer((_) async => 1); + + final bookRemovedRow = await bookRepository.deleteBookById( + id: bookModel.id, + ); expect(bookRemovedRow, equals(1)); }); test('verify book is already inserted', () async { - when(() => localDatabase.verifyItemIsAlreadyInserted( - table: any(named: 'table'), - column: any(named: 'column'), - columnValue: any(named: 'columnValue'), - )).thenAnswer((_) async => true); - - final bookIsInserted = - await bookRepository.verifyBookIsAlreadyInserted(id: bookModel.id); + when( + () => localDatabase.verifyItemIsAlreadyInserted( + table: any(named: 'table'), + column: any(named: 'column'), + columnValue: any(named: 'columnValue'), + ), + ).thenAnswer((_) async => true); + + final bookIsInserted = await bookRepository.verifyBookIsAlreadyInserted( + id: bookModel.id, + ); expect(bookIsInserted, equals(true)); }); @@ -63,19 +72,23 @@ void main() { 'status': 1, }; - when(() => localDatabase.getItemById( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenAnswer((_) async => bookMap); + when( + () => localDatabase.getItemById( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenAnswer((_) async => bookMap); final bookModelFromMap = await bookRepository.getBookById(id: '1'); expect(bookModelFromMap.id, equals('1')); expect(bookModelFromMap.title, equals('Memórias Póstumas De Brás Cubas')); expect(bookModelFromMap.publisher, equals('FTD Editora')); - expect(bookModelFromMap.description, - equals('É narrada pelo defunto Brás Cubas...')); + expect( + bookModelFromMap.description, + equals('É narrada pelo defunto Brás Cubas...'), + ); expect(bookModelFromMap.pageCount, equals(320)); expect(bookModelFromMap.imageUrl, equals('imageUrl')); expect(bookModelFromMap.buyLink, equals('buyLink')); @@ -100,14 +113,17 @@ void main() { 'status': 1, }; - when(() => localDatabase.researchBy( - table: any(named: 'table'), - column: any(named: 'column'), - columnValues: any(named: 'columnValues'))) - .thenAnswer((_) async => [bookMap]); + when( + () => localDatabase.researchBy( + table: any(named: 'table'), + column: any(named: 'column'), + columnValues: any(named: 'columnValues'), + ), + ).thenAnswer((_) async => [bookMap]); final bookModelByName = await bookRepository.getBooksByTitle( - title: 'Memórias Póstumas De Brás Cubas'); + title: 'Memórias Póstumas De Brás Cubas', + ); expect(bookModelByName[0].id, equals('1')); expect(bookModelByName[0].title, 'Memórias Póstumas De Brás Cubas'); @@ -127,9 +143,11 @@ void main() { }); test('get all books', () async { - when(() => localDatabase.getAll( - table: any(named: 'table'), - )).thenAnswer( + when( + () => localDatabase.getAll( + table: any(named: 'table'), + ), + ).thenAnswer( (_) async => booksModelMock.map((book) => book.toMap()).toList(), ); @@ -147,12 +165,14 @@ void main() { }); test('get book image', () async { - when(() => localDatabase.getColumnsById( - table: any(named: 'table'), - columns: any(named: 'columns'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenAnswer( + when( + () => localDatabase.getColumnsById( + table: any(named: 'table'), + columns: any(named: 'columns'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenAnswer( (_) async => {'imageUrl': 'http:www//imageurl.com'}, ); @@ -177,32 +197,40 @@ void main() { }); test('update book status', () async { - when(() => localDatabase.update( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - values: any(named: 'values'), - )).thenAnswer( + when( + () => localDatabase.update( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + values: any(named: 'values'), + ), + ).thenAnswer( (_) async => 1, ); final bookUpdated = await bookRepository.updateBookStatus( - id: '1', status: BookStatus.reading); + id: '1', + status: BookStatus.reading, + ); expect(bookUpdated, equals(1)); }); test('update book page Count', () async { - when(() => localDatabase.update( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - values: any(named: 'values'), - )).thenAnswer( + when( + () => localDatabase.update( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + values: any(named: 'values'), + ), + ).thenAnswer( (_) async => 1, ); - final bookUpdated = - await bookRepository.updateBookPageCount(id: '1', pageCount: 100); + final bookUpdated = await bookRepository.updateBookPageCount( + id: '1', + pageCount: 100, + ); expect(bookUpdated, equals(1)); }); @@ -223,160 +251,315 @@ void main() { group('Test normal CRUD book with error ||', () { test('insert book -- LocalDatabaseException', () async { - when(() => localDatabase.insert( - table: any(named: 'table'), - values: any(named: 'values'), - )).thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.insert( + table: any(named: 'table'), + values: any(named: 'values'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookRepository.insert(bookModel: bookModel), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('delete book -- LocalDatabaseException', () async { - when(() => localDatabase.delete( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.delete( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookRepository.deleteBookById(id: bookModel.id), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('verify book is already inserted -- LocalDatabaseException', () async { - when(() => localDatabase.verifyItemIsAlreadyInserted( - table: any(named: 'table'), - column: any(named: 'column'), - columnValue: any(named: 'columnValue'), - )).thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.verifyItemIsAlreadyInserted( + table: any(named: 'table'), + column: any(named: 'column'), + columnValue: any(named: 'columnValue'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookRepository.verifyBookIsAlreadyInserted(id: '1'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('get book by id -- TypeError', () async { - when(() => localDatabase.getItemById( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenAnswer((_) async => {'id': '1'}); + when( + () => localDatabase.getItemById( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenAnswer((_) async => {'id': '1'}); expect( () async => await bookRepository.getBookById(id: '1'), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível converter o dado do database'), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), ); }); test('get book by id -- LocalDatabaseException', () async { - when(() => localDatabase.getItemById( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.getItemById( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookRepository.getBookById(id: '1'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('get book by Title -- TypeError', () async { - when(() => localDatabase.researchBy( - table: any(named: 'table'), - column: any(named: 'column'), - columnValues: any(named: 'columnValues'))) - .thenAnswer((_) async => [{}]); + when( + () => localDatabase.researchBy( + table: any(named: 'table'), + column: any(named: 'column'), + columnValues: any(named: 'columnValues'), + ), + ).thenAnswer((_) async => [{}]); expect( - () async => await bookRepository.getBooksByTitle( - title: 'Memórias Póstumas de Bras Cubas'), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == - 'Impossível encontrar os livros com esse título no database')); + () async => await bookRepository.getBooksByTitle( + title: 'Memórias Póstumas de Bras Cubas', + ), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), + ); }); test('get book by Title -- LocalDatabaseException', () async { - when(() => localDatabase.researchBy( - table: any(named: 'table'), - column: any(named: 'column'), - columnValues: any(named: 'columnValues'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.researchBy( + table: any(named: 'table'), + column: any(named: 'column'), + columnValues: any(named: 'columnValues'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( - () async => await bookRepository.getBooksByTitle( - title: 'Memórias Póstumas de Bras Cubas'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database')); + () async => await bookRepository.getBooksByTitle( + title: 'Memórias Póstumas de Bras Cubas', + ), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), + ); }); test('get all books -- TypeError', () async { - when(() => localDatabase.getAll( - table: any(named: 'table'), - )).thenAnswer((_) async => [ - {'id': '1'} - ]); + when( + () => localDatabase.getAll( + table: any(named: 'table'), + ), + ).thenAnswer( + (_) async => [ + {'id': '1'}, + ], + ); expect( () async => await bookRepository.getAll(), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível converter o dado do database'), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), ); }); test('get all books -- LocalDatabaseException', () async { - when(() => localDatabase.getAll( - table: any(named: 'table'), - )).thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.getAll( + table: any(named: 'table'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookRepository.getAll(), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('get book image -- TypeError', () async { - when(() => localDatabase.getColumnsById( - table: any(named: 'table'), - columns: any(named: 'columns'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenAnswer((_) async => {}); + when( + () => localDatabase.getColumnsById( + table: any(named: 'table'), + columns: any(named: 'columns'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenAnswer((_) async => {}); expect( () async => await bookRepository.getBookImageById(id: '1'), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível converter o dado do database'), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), ); }); test('get book image -- LocalDatabaseException', () async { - when(() => localDatabase.getColumnsById( - table: any(named: 'table'), - columns: any(named: 'columns'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenThrow(const LocalDatabaseException('Error on Database')); + when( + () => localDatabase.getColumnsById( + table: any(named: 'table'), + columns: any(named: 'columns'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookRepository.getBookImageById(id: '1'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on Database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); @@ -392,9 +575,13 @@ void main() { expect( () async => await bookRepository.getBookStatus(id: 'bookId'), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível encontrar o status do livro no database'), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), ); }); @@ -406,40 +593,80 @@ void main() { idColumn: any(named: 'idColumn'), id: any(named: 'id'), ), - ).thenThrow(const LocalDatabaseException('error on database')); - + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookRepository.getBookStatus(id: 'bookId'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('update book status -- LocalDatabaseException', () async { - when(() => localDatabase.update( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - values: any(named: 'values'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.update( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + values: any(named: 'values'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookRepository.updateBookStatus( id: '1', status: BookStatus.reading, ), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('update book page Count -- assertion failed', () async { - when(() => localDatabase.update( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - values: any(named: 'values'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.update( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + values: any(named: 'values'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.conversionFailed, + descriptionMessage: 'Invalid page count', + ), + ); expect( () async => await bookRepository.updateBookPageCount( @@ -447,27 +674,48 @@ void main() { pageCount: 0, ), throwsA( - (AssertionError e) => - e.message == 'pagesCount must be greater than 0', + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), ), ); }); test('update book page Count -- LocalDatabaseException', () async { - when(() => localDatabase.update( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - values: any(named: 'values'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.update( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + values: any(named: 'values'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookRepository.updateBookPageCount( id: '1', pageCount: 100, ), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); @@ -476,12 +724,28 @@ void main() { () => localDatabase.countItems( table: any(named: 'table'), ), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookRepository.countBooks(), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); }); diff --git a/test/src/core/repositories/category_repository/categories_repository_impl_test.dart b/test/src/core/repositories/category_repository/categories_repository_impl_test.dart index a9ceacf1..ab8a4abc 100644 --- a/test/src/core/repositories/category_repository/categories_repository_impl_test.dart +++ b/test/src/core/repositories/category_repository/categories_repository_impl_test.dart @@ -2,6 +2,7 @@ import 'package:bookify/src/core/database/local_database.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/models/category_model.dart'; import 'package:bookify/src/core/repositories/category_repository/categories_repository_impl.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -13,10 +14,12 @@ void main() { group('Test normal CRUD category without error ||', () { test('insert new category', () async { - when(() => localDatabase.insert( - table: any(named: 'table'), - values: any(named: 'values'), - )).thenAnswer((_) async => 1); + when( + () => localDatabase.insert( + table: any(named: 'table'), + values: any(named: 'values'), + ), + ).thenAnswer((_) async => 1); final categoryId = await categoriesRepository.insert( categoryModel: CategoryModel(name: 'Fiction'), @@ -26,13 +29,17 @@ void main() { }); test('get actual category id by name', () async { - when(() => localDatabase.getItemsByColumn( - table: any(named: 'table'), - column: any(named: 'column'), - columnValues: any(named: 'columnValues'), - )).thenAnswer((_) async => [ - {'id': 1, 'name': 'Fiction'} - ]); + when( + () => localDatabase.getItemsByColumn( + table: any(named: 'table'), + column: any(named: 'column'), + columnValues: any(named: 'columnValues'), + ), + ).thenAnswer( + (_) async => [ + {'id': 1, 'name': 'Fiction'}, + ], + ); final categoryId = await categoriesRepository.getCategoryIdByColumnName( categoryName: 'Fiction', @@ -42,11 +49,13 @@ void main() { }); test('get -1 when is a empty list', () async { - when(() => localDatabase.getItemsByColumn( - table: any(named: 'table'), - column: any(named: 'column'), - columnValues: any(named: 'columnValues'), - )).thenAnswer((_) async => []); + when( + () => localDatabase.getItemsByColumn( + table: any(named: 'table'), + column: any(named: 'column'), + columnValues: any(named: 'columnValues'), + ), + ).thenAnswer((_) async => []); final categoryId = await categoriesRepository.getCategoryIdByColumnName( categoryName: 'Fiction', @@ -56,11 +65,13 @@ void main() { }); test('get category by Id', () async { - when(() => localDatabase.getItemById( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenAnswer((_) async => {'id': 1, 'name': 'Fiction'}); + when( + () => localDatabase.getItemById( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenAnswer((_) async => {'id': 1, 'name': 'Fiction'}); final categoryModel = await categoriesRepository.getCategoryById(id: 1); @@ -69,11 +80,13 @@ void main() { }); test('delete category by Id', () async { - when(() => localDatabase.delete( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenAnswer((_) async => 1); + when( + () => localDatabase.delete( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenAnswer((_) async => 1); final rowDeleted = await categoriesRepository.deleteCategoryById(id: 1); expect(rowDeleted, equals(1)); @@ -82,63 +95,111 @@ void main() { group('Test normal CRUD category with error ||', () { test('insert new category', () async { - when(() => localDatabase.insert( - table: any(named: 'table'), - values: any(named: 'values'), - )).thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.insert( + table: any(named: 'table'), + values: any(named: 'values'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await categoriesRepository.insert( categoryModel: CategoryModel(name: 'Fiction'), ), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('get actual category id by name', () async { - when(() => localDatabase.getItemsByColumn( - table: any(named: 'table'), - column: any(named: 'column'), - columnValues: any(named: 'columnValues'), - )).thenAnswer((_) async => [{}]); + when( + () => localDatabase.getItemsByColumn( + table: any(named: 'table'), + column: any(named: 'column'), + columnValues: any(named: 'columnValues'), + ), + ).thenAnswer((_) async => [{}]); expect( () async => await categoriesRepository.getCategoryIdByColumnName( categoryName: 'Fiction', ), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível converter o dado do database'), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), ); }); test('get category by Id', () async { - when(() => localDatabase.getItemById( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenAnswer((_) async => {'id': '1', 'name': 'Fiction'}); + when( + () => localDatabase.getItemById( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenAnswer((_) async => {'id': '1', 'name': 'Fiction'}); expect( () async => await categoriesRepository.getCategoryById(id: 1), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível converter o dado do database'), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), ); }); test('delete category by Id', () async { - when(() => localDatabase.delete( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'), - )).thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.delete( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await categoriesRepository.deleteCategoryById(id: 1), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); }); diff --git a/test/src/core/repositories/loan_repository/loan_repository_impl_test.dart b/test/src/core/repositories/loan_repository/loan_repository_impl_test.dart index 917419ae..f6dd41bc 100644 --- a/test/src/core/repositories/loan_repository/loan_repository_impl_test.dart +++ b/test/src/core/repositories/loan_repository/loan_repository_impl_test.dart @@ -2,6 +2,7 @@ import 'package:bookify/src/core/database/local_database.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/models/loan_model.dart'; import 'package:bookify/src/core/repositories/loan_repository/loan_repository_impl.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -19,8 +20,10 @@ void main() { 'id': 1, 'observation': 'observation', 'loanDate': DateTime(2024, 01, 10).millisecondsSinceEpoch, - 'devolutionDate': - DateTime(DateTime.april, 2024).millisecondsSinceEpoch, + 'devolutionDate': DateTime( + DateTime.april, + 2024, + ).millisecondsSinceEpoch, 'idContact': 'idContact', 'bookId': 'bookId', }, @@ -28,8 +31,10 @@ void main() { 'id': 2, 'observation': 'observation', 'loanDate': DateTime(2024, 01, 10).millisecondsSinceEpoch, - 'devolutionDate': - DateTime(DateTime.april, 2024).millisecondsSinceEpoch, + 'devolutionDate': DateTime( + DateTime.april, + 2024, + ).millisecondsSinceEpoch, 'idContact': 'idContact', 'bookId': 'bookId', }, @@ -37,8 +42,10 @@ void main() { 'id': 3, 'observation': 'observation', 'loanDate': DateTime(2024, 01, 10).millisecondsSinceEpoch, - 'devolutionDate': - DateTime(DateTime.april, 2024).millisecondsSinceEpoch, + 'devolutionDate': DateTime( + DateTime.april, + 2024, + ).millisecondsSinceEpoch, 'idContact': 'idContact', 'bookId': 'bookId', }, @@ -71,10 +78,11 @@ void main() { equals(DateTime(2024, 01, 10)), ); expect( - loansModel[0].devolutionDate, - equals( - DateTime(DateTime.april, 2024), - )); + loansModel[0].devolutionDate, + equals( + DateTime(DateTime.april, 2024), + ), + ); expect(loansModel[0].idContact, equals('idContact')); expect(loansModel[0].bookId, equals('bookId')); }); @@ -93,8 +101,9 @@ void main() { ), ).thenAnswer((_) async => loansMap); - final loansModel = - await loanRepository.getLoansByBookTitle(title: 'title'); + final loansModel = await loanRepository.getLoansByBookTitle( + title: 'title', + ); expect(loansModel.length, equals(3)); expect(loansModel[0].id, equals(1)); @@ -104,19 +113,23 @@ void main() { equals(DateTime(2024, 01, 10)), ); expect( - loansModel[0].devolutionDate, - equals( - DateTime(DateTime.april, 2024), - )); + loansModel[0].devolutionDate, + equals( + DateTime(DateTime.april, 2024), + ), + ); expect(loansModel[0].idContact, equals('idContact')); expect(loansModel[0].bookId, equals('bookId')); }); test('get by Id', () async { - when(() => localDatabase.getItemById( + when( + () => localDatabase.getItemById( table: any(named: 'table'), idColumn: any(named: 'idColumn'), - id: any(named: 'id'))).thenAnswer( + id: any(named: 'id'), + ), + ).thenAnswer( (_) async => loansMap.where((element) => element['id'] == 2).first, ); @@ -129,10 +142,11 @@ void main() { equals(DateTime(2024, 01, 10)), ); expect( - loanModel.devolutionDate, - equals( - DateTime(DateTime.april, 2024), - )); + loanModel.devolutionDate, + equals( + DateTime(DateTime.april, 2024), + ), + ); expect(loanModel.idContact, equals('idContact')); expect(loanModel.bookId, equals('bookId')); }); @@ -209,15 +223,21 @@ void main() { orderColumn: any(named: 'orderColumn'), orderBy: any(named: 'orderBy'), ), - ).thenAnswer((_) async => [ - {'id': 1} - ]); + ).thenAnswer( + (_) async => [ + {'id': 1}, + ], + ); expect( () async => await loanRepository.getAll(), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível encontrar os empréstimos no database'), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), ); }); @@ -228,12 +248,28 @@ void main() { orderColumn: any(named: 'orderColumn'), orderBy: any(named: 'orderBy'), ), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await loanRepository.getAll(), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); @@ -249,15 +285,21 @@ void main() { whereArgs: any(named: 'whereArgs'), usingLikeCondition: true, ), - ).thenAnswer((_) async => [ - {'id': 1} - ]); + ).thenAnswer( + (_) async => [ + {'id': 1}, + ], + ); expect( () async => await loanRepository.getLoansByBookTitle(title: 'title'), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível encontrar os empréstimos no database'), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), ); }); @@ -273,43 +315,80 @@ void main() { whereArgs: any(named: 'whereArgs'), usingLikeCondition: true, ), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await loanRepository.getLoansByBookTitle(title: 'title'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('getById -- TypeError', () async { - when(() => localDatabase.getItemById( + when( + () => localDatabase.getItemById( table: any(named: 'table'), idColumn: any(named: 'idColumn'), - id: any(named: 'id'))).thenAnswer((_) async => {'id': 1}); + id: any(named: 'id'), + ), + ).thenAnswer((_) async => {'id': 1}); expect( () async => await loanRepository.getById(loanId: 1), throwsA( - (Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível encontrar o empréstimo no database', + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), ), ); }); test('getById -- LocalDatabaseException', () async { - when(() => localDatabase.getItemById( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.getItemById( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await loanRepository.getById(loanId: 1), throwsA( - (Exception e) => - e is LocalDatabaseException && e.message == 'Error on database', + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), ), ); }); @@ -319,65 +398,127 @@ void main() { () => localDatabase.countItems( table: any(named: 'table'), ), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await loanRepository.countLoans(), throwsA( - (Exception e) => - e is LocalDatabaseException && e.message == 'Error on database', + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), ), ); }); test('insert -- LocalDatabaseException', () async { - when(() => localDatabase.insert( - table: any(named: 'table'), values: any(named: 'values'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.insert( + table: any(named: 'table'), + values: any(named: 'values'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await loanRepository.insert( - loanModel: LoanModel.fromMap(loansMap[0])), + loanModel: LoanModel.fromMap(loansMap[0]), + ), throwsA( - (Exception e) => - e is LocalDatabaseException && e.message == 'Error on database', + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), ), ); }); test('update -- LocalDatabaseException', () async { - when(() => localDatabase.update( + when( + () => localDatabase.update( table: any(named: 'table'), values: any(named: 'values'), idColumn: any(named: 'idColumn'), - id: any(named: 'id'))).thenThrow( + id: any(named: 'id'), + ), + ).thenThrow( const LocalDatabaseException( - 'Error on database', + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', ), ); expect( () async => await loanRepository.update( - loanModel: LoanModel.fromMap(loansMap[0])), + loanModel: LoanModel.fromMap(loansMap[0]), + ), throwsA( - (Exception e) => - e is LocalDatabaseException && e.message == 'Error on database', + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), ), ); }); test('delete -- LocalDatabaseException', () async { - when(() => localDatabase.delete( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.delete( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await loanRepository.delete(loanId: 1), throwsA( - (Exception e) => - e is LocalDatabaseException && e.message == 'Error on database', + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), ), ); }); diff --git a/test/src/core/repositories/reading_repository/reading_repository_impl_test.dart b/test/src/core/repositories/reading_repository/reading_repository_impl_test.dart index 9615c700..422ab43a 100644 --- a/test/src/core/repositories/reading_repository/reading_repository_impl_test.dart +++ b/test/src/core/repositories/reading_repository/reading_repository_impl_test.dart @@ -2,6 +2,7 @@ import 'package:bookify/src/core/database/local_database.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/models/reading_model.dart'; import 'package:bookify/src/core/repositories/reading_repository/reading_repository_impl.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -77,8 +78,9 @@ void main() { ), ).thenAnswer((_) async => readingsMap); - final readings = - await readingRepository.getReadingsByBookTitle(title: 'title'); + final readings = await readingRepository.getReadingsByBookTitle( + title: 'title', + ); expect(readings.length, equals(3)); expect(readings[0].id, equals(1)); @@ -93,10 +95,13 @@ void main() { }); test('get by Id', () async { - when(() => localDatabase.getItemById( + when( + () => localDatabase.getItemById( table: any(named: 'table'), idColumn: any(named: 'idColumn'), - id: any(named: 'id'))).thenAnswer( + id: any(named: 'id'), + ), + ).thenAnswer( (_) async => readingsMap.where((element) => element['id'] == 2).first, ); @@ -185,15 +190,21 @@ void main() { orderColumn: any(named: 'orderColumn'), orderBy: any(named: 'orderBy'), ), - ).thenAnswer((_) async => [ - {'id': 1} - ]); + ).thenAnswer( + (_) async => [ + {'id': 1}, + ], + ); expect( () async => await readingRepository.getAll(), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível encontrar as leituras no database'), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), ); }); @@ -204,12 +215,28 @@ void main() { orderColumn: any(named: 'orderColumn'), orderBy: any(named: 'orderBy'), ), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await readingRepository.getAll(), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); @@ -225,16 +252,22 @@ void main() { whereArgs: any(named: 'whereArgs'), usingLikeCondition: true, ), - ).thenAnswer((_) async => [ - {'id': 1} - ]); + ).thenAnswer( + (_) async => [ + {'id': 1}, + ], + ); expect( () async => await readingRepository.getReadingsByBookTitle(title: 'title'), - throwsA((Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível encontrar as leituras no database'), + throwsA( + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), + ), ); }); @@ -250,44 +283,81 @@ void main() { whereArgs: any(named: 'whereArgs'), usingLikeCondition: true, ), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await readingRepository.getReadingsByBookTitle(title: 'title'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('getById -- TypeError', () async { - when(() => localDatabase.getItemById( + when( + () => localDatabase.getItemById( table: any(named: 'table'), idColumn: any(named: 'idColumn'), - id: any(named: 'id'))).thenAnswer((_) async => {'id': 1}); + id: any(named: 'id'), + ), + ).thenAnswer((_) async => {'id': 1}); expect( () async => await readingRepository.getById(readingId: 1), throwsA( - (Exception e) => - e is LocalDatabaseException && - e.message == 'Impossível encontrar a leitura no database', + isA().having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.conversionFailed, + ), ), ); }); test('getById -- LocalDatabaseException', () async { - when(() => localDatabase.getItemById( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.getItemById( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await readingRepository.getById(readingId: 1), throwsA( - (Exception e) => - e is LocalDatabaseException && e.message == 'Error on database', + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), ), ); }); @@ -297,65 +367,127 @@ void main() { () => localDatabase.countItems( table: any(named: 'table'), ), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await readingRepository.countReadings(), throwsA( - (Exception e) => - e is LocalDatabaseException && e.message == 'Error on database', + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), ), ); }); test('insert -- LocalDatabaseException', () async { - when(() => localDatabase.insert( - table: any(named: 'table'), values: any(named: 'values'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.insert( + table: any(named: 'table'), + values: any(named: 'values'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await readingRepository.insert( - readingModel: ReadingModel.fromMap(readingsMap[0])), + readingModel: ReadingModel.fromMap(readingsMap[0]), + ), throwsA( - (Exception e) => - e is LocalDatabaseException && e.message == 'Error on database', + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), ), ); }); test('update -- LocalDatabaseException', () async { - when(() => localDatabase.update( + when( + () => localDatabase.update( table: any(named: 'table'), values: any(named: 'values'), idColumn: any(named: 'idColumn'), - id: any(named: 'id'))).thenThrow( + id: any(named: 'id'), + ), + ).thenThrow( const LocalDatabaseException( - 'Error on database', + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', ), ); expect( () async => await readingRepository.update( - readingModel: ReadingModel.fromMap(readingsMap[0])), + readingModel: ReadingModel.fromMap(readingsMap[0]), + ), throwsA( - (Exception e) => - e is LocalDatabaseException && e.message == 'Error on database', + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), ), ); }); test('delete -- LocalDatabaseException', () async { - when(() => localDatabase.delete( - table: any(named: 'table'), - idColumn: any(named: 'idColumn'), - id: any(named: 'id'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => localDatabase.delete( + table: any(named: 'table'), + idColumn: any(named: 'idColumn'), + id: any(named: 'id'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await readingRepository.delete(readingId: 1), throwsA( - (Exception e) => - e is LocalDatabaseException && e.message == 'Error on database', + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), ), ); }); diff --git a/test/src/core/repositories/remote_books_repository/remote_books_repository_test.dart b/test/src/core/repositories/remote_books_repository/remote_books_repository_test.dart index 27a1cea1..6d149cbf 100644 --- a/test/src/core/repositories/remote_books_repository/remote_books_repository_test.dart +++ b/test/src/core/repositories/remote_books_repository/remote_books_repository_test.dart @@ -1,7 +1,4 @@ -import 'dart:io'; - import 'package:bookify/src/core/data_sources/remote_books_data_source/remote_books_data_source.dart'; -import 'package:bookify/src/core/errors/book_exception/book_exception.dart'; import 'package:bookify/src/core/models/author_model.dart'; import 'package:bookify/src/core/models/category_model.dart'; import 'package:bookify/src/core/repositories/remote_books_repository/remote_books_repository_impl.dart'; @@ -18,9 +15,9 @@ void main() { group('Test all methods of GoogleBookRepository:', () { test('Get a List of books by author', () async { - when(() => - booksDataSource.findBooksByAuthor(author: any(named: 'author'))) - .thenAnswer((_) async { + when( + () => booksDataSource.findBooksByAuthor(author: any(named: 'author')), + ).thenAnswer((_) async { return booksModelMock .map( (book) => book.copyWith( @@ -30,16 +27,18 @@ void main() { .toList(); }); - final books = - await bookRepository.findBooksByAuthor(author: 'J.R.R. Tolkien'); + final books = await bookRepository.findBooksByAuthor( + author: 'J.R.R. Tolkien', + ); expect(books[0].authors.first.name, 'J. R. R. Tolkien'); expect(books[1].authors.first.name, 'J. R. R. Tolkien'); }); test('Get a book by ISBN', () async { - when(() => booksDataSource.findBooksByIsbn(isbn: any(named: 'isbn'))) - .thenAnswer((_) async { + when( + () => booksDataSource.findBooksByIsbn(isbn: any(named: 'isbn')), + ).thenAnswer((_) async { return booksModelMock .map( (book) => book.copyWith( @@ -54,8 +53,11 @@ void main() { }); test('Get a List of books by publisher', () async { - when(() => booksDataSource.findBooksByPublisher( - publisher: any(named: 'publisher'))).thenAnswer((_) async { + when( + () => booksDataSource.findBooksByPublisher( + publisher: any(named: 'publisher'), + ), + ).thenAnswer((_) async { return booksModelMock .map( (book) => book.copyWith( @@ -66,7 +68,8 @@ void main() { }); final books = await bookRepository.findBooksByPublisher( - publisher: 'Alta Books Editora'); + publisher: 'Alta Books Editora', + ); for (var book in books) { expect(book.publisher, 'Alta Books Editora'); @@ -85,8 +88,9 @@ void main() { }); test('Get a list of books by title', () async { - when(() => booksDataSource.findBooksByTitle(title: any(named: 'title'))) - .thenAnswer((_) async { + when( + () => booksDataSource.findBooksByTitle(title: any(named: 'title')), + ).thenAnswer((_) async { return booksModelMock .map( (book) => book.copyWith( @@ -104,8 +108,11 @@ void main() { }); test('Get a list of books by category', () async { - when(() => booksDataSource.findBooksByCategory( - category: any(named: 'category'))).thenAnswer((_) async { + when( + () => booksDataSource.findBooksByCategory( + category: any(named: 'category'), + ), + ).thenAnswer((_) async { return booksModelMock .map( (book) => book.copyWith( @@ -115,36 +122,13 @@ void main() { .toList(); }); - final books = - await bookRepository.findBooksByCategory(category: 'Fiction'); + final books = await bookRepository.findBooksByCategory( + category: 'Fiction', + ); for (var book in books) { expect(book.categories.first.name, 'Fiction'); } }); - - test('test a BookException', () async { - when(() => booksDataSource.getAllBooks()) - .thenThrow(const BookException('')); - expect(bookRepository.getAllBooks(), throwsA(isA())); - }); - - test('test a BookNotFoundException', () async { - when(() => booksDataSource.getAllBooks()) - .thenThrow(const BookNotFoundException('BookNotFoundException')); - expect( - bookRepository.getAllBooks(), throwsA(isA())); - }); - - test('test a SocketException', () async { - when(() => booksDataSource.getAllBooks()) - .thenThrow(const SocketException('message')); - expect(bookRepository.getAllBooks(), throwsA(isA())); - }); - - test('test a generic Exception', () async { - when(() => booksDataSource.getAllBooks()).thenThrow(Exception()); - expect(bookRepository.getAllBooks(), throwsA(isA())); - }); }); } diff --git a/test/src/core/repositories/user_hour_time_repository/user_hour_time_repository_impl_test.dart b/test/src/core/repositories/user_hour_time_repository/user_hour_time_repository_impl_test.dart index 1c6f917e..e3d64420 100644 --- a/test/src/core/repositories/user_hour_time_repository/user_hour_time_repository_impl_test.dart +++ b/test/src/core/repositories/user_hour_time_repository/user_hour_time_repository_impl_test.dart @@ -1,5 +1,6 @@ +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; -import 'package:bookify/src/core/enums/repeat_hour_time_type.dart'; +import 'package:bookify/src/shared/enums/repeat_hour_time_type.dart'; import 'package:bookify/src/core/models/user_hour_time_model.dart'; import 'package:bookify/src/core/repositories/user_hour_time_repository/user_hour_time_repository_impl.dart'; import 'package:bookify/src/core/storage/storage.dart'; @@ -92,7 +93,9 @@ void main() { throwsA( (Exception e) => e is StorageException && - e.message == 'impossível converter a hora de leitura.', + e.code == StorageErrorCode.invalidValue && + e.descriptionMessage == + 'Impossible to convert user reading time.', ), ); }); @@ -102,13 +105,20 @@ void main() { () => storage.getStorage( key: any(named: 'key'), ), - ).thenThrow(const StorageException('Storage error')); + ).thenThrow( + const StorageException( + StorageErrorCode.readFailed, + descriptionMessage: 'Storage error', + ), + ); expect( () async => await userHourTimeRepository.getUserHourTime(), throwsA( (Exception e) => - e is StorageException && e.message == 'Storage error', + e is StorageException && + e.code == StorageErrorCode.readFailed && + e.descriptionMessage == 'Storage error', ), ); }); @@ -119,7 +129,12 @@ void main() { key: any(named: 'key'), value: any(named: 'value'), ), - ).thenThrow(const StorageException('Storage error')); + ).thenThrow( + const StorageException( + StorageErrorCode.writeFailed, + descriptionMessage: 'Storage error', + ), + ); expect( () async => await userHourTimeRepository.setUserHourTime( @@ -127,7 +142,9 @@ void main() { ), throwsA( (Exception e) => - e is StorageException && e.message == 'Storage error', + e is StorageException && + e.code == StorageErrorCode.writeFailed && + e.descriptionMessage == 'Storage error', ), ); }); diff --git a/test/src/core/repositories/user_page_reading_time_repository/user_page_reading_time_repository_impl_test.dart b/test/src/core/repositories/user_page_reading_time_repository/user_page_reading_time_repository_impl_test.dart index be3a3772..ddf03dc6 100644 --- a/test/src/core/repositories/user_page_reading_time_repository/user_page_reading_time_repository_impl_test.dart +++ b/test/src/core/repositories/user_page_reading_time_repository/user_page_reading_time_repository_impl_test.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/models/user_page_reading_time_model.dart'; import 'package:bookify/src/core/repositories/user_page_reading_time_repository/user_page_reading_time_repository_impl.dart'; @@ -27,8 +28,8 @@ void main() { (_) async => const Duration(minutes: 10).inSeconds, ); - final userPageReadingTime = - await userPageReadingTimeRepository.getUserPageReadingTime(); + final userPageReadingTime = await userPageReadingTimeRepository + .getUserPageReadingTime(); expect( userPageReadingTime.pageReadingTimeSeconds, @@ -46,10 +47,10 @@ void main() { (_) async => 1, ); - final userPageReadingInserted = - await userPageReadingTimeRepository.setUserPageReadingTime( - userPageReadingTime: userPageReadingTime, - ); + final userPageReadingInserted = await userPageReadingTimeRepository + .setUserPageReadingTime( + userPageReadingTime: userPageReadingTime, + ); expect( userPageReadingInserted, @@ -74,7 +75,9 @@ void main() { throwsA( (Exception e) => e is StorageException && - e.message == 'impossível converter o tempo de leitura da página.', + e.code == StorageErrorCode.invalidValue && + e.descriptionMessage == + 'Impossible to convert user page reading time.', ), ); }); @@ -84,14 +87,21 @@ void main() { () => storage.getStorage( key: any(named: 'key'), ), - ).thenThrow(const StorageException('Storage error')); + ).thenThrow( + StorageException( + StorageErrorCode.readFailed, + descriptionMessage: 'Storage error', + ), + ); expect( () async => await userPageReadingTimeRepository.getUserPageReadingTime(), throwsA( (Exception e) => - e is StorageException && e.message == 'Storage error', + e is StorageException && + e.code == StorageErrorCode.readFailed && + e.descriptionMessage == 'Storage error', ), ); }); @@ -102,7 +112,12 @@ void main() { key: any(named: 'key'), value: any(named: 'value'), ), - ).thenThrow(const StorageException('Storage error')); + ).thenThrow( + StorageException( + StorageErrorCode.writeFailed, + descriptionMessage: 'Storage error', + ), + ); expect( () async => await userPageReadingTimeRepository.setUserPageReadingTime( @@ -110,7 +125,9 @@ void main() { ), throwsA( (Exception e) => - e is StorageException && e.message == 'Storage error', + e is StorageException && + e.code == StorageErrorCode.writeFailed && + e.descriptionMessage == 'Storage error', ), ); }); diff --git a/test/src/core/repositories/user_theme_repository/user_theme_repository_impl_test.dart b/test/src/core/repositories/user_theme_repository/user_theme_repository_impl_test.dart index 07d6a3af..27770609 100644 --- a/test/src/core/repositories/user_theme_repository/user_theme_repository_impl_test.dart +++ b/test/src/core/repositories/user_theme_repository/user_theme_repository_impl_test.dart @@ -1,3 +1,4 @@ +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/repositories/user_theme_repository/user_theme_repository_impl.dart'; import 'package:bookify/src/core/storage/storage.dart'; @@ -56,9 +57,12 @@ void main() { expect( () async => await userThemeRepository.getThemeMode(), - throwsA((Exception e) => - e is StorageException && - e.message == 'impossível converter o tema.'), + throwsA( + (Exception e) => + e is StorageException && + e.code == StorageErrorCode.invalidValue && + e.descriptionMessage == 'Impossible to convert theme mode.', + ), ); }); @@ -67,12 +71,21 @@ void main() { () => storage.getStorage( key: any(named: 'key'), ), - ).thenThrow(const StorageException('Storage error')); + ).thenThrow( + StorageException( + StorageErrorCode.readFailed, + descriptionMessage: 'Storage error', + ), + ); expect( () async => await userThemeRepository.getThemeMode(), - throwsA((Exception e) => - e is StorageException && e.message == 'Storage error'), + throwsA( + (Exception e) => + e is StorageException && + e.code == StorageErrorCode.readFailed && + e.descriptionMessage == 'Storage error', + ), ); }); @@ -82,14 +95,23 @@ void main() { key: any(named: 'key'), value: any(named: 'value'), ), - ).thenThrow(const StorageException('Storage error')); + ).thenThrow( + StorageException( + StorageErrorCode.writeFailed, + descriptionMessage: 'Storage error', + ), + ); expect( () async => await userThemeRepository.setThemeMode( themeMode: ThemeMode.light, ), - throwsA((Exception e) => - e is StorageException && e.message == 'Storage error'), + throwsA( + (Exception e) => + e is StorageException && + e.code == StorageErrorCode.writeFailed && + e.descriptionMessage == 'Storage error', + ), ); }); }); diff --git a/test/src/core/services/auth_service/auth_service_impl_test.dart b/test/src/core/services/auth_service/auth_service_impl_test.dart index 8d56838f..567bf033 100644 --- a/test/src/core/services/auth_service/auth_service_impl_test.dart +++ b/test/src/core/services/auth_service/auth_service_impl_test.dart @@ -1,3 +1,5 @@ +import 'package:bookify/src/shared/enums/auth_error_code.dart'; +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/auth_exception/auth_exception.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/models/user_model.dart'; @@ -45,8 +47,9 @@ void main() { test( 'Test signIn success', () async { - when(() => authStrategyFactory.create(SignInType.google)) - .thenReturn(authStrategy); + when( + () => authStrategyFactory.create(SignInType.google), + ).thenReturn(authStrategy); when(() => authStrategy.signIn()).thenAnswer((_) async => userModel); when( () => authRepository.setUserModel(userModel: userModel), @@ -61,15 +64,26 @@ void main() { test( 'Test signIn throws AuthException when strategy fails', () async { - when(() => authStrategyFactory.create(SignInType.google)) - .thenReturn(authStrategy); - when(() => authStrategy.signIn()) - .thenThrow(AuthException('Strategy failed')); + when( + () => authStrategyFactory.create(SignInType.google), + ).thenReturn(authStrategy); + when( + () => authStrategy.signIn(), + ).thenThrow( + AuthException( + AuthErrorCode.internalError, + descriptionMessage: 'Strategy failed', + ), + ); expect( () async => await authService.signIn(signInType: SignInType.google), - throwsA((Exception e) => - e is AuthException && e.message == 'Strategy failed'), + throwsA( + (Exception e) => + e is AuthException && + e.code == AuthErrorCode.internalError && + e.descriptionMessage == 'Strategy failed', + ), ); }, ); @@ -77,16 +91,27 @@ void main() { test( 'Test signIn throws AuthException when repository fails', () async { - when(() => authStrategyFactory.create(SignInType.google)) - .thenReturn(authStrategy); + when( + () => authStrategyFactory.create(SignInType.google), + ).thenReturn(authStrategy); when(() => authStrategy.signIn()).thenAnswer((_) async => userModel); - when(() => authRepository.setUserModel(userModel: userModel)) - .thenThrow(StorageException('DB failed')); + when( + () => authRepository.setUserModel(userModel: userModel), + ).thenThrow( + StorageException( + StorageErrorCode.invalidValue, + descriptionMessage: 'DB failed', + ), + ); expect( () async => await authService.signIn(signInType: SignInType.google), throwsA( - (Exception e) => e is AuthException && e.message == 'DB failed'), + (Exception e) => + e is AuthException && + e.code == AuthErrorCode.internalError && + e.descriptionMessage == 'DB failed', + ), ); }, ); @@ -96,31 +121,42 @@ void main() { test( 'Test signOut success', () async { - when(() => authStrategyFactory.create(SignInType.google)) - .thenReturn(authStrategy); + when( + () => authStrategyFactory.create(SignInType.google), + ).thenReturn(authStrategy); when(() => authStrategy.signOut()).thenAnswer((_) async => true); + when(() => authRepository.deleteUserModel()).thenAnswer((_) async => 1); final result = await authService.signOut(signInType: SignInType.google); expect(result, isTrue); verify(() => authStrategyFactory.create(SignInType.google)).called(1); verify(() => authStrategy.signOut()).called(1); + verify(() => authRepository.deleteUserModel()).called(1); }, ); test( 'Test signOut throws AuthException when strategy fails', () async { - when(() => authStrategyFactory.create(SignInType.google)) - .thenReturn(authStrategy); + when( + () => authStrategyFactory.create(SignInType.google), + ).thenReturn(authStrategy); when(() => authStrategy.signOut()).thenThrow( - AuthException('Strategy failed'), + AuthException( + AuthErrorCode.internalError, + descriptionMessage: 'Strategy failed', + ), ); expect( () async => await authService.signOut(signInType: SignInType.google), - throwsA((Exception e) => - e is AuthException && e.message == 'Strategy failed'), + throwsA( + (Exception e) => + e is AuthException && + e.code == AuthErrorCode.internalError && + e.descriptionMessage == 'Strategy failed', + ), ); verify(() => authStrategyFactory.create(SignInType.google)).called(1); verify(() => authStrategy.signOut()).called(1); diff --git a/test/src/core/services/book_service/book_service_impl_test.dart b/test/src/core/services/book_service/book_service_impl_test.dart index 2901949b..6b321e2e 100644 --- a/test/src/core/services/book_service/book_service_impl_test.dart +++ b/test/src/core/services/book_service/book_service_impl_test.dart @@ -8,6 +8,7 @@ import 'package:bookify/src/core/repositories/book_categories_repository/book_ca import 'package:bookify/src/core/repositories/books_repository/books_repository.dart'; import 'package:bookify/src/core/repositories/category_repository/categories_repository.dart'; import 'package:bookify/src/core/services/book_service/book_service_impl.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -64,22 +65,28 @@ void main() { ).thenAnswer((_) async => [bookModel]); //for author repository - when(() => authorsRepository.getAuthorById(id: any(named: 'id'))) - .thenAnswer((_) async => authorModel); + when( + () => authorsRepository.getAuthorById(id: any(named: 'id')), + ).thenAnswer((_) async => authorModel); // for category repository - when(() => categoriesRepository.getCategoryById(id: any(named: 'id'))) - .thenAnswer((_) async => categoryModel); + when( + () => categoriesRepository.getCategoryById(id: any(named: 'id')), + ).thenAnswer((_) async => categoryModel); // for book authors repository - when(() => bookAuthorsRepository.getRelationshipsById( - bookId: any(named: 'bookId'))) - .thenAnswer((_) async => [bookAuthorsRelationship]); + when( + () => bookAuthorsRepository.getRelationshipsById( + bookId: any(named: 'bookId'), + ), + ).thenAnswer((_) async => [bookAuthorsRelationship]); // for book categories repository - when(() => bookCategoriesRepository.getRelationshipsById( - bookId: any(named: 'bookId'))) - .thenAnswer((_) async => [bookCategoriesRelationship]); + when( + () => bookCategoriesRepository.getRelationshipsById( + bookId: any(named: 'bookId'), + ), + ).thenAnswer((_) async => [bookCategoriesRelationship]); final booksModel = await bookService.getAllBook(); @@ -95,22 +102,28 @@ void main() { ).thenAnswer((_) async => [bookModel]); //for author repository - when(() => authorsRepository.getAuthorById(id: any(named: 'id'))) - .thenAnswer((_) async => authorModel); + when( + () => authorsRepository.getAuthorById(id: any(named: 'id')), + ).thenAnswer((_) async => authorModel); // for category repository - when(() => categoriesRepository.getCategoryById(id: any(named: 'id'))) - .thenAnswer((_) async => categoryModel); + when( + () => categoriesRepository.getCategoryById(id: any(named: 'id')), + ).thenAnswer((_) async => categoryModel); // for book authors repository - when(() => bookAuthorsRepository.getRelationshipsById( - bookId: any(named: 'bookId'))) - .thenAnswer((_) async => [bookAuthorsRelationship]); + when( + () => bookAuthorsRepository.getRelationshipsById( + bookId: any(named: 'bookId'), + ), + ).thenAnswer((_) async => [bookAuthorsRelationship]); // for book categories repository - when(() => bookCategoriesRepository.getRelationshipsById( - bookId: any(named: 'bookId'))) - .thenAnswer((_) async => [bookCategoriesRelationship]); + when( + () => bookCategoriesRepository.getRelationshipsById( + bookId: any(named: 'bookId'), + ), + ).thenAnswer((_) async => [bookCategoriesRelationship]); final booksModel = await bookService.getBooksByTitle(title: 'title'); @@ -129,22 +142,28 @@ void main() { ).thenAnswer((_) async => bookModel); //for author repository - when(() => authorsRepository.getAuthorById(id: any(named: 'id'))) - .thenAnswer((_) async => authorModel); + when( + () => authorsRepository.getAuthorById(id: any(named: 'id')), + ).thenAnswer((_) async => authorModel); // for category repository - when(() => categoriesRepository.getCategoryById(id: any(named: 'id'))) - .thenAnswer((_) async => categoryModel); + when( + () => categoriesRepository.getCategoryById(id: any(named: 'id')), + ).thenAnswer((_) async => categoryModel); // for book authors repository - when(() => bookAuthorsRepository.getRelationshipsById( - bookId: any(named: 'bookId'))) - .thenAnswer((_) async => [bookAuthorsRelationship]); + when( + () => bookAuthorsRepository.getRelationshipsById( + bookId: any(named: 'bookId'), + ), + ).thenAnswer((_) async => [bookAuthorsRelationship]); // for book categories repository - when(() => bookCategoriesRepository.getRelationshipsById( - bookId: any(named: 'bookId'))) - .thenAnswer((_) async => [bookCategoriesRelationship]); + when( + () => bookCategoriesRepository.getRelationshipsById( + bookId: any(named: 'bookId'), + ), + ).thenAnswer((_) async => [bookCategoriesRelationship]); final completeBookModel = await bookService.getBookById(id: '1'); @@ -167,8 +186,10 @@ void main() { test('insert complete book', () async { // setUp all when - final completeBookModel = bookModel - .copyWith(authors: [authorModel], categories: [categoryModel]); + final completeBookModel = bookModel.copyWith( + authors: [authorModel], + categories: [categoryModel], + ); //for book repository when( @@ -178,7 +199,8 @@ void main() { //for author repository when( () => authorsRepository.getAuthorIdByColumnName( - authorName: any(named: 'authorName')), + authorName: any(named: 'authorName'), + ), ).thenAnswer((_) async => -1); when( @@ -188,7 +210,8 @@ void main() { // for category repository when( () => categoriesRepository.getCategoryIdByColumnName( - categoryName: any(named: 'categoryName')), + categoryName: any(named: 'categoryName'), + ), ).thenAnswer((_) async => 1); // for book authors repository @@ -207,19 +230,23 @@ void main() { ), ).thenAnswer((_) async => 1); - final isInserted = - await bookService.insertCompleteBook(bookModel: completeBookModel); + final isInserted = await bookService.insertCompleteBook( + bookModel: completeBookModel, + ); expect(isInserted, equals(1)); }); test('verify book is exist', () async { - when(() => booksRepository.verifyBookIsAlreadyInserted( - id: any(named: 'id'), - )).thenAnswer((_) async => true); + when( + () => booksRepository.verifyBookIsAlreadyInserted( + id: any(named: 'id'), + ), + ).thenAnswer((_) async => true); - final bookIsInserted = - await bookService.verifyBookIsAlreadyInserted(id: '1'); + final bookIsInserted = await bookService.verifyBookIsAlreadyInserted( + id: '1', + ); expect(bookIsInserted, isTrue); }); @@ -235,7 +262,9 @@ void main() { test('update status', () async { when( () => booksRepository.updateBookStatus( - id: any(named: 'id'), status: BookStatus.reading), + id: any(named: 'id'), + status: BookStatus.reading, + ), ).thenAnswer((_) async => 1); final bookRowUpdated = await bookService.updateStatus( @@ -248,7 +277,9 @@ void main() { test('update pageCount', () async { when( () => booksRepository.updateBookPageCount( - id: any(named: 'id'), pageCount: any(named: 'pageCount')), + id: any(named: 'id'), + pageCount: any(named: 'pageCount'), + ), ).thenAnswer((_) async => 1); final bookRowUpdated = await bookService.updatePageCount( @@ -268,8 +299,9 @@ void main() { }); test('delete book', () async { - when(() => booksRepository.deleteBookById(id: any(named: 'id'))) - .thenAnswer((_) async => 1); + when( + () => booksRepository.deleteBookById(id: any(named: 'id')), + ).thenAnswer((_) async => 1); final deleteBookRow = await bookService.deleteBook(id: '1'); @@ -281,60 +313,104 @@ void main() { test('get all book', () async { when( () => booksRepository.getAll(), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); //for author repository - when(() => authorsRepository.getAuthorById(id: any(named: 'id'))) - .thenAnswer((_) async => authorModel); + when( + () => authorsRepository.getAuthorById(id: any(named: 'id')), + ).thenAnswer((_) async => authorModel); // for category repository - when(() => categoriesRepository.getCategoryById(id: any(named: 'id'))) - .thenAnswer((_) async => categoryModel); + when( + () => categoriesRepository.getCategoryById(id: any(named: 'id')), + ).thenAnswer((_) async => categoryModel); // for book authors repository - when(() => bookAuthorsRepository.getRelationshipsById( - bookId: any(named: 'bookId'))) - .thenAnswer((_) async => [bookAuthorsRelationship]); + when( + () => bookAuthorsRepository.getRelationshipsById( + bookId: any(named: 'bookId'), + ), + ).thenAnswer((_) async => [bookAuthorsRelationship]); // for book categories repository - when(() => bookCategoriesRepository.getRelationshipsById( - bookId: any(named: 'bookId'))) - .thenAnswer((_) async => [bookCategoriesRelationship]); + when( + () => bookCategoriesRepository.getRelationshipsById( + bookId: any(named: 'bookId'), + ), + ).thenAnswer((_) async => [bookCategoriesRelationship]); expect( () async => await bookService.getAllBook(), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('get book by name', () async { when( () => booksRepository.getBooksByTitle(title: any(named: 'title')), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); //for author repository - when(() => authorsRepository.getAuthorById(id: any(named: 'id'))) - .thenAnswer((_) async => authorModel); + when( + () => authorsRepository.getAuthorById(id: any(named: 'id')), + ).thenAnswer((_) async => authorModel); // for category repository - when(() => categoriesRepository.getCategoryById(id: any(named: 'id'))) - .thenAnswer((_) async => categoryModel); + when( + () => categoriesRepository.getCategoryById(id: any(named: 'id')), + ).thenAnswer((_) async => categoryModel); // for book authors repository - when(() => bookAuthorsRepository.getRelationshipsById( - bookId: any(named: 'bookId'))) - .thenAnswer((_) async => [bookAuthorsRelationship]); + when( + () => bookAuthorsRepository.getRelationshipsById( + bookId: any(named: 'bookId'), + ), + ).thenAnswer((_) async => [bookAuthorsRelationship]); // for book categories repository - when(() => bookCategoriesRepository.getRelationshipsById( - bookId: any(named: 'bookId'))) - .thenAnswer((_) async => [bookCategoriesRelationship]); + when( + () => bookCategoriesRepository.getRelationshipsById( + bookId: any(named: 'bookId'), + ), + ).thenAnswer((_) async => [bookCategoriesRelationship]); expect( () async => await bookService.getBooksByTitle(title: 'title'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); @@ -347,46 +423,86 @@ void main() { ).thenAnswer((_) async => bookModel); //for author repository - when(() => authorsRepository.getAuthorById(id: any(named: 'id'))) - .thenAnswer((_) async => authorModel); + when( + () => authorsRepository.getAuthorById(id: any(named: 'id')), + ).thenAnswer((_) async => authorModel); // for category repository - when(() => categoriesRepository.getCategoryById(id: any(named: 'id'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => categoriesRepository.getCategoryById(id: any(named: 'id')), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); // for book authors repository - when(() => bookAuthorsRepository.getRelationshipsById( - bookId: any(named: 'bookId'))) - .thenAnswer((_) async => [bookAuthorsRelationship]); + when( + () => bookAuthorsRepository.getRelationshipsById( + bookId: any(named: 'bookId'), + ), + ).thenAnswer((_) async => [bookAuthorsRelationship]); // for book categories repository - when(() => bookCategoriesRepository.getRelationshipsById( - bookId: any(named: 'bookId'))) - .thenAnswer((_) async => [bookCategoriesRelationship]); + when( + () => bookCategoriesRepository.getRelationshipsById( + bookId: any(named: 'bookId'), + ), + ).thenAnswer((_) async => [bookCategoriesRelationship]); expect( () async => await bookService.getBookById(id: '1'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('countBooks', () async { when( () => booksRepository.countBooks(), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookService.countBooks(), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('insert complete book', () async { // setUp all when - final completeBookModel = bookModel - .copyWith(authors: [authorModel], categories: [categoryModel]); + final completeBookModel = bookModel.copyWith( + authors: [authorModel], + categories: [categoryModel], + ); //for book repository when( @@ -396,17 +512,24 @@ void main() { //for author repository when( () => authorsRepository.getAuthorIdByColumnName( - authorName: any(named: 'authorName')), + authorName: any(named: 'authorName'), + ), ).thenAnswer((_) async => -1); when( () => authorsRepository.insert(authorModel: authorModel), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); // for category repository when( () => categoriesRepository.getCategoryIdByColumnName( - categoryName: any(named: 'categoryName')), + categoryName: any(named: 'categoryName'), + ), ).thenAnswer((_) async => 1); // for book authors repository @@ -428,87 +551,201 @@ void main() { expect( () async => await bookService.insertCompleteBook(bookModel: completeBookModel), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('verify book is exist', () async { - when(() => booksRepository.verifyBookIsAlreadyInserted( - id: any(named: 'id'), - )).thenThrow(const LocalDatabaseException('Error on database')); + when( + () => booksRepository.verifyBookIsAlreadyInserted( + id: any(named: 'id'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookService.verifyBookIsAlreadyInserted(id: '1'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('get status', () async { when( () => booksRepository.getBookStatus(id: any(named: 'id')), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookService.getBookStatus(id: '1'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('update status', () async { when( () => booksRepository.updateBookStatus( - id: any(named: 'id'), status: BookStatus.reading), - ).thenThrow(const LocalDatabaseException('Error on database')); + id: any(named: 'id'), + status: BookStatus.reading, + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookService.updateStatus( id: '1', status: BookStatus.reading, ), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('update pageCount', () async { when( () => booksRepository.updateBookPageCount( - id: any(named: 'id'), pageCount: any(named: 'pageCount')), - ).thenThrow(const LocalDatabaseException('Error on database')); + id: any(named: 'id'), + pageCount: any(named: 'pageCount'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookService.updatePageCount( id: '1', pageCount: 100, ), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('get book Image', () async { when( () => booksRepository.getBookImageById(id: any(named: 'id')), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookService.getBookImage(id: '1'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('delete book', () async { - when(() => booksRepository.deleteBookById(id: any(named: 'id'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => booksRepository.deleteBookById(id: any(named: 'id')), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookService.deleteBook(id: '1'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); }); diff --git a/test/src/core/services/bookcase_service/bookcase_service_impl_test.dart b/test/src/core/services/bookcase_service/bookcase_service_impl_test.dart index 7c5780f6..c6b919fc 100644 --- a/test/src/core/services/bookcase_service/bookcase_service_impl_test.dart +++ b/test/src/core/services/bookcase_service/bookcase_service_impl_test.dart @@ -3,6 +3,7 @@ import 'package:bookify/src/core/models/bookcase_model.dart'; import 'package:bookify/src/core/repositories/book_on_case_repository/book_on_case_repository.dart'; import 'package:bookify/src/core/repositories/bookcase_repository/bookcase_repository.dart'; import 'package:bookify/src/core/services/bookcase_service/bookcase_service_impl.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -36,8 +37,9 @@ void main() { group('test normal CRUD of complete book without error ||', () { test('getAllBookcases()', () async { - when(() => bookcaseRepository.getAll()) - .thenAnswer((_) async => bookcases); + when( + () => bookcaseRepository.getAll(), + ).thenAnswer((_) async => bookcases); final bookcasesModel = await bookcaseService.getAllBookcases(); @@ -50,12 +52,13 @@ void main() { }); test('getBookcasesByName()', () async { - when(() => - bookcaseRepository.getBookcasesByName(name: any(named: 'name'))) - .thenAnswer((_) async => [bookcases[0]]); + when( + () => bookcaseRepository.getBookcasesByName(name: any(named: 'name')), + ).thenAnswer((_) async => [bookcases[0]]); - final bookcaseModel = - await bookcaseService.getBookcasesByName(name: 'name'); + final bookcaseModel = await bookcaseService.getBookcasesByName( + name: 'name', + ); expect(bookcaseModel[0].name, equals('name')); expect(bookcaseModel[0].description, equals('description')); @@ -63,17 +66,21 @@ void main() { }); test('getAllBookcaseRelationships()', () async { - when(() => bookOnCaseRepository - .getBooksOnCaseRelationship(bookcaseId: any(named: 'bookcaseId'))) - .thenAnswer((_) async => [ - {'bookcaseId': 1, 'bookId': '1'}, - {'bookcaseId': 1, 'bookId': '2'}, - {'bookcaseId': 1, 'bookId': '5'}, - {'bookcaseId': 1, 'bookId': '6'}, - ]); - - final bookcasesRelationships = - await bookcaseService.getAllBookcaseRelationships(bookcaseId: 1); + when( + () => bookOnCaseRepository.getBooksOnCaseRelationship( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer( + (_) async => [ + {'bookcaseId': 1, 'bookId': '1'}, + {'bookcaseId': 1, 'bookId': '2'}, + {'bookcaseId': 1, 'bookId': '5'}, + {'bookcaseId': 1, 'bookId': '6'}, + ], + ); + + final bookcasesRelationships = await bookcaseService + .getAllBookcaseRelationships(bookcaseId: 1); expect(bookcasesRelationships[0]['bookcaseId'], equals(1)); expect(bookcasesRelationships[0]['bookId'], equals('1')); @@ -86,31 +93,39 @@ void main() { }); test('getBookIdForImagePreview()', () async { - when(() => bookOnCaseRepository.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId'))) - .thenAnswer((_) async => 'bookId'); + when( + () => bookOnCaseRepository.getBookIdForImagePreview( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer((_) async => 'bookId'); - final bookId = - await bookcaseService.getBookIdForImagePreview(bookcaseId: 1); + final bookId = await bookcaseService.getBookIdForImagePreview( + bookcaseId: 1, + ); expect(bookId, equals('bookId')); }); test('getBookIdForImagePreview() -- with null', () async { - when(() => bookOnCaseRepository.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId'))).thenAnswer((_) async => null); + when( + () => bookOnCaseRepository.getBookIdForImagePreview( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer((_) async => null); - final bookId = - await bookcaseService.getBookIdForImagePreview(bookcaseId: 1); + final bookId = await bookcaseService.getBookIdForImagePreview( + bookcaseId: 1, + ); expect(bookId, isNull); }); test('getBookcaseById()', () async { - when(() => - bookcaseRepository.getById(bookcaseId: any(named: 'bookcaseId'))) - .thenAnswer((_) async => bookcases[0]); + when( + () => bookcaseRepository.getById(bookcaseId: any(named: 'bookcaseId')), + ).thenAnswer((_) async => bookcases[0]); - final bookcaseModel = - await bookcaseService.getBookcaseById(bookcaseId: 1); + final bookcaseModel = await bookcaseService.getBookcaseById( + bookcaseId: 1, + ); expect(bookcaseModel.name, equals('name')); expect(bookcaseModel.description, equals('description')); @@ -122,8 +137,9 @@ void main() { () => bookcaseRepository.insert(bookcaseModel: bookcases[0]), ).thenAnswer((_) async => 1); - final newBookcaseId = - await bookcaseService.insertBookcase(bookcaseModel: bookcases[0]); + final newBookcaseId = await bookcaseService.insertBookcase( + bookcaseModel: bookcases[0], + ); expect(newBookcaseId, equals(1)); }); @@ -131,7 +147,9 @@ void main() { test('insertBookcaseRelationship()', () async { when( () => bookOnCaseRepository.insert( - bookcaseId: any(named: 'bookcaseId'), bookId: any(named: 'bookId')), + bookcaseId: any(named: 'bookcaseId'), + bookId: any(named: 'bookId'), + ), ).thenAnswer((_) async => 1); final newRelationshipRow = await bookcaseService @@ -172,8 +190,9 @@ void main() { () => bookcaseRepository.update(bookcaseModel: bookcases[0]), ).thenAnswer((_) async => 1); - final bookcaseRowUpdated = - await bookcaseService.updateBookcase(bookcaseModel: bookcases[0]); + final bookcaseRowUpdated = await bookcaseService.updateBookcase( + bookcaseModel: bookcases[0], + ); expect(bookcaseRowUpdated, equals(1)); }); @@ -183,8 +202,9 @@ void main() { () => bookcaseRepository.delete(bookcaseId: any(named: 'bookcaseId')), ).thenAnswer((_) async => 1); - final bookcaseRowDeleted = - await bookcaseService.deleteBookcase(bookcaseId: 1); + final bookcaseRowDeleted = await bookcaseService.deleteBookcase( + bookcaseId: 1, + ); expect(bookcaseRowDeleted, equals(1)); }); @@ -206,102 +226,239 @@ void main() { group('test normal CRUD of complete book with error ||', () { test('getAllBookcases()', () async { - when(() => bookcaseRepository.getAll()) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => bookcaseRepository.getAll(), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookcaseService.getAllBookcases(), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('getBookcasesByName()', () async { - when(() => - bookcaseRepository.getBookcasesByName(name: any(named: 'name'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => bookcaseRepository.getBookcasesByName(name: any(named: 'name')), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookcaseService.getBookcasesByName(name: 'name'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('getAllBookcaseRelationships()', () async { - when(() => bookOnCaseRepository.getBooksOnCaseRelationship( - bookcaseId: any(named: 'bookcaseId'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => bookOnCaseRepository.getBooksOnCaseRelationship( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookcaseService.getAllBookcaseRelationships(bookcaseId: 1), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('getBookIdForImagePreview()', () async { - when(() => bookOnCaseRepository.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => bookOnCaseRepository.getBookIdForImagePreview( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookcaseService.getBookIdForImagePreview(bookcaseId: 1), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('getBookcaseById()', () async { - when(() => - bookcaseRepository.getById(bookcaseId: any(named: 'bookcaseId'))) - .thenThrow(const LocalDatabaseException('Error on database')); + when( + () => bookcaseRepository.getById(bookcaseId: any(named: 'bookcaseId')), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookcaseService.getBookcaseById(bookcaseId: 1), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('insertBookcase()', () async { when( () => bookcaseRepository.insert(bookcaseModel: bookcases[0]), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookcaseService.insertBookcase(bookcaseModel: bookcases[0]), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('insertBookcaseRelationship()', () async { when( () => bookOnCaseRepository.insert( - bookcaseId: any(named: 'bookcaseId'), bookId: any(named: 'bookId')), - ).thenThrow(const LocalDatabaseException('Error on database')); + bookcaseId: any(named: 'bookcaseId'), + bookId: any(named: 'bookId'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookcaseService.insertBookcaseRelationship( - bookcaseId: 1, bookId: '1'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + bookcaseId: 1, + bookId: '1', + ), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('countBookcases()', () async { when( () => bookcaseRepository.countBookcases(), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookcaseService.countBookcases(), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); @@ -312,39 +469,87 @@ void main() { named: 'bookId', ), ), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookcaseService.countBookcasesByBook( bookId: '1', ), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('updateBookcase()', () async { when( () => bookcaseRepository.update(bookcaseModel: bookcases[0]), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookcaseService.updateBookcase(bookcaseModel: bookcases[0]), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('deleteBookcase()', () async { when( () => bookcaseRepository.delete(bookcaseId: any(named: 'bookcaseId')), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookcaseService.deleteBookcase(bookcaseId: 1), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); @@ -354,13 +559,31 @@ void main() { bookcaseId: any(named: 'bookcaseId'), bookId: any(named: 'bookId'), ), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await bookcaseService.deleteBookcaseRelationship( - bookcaseId: 1, bookId: '1'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on database'), + bookcaseId: 1, + bookId: '1', + ), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); }); diff --git a/test/src/core/services/loan_services/loan_service_impl_test.dart b/test/src/core/services/loan_services/loan_service_impl_test.dart index 28fb664e..f72d447a 100644 --- a/test/src/core/services/loan_services/loan_service_impl_test.dart +++ b/test/src/core/services/loan_services/loan_service_impl_test.dart @@ -2,6 +2,7 @@ import 'package:bookify/src/core/errors/local_database_exception/local_database_ import 'package:bookify/src/core/models/loan_model.dart'; import 'package:bookify/src/core/repositories/loan_repository/loan_repository.dart'; import 'package:bookify/src/core/services/loan_services/loan_service_impl.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -62,10 +63,11 @@ void main() { equals(DateTime(2024, 01, 10)), ); expect( - loansModel[0].devolutionDate, - equals( - DateTime(DateTime.april, 2024), - )); + loansModel[0].devolutionDate, + equals( + DateTime(DateTime.april, 2024), + ), + ); expect(loansModel[0].idContact, equals('idContact')); expect(loansModel[0].bookId, equals('bookId')); }); @@ -89,17 +91,19 @@ void main() { equals(DateTime(2024, 01, 10)), ); expect( - loansModel[0].devolutionDate, - equals( - DateTime(DateTime.april, 2024), - )); + loansModel[0].devolutionDate, + equals( + DateTime(DateTime.april, 2024), + ), + ); expect(loansModel[0].idContact, equals('idContact')); expect(loansModel[0].bookId, equals('bookId')); }); test('get by Id', () async { - when(() => loanRepository.getById(loanId: any(named: 'loanId'))) - .thenAnswer( + when( + () => loanRepository.getById(loanId: any(named: 'loanId')), + ).thenAnswer( (_) async => loans[1], ); @@ -112,10 +116,11 @@ void main() { equals(DateTime(2024, 01, 10)), ); expect( - loanModel.devolutionDate, - equals( - DateTime(DateTime.april, 2024), - )); + loanModel.devolutionDate, + equals( + DateTime(DateTime.april, 2024), + ), + ); expect(loanModel.idContact, equals('idContact')); expect(loanModel.bookId, equals('bookId')); }); @@ -172,13 +177,30 @@ void main() { group('test normal CRUD of loan service with error ||', () { test('get all -- LocalDatabaseException', () async { - when(() => loanRepository.getAll()) - .thenThrow(const LocalDatabaseException('Error on Database')); + when( + () => loanRepository.getAll(), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await loanService.getAll(), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on Database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); @@ -187,68 +209,168 @@ void main() { () => loanRepository.getLoansByBookTitle( title: any(named: 'title'), ), - ).thenThrow(const LocalDatabaseException('Error on Database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await loanService.getLoansByBookTitle(title: 'title'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on Database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('get by Id -- LocalDatabaseException', () async { - when(() => loanRepository.getById(loanId: any(named: 'loanId'))) - .thenThrow(const LocalDatabaseException('Error on Database')); + when( + () => loanRepository.getById(loanId: any(named: 'loanId')), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await loanService.getById(loanId: 1), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on Database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('countLoans -- LocalDatabaseException', () async { when( () => loanRepository.countLoans(), - ).thenThrow(const LocalDatabaseException('Error on Database')); - + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); + expect( () async => await loanService.countLoans(), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on Database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('insert -- LocalDatabaseException', () async { - when(() => loanRepository.insert(loanModel: loans[1])) - .thenThrow(const LocalDatabaseException('Error on Database')); + when( + () => loanRepository.insert(loanModel: loans[1]), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await loanService.insert(loanModel: loans[1]), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on Database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('update -- LocalDatabaseException', () async { - when(() => loanRepository.update(loanModel: loans[1])) - .thenThrow(const LocalDatabaseException('Error on Database')); + when( + () => loanRepository.update(loanModel: loans[1]), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await loanService.update(loanModel: loans[1]), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on Database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('delete -- LocalDatabaseException', () async { - when(() => loanRepository.delete(loanId: any(named: 'loanId'))) - .thenThrow(const LocalDatabaseException('Error on Database')); + when( + () => loanRepository.delete(loanId: any(named: 'loanId')), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await loanService.delete(loanId: 1), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on Database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); }); diff --git a/test/src/core/services/reading_services/reading_service_impl_test.dart b/test/src/core/services/reading_services/reading_service_impl_test.dart index 524acd64..dcffee72 100644 --- a/test/src/core/services/reading_services/reading_service_impl_test.dart +++ b/test/src/core/services/reading_services/reading_service_impl_test.dart @@ -2,6 +2,7 @@ import 'package:bookify/src/core/errors/local_database_exception/local_database_ import 'package:bookify/src/core/models/reading_model.dart'; import 'package:bookify/src/core/repositories/reading_repository/reading_repository.dart'; import 'package:bookify/src/core/services/reading_services/reading_service_impl.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -82,8 +83,9 @@ void main() { }); test('get by Id', () async { - when(() => readingRepository.getById(readingId: any(named: 'readingId'))) - .thenAnswer( + when( + () => readingRepository.getById(readingId: any(named: 'readingId')), + ).thenAnswer( (_) async => readings[1], ); @@ -150,13 +152,30 @@ void main() { group('test normal CRUD of reading service with error ||', () { test('get all -- LocalDatabaseException', () async { - when(() => readingRepository.getAll()) - .thenThrow(const LocalDatabaseException('Error on Database')); + when( + () => readingRepository.getAll(), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await readingService.getAll(), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on Database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); @@ -165,68 +184,168 @@ void main() { () => readingRepository.getReadingsByBookTitle( title: any(named: 'title'), ), - ).thenThrow(const LocalDatabaseException('Error on Database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await readingService.getReadingsByBookTitle(title: 'title'), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on Database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('get by Id -- LocalDatabaseException', () async { - when(() => readingRepository.getById(readingId: any(named: 'readingId'))) - .thenThrow(const LocalDatabaseException('Error on Database')); + when( + () => readingRepository.getById(readingId: any(named: 'readingId')), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await readingService.getById(readingId: 1), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on Database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('countReadings -- LocalDatabaseException', () async { when( () => readingRepository.countReadings(), - ).thenThrow(const LocalDatabaseException('Error on Database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await readingService.countReadings(), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on Database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('insert -- LocalDatabaseException', () async { - when(() => readingRepository.insert(readingModel: readings[1])) - .thenThrow(const LocalDatabaseException('Error on Database')); + when( + () => readingRepository.insert(readingModel: readings[1]), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await readingService.insert(readingModel: readings[1]), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on Database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('update -- LocalDatabaseException', () async { - when(() => readingRepository.update(readingModel: readings[1])) - .thenThrow(const LocalDatabaseException('Error on Database')); + when( + () => readingRepository.update(readingModel: readings[1]), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await readingService.update(readingModel: readings[1]), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on Database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); test('delete -- LocalDatabaseException', () async { - when(() => readingRepository.delete(readingId: any(named: 'readingId'))) - .thenThrow(const LocalDatabaseException('Error on Database')); + when( + () => readingRepository.delete(readingId: any(named: 'readingId')), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); expect( () async => await readingService.delete(readingId: 1), - throwsA((Exception e) => - e is LocalDatabaseException && e.message == 'Error on Database'), + throwsA( + isA() + .having( + (e) => e.code, + 'code', + LocalDatabaseErrorCode.unknown, + ) + .having( + (e) => e.descriptionMessage, + 'descriptionMessage', + 'Error on database', + ), + ), ); }); }); diff --git a/test/src/features/about/bloc/about_bloc_test.dart b/test/src/features/about/bloc/about_bloc_test.dart index ee301c0c..bc3a5b8c 100644 --- a/test/src/features/about/bloc/about_bloc_test.dart +++ b/test/src/features/about/bloc/about_bloc_test.dart @@ -44,8 +44,9 @@ void main() { blocTest( 'Test GotAppVersionEvent work when throw Generic Exception', build: () => aboutBloc, - setUp: () => when(() => appVersionService.getAppVersion()) - .thenThrow(Exception('Generic Error')), + setUp: () => when( + () => appVersionService.getAppVersion(), + ).thenThrow(Exception('Generic Error')), act: (bloc) => bloc.add(GotAppVersionEvent()), verify: (_) => verify(() => appVersionService.getAppVersion()).called(1), expect: () => [ diff --git a/test/src/features/auth/bloc/auth_bloc_test.dart b/test/src/features/auth/bloc/auth_bloc_test.dart index f25033a6..fe3aa992 100644 --- a/test/src/features/auth/bloc/auth_bloc_test.dart +++ b/test/src/features/auth/bloc/auth_bloc_test.dart @@ -1,4 +1,5 @@ import 'package:bloc_test/bloc_test.dart'; +import 'package:bookify/src/shared/enums/auth_error_code.dart'; import 'package:bookify/src/features/auth/bloc/auth_bloc.dart'; import 'package:bookify/src/core/errors/auth_exception/auth_exception.dart'; import 'package:bookify/src/core/services/auth_service/auth_service.dart'; @@ -27,13 +28,14 @@ void main() { blocTest( 'Test SignedInAuthEvent work when Google button', build: () => authBloc, - setUp: () => when( - () => authService.signIn( - signInType: SignInType.google, - ), - ).thenAnswer( - (_) async => 1, - ), + setUp: () => + when( + () => authService.signIn( + signInType: SignInType.google, + ), + ).thenAnswer( + (_) async => 1, + ), act: (bloc) => bloc.add( SignedInAuthEvent(signInTypeButton: SignInType.google), ), @@ -51,13 +53,14 @@ void main() { blocTest( 'Test SignedInAuthEvent work emit error on Apple button', build: () => authBloc, - setUp: () => when( - () => authService.signIn( - signInType: SignInType.apple, - ), - ).thenAnswer( - (_) async => 1, - ), + setUp: () => + when( + () => authService.signIn( + signInType: SignInType.apple, + ), + ).thenAnswer( + (_) async => 1, + ), act: (bloc) => bloc.add( SignedInAuthEvent(signInTypeButton: SignInType.apple), ), @@ -75,13 +78,14 @@ void main() { blocTest( 'Test SignedInAuthEvent work when Facebook button', build: () => authBloc, - setUp: () => when( - () => authService.signIn( - signInType: SignInType.facebook, - ), - ).thenAnswer( - (_) async => 1, - ), + setUp: () => + when( + () => authService.signIn( + signInType: SignInType.facebook, + ), + ).thenAnswer( + (_) async => 1, + ), act: (bloc) => bloc.add( SignedInAuthEvent(signInTypeButton: SignInType.facebook), ), @@ -99,13 +103,14 @@ void main() { blocTest( 'Test SignedInAuthEvent work when authSignedIn is 0', build: () => authBloc, - setUp: () => when( - () => authService.signIn( - signInType: SignInType.google, - ), - ).thenAnswer( - (_) async => 0, - ), + setUp: () => + when( + () => authService.signIn( + signInType: SignInType.google, + ), + ).thenAnswer( + (_) async => 0, + ), act: (bloc) => bloc.add( SignedInAuthEvent(signInTypeButton: SignInType.google), ), @@ -123,13 +128,17 @@ void main() { blocTest( 'Test SignedInAuthEvent work when throw AuthException', build: () => authBloc, - setUp: () => when( - () => authService.signIn( - signInType: SignInType.google, - ), - ).thenThrow( - const AuthException('Error on authentication'), - ), + setUp: () => + when( + () => authService.signIn( + signInType: SignInType.google, + ), + ).thenThrow( + const AuthException( + AuthErrorCode.internalError, + descriptionMessage: 'Error on authentication', + ), + ), act: (bloc) => bloc.add( SignedInAuthEvent(signInTypeButton: SignInType.google), ), @@ -147,13 +156,14 @@ void main() { blocTest( 'Test SignedInAuthEvent work when throw Generic Exception', build: () => authBloc, - setUp: () => when( - () => authService.signIn( - signInType: SignInType.google, - ), - ).thenThrow( - Exception('Generic Error'), - ), + setUp: () => + when( + () => authService.signIn( + signInType: SignInType.google, + ), + ).thenThrow( + Exception('Generic Error'), + ), act: (bloc) => bloc.add( SignedInAuthEvent(signInTypeButton: SignInType.google), ), diff --git a/test/src/features/book_detail/bloc/book_detail_bloc_test.dart b/test/src/features/book_detail/bloc/book_detail_bloc_test.dart index 1bc2d5e0..770f8cf8 100644 --- a/test/src/features/book_detail/bloc/book_detail_bloc_test.dart +++ b/test/src/features/book_detail/bloc/book_detail_bloc_test.dart @@ -5,6 +5,7 @@ import 'package:bookify/src/core/models/author_model.dart'; import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/models/category_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -48,8 +49,9 @@ void main() { ).thenAnswer((_) async => true), act: (bloc) => bloc.add(VerifiedBookIsInsertedEvent(bookId: '1')), verify: (_) { - verify(() => bookService.verifyBookIsAlreadyInserted(id: '1')) - .called(1); + verify( + () => bookService.verifyBookIsAlreadyInserted(id: '1'), + ).called(1); }, expect: () => [ isA(), @@ -60,13 +62,20 @@ void main() { blocTest( 'test if VerifiedBookIsInsertedEvent work with error state', build: () => bookDetailBloc, - setUp: () => when( - () => bookService.verifyBookIsAlreadyInserted(id: any(named: 'id')), - ).thenThrow(const LocalDatabaseException('error on database')), + setUp: () => + when( + () => bookService.verifyBookIsAlreadyInserted(id: any(named: 'id')), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ), act: (bloc) => bloc.add(VerifiedBookIsInsertedEvent(bookId: '1')), verify: (_) { - verify(() => bookService.verifyBookIsAlreadyInserted(id: '1')) - .called(1); + verify( + () => bookService.verifyBookIsAlreadyInserted(id: '1'), + ).called(1); }, expect: () => [ isA(), @@ -82,8 +91,9 @@ void main() { ).thenThrow(Exception('generic exception')), act: (bloc) => bloc.add(VerifiedBookIsInsertedEvent(bookId: '1')), verify: (_) { - verify(() => bookService.verifyBookIsAlreadyInserted(id: '1')) - .called(1); + verify( + () => bookService.verifyBookIsAlreadyInserted(id: '1'), + ).called(1); }, expect: () => [ isA(), @@ -99,8 +109,9 @@ void main() { ).thenAnswer((_) async => 1), act: (bloc) => bloc.add(BookInsertedEvent(bookModel: bookModel)), verify: (_) { - verify(() => bookService.insertCompleteBook(bookModel: bookModel)) - .called(1); + verify( + () => bookService.insertCompleteBook(bookModel: bookModel), + ).called(1); }, expect: () => [ isA(), @@ -116,8 +127,9 @@ void main() { ).thenAnswer((_) async => 0), act: (bloc) => bloc.add(BookInsertedEvent(bookModel: bookModel)), verify: (_) { - verify(() => bookService.insertCompleteBook(bookModel: bookModel)) - .called(1); + verify( + () => bookService.insertCompleteBook(bookModel: bookModel), + ).called(1); }, expect: () => [ isA(), @@ -128,13 +140,20 @@ void main() { blocTest( 'test if BookInsertedEvent work with error state', build: () => bookDetailBloc, - setUp: () => when( - () => bookService.insertCompleteBook(bookModel: bookModel), - ).thenThrow(const LocalDatabaseException('error on database')), + setUp: () => + when( + () => bookService.insertCompleteBook(bookModel: bookModel), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ), act: (bloc) => bloc.add(BookInsertedEvent(bookModel: bookModel)), verify: (_) { - verify(() => bookService.insertCompleteBook(bookModel: bookModel)) - .called(1); + verify( + () => bookService.insertCompleteBook(bookModel: bookModel), + ).called(1); }, expect: () => [ isA(), @@ -150,8 +169,9 @@ void main() { ).thenThrow(Exception('generic exception')), act: (bloc) => bloc.add(BookInsertedEvent(bookModel: bookModel)), verify: (_) { - verify(() => bookService.insertCompleteBook(bookModel: bookModel)) - .called(1); + verify( + () => bookService.insertCompleteBook(bookModel: bookModel), + ).called(1); }, expect: () => [ isA(), @@ -243,7 +263,12 @@ void main() { setUp: () { when( () => bookService.deleteBook(id: '1'), - ).thenThrow(const LocalDatabaseException('error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); when( () => bookService.getBookStatus(id: '1'), ).thenAnswer((_) async => BookStatus.library); diff --git a/test/src/features/book_detail/views/book_detail_page_test.dart b/test/src/features/book_detail/views/book_detail_page_test.dart index 726fad98..dc51863e 100644 --- a/test/src/features/book_detail/views/book_detail_page_test.dart +++ b/test/src/features/book_detail/views/book_detail_page_test.dart @@ -5,6 +5,7 @@ import 'package:bookify/src/core/models/category_model.dart'; import 'package:bookify/src/features/book_detail/bloc/book_detail_bloc.dart'; import 'package:bookify/src/features/book_detail/views/book_detail_page.dart'; import 'package:bookify/src/features/book_detail/views/widgets/book_pages_reading_time/bloc/book_pages_reading_time_bloc.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -271,7 +272,8 @@ void main() { BookDetailLoadedState(bookIsInserted: false), BookDetailLoadingState(), BookDetailErrorState( - errorMessage: 'Error on inserting the book in database', + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: 'Error on inserting the book in database', ), ]), ); @@ -289,7 +291,7 @@ void main() { expect( find.widgetWithText( SnackBar, - 'Error on inserting the book in database', + 'error-unknown', ), findsOneWidget, ); @@ -377,7 +379,8 @@ void main() { BookDetailLoadedState(bookIsInserted: true), BookDetailLoadingState(), BookDetailErrorState( - errorMessage: 'Error on removing the book from database', + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: 'Error on removing the book from database', ), ]), ); @@ -398,7 +401,7 @@ void main() { expect( find.widgetWithText( SnackBar, - 'Error on removing the book from database', + 'error-unknown', ), findsOneWidget, ); diff --git a/test/src/features/book_detail/widgets/book_pages_reading_time/bloc/book_pages_reading_time_bloc_test.dart b/test/src/features/book_detail/widgets/book_pages_reading_time/bloc/book_pages_reading_time_bloc_test.dart index 1237d81a..fb496966 100644 --- a/test/src/features/book_detail/widgets/book_pages_reading_time/bloc/book_pages_reading_time_bloc_test.dart +++ b/test/src/features/book_detail/widgets/book_pages_reading_time/bloc/book_pages_reading_time_bloc_test.dart @@ -1,4 +1,5 @@ import 'package:bloc_test/bloc_test.dart'; +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/models/user_page_reading_time_model.dart'; import 'package:bookify/src/core/repositories/user_page_reading_time_repository/user_page_reading_time_repository.dart'; @@ -34,11 +35,12 @@ void main() { blocTest( 'Test GotBookPagesReadingTimeEvent work', build: () => bookPagesReadingTimeBloc, - setUp: () => when( - () => userPageReadingTimeRepository.getUserPageReadingTime(), - ).thenAnswer( - (_) async => userPageReadingTime, - ), + setUp: () => + when( + () => userPageReadingTimeRepository.getUserPageReadingTime(), + ).thenAnswer( + (_) async => userPageReadingTime, + ), act: (bloc) => bloc.add(GotBookPagesReadingTimeEvent()), verify: (_) => verify( () => userPageReadingTimeRepository.getUserPageReadingTime(), @@ -52,11 +54,15 @@ void main() { blocTest( 'Test GotBookPagesReadingTimeEvent work when throw StorageException', build: () => bookPagesReadingTimeBloc, - setUp: () => when( - () => userPageReadingTimeRepository.getUserPageReadingTime(), - ).thenThrow( - const StorageException('Error on storage'), - ), + setUp: () => + when( + () => userPageReadingTimeRepository.getUserPageReadingTime(), + ).thenThrow( + const StorageException( + StorageErrorCode.invalidValue, + descriptionMessage: 'Error on storage', + ), + ), act: (bloc) => bloc.add(GotBookPagesReadingTimeEvent()), verify: (_) => verify( () => userPageReadingTimeRepository.getUserPageReadingTime(), @@ -70,11 +76,12 @@ void main() { blocTest( 'Test GotBookPagesReadingTimeEvent work when throw Generic Exception', build: () => bookPagesReadingTimeBloc, - setUp: () => when( - () => userPageReadingTimeRepository.getUserPageReadingTime(), - ).thenThrow( - Exception('Generic Error'), - ), + setUp: () => + when( + () => userPageReadingTimeRepository.getUserPageReadingTime(), + ).thenThrow( + Exception('Generic Error'), + ), act: (bloc) => bloc.add(GotBookPagesReadingTimeEvent()), verify: (_) => verify( () => userPageReadingTimeRepository.getUserPageReadingTime(), diff --git a/test/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_bloc_test.dart b/test/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_bloc_test.dart index 510bf889..dc2bc9d1 100644 --- a/test/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_bloc_test.dart +++ b/test/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_bloc_test.dart @@ -2,6 +2,7 @@ import 'package:bloc_test/bloc_test.dart'; import 'package:bookify/src/features/book_on_bookcase_detail/bloc/book_on_bookcase_detail_bloc.dart'; import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/services/bookcase_service/bookcase_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -49,11 +50,17 @@ void main() { blocTest( 'test GotCountOfBookcasesByBookEvent work when throw LocalDatabaseException', build: () => bookOnBookcaseDetailBloc, - setUp: () => when( - () => bookcaseService.countBookcasesByBook( - bookId: any(named: 'bookId'), - ), - ).thenThrow(const LocalDatabaseException('Error on Database')), + setUp: () => + when( + () => bookcaseService.countBookcasesByBook( + bookId: any(named: 'bookId'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ), act: (bloc) => bloc.add( GotCountOfBookcasesByBookEvent(bookId: 'bookId'), ), @@ -147,12 +154,18 @@ void main() { blocTest( 'test DeletedBookOnBookcaseEvent work throw LocalDatabaseException', build: () => bookOnBookcaseDetailBloc, - setUp: () => when( - () => bookcaseService.deleteBookcaseRelationship( - bookId: any(named: 'bookId'), - bookcaseId: any(named: 'bookcaseId'), - ), - ).thenThrow(const LocalDatabaseException('Error on Database')), + setUp: () => + when( + () => bookcaseService.deleteBookcaseRelationship( + bookId: any(named: 'bookId'), + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ), act: (bloc) => bloc.add( DeletedBookOnBookcaseEvent( bookId: 'bookId', diff --git a/test/src/features/bookcase/bloc/bookcase_bloc_test.dart b/test/src/features/bookcase/bloc/bookcase_bloc_test.dart index 6327f346..8101eeb1 100644 --- a/test/src/features/bookcase/bloc/bookcase_bloc_test.dart +++ b/test/src/features/bookcase/bloc/bookcase_bloc_test.dart @@ -5,6 +5,7 @@ import 'package:bookify/src/core/errors/local_database_exception/local_database_ import 'package:bookify/src/core/models/bookcase_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/bookcase_service/bookcase_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -52,22 +53,27 @@ void main() { 'test if GotAllBookcaseEvent work', build: () => bookcaseBloc, setUp: () async { - when(() => bookcaseService.getAllBookcases()) - .thenAnswer((_) async => bookcasesModel); + when( + () => bookcaseService.getAllBookcases(), + ).thenAnswer((_) async => bookcasesModel); - when(() => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId'))) - .thenAnswer((_) async => 'bookId'); + when( + () => bookcaseService.getBookIdForImagePreview( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer((_) async => 'bookId'); - when(() => bookService.getBookImage(id: any(named: 'id'))) - .thenAnswer((_) async => 'bookImg'); + when( + () => bookService.getBookImage(id: any(named: 'id')), + ).thenAnswer((_) async => 'bookImg'); }, act: (bloc) => bloc.add(GotAllBookcasesEvent()), verify: (_) { verify(() => bookcaseService.getAllBookcases()).called(1); verify( () => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId')), + bookcaseId: any(named: 'bookcaseId'), + ), ).called(2); verify(() => bookService.getBookImage(id: any(named: 'id'))).called(2); }, @@ -81,15 +87,17 @@ void main() { 'test if GotAllBookcaseEvent work when is empty List', build: () => bookcaseBloc, setUp: () async { - when(() => bookcaseService.getAllBookcases()) - .thenAnswer((_) async => []); + when( + () => bookcaseService.getAllBookcases(), + ).thenAnswer((_) async => []); }, act: (bloc) => bloc.add(GotAllBookcasesEvent()), verify: (_) { verify(() => bookcaseService.getAllBookcases()).called(1); verifyNever( () => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId')), + bookcaseId: any(named: 'bookcaseId'), + ), ); verifyNever(() => bookService.getBookImage(id: any(named: 'id'))); }, @@ -103,20 +111,23 @@ void main() { 'test if GotAllBookcaseEvent work when bookcaseId is null', build: () => bookcaseBloc, setUp: () async { - when(() => bookcaseService.getAllBookcases()).thenAnswer((_) async => [ - const BookcaseModel( - name: 'name', - description: 'description', - color: Colors.black, - ), - ]); + when(() => bookcaseService.getAllBookcases()).thenAnswer( + (_) async => [ + const BookcaseModel( + name: 'name', + description: 'description', + color: Colors.black, + ), + ], + ); }, act: (bloc) => bloc.add(GotAllBookcasesEvent()), verify: (_) { verify(() => bookcaseService.getAllBookcases()).called(1); verifyNever( () => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId')), + bookcaseId: any(named: 'bookcaseId'), + ), ); verifyNever(() => bookService.getBookImage(id: any(named: 'id'))); }, @@ -130,15 +141,22 @@ void main() { 'test if GotAllBookcaseEvent work when throw LocalDatabaseException', build: () => bookcaseBloc, setUp: () async { - when(() => bookcaseService.getAllBookcases()) - .thenThrow(const LocalDatabaseException('Error on Database')); + when( + () => bookcaseService.getAllBookcases(), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); }, act: (bloc) => bloc.add(GotAllBookcasesEvent()), verify: (_) { verify(() => bookcaseService.getAllBookcases()).called(1); verifyNever( () => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId')), + bookcaseId: any(named: 'bookcaseId'), + ), ); verifyNever(() => bookService.getBookImage(id: any(named: 'id'))); }, @@ -152,15 +170,17 @@ void main() { 'test if GotAllBookcaseEvent work when throw Generic Exception', build: () => bookcaseBloc, setUp: () async { - when(() => bookcaseService.getAllBookcases()) - .thenThrow(Exception('Generic Error')); + when( + () => bookcaseService.getAllBookcases(), + ).thenThrow(Exception('Generic Error')); }, act: (bloc) => bloc.add(GotAllBookcasesEvent()), verify: (_) { verify(() => bookcaseService.getAllBookcases()).called(1); verifyNever( () => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId')), + bookcaseId: any(named: 'bookcaseId'), + ), ); verifyNever(() => bookService.getBookImage(id: any(named: 'id'))); }, @@ -174,31 +194,38 @@ void main() { 'test if FoundBookcaseByNameEvent work', build: () => bookcaseBloc, setUp: () async { - when(() => bookcaseService.getBookcasesByName(name: any(named: 'name'))) - .thenAnswer((_) async => [ - const BookcaseModel( - id: 1, - name: 'Fantasia', - description: 'Fantasia Description', - color: Colors.black, - ), - ]); - when(() => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId'))) - .thenAnswer((_) async => 'bookId'); + when( + () => bookcaseService.getBookcasesByName(name: any(named: 'name')), + ).thenAnswer( + (_) async => [ + const BookcaseModel( + id: 1, + name: 'Fantasia', + description: 'Fantasia Description', + color: Colors.black, + ), + ], + ); + when( + () => bookcaseService.getBookIdForImagePreview( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer((_) async => 'bookId'); - when(() => bookService.getBookImage(id: any(named: 'id'))) - .thenAnswer((_) async => 'bookImg'); + when( + () => bookService.getBookImage(id: any(named: 'id')), + ).thenAnswer((_) async => 'bookImg'); }, act: (bloc) => bloc.add(FoundBookcaseByNameEvent(searchQueryName: 'Fantasia')), verify: (_) { - verify(() => - bookcaseService.getBookcasesByName(name: any(named: 'name'))) - .called(1); + verify( + () => bookcaseService.getBookcasesByName(name: any(named: 'name')), + ).called(1); verify( () => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId')), + bookcaseId: any(named: 'bookcaseId'), + ), ).called(1); verify(() => bookService.getBookImage(id: any(named: 'id'))).called(1); }, @@ -212,15 +239,16 @@ void main() { 'test if FoundBookcaseByNameEvent work hen is empty List', build: () => bookcaseBloc, setUp: () async { - when(() => bookcaseService.getBookcasesByName(name: any(named: 'name'))) - .thenAnswer((_) async => []); + when( + () => bookcaseService.getBookcasesByName(name: any(named: 'name')), + ).thenAnswer((_) async => []); }, act: (bloc) => bloc.add(FoundBookcaseByNameEvent(searchQueryName: 'Fantasia')), verify: (_) { - verify(() => - bookcaseService.getBookcasesByName(name: any(named: 'name'))) - .called(1); + verify( + () => bookcaseService.getBookcasesByName(name: any(named: 'name')), + ).called(1); verifyNever( () => bookcaseService.getBookIdForImagePreview( bookcaseId: any(named: 'bookcaseId'), @@ -242,24 +270,28 @@ void main() { 'test if FoundBookcaseByNameEvent work when bookcaseId is null', build: () => bookcaseBloc, setUp: () async { - when(() => bookcaseService.getBookcasesByName(name: any(named: 'name'))) - .thenAnswer((_) async => [ - const BookcaseModel( - name: 'Fantasia', - description: 'description', - color: Colors.black, - ), - ]); + when( + () => bookcaseService.getBookcasesByName(name: any(named: 'name')), + ).thenAnswer( + (_) async => [ + const BookcaseModel( + name: 'Fantasia', + description: 'description', + color: Colors.black, + ), + ], + ); }, act: (bloc) => bloc.add(FoundBookcaseByNameEvent(searchQueryName: 'Fantasia')), verify: (_) { - verify(() => - bookcaseService.getBookcasesByName(name: any(named: 'name'))) - .called(1); + verify( + () => bookcaseService.getBookcasesByName(name: any(named: 'name')), + ).called(1); verifyNever( () => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId')), + bookcaseId: any(named: 'bookcaseId'), + ), ); verifyNever(() => bookService.getBookImage(id: any(named: 'id'))); }, @@ -273,18 +305,25 @@ void main() { 'test if FoundBookcaseByNameEvent work when throw LocalDatabaseException', build: () => bookcaseBloc, setUp: () async { - when(() => bookcaseService.getBookcasesByName(name: any(named: 'name'))) - .thenThrow(const LocalDatabaseException('Error on Database')); + when( + () => bookcaseService.getBookcasesByName(name: any(named: 'name')), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); }, act: (bloc) => bloc.add(FoundBookcaseByNameEvent(searchQueryName: 'Fantasia')), verify: (_) { - verify(() => - bookcaseService.getBookcasesByName(name: any(named: 'name'))) - .called(1); + verify( + () => bookcaseService.getBookcasesByName(name: any(named: 'name')), + ).called(1); verifyNever( () => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId')), + bookcaseId: any(named: 'bookcaseId'), + ), ); verifyNever(() => bookService.getBookImage(id: any(named: 'id'))); }, @@ -298,18 +337,20 @@ void main() { 'test if FoundBookcaseByNameEvent work when throw Generic Exception', build: () => bookcaseBloc, setUp: () async { - when(() => bookcaseService.getBookcasesByName(name: any(named: 'name'))) - .thenThrow(Exception('Generic Error')); + when( + () => bookcaseService.getBookcasesByName(name: any(named: 'name')), + ).thenThrow(Exception('Generic Error')); }, act: (bloc) => bloc.add(FoundBookcaseByNameEvent(searchQueryName: 'Fantasia')), verify: (_) { - verify(() => - bookcaseService.getBookcasesByName(name: any(named: 'name'))) - .called(1); + verify( + () => bookcaseService.getBookcasesByName(name: any(named: 'name')), + ).called(1); verifyNever( () => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId')), + bookcaseId: any(named: 'bookcaseId'), + ), ); verifyNever(() => bookService.getBookImage(id: any(named: 'id'))); }, @@ -323,15 +364,22 @@ void main() { 'test if DeletedBookcasesEvent work', build: () => bookcaseBloc, setUp: () async { - when(() => bookcaseService.deleteBookcase( - bookcaseId: any(named: 'bookcaseId'))).thenAnswer((_) async => 1); - when(() => bookcaseService.getAllBookcases()) - .thenAnswer((_) async => bookcasesModel); - when(() => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId'))) - .thenAnswer((_) async => 'bookId'); - when(() => bookService.getBookImage(id: any(named: 'id'))) - .thenAnswer((_) async => 'bookImg'); + when( + () => bookcaseService.deleteBookcase( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer((_) async => 1); + when( + () => bookcaseService.getAllBookcases(), + ).thenAnswer((_) async => bookcasesModel); + when( + () => bookcaseService.getBookIdForImagePreview( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer((_) async => 'bookId'); + when( + () => bookService.getBookImage(id: any(named: 'id')), + ).thenAnswer((_) async => 'bookImg'); }, act: (bloc) => bloc.add( DeletedBookcasesEvent( @@ -341,8 +389,11 @@ void main() { ), ), verify: (_) { - verify(() => bookcaseService.deleteBookcase( - bookcaseId: any(named: 'bookcaseId'))).called(1); + verify( + () => bookcaseService.deleteBookcase( + bookcaseId: any(named: 'bookcaseId'), + ), + ).called(1); verify(() => bookcaseService.getAllBookcases()).called(1); verify( () => bookcaseService.getBookIdForImagePreview( @@ -361,8 +412,11 @@ void main() { 'test if DeletedBookcasesEvent work with error on delete', build: () => bookcaseBloc, setUp: () async { - when(() => bookcaseService.deleteBookcase( - bookcaseId: any(named: 'bookcaseId'))).thenAnswer((_) async => -1); + when( + () => bookcaseService.deleteBookcase( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer((_) async => -1); }, act: (bloc) => bloc.add( DeletedBookcasesEvent( @@ -372,8 +426,11 @@ void main() { ), ), verify: (_) { - verify(() => bookcaseService.deleteBookcase( - bookcaseId: any(named: 'bookcaseId'))).called(1); + verify( + () => bookcaseService.deleteBookcase( + bookcaseId: any(named: 'bookcaseId'), + ), + ).called(1); verifyNever(() => bookcaseService.getAllBookcases()); verifyNever( () => bookcaseService.getBookIdForImagePreview( @@ -392,10 +449,14 @@ void main() { 'test if DeletedBookcasesEvent work with empty list', build: () => bookcaseBloc, setUp: () async { - when(() => bookcaseService.deleteBookcase( - bookcaseId: any(named: 'bookcaseId'))).thenAnswer((_) async => 1); - when(() => bookcaseService.getAllBookcases()) - .thenAnswer((_) async => []); + when( + () => bookcaseService.deleteBookcase( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer((_) async => 1); + when( + () => bookcaseService.getAllBookcases(), + ).thenAnswer((_) async => []); }, act: (bloc) => bloc.add( DeletedBookcasesEvent( @@ -405,12 +466,16 @@ void main() { ), ), verify: (_) { - verify(() => bookcaseService.deleteBookcase( - bookcaseId: any(named: 'bookcaseId'))).called(1); + verify( + () => bookcaseService.deleteBookcase( + bookcaseId: any(named: 'bookcaseId'), + ), + ).called(1); verify(() => bookcaseService.getAllBookcases()).called(1); verifyNever( () => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId')), + bookcaseId: any(named: 'bookcaseId'), + ), ); verifyNever(() => bookService.getBookImage(id: any(named: 'id'))); }, @@ -424,9 +489,16 @@ void main() { 'test if DeletedBookcasesEvent work when throw LocalDatabaseException', build: () => bookcaseBloc, setUp: () async { - when(() => bookcaseService.deleteBookcase( - bookcaseId: any(named: 'bookcaseId'))) - .thenThrow(const LocalDatabaseException('Error on Database')); + when( + () => bookcaseService.deleteBookcase( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); }, act: (bloc) => bloc.add( DeletedBookcasesEvent( @@ -436,12 +508,16 @@ void main() { ), ), verify: (_) { - verify(() => bookcaseService.deleteBookcase( - bookcaseId: any(named: 'bookcaseId'))).called(1); + verify( + () => bookcaseService.deleteBookcase( + bookcaseId: any(named: 'bookcaseId'), + ), + ).called(1); verifyNever(() => bookcaseService.getAllBookcases()); verifyNever( () => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId')), + bookcaseId: any(named: 'bookcaseId'), + ), ); verifyNever(() => bookService.getBookImage(id: any(named: 'id'))); }, @@ -455,9 +531,11 @@ void main() { 'test if DeletedBookcasesEvent work when throw Generic Exception', build: () => bookcaseBloc, setUp: () async { - when(() => bookcaseService.deleteBookcase( - bookcaseId: any(named: 'bookcaseId'))) - .thenThrow(Exception('Generic Exception')); + when( + () => bookcaseService.deleteBookcase( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenThrow(Exception('Generic Exception')); }, act: (bloc) => bloc.add( DeletedBookcasesEvent( @@ -467,12 +545,16 @@ void main() { ), ), verify: (_) { - verify(() => bookcaseService.deleteBookcase( - bookcaseId: any(named: 'bookcaseId'))).called(1); + verify( + () => bookcaseService.deleteBookcase( + bookcaseId: any(named: 'bookcaseId'), + ), + ).called(1); verifyNever(() => bookcaseService.getAllBookcases()); verifyNever( () => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId')), + bookcaseId: any(named: 'bookcaseId'), + ), ); verifyNever(() => bookService.getBookImage(id: any(named: 'id'))); }, diff --git a/test/src/features/bookcase/views/bookcase_page_test.dart b/test/src/features/bookcase/views/bookcase_page_test.dart index ab2a19a7..810a4f2c 100644 --- a/test/src/features/bookcase/views/bookcase_page_test.dart +++ b/test/src/features/bookcase/views/bookcase_page_test.dart @@ -3,6 +3,7 @@ import 'package:bookify/src/core/dtos/bookcase_dto.dart'; import 'package:bookify/src/core/models/bookcase_model.dart'; import 'package:bookify/src/features/bookcase/bloc/bookcase_bloc.dart'; import 'package:bookify/src/features/bookcase/views/bookcase_page.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -95,7 +96,10 @@ void main() { 'Test find Bookcase Error state Widget when Bloc emit Error', (tester) async { when(() => bookcaseBloc.state).thenReturn( - BookcaseErrorState(errorMessage: 'Error message'), + BookcaseErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: 'Error message', + ), ); await _initBookcasePage(tester, bookcaseBloc); @@ -106,7 +110,7 @@ void main() { ); expect( - find.text('Error message'), + find.text('error-unknown'), findsOne, ); }, diff --git a/test/src/features/bookcase_books_insertion/bloc/bookcase_books_insertion_bloc_test.dart b/test/src/features/bookcase_books_insertion/bloc/bookcase_books_insertion_bloc_test.dart index e1f7ba20..7e46cfae 100644 --- a/test/src/features/bookcase_books_insertion/bloc/bookcase_books_insertion_bloc_test.dart +++ b/test/src/features/bookcase_books_insertion/bloc/bookcase_books_insertion_bloc_test.dart @@ -6,6 +6,7 @@ import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/models/category_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/bookcase_service/bookcase_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -54,7 +55,7 @@ void main() { buyLink: 'buyLink', averageRating: 4.5, ratingsCount: 720, - ) + ), ]; final bookRelationShip = [ @@ -93,8 +94,11 @@ void main() { act: (bloc) => bloc.add(GotAllBooksForThisBookcaseEvent(bookcaseId: 1)), verify: (_) { verify(() => bookService.getAllBook()).called(1); - verify(() => bookcaseService.getAllBookcaseRelationships( - bookcaseId: any(named: 'bookcaseId'))).called(1); + verify( + () => bookcaseService.getAllBookcaseRelationships( + bookcaseId: any(named: 'bookcaseId'), + ), + ).called(1); }, expect: () => [ isA(), @@ -123,8 +127,11 @@ void main() { act: (bloc) => bloc.add(GotAllBooksForThisBookcaseEvent(bookcaseId: 1)), verify: (_) { verify(() => bookService.getAllBook()).called(1); - verifyNever(() => bookcaseService.getAllBookcaseRelationships( - bookcaseId: any(named: 'bookcaseId'))); + verifyNever( + () => bookcaseService.getAllBookcaseRelationships( + bookcaseId: any(named: 'bookcaseId'), + ), + ); }, expect: () => [ isA(), @@ -146,7 +153,7 @@ void main() { { 'bookcaseId': 1, 'bookId': '2', - } + }, ], ); @@ -159,8 +166,11 @@ void main() { act: (bloc) => bloc.add(GotAllBooksForThisBookcaseEvent(bookcaseId: 1)), verify: (_) { verify(() => bookService.getAllBook()).called(1); - verify(() => bookcaseService.getAllBookcaseRelationships( - bookcaseId: any(named: 'bookcaseId'))).called(1); + verify( + () => bookcaseService.getAllBookcaseRelationships( + bookcaseId: any(named: 'bookcaseId'), + ), + ).called(1); }, expect: () => [ isA(), @@ -182,19 +192,27 @@ void main() { { 'bookcaseId': 1, 'bookId': '2', - } + }, ], ); when( () => bookService.getAllBook(), - ).thenThrow(const LocalDatabaseException('Error on Database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); }, act: (bloc) => bloc.add(GotAllBooksForThisBookcaseEvent(bookcaseId: 1)), verify: (_) { verify(() => bookService.getAllBook()).called(1); - verifyNever(() => bookcaseService.getAllBookcaseRelationships( - bookcaseId: any(named: 'bookcaseId'))); + verifyNever( + () => bookcaseService.getAllBookcaseRelationships( + bookcaseId: any(named: 'bookcaseId'), + ), + ); }, expect: () => [ isA(), @@ -216,7 +234,7 @@ void main() { { 'bookcaseId': 1, 'bookId': '2', - } + }, ], ); @@ -242,45 +260,48 @@ void main() { blocTest( 'Test if InsertBooksOnBookcaseEvent work', build: () => bloc, - setUp: () => when( - () => bookcaseService.insertBookcaseRelationship( - bookcaseId: any(named: 'bookcaseId'), - bookId: any(named: 'bookId'), + setUp: () => + when( + () => bookcaseService.insertBookcaseRelationship( + bookcaseId: any(named: 'bookcaseId'), + bookId: any(named: 'bookId'), + ), + ).thenAnswer( + (invocation) async => 1, + ), + act: (bloc) => bloc.add( + InsertBooksOnBookcaseEvent( + bookcaseId: 2, + books: [ + BookModel( + id: '1', + title: 'title', + authors: [AuthorModel.withEmptyName()], + publisher: 'publisher', + description: 'description', + categories: [CategoryModel.withEmptyName()], + pageCount: 320, + imageUrl: 'imageUrl', + buyLink: 'buyLink', + averageRating: 4.5, + ratingsCount: 720, + ), + BookModel( + id: '2', + title: 'title', + authors: [AuthorModel.withEmptyName()], + publisher: 'publisher', + description: 'description', + categories: [CategoryModel.withEmptyName()], + pageCount: 320, + imageUrl: 'imageUrl', + buyLink: 'buyLink', + averageRating: 4.5, + ratingsCount: 720, + ), + ], ), - ).thenAnswer( - (invocation) async => 1, ), - act: (bloc) => bloc.add(InsertBooksOnBookcaseEvent( - bookcaseId: 2, - books: [ - BookModel( - id: '1', - title: 'title', - authors: [AuthorModel.withEmptyName()], - publisher: 'publisher', - description: 'description', - categories: [CategoryModel.withEmptyName()], - pageCount: 320, - imageUrl: 'imageUrl', - buyLink: 'buyLink', - averageRating: 4.5, - ratingsCount: 720, - ), - BookModel( - id: '2', - title: 'title', - authors: [AuthorModel.withEmptyName()], - publisher: 'publisher', - description: 'description', - categories: [CategoryModel.withEmptyName()], - pageCount: 320, - imageUrl: 'imageUrl', - buyLink: 'buyLink', - averageRating: 4.5, - ratingsCount: 720, - ) - ], - )), verify: (_) => verify( () => bookcaseService.insertBookcaseRelationship( bookcaseId: any(named: 'bookcaseId'), @@ -302,37 +323,39 @@ void main() { bookId: any(named: 'bookId'), ), ).thenAnswer((_) async => 0), - act: (bloc) => bloc.add(InsertBooksOnBookcaseEvent( - bookcaseId: 2, - books: [ - BookModel( - id: '1', - title: 'title', - authors: [AuthorModel.withEmptyName()], - publisher: 'publisher', - description: 'description', - categories: [CategoryModel.withEmptyName()], - pageCount: 320, - imageUrl: 'imageUrl', - buyLink: 'buyLink', - averageRating: 4.5, - ratingsCount: 720, - ), - BookModel( - id: '2', - title: 'title', - authors: [AuthorModel.withEmptyName()], - publisher: 'publisher', - description: 'description', - categories: [CategoryModel.withEmptyName()], - pageCount: 320, - imageUrl: 'imageUrl', - buyLink: 'buyLink', - averageRating: 4.5, - ratingsCount: 720, - ) - ], - )), + act: (bloc) => bloc.add( + InsertBooksOnBookcaseEvent( + bookcaseId: 2, + books: [ + BookModel( + id: '1', + title: 'title', + authors: [AuthorModel.withEmptyName()], + publisher: 'publisher', + description: 'description', + categories: [CategoryModel.withEmptyName()], + pageCount: 320, + imageUrl: 'imageUrl', + buyLink: 'buyLink', + averageRating: 4.5, + ratingsCount: 720, + ), + BookModel( + id: '2', + title: 'title', + authors: [AuthorModel.withEmptyName()], + publisher: 'publisher', + description: 'description', + categories: [CategoryModel.withEmptyName()], + pageCount: 320, + imageUrl: 'imageUrl', + buyLink: 'buyLink', + averageRating: 4.5, + ratingsCount: 720, + ), + ], + ), + ), verify: (_) => verify( () => bookcaseService.insertBookcaseRelationship( bookcaseId: any(named: 'bookcaseId'), @@ -348,43 +371,51 @@ void main() { blocTest( 'Test if InsertBooksOnBookcaseEvent work when throw LocalDatabaseException', build: () => bloc, - setUp: () => when( - () => bookcaseService.insertBookcaseRelationship( - bookcaseId: any(named: 'bookcaseId'), - bookId: any(named: 'bookId'), - ), - ).thenThrow(const LocalDatabaseException('Error on Database')), - act: (bloc) => bloc.add(InsertBooksOnBookcaseEvent( - bookcaseId: 2, - books: [ - BookModel( - id: '1', - title: 'title', - authors: [AuthorModel.withEmptyName()], - publisher: 'publisher', - description: 'description', - categories: [CategoryModel.withEmptyName()], - pageCount: 320, - imageUrl: 'imageUrl', - buyLink: 'buyLink', - averageRating: 4.5, - ratingsCount: 720, + setUp: () => + when( + () => bookcaseService.insertBookcaseRelationship( + bookcaseId: any(named: 'bookcaseId'), + bookId: any(named: 'bookId'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), ), - BookModel( - id: '2', - title: 'title', - authors: [AuthorModel.withEmptyName()], - publisher: 'publisher', - description: 'description', - categories: [CategoryModel.withEmptyName()], - pageCount: 320, - imageUrl: 'imageUrl', - buyLink: 'buyLink', - averageRating: 4.5, - ratingsCount: 720, - ) - ], - )), + act: (bloc) => bloc.add( + InsertBooksOnBookcaseEvent( + bookcaseId: 2, + books: [ + BookModel( + id: '1', + title: 'title', + authors: [AuthorModel.withEmptyName()], + publisher: 'publisher', + description: 'description', + categories: [CategoryModel.withEmptyName()], + pageCount: 320, + imageUrl: 'imageUrl', + buyLink: 'buyLink', + averageRating: 4.5, + ratingsCount: 720, + ), + BookModel( + id: '2', + title: 'title', + authors: [AuthorModel.withEmptyName()], + publisher: 'publisher', + description: 'description', + categories: [CategoryModel.withEmptyName()], + pageCount: 320, + imageUrl: 'imageUrl', + buyLink: 'buyLink', + averageRating: 4.5, + ratingsCount: 720, + ), + ], + ), + ), verify: (_) => verify( () => bookcaseService.insertBookcaseRelationship( bookcaseId: any(named: 'bookcaseId'), @@ -406,37 +437,39 @@ void main() { bookId: any(named: 'bookId'), ), ).thenThrow(Exception('Generic Exception')), - act: (bloc) => bloc.add(InsertBooksOnBookcaseEvent( - bookcaseId: 2, - books: [ - BookModel( - id: '1', - title: 'title', - authors: [AuthorModel.withEmptyName()], - publisher: 'publisher', - description: 'description', - categories: [CategoryModel.withEmptyName()], - pageCount: 320, - imageUrl: 'imageUrl', - buyLink: 'buyLink', - averageRating: 4.5, - ratingsCount: 720, - ), - BookModel( - id: '2', - title: 'title', - authors: [AuthorModel.withEmptyName()], - publisher: 'publisher', - description: 'description', - categories: [CategoryModel.withEmptyName()], - pageCount: 320, - imageUrl: 'imageUrl', - buyLink: 'buyLink', - averageRating: 4.5, - ratingsCount: 720, - ) - ], - )), + act: (bloc) => bloc.add( + InsertBooksOnBookcaseEvent( + bookcaseId: 2, + books: [ + BookModel( + id: '1', + title: 'title', + authors: [AuthorModel.withEmptyName()], + publisher: 'publisher', + description: 'description', + categories: [CategoryModel.withEmptyName()], + pageCount: 320, + imageUrl: 'imageUrl', + buyLink: 'buyLink', + averageRating: 4.5, + ratingsCount: 720, + ), + BookModel( + id: '2', + title: 'title', + authors: [AuthorModel.withEmptyName()], + publisher: 'publisher', + description: 'description', + categories: [CategoryModel.withEmptyName()], + pageCount: 320, + imageUrl: 'imageUrl', + buyLink: 'buyLink', + averageRating: 4.5, + ratingsCount: 720, + ), + ], + ), + ), verify: (_) => verify( () => bookcaseService.insertBookcaseRelationship( bookcaseId: any(named: 'bookcaseId'), diff --git a/test/src/features/bookcase_detail/bloc/bookcase_detail_bloc_test.dart b/test/src/features/bookcase_detail/bloc/bookcase_detail_bloc_test.dart index e78afd13..08e77500 100644 --- a/test/src/features/bookcase_detail/bloc/bookcase_detail_bloc_test.dart +++ b/test/src/features/bookcase_detail/bloc/bookcase_detail_bloc_test.dart @@ -6,6 +6,7 @@ import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/models/category_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/bookcase_service/bookcase_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -55,8 +56,11 @@ void main() { () => bookService.getBookById(id: any(named: 'id')), ).thenAnswer((_) async => bookModel); - when(() => bookcaseService.getAllBookcaseRelationships( - bookcaseId: any(named: 'bookcaseId'))).thenAnswer( + when( + () => bookcaseService.getAllBookcaseRelationships( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer( (_) async => [ {'bookcaseId': 1, 'bookId': 'id'}, ], @@ -65,8 +69,9 @@ void main() { act: (bloc) => bloc.add(GotBookcaseBooksEvent(bookcaseId: 1)), verify: (bloc) { verify(() => bookService.getBookById(id: 'id')).called(1); - verify(() => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1)) - .called(1); + verify( + () => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1), + ).called(1); }, expect: () => [ isA(), @@ -82,16 +87,20 @@ void main() { () => bookService.getBookById(id: any(named: 'id')), ).thenAnswer((_) async => bookModel); - when(() => bookcaseService.getAllBookcaseRelationships( - bookcaseId: any(named: 'bookcaseId'))).thenAnswer( + when( + () => bookcaseService.getAllBookcaseRelationships( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer( (_) async => [], ); }, act: (bloc) => bloc.add(GotBookcaseBooksEvent(bookcaseId: 1)), verify: (_) { verifyNever(() => bookService.getBookById(id: 'id')); - verify(() => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1)) - .called(1); + verify( + () => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1), + ).called(1); }, expect: () => [ isA(), @@ -105,10 +114,18 @@ void main() { setUp: () { when( () => bookService.getBookById(id: any(named: 'id')), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); - when(() => bookcaseService.getAllBookcaseRelationships( - bookcaseId: any(named: 'bookcaseId'))).thenAnswer( + when( + () => bookcaseService.getAllBookcaseRelationships( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer( (_) async => [ {'bookcaseId': 1, 'bookId': 'id'}, ], @@ -117,8 +134,9 @@ void main() { act: (bloc) => bloc.add(GotBookcaseBooksEvent(bookcaseId: 1)), verify: (_) { verify(() => bookService.getBookById(id: 'id')).called(1); - verify(() => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1)) - .called(1); + verify( + () => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1), + ).called(1); }, expect: () => [ isA(), @@ -134,8 +152,11 @@ void main() { () => bookService.getBookById(id: any(named: 'id')), ).thenThrow(Exception('Generic Error')); - when(() => bookcaseService.getAllBookcaseRelationships( - bookcaseId: any(named: 'bookcaseId'))).thenAnswer( + when( + () => bookcaseService.getAllBookcaseRelationships( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer( (_) async => [ {'bookcaseId': 1, 'bookId': 'id'}, ], @@ -144,8 +165,9 @@ void main() { act: (bloc) => bloc.add(GotBookcaseBooksEvent(bookcaseId: 1)), verify: (_) { verify(() => bookService.getBookById(id: 'id')).called(1); - verify(() => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1)) - .called(1); + verify( + () => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1), + ).called(1); }, expect: () => [ isA(), @@ -157,8 +179,10 @@ void main() { blocTest( 'test if DeletedBookcaseEvent work', build: () => bloc, - setUp: () => when(() => bookcaseService.deleteBookcase( - bookcaseId: any(named: 'bookcaseId'))).thenAnswer((_) async => 1), + setUp: () => when( + () => + bookcaseService.deleteBookcase(bookcaseId: any(named: 'bookcaseId')), + ).thenAnswer((_) async => 1), act: (bloc) => bloc.add(DeletedBookcaseEvent(bookcaseId: 1)), verify: (_) { verify(() => bookcaseService.deleteBookcase(bookcaseId: 1)).called(1); @@ -172,8 +196,10 @@ void main() { blocTest( 'test if DeletedBookcaseEvent work with deleted is -1', build: () => bloc, - setUp: () => when(() => bookcaseService.deleteBookcase( - bookcaseId: any(named: 'bookcaseId'))).thenAnswer((_) async => -1), + setUp: () => when( + () => + bookcaseService.deleteBookcase(bookcaseId: any(named: 'bookcaseId')), + ).thenAnswer((_) async => -1), act: (bloc) => bloc.add(DeletedBookcaseEvent(bookcaseId: 1)), verify: (_) { verify(() => bookcaseService.deleteBookcase(bookcaseId: 1)).called(1); @@ -187,9 +213,17 @@ void main() { blocTest( 'test if DeletedBookcaseEvent work when throw LocalDatabaseException', build: () => bloc, - setUp: () => when(() => bookcaseService.deleteBookcase( - bookcaseId: any(named: 'bookcaseId'))) - .thenThrow(const LocalDatabaseException('Error on database')), + setUp: () => + when( + () => bookcaseService.deleteBookcase( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ), act: (bloc) => bloc.add(DeletedBookcaseEvent(bookcaseId: 1)), verify: (_) { verify(() => bookcaseService.deleteBookcase(bookcaseId: 1)).called(1); @@ -203,9 +237,10 @@ void main() { blocTest( 'test if DeletedBookcaseEvent work when throw Generic Exception', build: () => bloc, - setUp: () => when(() => bookcaseService.deleteBookcase( - bookcaseId: any(named: 'bookcaseId'))) - .thenThrow(Exception('Generic Error')), + setUp: () => when( + () => + bookcaseService.deleteBookcase(bookcaseId: any(named: 'bookcaseId')), + ).thenThrow(Exception('Generic Error')), act: (bloc) => bloc.add(DeletedBookcaseEvent(bookcaseId: 1)), verify: (_) { verify(() => bookcaseService.deleteBookcase(bookcaseId: 1)).called(1); @@ -233,8 +268,11 @@ void main() { id: any(named: 'id'), ), ).thenAnswer((_) async => bookModel); - when(() => bookcaseService.getAllBookcaseRelationships( - bookcaseId: any(named: 'bookcaseId'))).thenAnswer( + when( + () => bookcaseService.getAllBookcaseRelationships( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer( (_) async => [ {'bookcaseId': 1, 'bookId': 'id'}, ], @@ -247,12 +285,16 @@ void main() { ), ), verify: (_) { - verify(() => bookcaseService.deleteBookcaseRelationship( + verify( + () => bookcaseService.deleteBookcaseRelationship( bookcaseId: any(named: 'bookcaseId'), - bookId: any(named: 'bookId'))).called(1); + bookId: any(named: 'bookId'), + ), + ).called(1); verify(() => bookService.getBookById(id: 'id')).called(1); - verify(() => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1)) - .called(1); + verify( + () => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1), + ).called(1); }, expect: () => [ isA(), @@ -277,8 +319,11 @@ void main() { id: any(named: 'id'), ), ).thenAnswer((_) async => bookModel); - when(() => bookcaseService.getAllBookcaseRelationships( - bookcaseId: any(named: 'bookcaseId'))).thenAnswer( + when( + () => bookcaseService.getAllBookcaseRelationships( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer( (_) async => [ {'bookcaseId': 1, 'bookId': 'id'}, ], @@ -291,12 +336,16 @@ void main() { ), ), verify: (_) { - verify(() => bookcaseService.deleteBookcaseRelationship( + verify( + () => bookcaseService.deleteBookcaseRelationship( bookcaseId: any(named: 'bookcaseId'), - bookId: any(named: 'bookId'))).called(1); + bookId: any(named: 'bookId'), + ), + ).called(1); verifyNever(() => bookService.getBookById(id: 'id')); verifyNever( - () => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1)); + () => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1), + ); }, expect: () => [ isA(), @@ -321,8 +370,11 @@ void main() { id: any(named: 'id'), ), ).thenAnswer((_) async => bookModel); - when(() => bookcaseService.getAllBookcaseRelationships( - bookcaseId: any(named: 'bookcaseId'))).thenAnswer( + when( + () => bookcaseService.getAllBookcaseRelationships( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer( (_) async => [], ); }, @@ -333,9 +385,12 @@ void main() { ), ), verify: (_) { - verify(() => bookcaseService.deleteBookcaseRelationship( + verify( + () => bookcaseService.deleteBookcaseRelationship( bookcaseId: any(named: 'bookcaseId'), - bookId: any(named: 'bookId'))).called(1); + bookId: any(named: 'bookId'), + ), + ).called(1); verifyNever(() => bookService.getBookById(id: 'id')); verify(() => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1)); }, @@ -362,9 +417,16 @@ void main() { id: any(named: 'id'), ), ).thenAnswer((_) async => bookModel); - when(() => bookcaseService.getAllBookcaseRelationships( - bookcaseId: any(named: 'bookcaseId'))) - .thenThrow(const LocalDatabaseException('Error on Database')); + when( + () => bookcaseService.getAllBookcaseRelationships( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); }, act: (bloc) => bloc.add( DeletedBooksOnBookcaseEvent( @@ -373,9 +435,12 @@ void main() { ), ), verify: (_) { - verify(() => bookcaseService.deleteBookcaseRelationship( + verify( + () => bookcaseService.deleteBookcaseRelationship( bookcaseId: any(named: 'bookcaseId'), - bookId: any(named: 'bookId'))).called(1); + bookId: any(named: 'bookId'), + ), + ).called(1); verifyNever(() => bookService.getBookById(id: 'id')); verify(() => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1)); }, @@ -402,9 +467,11 @@ void main() { id: any(named: 'id'), ), ).thenAnswer((_) async => bookModel); - when(() => bookcaseService.getAllBookcaseRelationships( - bookcaseId: any(named: 'bookcaseId'))) - .thenThrow(Exception('Generic Exception')); + when( + () => bookcaseService.getAllBookcaseRelationships( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenThrow(Exception('Generic Exception')); }, act: (bloc) => bloc.add( DeletedBooksOnBookcaseEvent( @@ -413,9 +480,12 @@ void main() { ), ), verify: (_) { - verify(() => bookcaseService.deleteBookcaseRelationship( + verify( + () => bookcaseService.deleteBookcaseRelationship( bookcaseId: any(named: 'bookcaseId'), - bookId: any(named: 'bookId'))).called(1); + bookId: any(named: 'bookId'), + ), + ).called(1); verifyNever(() => bookService.getBookById(id: 'id')); verify(() => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1)); }, diff --git a/test/src/features/bookcase_insertion/bloc/bookcase_insertion_bloc_test.dart b/test/src/features/bookcase_insertion/bloc/bookcase_insertion_bloc_test.dart index 26a2110d..5164d23a 100644 --- a/test/src/features/bookcase_insertion/bloc/bookcase_insertion_bloc_test.dart +++ b/test/src/features/bookcase_insertion/bloc/bookcase_insertion_bloc_test.dart @@ -4,6 +4,7 @@ import 'package:bookify/src/features/bookcase_insertion/bloc/bookcase_insertion_ import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart'; import 'package:bookify/src/core/models/bookcase_model.dart'; import 'package:bookify/src/core/services/bookcase_service/bookcase_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -37,18 +38,20 @@ void main() { blocTest( 'Test InsertedBookcaseEvent() work', build: () => bookcaseInsertionBloc, - setUp: () => when(() => - bookcaseService.insertBookcase(bookcaseModel: bookcaseModel)) - .thenAnswer((_) async => 4), - act: (bloc) => bloc.add(InsertedBookcaseEvent( - name: 'name', - description: 'description', - color: Colors.pink, - )), + setUp: () => when( + () => bookcaseService.insertBookcase(bookcaseModel: bookcaseModel), + ).thenAnswer((_) async => 4), + act: (bloc) => bloc.add( + InsertedBookcaseEvent( + name: 'name', + description: 'description', + color: Colors.pink, + ), + ), verify: (_) { - verify(() => - bookcaseService.insertBookcase(bookcaseModel: bookcaseModel)) - .called(1); + verify( + () => bookcaseService.insertBookcase(bookcaseModel: bookcaseModel), + ).called(1); }, expect: () => [ isA(), @@ -59,18 +62,20 @@ void main() { blocTest( 'Test InsertedBookcaseEvent() with Error on insertion work', build: () => bookcaseInsertionBloc, - setUp: () => when(() => - bookcaseService.insertBookcase(bookcaseModel: bookcaseModel)) - .thenAnswer((_) async => 0), - act: (bloc) => bloc.add(InsertedBookcaseEvent( - name: 'name', - description: 'description', - color: Colors.pink, - )), + setUp: () => when( + () => bookcaseService.insertBookcase(bookcaseModel: bookcaseModel), + ).thenAnswer((_) async => 0), + act: (bloc) => bloc.add( + InsertedBookcaseEvent( + name: 'name', + description: 'description', + color: Colors.pink, + ), + ), verify: (_) { - verify(() => - bookcaseService.insertBookcase(bookcaseModel: bookcaseModel)) - .called(1); + verify( + () => bookcaseService.insertBookcase(bookcaseModel: bookcaseModel), + ).called(1); }, expect: () => [ isA(), @@ -81,18 +86,26 @@ void main() { blocTest( 'Test InsertedBookcaseEvent() with LocalDatabaseException work', build: () => bookcaseInsertionBloc, - setUp: () => when(() => - bookcaseService.insertBookcase(bookcaseModel: bookcaseModel)) - .thenThrow(const LocalDatabaseException('Error on database')), - act: (bloc) => bloc.add(InsertedBookcaseEvent( - name: 'name', - description: 'description', - color: Colors.pink, - )), + setUp: () => + when( + () => bookcaseService.insertBookcase(bookcaseModel: bookcaseModel), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ), + act: (bloc) => bloc.add( + InsertedBookcaseEvent( + name: 'name', + description: 'description', + color: Colors.pink, + ), + ), verify: (_) { - verify(() => - bookcaseService.insertBookcase(bookcaseModel: bookcaseModel)) - .called(1); + verify( + () => bookcaseService.insertBookcase(bookcaseModel: bookcaseModel), + ).called(1); }, expect: () => [ isA(), @@ -103,18 +116,20 @@ void main() { blocTest( 'Test InsertedBookcaseEvent() with generic Exception work', build: () => bookcaseInsertionBloc, - setUp: () => when(() => - bookcaseService.insertBookcase(bookcaseModel: bookcaseModel)) - .thenThrow(Exception('Generic Exception')), - act: (bloc) => bloc.add(InsertedBookcaseEvent( - name: 'name', - description: 'description', - color: Colors.pink, - )), + setUp: () => when( + () => bookcaseService.insertBookcase(bookcaseModel: bookcaseModel), + ).thenThrow(Exception('Generic Exception')), + act: (bloc) => bloc.add( + InsertedBookcaseEvent( + name: 'name', + description: 'description', + color: Colors.pink, + ), + ), verify: (_) { - verify(() => - bookcaseService.insertBookcase(bookcaseModel: bookcaseModel)) - .called(1); + verify( + () => bookcaseService.insertBookcase(bookcaseModel: bookcaseModel), + ).called(1); }, expect: () => [ isA(), @@ -130,15 +145,20 @@ void main() { bookcaseModel: bookcaseModel.copyWith(id: 1), ), ).thenAnswer((_) async => 1), - act: (bloc) => bloc.add(UpdatedBookcaseEvent( - id: 1, - name: 'name', - description: 'description', - color: Colors.pink, - )), + act: (bloc) => bloc.add( + UpdatedBookcaseEvent( + id: 1, + name: 'name', + description: 'description', + color: Colors.pink, + ), + ), verify: (_) { - verify(() => bookcaseService.updateBookcase( - bookcaseModel: bookcaseModel.copyWith(id: 1))).called(1); + verify( + () => bookcaseService.updateBookcase( + bookcaseModel: bookcaseModel.copyWith(id: 1), + ), + ).called(1); }, expect: () => [ isA(), @@ -154,15 +174,20 @@ void main() { bookcaseModel: bookcaseModel.copyWith(id: 1), ), ).thenAnswer((_) async => 0), - act: (bloc) => bloc.add(UpdatedBookcaseEvent( - id: 1, - name: 'name', - description: 'description', - color: Colors.pink, - )), + act: (bloc) => bloc.add( + UpdatedBookcaseEvent( + id: 1, + name: 'name', + description: 'description', + color: Colors.pink, + ), + ), verify: (_) { - verify(() => bookcaseService.updateBookcase( - bookcaseModel: bookcaseModel.copyWith(id: 1))).called(1); + verify( + () => bookcaseService.updateBookcase( + bookcaseModel: bookcaseModel.copyWith(id: 1), + ), + ).called(1); }, expect: () => [ isA(), @@ -173,20 +198,31 @@ void main() { blocTest( 'Test UpdatedBookcaseEvent() with LocalDatabaseException work', build: () => bookcaseInsertionBloc, - setUp: () => when( - () => bookcaseService.updateBookcase( - bookcaseModel: bookcaseModel.copyWith(id: 1), + setUp: () => + when( + () => bookcaseService.updateBookcase( + bookcaseModel: bookcaseModel.copyWith(id: 1), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ), + act: (bloc) => bloc.add( + UpdatedBookcaseEvent( + id: 1, + name: 'name', + description: 'description', + color: Colors.pink, ), - ).thenThrow(const LocalDatabaseException('Error on database')), - act: (bloc) => bloc.add(UpdatedBookcaseEvent( - id: 1, - name: 'name', - description: 'description', - color: Colors.pink, - )), + ), verify: (_) { - verify(() => bookcaseService.updateBookcase( - bookcaseModel: bookcaseModel.copyWith(id: 1))).called(1); + verify( + () => bookcaseService.updateBookcase( + bookcaseModel: bookcaseModel.copyWith(id: 1), + ), + ).called(1); }, expect: () => [ isA(), @@ -202,15 +238,20 @@ void main() { bookcaseModel: bookcaseModel.copyWith(id: 1), ), ).thenThrow(Exception('Generic Exception')), - act: (bloc) => bloc.add(UpdatedBookcaseEvent( - id: 1, - name: 'name', - description: 'description', - color: Colors.pink, - )), + act: (bloc) => bloc.add( + UpdatedBookcaseEvent( + id: 1, + name: 'name', + description: 'description', + color: Colors.pink, + ), + ), verify: (_) { - verify(() => bookcaseService.updateBookcase( - bookcaseModel: bookcaseModel.copyWith(id: 1))).called(1); + verify( + () => bookcaseService.updateBookcase( + bookcaseModel: bookcaseModel.copyWith(id: 1), + ), + ).called(1); }, expect: () => [ isA(), diff --git a/test/src/features/bookcase_insertion/views/bookcase_insertion_page_test.dart b/test/src/features/bookcase_insertion/views/bookcase_insertion_page_test.dart index f4517a71..44625204 100644 --- a/test/src/features/bookcase_insertion/views/bookcase_insertion_page_test.dart +++ b/test/src/features/bookcase_insertion/views/bookcase_insertion_page_test.dart @@ -2,6 +2,7 @@ import 'package:bloc_test/bloc_test.dart'; import 'package:bookify/src/core/models/bookcase_model.dart'; import 'package:bookify/src/features/bookcase_insertion/bloc/bookcase_insertion_bloc.dart'; import 'package:bookify/src/features/bookcase_insertion/views/bookcase_insertion_page.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -63,7 +64,7 @@ void main() { bookcaseInsertionBloc, Stream.fromIterable([ BookcaseInsertionInsertedState( - bookcaseInsertionMessage: 'Bookcase inserted successfully', + reason: BookcaseInsertionSuccessReason.inserted, ), ]), ); @@ -85,7 +86,7 @@ void main() { await tester.pumpAndSettle(); expect(find.byType(SnackBar), findsOneWidget); - expect(find.text('Bookcase inserted successfully'), findsOneWidget); + expect(find.text('bookcase-inserted-success-snackbar'), findsOneWidget); await tester.pumpAndSettle(const Duration(seconds: 2)); @@ -115,7 +116,10 @@ void main() { whenListen( bookcaseInsertionBloc, Stream.fromIterable([ - BookcaseInsertionErrorState(errorMessage: 'Database Error'), + BookcaseInsertionErrorState( + errorCode: LocalDatabaseErrorCode.unknown, + errorDescriptionMessage: 'Database Error', + ), ]), ); @@ -130,7 +134,7 @@ void main() { await tester.pumpAndSettle(); expect(find.byType(SnackBar), findsOneWidget); - expect(find.text('Database Error'), findsOneWidget); + expect(find.text('error-unknown'), findsOneWidget); await tester.pumpAndSettle(const Duration(seconds: 2)); expect(find.byType(BookcaseInsertionPage), findsNothing); @@ -170,7 +174,7 @@ void main() { bookcaseInsertionBloc, Stream.fromIterable([ BookcaseInsertionInsertedState( - bookcaseInsertionMessage: 'Updated successfully', + reason: BookcaseInsertionSuccessReason.updated, ), ]), ); @@ -188,7 +192,7 @@ void main() { await tester.tap(find.byKey(const Key('ConfirmBookcaseInsertionButton'))); await tester.pumpAndSettle(); - expect(find.text('Updated successfully'), findsOneWidget); + expect(find.text('bookcase-updated-success-snackbar'), findsOneWidget); await tester.pumpAndSettle(const Duration(seconds: 2)); expect(find.byType(BookcaseInsertionPage), findsNothing); }); diff --git a/test/src/features/books_picker/views/widgets/book_on_bookcase_picker/bloc/book_on_bookcase_picker_bloc_test.dart b/test/src/features/books_picker/views/widgets/book_on_bookcase_picker/bloc/book_on_bookcase_picker_bloc_test.dart index d2a1cb0d..b9d61ce3 100644 --- a/test/src/features/books_picker/views/widgets/book_on_bookcase_picker/bloc/book_on_bookcase_picker_bloc_test.dart +++ b/test/src/features/books_picker/views/widgets/book_on_bookcase_picker/bloc/book_on_bookcase_picker_bloc_test.dart @@ -6,6 +6,7 @@ import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/models/category_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/bookcase_service/bookcase_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -56,8 +57,11 @@ void main() { () => bookService.getBookById(id: any(named: 'id')), ).thenAnswer((_) async => bookModel); - when(() => bookcaseService.getAllBookcaseRelationships( - bookcaseId: any(named: 'bookcaseId'))).thenAnswer( + when( + () => bookcaseService.getAllBookcaseRelationships( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer( (_) async => [ {'bookcaseId': 1, 'bookId': 'id'}, ], @@ -66,8 +70,9 @@ void main() { act: (bloc) => bloc.add(GotAllBookOnBookcasePickerEvent(bookcaseId: 1)), verify: (bloc) { verify(() => bookService.getBookById(id: 'id')).called(1); - verify(() => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1)) - .called(1); + verify( + () => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1), + ).called(1); }, expect: () => [ isA(), @@ -83,16 +88,20 @@ void main() { () => bookService.getBookById(id: any(named: 'id')), ).thenAnswer((_) async => bookModel); - when(() => bookcaseService.getAllBookcaseRelationships( - bookcaseId: any(named: 'bookcaseId'))).thenAnswer( + when( + () => bookcaseService.getAllBookcaseRelationships( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer( (_) async => [], ); }, act: (bloc) => bloc.add(GotAllBookOnBookcasePickerEvent(bookcaseId: 1)), verify: (_) { verifyNever(() => bookService.getBookById(id: 'id')); - verify(() => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1)) - .called(1); + verify( + () => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1), + ).called(1); }, expect: () => [ isA(), @@ -107,18 +116,23 @@ void main() { when( () => bookService.getBookById(id: any(named: 'id')), ).thenAnswer( - (_) async => bookModel.copyWith(status: BookStatus.loaned)); + (_) async => bookModel.copyWith(status: BookStatus.loaned), + ); - when(() => bookcaseService.getAllBookcaseRelationships( - bookcaseId: any(named: 'bookcaseId'))).thenAnswer( + when( + () => bookcaseService.getAllBookcaseRelationships( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer( (_) async => [], ); }, act: (bloc) => bloc.add(GotAllBookOnBookcasePickerEvent(bookcaseId: 1)), verify: (_) { verifyNever(() => bookService.getBookById(id: 'id')); - verify(() => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1)) - .called(1); + verify( + () => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1), + ).called(1); }, expect: () => [ isA(), @@ -132,10 +146,18 @@ void main() { setUp: () { when( () => bookService.getBookById(id: any(named: 'id')), - ).thenThrow(const LocalDatabaseException('Error on database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); - when(() => bookcaseService.getAllBookcaseRelationships( - bookcaseId: any(named: 'bookcaseId'))).thenAnswer( + when( + () => bookcaseService.getAllBookcaseRelationships( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer( (_) async => [ {'bookcaseId': 1, 'bookId': 'id'}, ], @@ -144,8 +166,9 @@ void main() { act: (bloc) => bloc.add(GotAllBookOnBookcasePickerEvent(bookcaseId: 1)), verify: (_) { verify(() => bookService.getBookById(id: 'id')).called(1); - verify(() => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1)) - .called(1); + verify( + () => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1), + ).called(1); }, expect: () => [ isA(), @@ -161,8 +184,11 @@ void main() { () => bookService.getBookById(id: any(named: 'id')), ).thenThrow(Exception('Generic Error')); - when(() => bookcaseService.getAllBookcaseRelationships( - bookcaseId: any(named: 'bookcaseId'))).thenAnswer( + when( + () => bookcaseService.getAllBookcaseRelationships( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer( (_) async => [ {'bookcaseId': 1, 'bookId': 'id'}, ], @@ -171,8 +197,9 @@ void main() { act: (bloc) => bloc.add(GotAllBookOnBookcasePickerEvent(bookcaseId: 1)), verify: (_) { verify(() => bookService.getBookById(id: 'id')).called(1); - verify(() => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1)) - .called(1); + verify( + () => bookcaseService.getAllBookcaseRelationships(bookcaseId: 1), + ).called(1); }, expect: () => [ isA(), diff --git a/test/src/features/books_picker/views/widgets/bookcase_picker/bloc/bookcase_picker_bloc_test.dart b/test/src/features/books_picker/views/widgets/bookcase_picker/bloc/bookcase_picker_bloc_test.dart index c1ca55db..8bfe74c2 100644 --- a/test/src/features/books_picker/views/widgets/bookcase_picker/bloc/bookcase_picker_bloc_test.dart +++ b/test/src/features/books_picker/views/widgets/bookcase_picker/bloc/bookcase_picker_bloc_test.dart @@ -4,6 +4,7 @@ import 'package:bookify/src/core/errors/local_database_exception/local_database_ import 'package:bookify/src/core/models/bookcase_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/bookcase_service/bookcase_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter/material.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -51,21 +52,26 @@ void main() { 'test if GotAllBookcasePickerEvent work', build: () => bookcasePickerBloc, setUp: () async { - when(() => bookcaseService.getAllBookcases()) - .thenAnswer((_) async => bookcasesModel); - when(() => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId'))) - .thenAnswer((_) async => 'bookId'); + when( + () => bookcaseService.getAllBookcases(), + ).thenAnswer((_) async => bookcasesModel); + when( + () => bookcaseService.getBookIdForImagePreview( + bookcaseId: any(named: 'bookcaseId'), + ), + ).thenAnswer((_) async => 'bookId'); - when(() => bookService.getBookImage(id: any(named: 'id'))) - .thenAnswer((_) async => 'bookImg'); + when( + () => bookService.getBookImage(id: any(named: 'id')), + ).thenAnswer((_) async => 'bookImg'); }, act: (bloc) => bloc.add(GotAllBookcasesPickerEvent()), verify: (_) { verify(() => bookcaseService.getAllBookcases()).called(1); verify( () => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId')), + bookcaseId: any(named: 'bookcaseId'), + ), ).called(2); verify(() => bookService.getBookImage(id: any(named: 'id'))).called(2); }, @@ -79,15 +85,17 @@ void main() { 'test if GotAllBookcasePickerEvent work when is empty List', build: () => bookcasePickerBloc, setUp: () async { - when(() => bookcaseService.getAllBookcases()) - .thenAnswer((_) async => []); + when( + () => bookcaseService.getAllBookcases(), + ).thenAnswer((_) async => []); }, act: (bloc) => bloc.add(GotAllBookcasesPickerEvent()), verify: (_) { verify(() => bookcaseService.getAllBookcases()).called(1); verifyNever( () => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId')), + bookcaseId: any(named: 'bookcaseId'), + ), ); verifyNever(() => bookService.getBookImage(id: any(named: 'id'))); }, @@ -101,20 +109,23 @@ void main() { 'test if GotAllBookcasePickerEvent work when bookcaseId is null', build: () => bookcasePickerBloc, setUp: () async { - when(() => bookcaseService.getAllBookcases()).thenAnswer((_) async => [ - const BookcaseModel( - name: 'name', - description: 'description', - color: Colors.black, - ), - ]); + when(() => bookcaseService.getAllBookcases()).thenAnswer( + (_) async => [ + const BookcaseModel( + name: 'name', + description: 'description', + color: Colors.black, + ), + ], + ); }, act: (bloc) => bloc.add(GotAllBookcasesPickerEvent()), verify: (_) { verify(() => bookcaseService.getAllBookcases()).called(1); verifyNever( () => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId')), + bookcaseId: any(named: 'bookcaseId'), + ), ); verifyNever(() => bookService.getBookImage(id: any(named: 'id'))); }, @@ -128,15 +139,20 @@ void main() { 'test if GotAllBookcasePickerEvent work when throw LocalDatabaseException', build: () => bookcasePickerBloc, setUp: () async { - when(() => bookcaseService.getAllBookcases()) - .thenThrow(const LocalDatabaseException('Error on Database')); + when(() => bookcaseService.getAllBookcases()).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); }, act: (bloc) => bloc.add(GotAllBookcasesPickerEvent()), verify: (_) { verify(() => bookcaseService.getAllBookcases()).called(1); verifyNever( () => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId')), + bookcaseId: any(named: 'bookcaseId'), + ), ); verifyNever(() => bookService.getBookImage(id: any(named: 'id'))); }, @@ -150,15 +166,17 @@ void main() { 'test if GotAllBookcasePickerEvent work when throw Exception', build: () => bookcasePickerBloc, setUp: () async { - when(() => bookcaseService.getAllBookcases()) - .thenThrow(Exception('Generic Error')); + when( + () => bookcaseService.getAllBookcases(), + ).thenThrow(Exception('Generic Error')); }, act: (bloc) => bloc.add(GotAllBookcasesPickerEvent()), verify: (_) { verify(() => bookcaseService.getAllBookcases()).called(1); verifyNever( () => bookcaseService.getBookIdForImagePreview( - bookcaseId: any(named: 'bookcaseId')), + bookcaseId: any(named: 'bookcaseId'), + ), ); verifyNever(() => bookService.getBookImage(id: any(named: 'id'))); }, diff --git a/test/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_bloc_test.dart b/test/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_bloc_test.dart index b8a4dcad..8d12bc94 100644 --- a/test/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_bloc_test.dart +++ b/test/src/features/books_picker/views/widgets/separate_books_picker/bloc/separate_books_picker_bloc_test.dart @@ -5,6 +5,7 @@ import 'package:bookify/src/core/models/author_model.dart'; import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/models/category_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -60,11 +61,12 @@ void main() { blocTest( 'Test if GotAllBooksEvent work', build: () => bloc, - setUp: () => when( - () => bookService.getAllBook(), - ).thenAnswer( - (_) async => booksModel, - ), + setUp: () => + when( + () => bookService.getAllBook(), + ).thenAnswer( + (_) async => booksModel, + ), act: (bloc) => bloc.add(GotAllSeparatedBooksPickerEvent()), verify: (_) => verify(() => bookService.getAllBook()).called(1), expect: () => [ @@ -76,11 +78,12 @@ void main() { blocTest( 'Test if GotAllBooksEvent work with empty state', build: () => bloc, - setUp: () => when( - () => bookService.getAllBook(), - ).thenAnswer( - (_) async => [], - ), + setUp: () => + when( + () => bookService.getAllBook(), + ).thenAnswer( + (_) async => [], + ), act: (bloc) => bloc.add(GotAllSeparatedBooksPickerEvent()), verify: (_) => verify(() => bookService.getAllBook()).called(1), expect: () => [ @@ -92,11 +95,12 @@ void main() { blocTest( 'Test if GotAllBooksEvent work with empty bookService', build: () => bloc, - setUp: () => when( - () => bookService.getAllBook(), - ).thenAnswer( - (_) async => [], - ), + setUp: () => + when( + () => bookService.getAllBook(), + ).thenAnswer( + (_) async => [], + ), act: (bloc) => bloc.add(GotAllSeparatedBooksPickerEvent()), verify: (_) => verify(() => bookService.getAllBook()).called(1), expect: () => [ @@ -108,11 +112,12 @@ void main() { blocTest( 'Test if GotAllBooksEvent work with empty book', build: () => bloc, - setUp: () => when( - () => bookService.getAllBook(), - ).thenAnswer( - (_) async => [booksModel.first.copyWith(status: BookStatus.loaned)], - ), + setUp: () => + when( + () => bookService.getAllBook(), + ).thenAnswer( + (_) async => [booksModel.first.copyWith(status: BookStatus.loaned)], + ), act: (bloc) => bloc.add(GotAllSeparatedBooksPickerEvent()), verify: (_) => verify(() => bookService.getAllBook()).called(1), expect: () => [ @@ -124,9 +129,15 @@ void main() { blocTest( 'Test if GotAllBooksEvent work when throw LocalDatabaseException', build: () => bloc, - setUp: () => when( - () => bookService.getAllBook(), - ).thenThrow(const LocalDatabaseException('Error on Database')), + setUp: () => + when( + () => bookService.getAllBook(), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ), act: (bloc) => bloc.add(GotAllSeparatedBooksPickerEvent()), verify: (_) => verify(() => bookService.getAllBook()).called(1), expect: () => [ diff --git a/test/src/features/contacts_picker/bloc/contacts_picker_bloc_test.dart b/test/src/features/contacts_picker/bloc/contacts_picker_bloc_test.dart index 79a6f05d..058133ae 100644 --- a/test/src/features/contacts_picker/bloc/contacts_picker_bloc_test.dart +++ b/test/src/features/contacts_picker/bloc/contacts_picker_bloc_test.dart @@ -52,7 +52,7 @@ void main() { verify: (_) => verify(() => contactsService.getContacts()).called(1), expect: () => [ isA(), - isA(), + isA(), ], ); diff --git a/test/src/features/home/views/home_page_test.dart b/test/src/features/home/views/home_page_test.dart index 2ea79900..3e9761ff 100644 --- a/test/src/features/home/views/home_page_test.dart +++ b/test/src/features/home/views/home_page_test.dart @@ -1,4 +1,5 @@ import 'package:bloc_test/bloc_test.dart'; +import 'package:bookify/src/shared/enums/rest_client_error_code.dart'; import 'package:bookify/src/core/models/author_model.dart'; import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/models/category_model.dart'; @@ -98,7 +99,10 @@ void main() { testWidgets('Test Home Page when is throw error', (tester) async { when(() => bookBloc.state).thenReturn( - BookErrorSate(errorMessage: 'errorMessage'), + BookErrorState( + errorCode: RestClientErrorCode.unknown, + errorDescriptionMessage: 'errorMessage', + ), ); await _initHomePage(tester, bookBloc); @@ -108,7 +112,7 @@ void main() { findsOneWidget, ); - expect(find.text('errorMessage'), findsOne); + expect(find.text('error-unknown'), findsOne); expect( find.byKey(const Key('AnimatedSearchBar')), diff --git a/test/src/features/loan/bloc/loan_bloc_test.dart b/test/src/features/loan/bloc/loan_bloc_test.dart index 7919587a..3642d5d1 100644 --- a/test/src/features/loan/bloc/loan_bloc_test.dart +++ b/test/src/features/loan/bloc/loan_bloc_test.dart @@ -11,6 +11,7 @@ import 'package:bookify/src/core/models/loan_model.dart'; import 'package:bookify/src/core/services/app_services/contacts_service/contacts_service.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/loan_services/loan_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -74,8 +75,9 @@ void main() { ), ); - when(() => contactsService.getContactById(id: any(named: 'id'))) - .thenAnswer( + when( + () => contactsService.getContactById(id: any(named: 'id')), + ).thenAnswer( (_) async => ContactModel( id: 'id', name: 'name', @@ -88,8 +90,9 @@ void main() { verify: (_) { verify(() => loanService.getAll()).called(1); verify(() => bookService.getBookById(id: any(named: 'id'))).called(1); - verify(() => contactsService.getContactById(id: any(named: 'id'))) - .called(1); + verify( + () => contactsService.getContactById(id: any(named: 'id')), + ).called(1); }, expect: () => [ isA(), @@ -161,7 +164,10 @@ void main() { id: any(named: 'id'), ), ).thenThrow( - const LocalDatabaseException('Error on Database'), + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), ); }, act: (bloc) => bloc.add(GotAllLoansEvent()), @@ -247,8 +253,9 @@ void main() { ), ); - when(() => contactsService.getContactById(id: any(named: 'id'))) - .thenAnswer( + when( + () => contactsService.getContactById(id: any(named: 'id')), + ).thenAnswer( (_) async => ContactModel( id: 'id', name: 'name', @@ -267,8 +274,9 @@ void main() { ), ).called(1); verify(() => bookService.getBookById(id: any(named: 'id'))).called(1); - verify(() => contactsService.getContactById(id: any(named: 'id'))) - .called(1); + verify( + () => contactsService.getContactById(id: any(named: 'id')), + ).called(1); }, expect: () => [ isA(), @@ -279,15 +287,17 @@ void main() { blocTest( 'Test FoundLoanByBookTitleEvent work when loans are empty', build: () => loanBloc, - setUp: () => when( - () => loanService.getLoansByBookTitle( - title: any(named: 'title'), - ), - ).thenAnswer( - (_) async => [], + setUp: () => + when( + () => loanService.getLoansByBookTitle( + title: any(named: 'title'), + ), + ).thenAnswer( + (_) async => [], + ), + act: (bloc) => bloc.add( + FoundLoanByBookTitleEvent(searchQueryName: 'searchQueryName'), ), - act: (bloc) => bloc - .add(FoundLoanByBookTitleEvent(searchQueryName: 'searchQueryName')), verify: (_) { verify( () => loanService.getLoansByBookTitle( @@ -307,8 +317,9 @@ void main() { 'Test FoundLoanByBookTitleEvent work when loan id is empty', build: () => loanBloc, setUp: () { - when(() => loanService.getLoansByBookTitle(title: any(named: 'title'))) - .thenAnswer( + when( + () => loanService.getLoansByBookTitle(title: any(named: 'title')), + ).thenAnswer( (_) async => [ LoanModel( observation: 'observation', @@ -320,8 +331,9 @@ void main() { ], ); }, - act: (bloc) => bloc - .add(FoundLoanByBookTitleEvent(searchQueryName: 'searchQueryName')), + act: (bloc) => bloc.add( + FoundLoanByBookTitleEvent(searchQueryName: 'searchQueryName'), + ), verify: (_) { verify( () => loanService.getLoansByBookTitle( @@ -341,8 +353,9 @@ void main() { 'Test FoundLoanByBookTitleEvent work when throw LocalDatabaseException', build: () => loanBloc, setUp: () { - when(() => loanService.getLoansByBookTitle(title: any(named: 'title'))) - .thenAnswer( + when( + () => loanService.getLoansByBookTitle(title: any(named: 'title')), + ).thenAnswer( (_) async => [ LoanModel( id: 1, @@ -359,16 +372,19 @@ void main() { id: any(named: 'id'), ), ).thenThrow( - const LocalDatabaseException('Error on Database'), + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), ); }, act: (bloc) => bloc.add( FoundLoanByBookTitleEvent(searchQueryName: 'searchQueryName'), ), verify: (_) { - verify(() => - loanService.getLoansByBookTitle(title: any(named: 'title'))) - .called(1); + verify( + () => loanService.getLoansByBookTitle(title: any(named: 'title')), + ).called(1); verify(() => bookService.getBookById(id: any(named: 'id'))).called(1); verifyNever(() => contactsService.getContactById(id: any(named: 'id'))); }, @@ -382,8 +398,9 @@ void main() { 'Test FoundLoanByBookTitleEvent work when throw Generic Exception', build: () => loanBloc, setUp: () { - when(() => loanService.getLoansByBookTitle(title: any(named: 'title'))) - .thenAnswer( + when( + () => loanService.getLoansByBookTitle(title: any(named: 'title')), + ).thenAnswer( (_) async => [ LoanModel( id: 1, diff --git a/test/src/features/loan_detail/bloc/loan_detail_bloc_test.dart b/test/src/features/loan_detail/bloc/loan_detail_bloc_test.dart index e4fdc217..f3c5f310 100644 --- a/test/src/features/loan_detail/bloc/loan_detail_bloc_test.dart +++ b/test/src/features/loan_detail/bloc/loan_detail_bloc_test.dart @@ -10,6 +10,7 @@ import 'package:bookify/src/core/services/app_services/contacts_service/contacts import 'package:bookify/src/core/services/app_services/notifications_service/notifications_service.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/loan_services/loan_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:mocktail/mocktail.dart'; import 'package:flutter_test/flutter_test.dart'; @@ -144,7 +145,10 @@ void main() { id: any(named: 'id'), ), ).thenThrow( - const LocalDatabaseException('Error on database'), + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), ); }, act: (bloc) => bloc.add( @@ -413,7 +417,12 @@ void main() { () => loanService.delete( loanId: any(named: 'loanId'), ), - ).thenThrow(const LocalDatabaseException('Error on Database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); }, act: (bloc) => bloc.add( FinishedLoanDetailEvent( diff --git a/test/src/features/loan_insertion/bloc/loan_insertion_bloc_test.dart b/test/src/features/loan_insertion/bloc/loan_insertion_bloc_test.dart index c6bef423..323abb18 100644 --- a/test/src/features/loan_insertion/bloc/loan_insertion_bloc_test.dart +++ b/test/src/features/loan_insertion/bloc/loan_insertion_bloc_test.dart @@ -7,6 +7,7 @@ import 'package:bookify/src/core/models/custom_notification_model.dart'; import 'package:bookify/src/core/services/app_services/notifications_service/notifications_service.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/loan_services/loan_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -78,10 +79,10 @@ void main() { observation: 'observation', loanDate: DateTime(2024, 02, 23), devolutionDate: DateTime(2024, 03, 22), - contactName: 'contactName', idContact: 'idContact', bookId: 'bookId', - bookTitle: 'bookTitle', + notificationTitle: 'notificationTitle', + notificationBody: 'notificationBody', ), ), verify: (_) { @@ -122,10 +123,10 @@ void main() { observation: 'observation', loanDate: DateTime(2024, 02, 23), devolutionDate: DateTime(2024, 03, 22), - contactName: 'contactName', idContact: 'idContact', bookId: 'bookId', - bookTitle: 'bookTitle', + notificationTitle: 'notificationTitle', + notificationBody: 'notificationBody', ), ), verify: (_) { @@ -173,10 +174,10 @@ void main() { observation: 'observation', loanDate: DateTime(2024, 02, 23), devolutionDate: DateTime(2024, 03, 22), - contactName: 'contactName', idContact: 'idContact', bookId: 'bookId', - bookTitle: 'bookTitle', + notificationTitle: 'notificationTitle', + notificationBody: 'notificationBody', ), ), verify: (_) { @@ -210,17 +211,22 @@ void main() { id: 'bookId', status: BookStatus.loaned, ), - ).thenThrow(const LocalDatabaseException('Error on Database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); }, act: (bloc) => bloc.add( InsertedLoanInsertionEvent( observation: 'observation', loanDate: DateTime(2024, 02, 23), devolutionDate: DateTime(2024, 03, 22), - contactName: 'contactName', idContact: 'idContact', bookId: 'bookId', - bookTitle: 'bookTitle', + notificationTitle: 'notificationTitle', + notificationBody: 'notificationBody', ), ), verify: (_) { @@ -261,10 +267,10 @@ void main() { observation: 'observation', loanDate: DateTime(2024, 02, 23), devolutionDate: DateTime(2024, 03, 22), - contactName: 'contactName', idContact: 'idContact', bookId: 'bookId', - bookTitle: 'bookTitle', + notificationTitle: 'notificationTitle', + notificationBody: 'notificationBody', ), ), verify: (_) { diff --git a/test/src/features/my_books/bloc/my_books_bloc_test.dart b/test/src/features/my_books/bloc/my_books_bloc_test.dart index 3c009533..db3ec2ca 100644 --- a/test/src/features/my_books/bloc/my_books_bloc_test.dart +++ b/test/src/features/my_books/bloc/my_books_bloc_test.dart @@ -5,6 +5,7 @@ import 'package:bookify/src/core/models/author_model.dart'; import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/models/category_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -58,11 +59,12 @@ void main() { blocTest( 'Test if GotAllBooksEvent work', build: () => bloc, - setUp: () => when( - () => bookService.getAllBook(), - ).thenAnswer( - (_) async => booksModel, - ), + setUp: () => + when( + () => bookService.getAllBook(), + ).thenAnswer( + (_) async => booksModel, + ), act: (bloc) => bloc.add(GotAllBooksEvent()), verify: (_) => verify(() => bookService.getAllBook()).called(1), expect: () => [ @@ -74,11 +76,12 @@ void main() { blocTest( 'Test if GotAllBooksEvent work with empty state', build: () => bloc, - setUp: () => when( - () => bookService.getAllBook(), - ).thenAnswer( - (_) async => [], - ), + setUp: () => + when( + () => bookService.getAllBook(), + ).thenAnswer( + (_) async => [], + ), act: (bloc) => bloc.add(GotAllBooksEvent()), verify: (_) => verify(() => bookService.getAllBook()).called(1), expect: () => [ @@ -90,9 +93,15 @@ void main() { blocTest( 'Test if GotAllBooksEvent work when throw LocalDatabaseException', build: () => bloc, - setUp: () => when( - () => bookService.getAllBook(), - ).thenThrow(const LocalDatabaseException('Error on Database')), + setUp: () => + when( + () => bookService.getAllBook(), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ), act: (bloc) => bloc.add(GotAllBooksEvent()), verify: (_) => verify(() => bookService.getAllBook()).called(1), expect: () => [ @@ -118,13 +127,14 @@ void main() { blocTest( 'Test if SearchedEvent work', build: () => bloc, - setUp: () => when( - () => bookService.getBooksByTitle( - title: any(named: 'title'), - ), - ).thenAnswer( - (_) async => booksModel, - ), + setUp: () => + when( + () => bookService.getBooksByTitle( + title: any(named: 'title'), + ), + ).thenAnswer( + (_) async => booksModel, + ), act: (bloc) => bloc.add( SearchedBooksEvent(searchQuery: 'title'), ), @@ -142,13 +152,14 @@ void main() { blocTest( 'Test if SearchedEvent work with not found state', build: () => bloc, - setUp: () => when( - () => bookService.getBooksByTitle( - title: any(named: 'title'), - ), - ).thenAnswer( - (_) async => [], - ), + setUp: () => + when( + () => bookService.getBooksByTitle( + title: any(named: 'title'), + ), + ).thenAnswer( + (_) async => [], + ), act: (bloc) => bloc.add( SearchedBooksEvent(searchQuery: 'title'), ), @@ -166,11 +177,17 @@ void main() { blocTest( 'Test if SearchedEvent work when throw LocalDatabaseException', build: () => bloc, - setUp: () => when( - () => bookService.getBooksByTitle( - title: any(named: 'title'), - ), - ).thenThrow(const LocalDatabaseException('Error on Database')), + setUp: () => + when( + () => bookService.getBooksByTitle( + title: any(named: 'title'), + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ), act: (bloc) => bloc.add( SearchedBooksEvent(searchQuery: 'title'), ), diff --git a/test/src/features/notifications/bloc/notifications_bloc_test.dart b/test/src/features/notifications/bloc/notifications_bloc_test.dart index bab174f4..c93381a8 100644 --- a/test/src/features/notifications/bloc/notifications_bloc_test.dart +++ b/test/src/features/notifications/bloc/notifications_bloc_test.dart @@ -30,19 +30,20 @@ void main() { blocTest( 'Test GotNotificationsEvent work', build: () => notificationsBloc, - setUp: () => when( - () => notificationsService.getNotifications(), - ).thenAnswer( - (_) async => [ - CustomNotificationModel( - id: 1, - notificationChannel: NotificationChannel.loanChannel, - title: 'title', - body: 'body', - scheduledDate: DateTime.now(), + setUp: () => + when( + () => notificationsService.getNotifications(), + ).thenAnswer( + (_) async => [ + CustomNotificationModel( + id: 1, + notificationChannel: NotificationChannel.loanChannel, + title: 'title', + body: 'body', + scheduledDate: DateTime.now(), + ), + ], ), - ], - ), act: (bloc) => bloc.add( GotNotificationsEvent(), ), @@ -58,11 +59,12 @@ void main() { blocTest( 'Test GotNotificationsEvent work when notifications is empty', build: () => notificationsBloc, - setUp: () => when( - () => notificationsService.getNotifications(), - ).thenAnswer( - (_) async => [], - ), + setUp: () => + when( + () => notificationsService.getNotifications(), + ).thenAnswer( + (_) async => [], + ), act: (bloc) => bloc.add( GotNotificationsEvent(), ), diff --git a/test/src/features/profile/bloc/profile_bloc_test.dart b/test/src/features/profile/bloc/profile_bloc_test.dart index 40778e55..82f30212 100644 --- a/test/src/features/profile/bloc/profile_bloc_test.dart +++ b/test/src/features/profile/bloc/profile_bloc_test.dart @@ -1,26 +1,22 @@ import 'package:bloc_test/bloc_test.dart'; +import 'package:bookify/src/shared/enums/auth_error_code.dart'; import 'package:bookify/src/features/profile/bloc/profile_bloc.dart'; import 'package:bookify/src/core/errors/auth_exception/auth_exception.dart'; import 'package:bookify/src/core/models/user_model.dart'; import 'package:bookify/src/core/services/auth_service/auth_service.dart'; -import 'package:bookify/src/core/services/storage_services/storage_services.dart'; import 'package:bookify/src/shared/enums/sign_in_type.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; class AuthServiceMock extends Mock implements AuthService {} -class StorageServiceMock extends Mock implements StorageServices {} - void main() { final authService = AuthServiceMock(); - final storageService = StorageServiceMock(); late ProfileBloc profileBloc; setUp(() { profileBloc = ProfileBloc( authService, - storageService, ); }); @@ -35,15 +31,16 @@ void main() { blocTest( 'Test GotUserSettingEvent work', build: () => profileBloc, - setUp: () => when( - () => authService.getUserModel(), - ).thenAnswer( - (_) async => const UserModel( - name: 'name', - photo: 'photo', - signInType: SignInType.google, - ), - ), + setUp: () => + when( + () => authService.getUserModel(), + ).thenAnswer( + (_) async => const UserModel( + name: 'name', + photo: 'photo', + signInType: SignInType.google, + ), + ), act: (bloc) => bloc.add( GotUserProfileEvent(), ), @@ -59,11 +56,12 @@ void main() { blocTest( 'Test GotUserSettingEvent work user is null', build: () => profileBloc, - setUp: () => when( - () => authService.getUserModel(), - ).thenAnswer( - (_) async => null, - ), + setUp: () => + when( + () => authService.getUserModel(), + ).thenAnswer( + (_) async => null, + ), act: (bloc) => bloc.add( GotUserProfileEvent(), ), @@ -79,11 +77,15 @@ void main() { blocTest( 'Test GotUserSettingEvent work when throw AuthException', build: () => profileBloc, - setUp: () => when( - () => authService.getUserModel(), - ).thenThrow( - const AuthException('Error on authentication'), - ), + setUp: () => + when( + () => authService.getUserModel(), + ).thenThrow( + const AuthException( + AuthErrorCode.tooManyRequests, + descriptionMessage: 'Error on authentication', + ), + ), act: (bloc) => bloc.add( GotUserProfileEvent(), ), @@ -99,11 +101,12 @@ void main() { blocTest( 'Test GotUserSettingEvent work when Generic Exception', build: () => profileBloc, - setUp: () => when( - () => authService.getUserModel(), - ).thenThrow( - Exception('Generic Error'), - ), + setUp: () => + when( + () => authService.getUserModel(), + ).thenThrow( + Exception('Generic Error'), + ), act: (bloc) => bloc.add( GotUserProfileEvent(), ), @@ -127,12 +130,6 @@ void main() { ).thenAnswer( (_) async => true, ); - - when( - () => storageService.clearStorage(), - ).thenAnswer( - (_) async => 1, - ); }, act: (bloc) => bloc.add( UserLoggedOutEvent( @@ -149,10 +146,6 @@ void main() { signInType: SignInType.google, ), ).called(1); - - verify( - () => storageService.clearStorage(), - ).called(1); }, expect: () => [ isA(), @@ -163,57 +156,14 @@ void main() { blocTest( 'Test UserLoggedOutEvent work when userLoggedOut is false', build: () => profileBloc, - setUp: () => when( - () => authService.signOut( - signInType: SignInType.google, - ), - ).thenAnswer( - (_) async => false, - ), - act: (bloc) => bloc.add( - UserLoggedOutEvent( - userModel: const UserModel( - name: 'name', - photo: 'photo', - signInType: SignInType.google, - ), - ), - ), - verify: (_) { - verify( - () => authService.signOut( - signInType: SignInType.google, - ), - ).called(1); - - verifyNever( - () => storageService.clearStorage(), - ); - }, - expect: () => [ - isA(), - isA(), - ], - ); - - blocTest( - 'Test UserLoggedOutEvent work when storageRemoved is 0', - build: () => profileBloc, - setUp: () { - when( - () => authService.signOut( - signInType: SignInType.google, + setUp: () => + when( + () => authService.signOut( + signInType: SignInType.google, + ), + ).thenAnswer( + (_) async => false, ), - ).thenAnswer( - (_) async => true, - ); - - when( - () => storageService.clearStorage(), - ).thenAnswer( - (_) async => 0, - ); - }, act: (bloc) => bloc.add( UserLoggedOutEvent( userModel: const UserModel( @@ -229,10 +179,6 @@ void main() { signInType: SignInType.google, ), ).called(1); - - verify( - () => storageService.clearStorage(), - ).called(1); }, expect: () => [ isA(), @@ -243,13 +189,17 @@ void main() { blocTest( 'Test UserLoggedOutEvent work when throw AuthException', build: () => profileBloc, - setUp: () => when( - () => authService.signOut( - signInType: SignInType.google, - ), - ).thenThrow( - const AuthException('Error on authentication'), - ), + setUp: () => + when( + () => authService.signOut( + signInType: SignInType.google, + ), + ).thenThrow( + const AuthException( + AuthErrorCode.tooManyRequests, + descriptionMessage: 'Error on authentication', + ), + ), act: (bloc) => bloc.add( UserLoggedOutEvent( userModel: const UserModel( @@ -265,10 +215,6 @@ void main() { signInType: SignInType.google, ), ).called(1); - - verifyNever( - () => storageService.clearStorage(), - ); }, expect: () => [ isA(), @@ -279,13 +225,14 @@ void main() { blocTest( 'Test UserLoggedOutEvent work when throw Generic Exception', build: () => profileBloc, - setUp: () => when( - () => authService.signOut( - signInType: SignInType.google, - ), - ).thenThrow( - Exception('Generic Error'), - ), + setUp: () => + when( + () => authService.signOut( + signInType: SignInType.google, + ), + ).thenThrow( + Exception('Generic Error'), + ), act: (bloc) => bloc.add( UserLoggedOutEvent( userModel: const UserModel( @@ -301,10 +248,6 @@ void main() { signInType: SignInType.google, ), ).called(1); - - verifyNever( - () => storageService.clearStorage(), - ); }, expect: () => [ isA(), diff --git a/test/src/features/profile/views/widgets/user_information_row/bloc/user_information_bloc_test.dart b/test/src/features/profile/views/widgets/user_information_row/bloc/user_information_bloc_test.dart index 988c5cc1..00ca12af 100644 --- a/test/src/features/profile/views/widgets/user_information_row/bloc/user_information_bloc_test.dart +++ b/test/src/features/profile/views/widgets/user_information_row/bloc/user_information_bloc_test.dart @@ -5,6 +5,7 @@ import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/bookcase_service/bookcase_service.dart'; import 'package:bookify/src/core/services/loan_services/loan_service.dart'; import 'package:bookify/src/core/services/reading_services/reading_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -104,7 +105,12 @@ void main() { when( () => bookcaseService.countBookcases(), - ).thenThrow(const LocalDatabaseException('Error on Database')); + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); }, act: (bloc) => bloc.add(GotUserInformationEvent()), verify: (_) { diff --git a/test/src/features/programming_reading/bloc/programming_reading_bloc_test.dart b/test/src/features/programming_reading/bloc/programming_reading_bloc_test.dart index f01e9982..7d92bd86 100644 --- a/test/src/features/programming_reading/bloc/programming_reading_bloc_test.dart +++ b/test/src/features/programming_reading/bloc/programming_reading_bloc_test.dart @@ -1,5 +1,6 @@ -import 'package:bookify/src/core/enums/repeat_hour_time_type.dart'; +import 'package:bookify/src/shared/enums/repeat_hour_time_type.dart'; import 'package:bloc_test/bloc_test.dart'; +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/models/user_hour_time_model.dart'; import 'package:bookify/src/core/repositories/user_hour_time_repository/user_hour_time_repository.dart'; @@ -52,11 +53,12 @@ void main() { blocTest( 'Test GotHourTimeEvent work', build: () => programmingReadingBloc, - setUp: () => when( - () => userHourTimeRepository.getUserHourTime(), - ).thenAnswer( - (_) async => userHourTime, - ), + setUp: () => + when( + () => userHourTimeRepository.getUserHourTime(), + ).thenAnswer( + (_) async => userHourTime, + ), act: (bloc) => bloc.add(GotHourTimeEvent()), verify: (_) => verify( () => userHourTimeRepository.getUserHourTime(), @@ -70,11 +72,15 @@ void main() { blocTest( 'Test GotHourTimeEvent work when throw StorageException', build: () => programmingReadingBloc, - setUp: () => when( - () => userHourTimeRepository.getUserHourTime(), - ).thenThrow( - const StorageException('Error on storage'), - ), + setUp: () => + when( + () => userHourTimeRepository.getUserHourTime(), + ).thenThrow( + const StorageException( + StorageErrorCode.invalidValue, + descriptionMessage: 'Error on storage', + ), + ), act: (bloc) => bloc.add(GotHourTimeEvent()), verify: (_) => verify( () => userHourTimeRepository.getUserHourTime(), @@ -88,11 +94,12 @@ void main() { blocTest( 'Test GotHourTimeEvent work when throw Generic Exception', build: () => programmingReadingBloc, - setUp: () => when( - () => userHourTimeRepository.getUserHourTime(), - ).thenThrow( - Exception('Generic Error'), - ), + setUp: () => + when( + () => userHourTimeRepository.getUserHourTime(), + ).thenThrow( + Exception('Generic Error'), + ), act: (bloc) => bloc.add(GotHourTimeEvent()), verify: (_) => verify( () => userHourTimeRepository.getUserHourTime(), @@ -116,14 +123,15 @@ void main() { ); when( - () => notificationsService.periodicallyShowNotificationWithSpecificDate( - id: any(named: 'id'), - title: any(named: 'title'), - body: any(named: 'body'), - notificationChannel: any(named: 'notificationChannel'), - repeatType: any(named: 'repeatType'), - scheduledDate: any(named: 'scheduledDate'), - ), + () => + notificationsService.periodicallyShowNotificationWithSpecificDate( + id: any(named: 'id'), + title: any(named: 'title'), + body: any(named: 'body'), + notificationChannel: any(named: 'notificationChannel'), + repeatType: any(named: 'repeatType'), + scheduledDate: any(named: 'scheduledDate'), + ), ).thenAnswer( (_) async {}, ); @@ -131,6 +139,8 @@ void main() { act: (bloc) => bloc.add( InsertedHourTimeEvent( userHourTimeModel: userHourTime, + readingTimeNotificationTitle: 'notificationTitle', + readingTimeNotificationBody: 'notificationBody', ), ), verify: (_) { @@ -141,14 +151,15 @@ void main() { ).called(1); verify( - () => notificationsService.periodicallyShowNotificationWithSpecificDate( - id: any(named: 'id'), - title: any(named: 'title'), - body: any(named: 'body'), - notificationChannel: any(named: 'notificationChannel'), - repeatType: any(named: 'repeatType'), - scheduledDate: any(named: 'scheduledDate'), - ), + () => + notificationsService.periodicallyShowNotificationWithSpecificDate( + id: any(named: 'id'), + title: any(named: 'title'), + body: any(named: 'body'), + notificationChannel: any(named: 'notificationChannel'), + repeatType: any(named: 'repeatType'), + scheduledDate: any(named: 'scheduledDate'), + ), ).called(1); }, expect: () => [ @@ -160,16 +171,19 @@ void main() { blocTest( 'Test InsertedHourTimeEvent work when userHourTimeInserted == 0', build: () => programmingReadingBloc, - setUp: () => when( - () => userHourTimeRepository.setUserHourTime( - userHourTime: userHourTime, - ), - ).thenAnswer( - (_) async => 0, - ), + setUp: () => + when( + () => userHourTimeRepository.setUserHourTime( + userHourTime: userHourTime, + ), + ).thenAnswer( + (_) async => 0, + ), act: (bloc) => bloc.add( InsertedHourTimeEvent( userHourTimeModel: userHourTime, + readingTimeNotificationTitle: 'notificationTitle', + readingTimeNotificationBody: 'notificationBody', ), ), verify: (_) { @@ -180,14 +194,15 @@ void main() { ).called(1); verifyNever( - () => notificationsService.periodicallyShowNotificationWithSpecificDate( - id: any(named: 'id'), - title: any(named: 'title'), - body: any(named: 'body'), - notificationChannel: any(named: 'notificationChannel'), - repeatType: any(named: 'repeatType'), - scheduledDate: any(named: 'scheduledDate'), - ), + () => + notificationsService.periodicallyShowNotificationWithSpecificDate( + id: any(named: 'id'), + title: any(named: 'title'), + body: any(named: 'body'), + notificationChannel: any(named: 'notificationChannel'), + repeatType: any(named: 'repeatType'), + scheduledDate: any(named: 'scheduledDate'), + ), ); }, expect: () => [ @@ -199,16 +214,22 @@ void main() { blocTest( 'Test InsertedHourTimeEvent work when throw StorageException', build: () => programmingReadingBloc, - setUp: () => when( - () => userHourTimeRepository.setUserHourTime( - userHourTime: userHourTime, - ), - ).thenThrow( - const StorageException('Error on storage'), - ), + setUp: () => + when( + () => userHourTimeRepository.setUserHourTime( + userHourTime: userHourTime, + ), + ).thenThrow( + const StorageException( + StorageErrorCode.invalidValue, + descriptionMessage: 'Error on storage', + ), + ), act: (bloc) => bloc.add( InsertedHourTimeEvent( userHourTimeModel: userHourTime, + readingTimeNotificationTitle: 'notificationTitle', + readingTimeNotificationBody: 'notificationBody', ), ), verify: (_) { @@ -219,14 +240,15 @@ void main() { ).called(1); verifyNever( - () => notificationsService.periodicallyShowNotificationWithSpecificDate( - id: any(named: 'id'), - title: any(named: 'title'), - body: any(named: 'body'), - notificationChannel: any(named: 'notificationChannel'), - repeatType: any(named: 'repeatType'), - scheduledDate: any(named: 'scheduledDate'), - ), + () => + notificationsService.periodicallyShowNotificationWithSpecificDate( + id: any(named: 'id'), + title: any(named: 'title'), + body: any(named: 'body'), + notificationChannel: any(named: 'notificationChannel'), + repeatType: any(named: 'repeatType'), + scheduledDate: any(named: 'scheduledDate'), + ), ); }, expect: () => [ @@ -238,16 +260,19 @@ void main() { blocTest( 'Test InsertedHourTimeEvent work when throw Generic Exception', build: () => programmingReadingBloc, - setUp: () => when( - () => userHourTimeRepository.setUserHourTime( - userHourTime: userHourTime, - ), - ).thenThrow( - Exception('Generic Error'), - ), + setUp: () => + when( + () => userHourTimeRepository.setUserHourTime( + userHourTime: userHourTime, + ), + ).thenThrow( + Exception('Generic Error'), + ), act: (bloc) => bloc.add( InsertedHourTimeEvent( userHourTimeModel: userHourTime, + readingTimeNotificationTitle: 'notificationTitle', + readingTimeNotificationBody: 'notificationBody', ), ), verify: (_) { @@ -258,14 +283,15 @@ void main() { ).called(1); verifyNever( - () => notificationsService.periodicallyShowNotificationWithSpecificDate( - id: any(named: 'id'), - title: any(named: 'title'), - body: any(named: 'body'), - notificationChannel: any(named: 'notificationChannel'), - repeatType: any(named: 'repeatType'), - scheduledDate: any(named: 'scheduledDate'), - ), + () => + notificationsService.periodicallyShowNotificationWithSpecificDate( + id: any(named: 'id'), + title: any(named: 'title'), + body: any(named: 'body'), + notificationChannel: any(named: 'notificationChannel'), + repeatType: any(named: 'repeatType'), + scheduledDate: any(named: 'scheduledDate'), + ), ); }, expect: () => [ @@ -278,13 +304,14 @@ void main() { blocTest( 'Test RemovedNotificationHourTimeEvent work', build: () => programmingReadingBloc, - setUp: () => when( - () => notificationsService.cancelNotificationById( - id: any(named: 'id'), - ), - ).thenAnswer( - (_) async {}, - ), + setUp: () => + when( + () => notificationsService.cancelNotificationById( + id: any(named: 'id'), + ), + ).thenAnswer( + (_) async {}, + ), act: (bloc) => bloc.add(RemovedNotificationHourTimeEvent()), verify: (_) { verify( @@ -302,13 +329,14 @@ void main() { blocTest( 'Test RemovedNotificationHourTimeEvent work when throw Generic Exception', build: () => programmingReadingBloc, - setUp: () => when( - () => notificationsService.cancelNotificationById( - id: any(named: 'id'), - ), - ).thenThrow( - Exception('Generic Error'), - ), + setUp: () => + when( + () => notificationsService.cancelNotificationById( + id: any(named: 'id'), + ), + ).thenThrow( + Exception('Generic Error'), + ), act: (bloc) => bloc.add(RemovedNotificationHourTimeEvent()), verify: (_) { verify( diff --git a/test/src/features/qr_code_scanner/views/qr_code_scanner_page_test.dart b/test/src/features/qr_code_scanner/views/qr_code_scanner_page_test.dart index f3ce2445..b16d7b0e 100644 --- a/test/src/features/qr_code_scanner/views/qr_code_scanner_page_test.dart +++ b/test/src/features/qr_code_scanner/views/qr_code_scanner_page_test.dart @@ -4,8 +4,9 @@ import 'package:flutter_test/flutter_test.dart'; const qrCodeScannerWidgetKey = Key('qrCodeScannerWidget'); const changeModeTextButtonKey = Key('changeModeTextButton'); -const isbnManuallyTextFormFieldWidgetKey = - Key('isbnManuallyTextFormFieldWidget'); +const isbnManuallyTextFormFieldWidgetKey = Key( + 'isbnManuallyTextFormFieldWidget', +); const isbnManuallyOutlinedButtonKey = Key('isbnManuallyOutlinedButton'); const isbnManuallyTextFormFieldKey = Key('isbnManuallyTextFormField'); diff --git a/test/src/features/reading_page_timer/bloc/reading_page_timer_bloc_test.dart b/test/src/features/reading_page_timer/bloc/reading_page_timer_bloc_test.dart index 47e1b1df..8cb0d16a 100644 --- a/test/src/features/reading_page_timer/bloc/reading_page_timer_bloc_test.dart +++ b/test/src/features/reading_page_timer/bloc/reading_page_timer_bloc_test.dart @@ -1,4 +1,5 @@ import 'package:bloc_test/bloc_test.dart'; +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/models/user_page_reading_time_model.dart'; import 'package:bookify/src/core/repositories/user_page_reading_time_repository/user_page_reading_time_repository.dart'; @@ -33,13 +34,14 @@ void main() { blocTest( 'Test InsertedReadingPageTimeEvent work', build: () => readingPageTimerBloc, - setUp: () => when( - () => userPageReadingTimeRepository.setUserPageReadingTime( - userPageReadingTime: userPageReadingTime, - ), - ).thenAnswer( - (_) async => 1, - ), + setUp: () => + when( + () => userPageReadingTimeRepository.setUserPageReadingTime( + userPageReadingTime: userPageReadingTime, + ), + ).thenAnswer( + (_) async => 1, + ), act: (bloc) => bloc.add( InsertedReadingPageTimeEvent( readingPageTime: 600, @@ -59,13 +61,14 @@ void main() { blocTest( 'Test InsertedReadingPageTimeEvent work when userPageReadingTimeInserted == 0', build: () => readingPageTimerBloc, - setUp: () => when( - () => userPageReadingTimeRepository.setUserPageReadingTime( - userPageReadingTime: userPageReadingTime, - ), - ).thenAnswer( - (_) async => 0, - ), + setUp: () => + when( + () => userPageReadingTimeRepository.setUserPageReadingTime( + userPageReadingTime: userPageReadingTime, + ), + ).thenAnswer( + (_) async => 0, + ), act: (bloc) => bloc.add( InsertedReadingPageTimeEvent( readingPageTime: 600, @@ -85,13 +88,17 @@ void main() { blocTest( 'Test InsertedReadingPageTimeEvent work when throw StorageException', build: () => readingPageTimerBloc, - setUp: () => when( - () => userPageReadingTimeRepository.setUserPageReadingTime( - userPageReadingTime: userPageReadingTime, - ), - ).thenThrow( - const StorageException('Error on storage'), - ), + setUp: () => + when( + () => userPageReadingTimeRepository.setUserPageReadingTime( + userPageReadingTime: userPageReadingTime, + ), + ).thenThrow( + const StorageException( + StorageErrorCode.invalidValue, + descriptionMessage: 'Error on storage', + ), + ), act: (bloc) => bloc.add( InsertedReadingPageTimeEvent( readingPageTime: 600, @@ -111,13 +118,14 @@ void main() { blocTest( 'Test InsertedReadingPageTimeEvent work when throw Generic Exception', build: () => readingPageTimerBloc, - setUp: () => when( - () => userPageReadingTimeRepository.setUserPageReadingTime( - userPageReadingTime: userPageReadingTime, - ), - ).thenThrow( - Exception('Generic Error'), - ), + setUp: () => + when( + () => userPageReadingTimeRepository.setUserPageReadingTime( + userPageReadingTime: userPageReadingTime, + ), + ).thenThrow( + Exception('Generic Error'), + ), act: (bloc) => bloc.add( InsertedReadingPageTimeEvent( readingPageTime: 600, diff --git a/test/src/features/readings/bloc/readings_bloc_test.dart b/test/src/features/readings/bloc/readings_bloc_test.dart index cc141f3b..5fb87ede 100644 --- a/test/src/features/readings/bloc/readings_bloc_test.dart +++ b/test/src/features/readings/bloc/readings_bloc_test.dart @@ -7,6 +7,7 @@ import 'package:bookify/src/core/models/category_model.dart'; import 'package:bookify/src/core/models/reading_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/reading_services/reading_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -135,7 +136,10 @@ void main() { id: any(named: 'id'), ), ).thenThrow( - const LocalDatabaseException('Error on Database'), + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), ); }, act: (bloc) => bloc.add(GotAllReadingsEvent()), @@ -236,13 +240,14 @@ void main() { blocTest( 'Test FoundReadingByBookTitleEvent work when readings are empty', build: () => readingsBloc, - setUp: () => when( - () => readingService.getReadingsByBookTitle( - title: any(named: 'title'), - ), - ).thenAnswer( - (_) async => [], - ), + setUp: () => + when( + () => readingService.getReadingsByBookTitle( + title: any(named: 'title'), + ), + ).thenAnswer( + (_) async => [], + ), act: (bloc) => bloc.add( FoundReadingByBookTitleEvent(searchQueryName: 'searchQueryName'), ), @@ -263,19 +268,20 @@ void main() { blocTest( 'Test FoundReadingByBookTitleEvent work when reading id is empty', build: () => readingsBloc, - setUp: () => when( - () => readingService.getReadingsByBookTitle( - title: any(named: 'title'), - ), - ).thenAnswer( - (_) async => [ - ReadingModel( - pagesReaded: 100, - lastReadingDate: DateTime(2024, 03, 06), - bookId: 'bookId', + setUp: () => + when( + () => readingService.getReadingsByBookTitle( + title: any(named: 'title'), + ), + ).thenAnswer( + (_) async => [ + ReadingModel( + pagesReaded: 100, + lastReadingDate: DateTime(2024, 03, 06), + bookId: 'bookId', + ), + ], ), - ], - ), act: (bloc) => bloc.add( FoundReadingByBookTitleEvent(searchQueryName: 'searchQueryName'), ), @@ -297,8 +303,10 @@ void main() { 'Test FoundReadingByBookTitleEvent work when throw LocalDatabaseException', build: () => readingsBloc, setUp: () { - when(() => readingService.getReadingsByBookTitle( - title: any(named: 'title'))).thenAnswer( + when( + () => + readingService.getReadingsByBookTitle(title: any(named: 'title')), + ).thenAnswer( (_) async => [ ReadingModel( id: 1, @@ -313,15 +321,20 @@ void main() { id: any(named: 'id'), ), ).thenThrow( - const LocalDatabaseException('Error on Database'), + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), ); }, act: (bloc) => bloc.add( FoundReadingByBookTitleEvent(searchQueryName: 'searchQueryName'), ), verify: (_) { - verify(() => readingService.getReadingsByBookTitle( - title: any(named: 'title'))).called(1); + verify( + () => + readingService.getReadingsByBookTitle(title: any(named: 'title')), + ).called(1); verify(() => bookService.getBookById(id: any(named: 'id'))).called(1); }, expect: () => [ @@ -334,8 +347,10 @@ void main() { 'Test FoundReadingByBookTitleEvent work when throw Generic Exception', build: () => readingsBloc, setUp: () { - when(() => readingService.getReadingsByBookTitle( - title: any(named: 'title'))).thenAnswer( + when( + () => + readingService.getReadingsByBookTitle(title: any(named: 'title')), + ).thenAnswer( (_) async => [ ReadingModel( id: 1, @@ -357,8 +372,10 @@ void main() { FoundReadingByBookTitleEvent(searchQueryName: 'searchQueryName'), ), verify: (_) { - verify(() => readingService.getReadingsByBookTitle( - title: any(named: 'title'))).called(1); + verify( + () => + readingService.getReadingsByBookTitle(title: any(named: 'title')), + ).called(1); verify(() => bookService.getBookById(id: any(named: 'id'))).called(1); }, expect: () => [ diff --git a/test/src/features/readings_detail/bloc/readings_detail_bloc_test.dart b/test/src/features/readings_detail/bloc/readings_detail_bloc_test.dart index 547a65a2..d1428eb5 100644 --- a/test/src/features/readings_detail/bloc/readings_detail_bloc_test.dart +++ b/test/src/features/readings_detail/bloc/readings_detail_bloc_test.dart @@ -5,6 +5,7 @@ import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/models/reading_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/reading_services/reading_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -90,13 +91,17 @@ void main() { blocTest( 'Test UpdatedReadingsEvent work when throw LocalDatabaseException', build: () => readingsDetailBloc, - setUp: () => when( - () => readingService.update( - readingModel: readingModel, - ), - ).thenThrow( - const LocalDatabaseException('Error on Database'), - ), + setUp: () => + when( + () => readingService.update( + readingModel: readingModel, + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ), act: (bloc) => bloc.add( UpdatedReadingsEvent( readingModel: readingModel, @@ -116,13 +121,14 @@ void main() { blocTest( 'Test UpdatedReadingsEvent work when throw Generic Exception', build: () => readingsDetailBloc, - setUp: () => when( - () => readingService.update( - readingModel: readingModel, - ), - ).thenThrow( - Exception('Generic Error'), - ), + setUp: () => + when( + () => readingService.update( + readingModel: readingModel, + ), + ).thenThrow( + Exception('Generic Error'), + ), act: (bloc) => bloc.add( UpdatedReadingsEvent( readingModel: readingModel, @@ -270,7 +276,10 @@ void main() { readingId: any(named: 'readingId'), ), ).thenThrow( - const LocalDatabaseException('Error on Database'), + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), ); }, act: (bloc) => bloc.add( diff --git a/test/src/features/readings_insertion/bloc/readings_insertion_bloc_test.dart b/test/src/features/readings_insertion/bloc/readings_insertion_bloc_test.dart index 5f1b371d..ef4d9cd3 100644 --- a/test/src/features/readings_insertion/bloc/readings_insertion_bloc_test.dart +++ b/test/src/features/readings_insertion/bloc/readings_insertion_bloc_test.dart @@ -5,6 +5,7 @@ import 'package:bookify/src/core/models/book_model.dart'; import 'package:bookify/src/core/models/reading_model.dart'; import 'package:bookify/src/core/services/book_service/book_service.dart'; import 'package:bookify/src/core/services/reading_services/reading_service.dart'; +import 'package:bookify/src/shared/enums/local_database_error_code.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -41,23 +42,31 @@ void main() { 'Test InsertedLoanEvent work', build: () => readingsInsertionBloc, setUp: () { - when(() => bookService.updateStatus( - id: any(named: 'id'), - status: BookStatus.reading, - )).thenAnswer((_) async => 1); - when(() => readingService.insert( - readingModel: readingModel, - )).thenAnswer((_) async => 1); + when( + () => bookService.updateStatus( + id: any(named: 'id'), + status: BookStatus.reading, + ), + ).thenAnswer((_) async => 1); + when( + () => readingService.insert( + readingModel: readingModel, + ), + ).thenAnswer((_) async => 1); }, act: (bloc) => bloc.add(InsertedReadingsEvent(bookId: 'bookId')), verify: (_) { - verify(() => bookService.updateStatus( - id: any(named: 'id'), - status: BookStatus.reading, - )).called(1); - verify(() => readingService.insert( - readingModel: readingModel, - )).called(1); + verify( + () => bookService.updateStatus( + id: any(named: 'id'), + status: BookStatus.reading, + ), + ).called(1); + verify( + () => readingService.insert( + readingModel: readingModel, + ), + ).called(1); }, expect: () => [ isA(), @@ -69,32 +78,44 @@ void main() { 'Test InsertedLoanEvent work when pageCount != 0', build: () => readingsInsertionBloc, setUp: () { - when(() => bookService.updatePageCount( - id: any(named: 'id'), - pageCount: any(named: 'pageCount'), - )).thenAnswer((_) async => 1); - when(() => bookService.updateStatus( - id: any(named: 'id'), - status: BookStatus.reading, - )).thenAnswer((_) async => 1); - when(() => readingService.insert( - readingModel: readingModel, - )).thenAnswer((_) async => 1); + when( + () => bookService.updatePageCount( + id: any(named: 'id'), + pageCount: any(named: 'pageCount'), + ), + ).thenAnswer((_) async => 1); + when( + () => bookService.updateStatus( + id: any(named: 'id'), + status: BookStatus.reading, + ), + ).thenAnswer((_) async => 1); + when( + () => readingService.insert( + readingModel: readingModel, + ), + ).thenAnswer((_) async => 1); }, act: (bloc) => bloc.add(InsertedReadingsEvent(bookId: 'bookId', pagesUpdated: 100)), verify: (_) { - verify(() => bookService.updatePageCount( - id: any(named: 'id'), - pageCount: any(named: 'pageCount'), - )).called(1); - verify(() => bookService.updateStatus( - id: any(named: 'id'), - status: BookStatus.reading, - )).called(1); - verify(() => readingService.insert( - readingModel: readingModel, - )).called(1); + verify( + () => bookService.updatePageCount( + id: any(named: 'id'), + pageCount: any(named: 'pageCount'), + ), + ).called(1); + verify( + () => bookService.updateStatus( + id: any(named: 'id'), + status: BookStatus.reading, + ), + ).called(1); + verify( + () => readingService.insert( + readingModel: readingModel, + ), + ).called(1); }, expect: () => [ isA(), @@ -106,32 +127,44 @@ void main() { 'Test InsertedLoanEvent work when pageCount != 0 with error update', build: () => readingsInsertionBloc, setUp: () { - when(() => bookService.updatePageCount( - id: any(named: 'id'), - pageCount: any(named: 'pageCount'), - )).thenAnswer((_) async => 0); - when(() => bookService.updateStatus( - id: any(named: 'id'), - status: BookStatus.reading, - )).thenAnswer((_) async => 1); - when(() => readingService.insert( - readingModel: readingModel, - )).thenAnswer((_) async => 1); + when( + () => bookService.updatePageCount( + id: any(named: 'id'), + pageCount: any(named: 'pageCount'), + ), + ).thenAnswer((_) async => 0); + when( + () => bookService.updateStatus( + id: any(named: 'id'), + status: BookStatus.reading, + ), + ).thenAnswer((_) async => 1); + when( + () => readingService.insert( + readingModel: readingModel, + ), + ).thenAnswer((_) async => 1); }, act: (bloc) => bloc.add(InsertedReadingsEvent(bookId: 'bookId', pagesUpdated: 100)), verify: (_) { - verify(() => bookService.updatePageCount( - id: any(named: 'id'), - pageCount: any(named: 'pageCount'), - )).called(1); - verifyNever(() => bookService.updateStatus( - id: any(named: 'id'), - status: BookStatus.reading, - )); - verifyNever(() => readingService.insert( - readingModel: readingModel, - )); + verify( + () => bookService.updatePageCount( + id: any(named: 'id'), + pageCount: any(named: 'pageCount'), + ), + ).called(1); + verifyNever( + () => bookService.updateStatus( + id: any(named: 'id'), + status: BookStatus.reading, + ), + ); + verifyNever( + () => readingService.insert( + readingModel: readingModel, + ), + ); }, expect: () => [ isA(), @@ -143,23 +176,31 @@ void main() { 'Test InsertedLoanEvent work when update status error', build: () => readingsInsertionBloc, setUp: () { - when(() => bookService.updateStatus( - id: any(named: 'id'), - status: BookStatus.reading, - )).thenAnswer((_) async => 0); - when(() => readingService.insert( - readingModel: readingModel, - )).thenAnswer((_) async => 1); + when( + () => bookService.updateStatus( + id: any(named: 'id'), + status: BookStatus.reading, + ), + ).thenAnswer((_) async => 0); + when( + () => readingService.insert( + readingModel: readingModel, + ), + ).thenAnswer((_) async => 1); }, act: (bloc) => bloc.add(InsertedReadingsEvent(bookId: 'bookId')), verify: (_) { - verify(() => bookService.updateStatus( - id: any(named: 'id'), - status: BookStatus.reading, - )).called(1); - verifyNever(() => readingService.insert( - readingModel: readingModel, - )); + verify( + () => bookService.updateStatus( + id: any(named: 'id'), + status: BookStatus.reading, + ), + ).called(1); + verifyNever( + () => readingService.insert( + readingModel: readingModel, + ), + ); }, expect: () => [ isA(), @@ -171,23 +212,31 @@ void main() { 'Test InsertedLoanEvent work when reading insertion error', build: () => readingsInsertionBloc, setUp: () { - when(() => bookService.updateStatus( - id: any(named: 'id'), - status: BookStatus.reading, - )).thenAnswer((_) async => 1); - when(() => readingService.insert( - readingModel: readingModel, - )).thenAnswer((_) async => 0); + when( + () => bookService.updateStatus( + id: any(named: 'id'), + status: BookStatus.reading, + ), + ).thenAnswer((_) async => 1); + when( + () => readingService.insert( + readingModel: readingModel, + ), + ).thenAnswer((_) async => 0); }, act: (bloc) => bloc.add(InsertedReadingsEvent(bookId: 'bookId')), verify: (_) { - verify(() => bookService.updateStatus( - id: any(named: 'id'), - status: BookStatus.reading, - )).called(1); - verify(() => readingService.insert( - readingModel: readingModel, - )).called(1); + verify( + () => bookService.updateStatus( + id: any(named: 'id'), + status: BookStatus.reading, + ), + ).called(1); + verify( + () => readingService.insert( + readingModel: readingModel, + ), + ).called(1); }, expect: () => [ isA(), @@ -199,23 +248,36 @@ void main() { 'Test InsertedLoanEvent work when throw LocalDatabaseException', build: () => readingsInsertionBloc, setUp: () { - when(() => bookService.updateStatus( - id: any(named: 'id'), - status: BookStatus.reading, - )).thenAnswer((_) async => 1); - when(() => readingService.insert( - readingModel: readingModel, - )).thenThrow(const LocalDatabaseException('Error on Database')); + when( + () => bookService.updateStatus( + id: any(named: 'id'), + status: BookStatus.reading, + ), + ).thenAnswer((_) async => 1); + when( + () => readingService.insert( + readingModel: readingModel, + ), + ).thenThrow( + const LocalDatabaseException( + LocalDatabaseErrorCode.unknown, + descriptionMessage: 'Error on database', + ), + ); }, act: (bloc) => bloc.add(InsertedReadingsEvent(bookId: 'bookId')), verify: (_) { - verify(() => bookService.updateStatus( - id: any(named: 'id'), - status: BookStatus.reading, - )).called(1); - verify(() => readingService.insert( - readingModel: readingModel, - )).called(1); + verify( + () => bookService.updateStatus( + id: any(named: 'id'), + status: BookStatus.reading, + ), + ).called(1); + verify( + () => readingService.insert( + readingModel: readingModel, + ), + ).called(1); }, expect: () => [ isA(), @@ -227,23 +289,31 @@ void main() { 'Test InsertedLoanEvent work when throw Generic Exception', build: () => readingsInsertionBloc, setUp: () { - when(() => bookService.updateStatus( - id: any(named: 'id'), - status: BookStatus.reading, - )).thenAnswer((_) async => 1); - when(() => readingService.insert( - readingModel: readingModel, - )).thenThrow(Exception('Generic Error')); + when( + () => bookService.updateStatus( + id: any(named: 'id'), + status: BookStatus.reading, + ), + ).thenAnswer((_) async => 1); + when( + () => readingService.insert( + readingModel: readingModel, + ), + ).thenThrow(Exception('Generic Error')); }, act: (bloc) => bloc.add(InsertedReadingsEvent(bookId: 'bookId')), verify: (_) { - verify(() => bookService.updateStatus( - id: any(named: 'id'), - status: BookStatus.reading, - )).called(1); - verify(() => readingService.insert( - readingModel: readingModel, - )).called(1); + verify( + () => bookService.updateStatus( + id: any(named: 'id'), + status: BookStatus.reading, + ), + ).called(1); + verify( + () => readingService.insert( + readingModel: readingModel, + ), + ).called(1); }, expect: () => [ isA(), diff --git a/test/src/features/readings_timer/bloc/readings_timer_bloc_test.dart b/test/src/features/readings_timer/bloc/readings_timer_bloc_test.dart index db54aadc..356e4fdc 100644 --- a/test/src/features/readings_timer/bloc/readings_timer_bloc_test.dart +++ b/test/src/features/readings_timer/bloc/readings_timer_bloc_test.dart @@ -1,5 +1,6 @@ -import 'package:bookify/src/core/enums/repeat_hour_time_type.dart'; +import 'package:bookify/src/shared/enums/repeat_hour_time_type.dart'; import 'package:bloc_test/bloc_test.dart'; +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/models/user_hour_time_model.dart'; import 'package:bookify/src/core/repositories/user_hour_time_repository/user_hour_time_repository.dart'; @@ -41,11 +42,12 @@ void main() { blocTest( 'Test GotReadingsUserTimerEvent work', build: () => readingsTimerBloc, - setUp: () => when( - () => userHourTimeRepository.getUserHourTime(), - ).thenAnswer( - (_) async => userHourTimeModel, - ), + setUp: () => + when( + () => userHourTimeRepository.getUserHourTime(), + ).thenAnswer( + (_) async => userHourTimeModel, + ), act: (bloc) => bloc.add(GotReadingsUserTimerEvent()), verify: (_) => verify( () => userHourTimeRepository.getUserHourTime(), @@ -59,11 +61,12 @@ void main() { blocTest( 'Test GotReadingsUserTimerEvent work when userHourTime is null', build: () => readingsTimerBloc, - setUp: () => when( - () => userHourTimeRepository.getUserHourTime(), - ).thenAnswer( - (_) async => null, - ), + setUp: () => + when( + () => userHourTimeRepository.getUserHourTime(), + ).thenAnswer( + (_) async => null, + ), act: (bloc) => bloc.add(GotReadingsUserTimerEvent()), verify: (_) => verify( () => userHourTimeRepository.getUserHourTime(), @@ -77,9 +80,15 @@ void main() { blocTest( 'Test GotReadingsUserTimerEvent work when throw Storage Exception', build: () => readingsTimerBloc, - setUp: () => when( - () => userHourTimeRepository.getUserHourTime(), - ).thenThrow(const StorageException('Error on storage')), + setUp: () => + when( + () => userHourTimeRepository.getUserHourTime(), + ).thenThrow( + const StorageException( + StorageErrorCode.invalidValue, + descriptionMessage: 'Error on storage', + ), + ), act: (bloc) => bloc.add(GotReadingsUserTimerEvent()), verify: (_) => verify( () => userHourTimeRepository.getUserHourTime(), diff --git a/test/src/mocks/json/books_json_mock.dart b/test/src/mocks/json/books_json_mock.dart index f2fed8f5..f0084edb 100644 --- a/test/src/mocks/json/books_json_mock.dart +++ b/test/src/mocks/json/books_json_mock.dart @@ -16,11 +16,11 @@ const authorJsonBooksMock = { 'ratingsCount': 2, 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=IsuqmVlFo30C&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=IsuqmVlFo30C&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=IsuqmVlFo30C&source=gbs_api' - } + 'https://play.google.com/store/books/details?id=IsuqmVlFo30C&source=gbs_api', + }, }, //2 @@ -38,11 +38,11 @@ const authorJsonBooksMock = { 'ratingsCount': 58, 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=dFlImpewmqUC&printsec=frontcover&img=1&zoom=1&source=gbs_api' + 'http://books.google.com/books/content?id=dFlImpewmqUC&printsec=frontcover&img=1&zoom=1&source=gbs_api', }, 'infoLink': - 'http://books.google.com.br/books?id=dFlImpewmqUC&dq=inauthor:J.R.R.+Tolkien%27&hl=&as_ebook=1&as_pt=BOOKS&source=gbs_api' - } + 'http://books.google.com.br/books?id=dFlImpewmqUC&dq=inauthor:J.R.R.+Tolkien%27&hl=&as_ebook=1&as_pt=BOOKS&source=gbs_api', + }, }, //3 @@ -58,11 +58,11 @@ const authorJsonBooksMock = { 'categories': ['Fiction'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=HTgpAwAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=HTgpAwAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=HTgpAwAAQBAJ&source=gbs_api' - } + 'https://play.google.com/store/books/details?id=HTgpAwAAQBAJ&source=gbs_api', + }, }, //4 @@ -80,11 +80,11 @@ const authorJsonBooksMock = { 'ratingsCount': 22, 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=05Cj67qkoaoC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=05Cj67qkoaoC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=05Cj67qkoaoC&source=gbs_api' - } + 'https://play.google.com/store/books/details?id=05Cj67qkoaoC&source=gbs_api', + }, }, //5 @@ -102,13 +102,13 @@ const authorJsonBooksMock = { 'ratingsCount': 28, 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=HbG0jd66h3EC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=HbG0jd66h3EC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'http://books.google.com.br/books?id=HbG0jd66h3EC&dq=inauthor:J.R.R.+Tolkien%27&hl=&as_ebook=1&as_pt=BOOKS&source=gbs_api' - } - } - ] + 'http://books.google.com.br/books?id=HbG0jd66h3EC&dq=inauthor:J.R.R.+Tolkien%27&hl=&as_ebook=1&as_pt=BOOKS&source=gbs_api', + }, + }, + ], }; // this is a const list of 5 google books by Author @@ -127,11 +127,11 @@ const publisherJsonBooksMock = { 'categories': ['Computers'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=mKW6BAAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=mKW6BAAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=mKW6BAAAQBAJ&source=gbs_api' - } + 'https://play.google.com/store/books/details?id=mKW6BAAAQBAJ&source=gbs_api', + }, }, //2 @@ -147,11 +147,11 @@ const publisherJsonBooksMock = { 'categories': ['Health & Fitness'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=TjziAwAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=TjziAwAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=TjziAwAAQBAJ&source=gbs_api' - } + 'https://play.google.com/store/books/details?id=TjziAwAAQBAJ&source=gbs_api', + }, }, //3 @@ -167,11 +167,11 @@ const publisherJsonBooksMock = { 'categories': ['Mathematics'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=TXblAwAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=TXblAwAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=TXblAwAAQBAJ&source=gbs_api' - } + 'https://play.google.com/store/books/details?id=TXblAwAAQBAJ&source=gbs_api', + }, }, //4 @@ -187,11 +187,11 @@ const publisherJsonBooksMock = { 'categories': ['Computers'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=JMKbBAAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=JMKbBAAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=JMKbBAAAQBAJ&source=gbs_api' - } + 'https://play.google.com/store/books/details?id=JMKbBAAAQBAJ&source=gbs_api', + }, }, //5 @@ -207,13 +207,13 @@ const publisherJsonBooksMock = { 'categories': ['Computers'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=I0MlDQAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=I0MlDQAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=I0MlDQAAQBAJ&source=gbs_api' - } - } - ] + 'https://play.google.com/store/books/details?id=I0MlDQAAQBAJ&source=gbs_api', + }, + }, + ], }; // this is a const list of 5 google books @@ -234,11 +234,11 @@ const allBooksMock = { 'ratingsCount': 1, 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=5unrAgAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=5unrAgAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=5unrAgAAQBAJ&source=gbs_api' - } + 'https://play.google.com/store/books/details?id=5unrAgAAQBAJ&source=gbs_api', + }, }, //2 @@ -254,11 +254,11 @@ const allBooksMock = { 'categories': ['Health & Fitness'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=Pm4uBAAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=Pm4uBAAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=Pm4uBAAAQBAJ&source=gbs_api' - } + 'https://play.google.com/store/books/details?id=Pm4uBAAAQBAJ&source=gbs_api', + }, }, //3 @@ -271,8 +271,8 @@ const allBooksMock = { 'Desde pequenos, descobrimos que os amigos são um bem precioso. Muitas crianças logo encontram seus pares. Outras têm mais dificuldades em se relacionar e se sentem sós, sem amigos. Artur era um desses. Todos os dias esperava na estação de trem que alguém viesse visitá-lo, mas nunca vinha ninguém. Até o dia em que ele resolveu procurar seus amigos em outras estações. As ilustrações, do próprio autor, enfatizam o texto, enchendo as páginas de amigos.', 'pageCount': 28, 'infoLink': - 'http://books.google.com.br/books?id=sQmtPwAACAAJ&dq=*&hl=&source=gbs_api' - } + 'http://books.google.com.br/books?id=sQmtPwAACAAJ&dq=*&hl=&source=gbs_api', + }, }, //4 @@ -283,7 +283,7 @@ const allBooksMock = { 'authors': [ 'Maria Cecília de Souza Minayo', 'Edinilsa Ramos de Souza', - 'Patrícia Constantino' + 'Patrícia Constantino', ], 'publisher': 'SciELO - Editora FIOCRUZ', 'description': @@ -292,11 +292,11 @@ const allBooksMock = { 'categories': ['Technology & Engineering'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=T-jrAgAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=T-jrAgAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=T-jrAgAAQBAJ&source=gbs_api' - } + 'https://play.google.com/store/books/details?id=T-jrAgAAQBAJ&source=gbs_api', + }, }, //5 @@ -313,13 +313,13 @@ const allBooksMock = { 'categories': ['Juvenile Fiction'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=e6-tAwAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=e6-tAwAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=e6-tAwAAQBAJ&source=gbs_api' - } - } - ] + 'https://play.google.com/store/books/details?id=e6-tAwAAQBAJ&source=gbs_api', + }, + }, + ], }; // this is a const list of 5 google books by title @@ -338,11 +338,11 @@ const titleBooksMock = { 'categories': ['Computers'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=RY7kp2dT0jwC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=RY7kp2dT0jwC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=RY7kp2dT0jwC&source=gbs_api' - } + 'https://play.google.com/store/books/details?id=RY7kp2dT0jwC&source=gbs_api', + }, }, //2 @@ -358,11 +358,11 @@ const titleBooksMock = { 'categories': ['Architecture'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=CWawDAAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=CWawDAAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=CWawDAAAQBAJ&source=gbs_api' - } + 'https://play.google.com/store/books/details?id=CWawDAAAQBAJ&source=gbs_api', + }, }, //3 @@ -378,11 +378,11 @@ const titleBooksMock = { 'categories': ['Architecture'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=o1rwDwAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=o1rwDwAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=o1rwDwAAQBAJ&source=gbs_api' - } + 'https://play.google.com/store/books/details?id=o1rwDwAAQBAJ&source=gbs_api', + }, }, //4 @@ -398,11 +398,11 @@ const titleBooksMock = { 'categories': ['Architecture'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=-DfnDwAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=-DfnDwAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=-DfnDwAAQBAJ&source=gbs_api' - } + 'https://play.google.com/store/books/details?id=-DfnDwAAQBAJ&source=gbs_api', + }, }, //5 @@ -413,7 +413,7 @@ const titleBooksMock = { 'authors': [ 'Maria Aldecy Rodrigues de Lima', 'Cleidson de Jesus Rocha', - 'Ana Flávia de Lima Rocha' + 'Ana Flávia de Lima Rocha', ], 'publisher': 'Editora CRV', 'description': @@ -422,13 +422,13 @@ const titleBooksMock = { 'categories': ['Education'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=m61TEAAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=m61TEAAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=m61TEAAAQBAJ&source=gbs_api' - } - } - ] + 'https://play.google.com/store/books/details?id=m61TEAAAQBAJ&source=gbs_api', + }, + }, + ], }; // this is a const list of 5 google books by Category @@ -447,11 +447,11 @@ const categoryBooksMock = { 'categories': ['Fiction'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=OajEDNw4lMUC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=OajEDNw4lMUC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=OajEDNw4lMUC&source=gbs_api' - } + 'https://play.google.com/store/books/details?id=OajEDNw4lMUC&source=gbs_api', + }, }, //2 @@ -467,11 +467,11 @@ const categoryBooksMock = { 'categories': ['Fiction'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=AUbf_9h5D6oC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=AUbf_9h5D6oC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'https://play.google.com/store/books/details?id=AUbf_9h5D6oC&source=gbs_api' - } + 'https://play.google.com/store/books/details?id=AUbf_9h5D6oC&source=gbs_api', + }, }, //3 @@ -487,11 +487,11 @@ const categoryBooksMock = { 'categories': ['Fiction'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=D0gVVh_FLJ8C&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=D0gVVh_FLJ8C&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'http://books.google.com.br/books?id=D0gVVh_FLJ8C&dq=subject:Fiction&hl=&as_ebook=1&as_pt=BOOKS&source=gbs_api' - } + 'http://books.google.com.br/books?id=D0gVVh_FLJ8C&dq=subject:Fiction&hl=&as_ebook=1&as_pt=BOOKS&source=gbs_api', + }, }, //4 @@ -507,11 +507,11 @@ const categoryBooksMock = { 'categories': ['Fiction'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=nAQkDwAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=nAQkDwAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'http://books.google.com.br/books?id=nAQkDwAAQBAJ&dq=subject:Fiction&hl=&as_ebook=1&as_pt=BOOKS&source=gbs_api' - } + 'http://books.google.com.br/books?id=nAQkDwAAQBAJ&dq=subject:Fiction&hl=&as_ebook=1&as_pt=BOOKS&source=gbs_api', + }, }, //5 @@ -527,13 +527,13 @@ const categoryBooksMock = { 'categories': ['Fiction'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=1Uuexwzku9gC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=1Uuexwzku9gC&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': - 'http://books.google.com.br/books?id=1Uuexwzku9gC&dq=subject:Fiction&hl=&as_ebook=1&as_pt=BOOKS&source=gbs_api' - } - } - ] + 'http://books.google.com.br/books?id=1Uuexwzku9gC&dq=subject:Fiction&hl=&as_ebook=1&as_pt=BOOKS&source=gbs_api', + }, + }, + ], }; // this is a const list of Google book by ISBN @@ -551,11 +551,11 @@ const isbnJsonBookMock = { 'categories': ['Computers'], 'imageLinks': { 'thumbnail': - 'http://books.google.com/books/content?id=BOaPDwAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api' + 'http://books.google.com/books/content?id=BOaPDwAAQBAJ&printsec=frontcover&img=1&zoom=1&edge=curl&source=gbs_api', }, 'infoLink': 'http://books.google.com.br/books?id=BOaPDwAAQBAJ&dq=isbn:9788550808161&hl=&source=gbs_api', - } - } - ] + }, + }, + ], }; diff --git a/test/src/shared/blocs/book_bloc/book_bloc_test.dart b/test/src/shared/blocs/book_bloc/book_bloc_test.dart index cf22d8eb..696450eb 100644 --- a/test/src/shared/blocs/book_bloc/book_bloc_test.dart +++ b/test/src/shared/blocs/book_bloc/book_bloc_test.dart @@ -1,7 +1,8 @@ import 'package:bloc_test/bloc_test.dart'; +import 'package:bookify/src/shared/enums/rest_client_error_code.dart'; import 'package:bookify/src/core/repositories/remote_books_repository/remote_books_repository.dart'; import 'package:bookify/src/shared/blocs/book_bloc/book_bloc.dart'; -import 'package:bookify/src/core/errors/book_exception/book_exception.dart'; +import 'package:bookify/src/core/errors/rest_client_exception/rest_client_exception.dart'; import 'package:flutter_test/flutter_test.dart'; import 'package:mocktail/mocktail.dart'; @@ -31,8 +32,9 @@ void main() { blocTest( '2- Test if the GetAllBooksEvent is not empty state', build: () => bookBloc, - setUp: () => when((() => repository.getAllBooks())) - .thenAnswer((_) async => booksMock), + setUp: () => when( + (() => repository.getAllBooks()), + ).thenAnswer((_) async => booksMock), act: (bloc) => bloc.add(GotAllBooksEvent()), verify: (_) { verify(() => repository.getAllBooks()).called(1); @@ -60,8 +62,9 @@ void main() { blocTest( '4- Test if the GetAllBooksEvent is a error state', - setUp: () => when((() => repository.getAllBooks())) - .thenThrow(const BookException('this is a error')), + setUp: () => when( + (() => repository.getAllBooks()), + ).thenThrow(const RestClientException(RestClientErrorCode.unknown)), build: () => bookBloc, act: (bloc) => bloc.add(GotAllBooksEvent()), verify: (_) { @@ -69,20 +72,25 @@ void main() { }, expect: () => [ isA(), - isA(), + isA().having( + (state) => state.errorCode, + 'errorCode', + RestClientErrorCode.unknown, + ), ], ); blocTest( '5- Test if the FindBookByIsbnEvent is not empty state', - setUp: () => - when((() => repository.findBooksByIsbn(isbn: '9788573076103'))) - .thenAnswer((_) async => booksMock), + setUp: () => when( + (() => repository.findBooksByIsbn(isbn: '9788573076103')), + ).thenAnswer((_) async => booksMock), build: () => bookBloc, act: (bloc) => bloc.add(FoundBooksByIsbnEvent(isbn: '978-85-7307-610-3')), verify: (_) { - verify(() => repository.findBooksByIsbn(isbn: '9788573076103')) - .called(1); + verify( + () => repository.findBooksByIsbn(isbn: '9788573076103'), + ).called(1); }, expect: () => [ isA(), @@ -92,14 +100,15 @@ void main() { blocTest( '6- Test if the FindBookByIsbnEvent is empty state', - setUp: () => - when((() => repository.findBooksByIsbn(isbn: '9788573076103'))) - .thenAnswer((_) async => []), + setUp: () => when( + (() => repository.findBooksByIsbn(isbn: '9788573076103')), + ).thenAnswer((_) async => []), build: () => bookBloc, act: (bloc) => bloc.add(FoundBooksByIsbnEvent(isbn: '978-8573076103')), verify: (_) { - verify(() => repository.findBooksByIsbn(isbn: '9788573076103')) - .called(1); + verify( + () => repository.findBooksByIsbn(isbn: '9788573076103'), + ).called(1); }, expect: () => [ isA(), @@ -109,20 +118,29 @@ void main() { blocTest( '7- Test if the FindBookByIsbnEvent is a error state', - setUp: () => when((() => repository.findBooksByIsbn(isbn: '11111'))) - .thenThrow(const BookException('this is a error')), + setUp: () => when( + (() => repository.findBooksByIsbn(isbn: '11111')), + ).thenThrow(const RestClientException(RestClientErrorCode.invalidInput)), build: () => bookBloc, act: (bloc) => bloc.add(FoundBooksByIsbnEvent(isbn: '11111')), + verify: (_) { + verifyNever(() => repository.findBooksByIsbn(isbn: any(named: 'isbn'))); + }, expect: () => [ isA(), - isA(), + isA().having( + (state) => state.errorCode, + 'errorCode', + RestClientErrorCode.invalidInput, + ), ], ); blocTest( '8- Test if the FindBooksByAuthorEvent is not empty state', - setUp: () => when((() => repository.findBooksByAuthor(author: 'author'))) - .thenAnswer((_) async => booksMock), + setUp: () => when( + (() => repository.findBooksByAuthor(author: 'author')), + ).thenAnswer((_) async => booksMock), build: () => bookBloc, act: (bloc) => bloc.add(FoundBooksByAuthorEvent(author: 'author')), verify: (_) { @@ -136,8 +154,9 @@ void main() { blocTest( '9- Test if the FindBooksByAuthorEvent is empty state', - setUp: () => when((() => repository.findBooksByAuthor(author: 'author'))) - .thenAnswer((_) async => []), + setUp: () => when( + (() => repository.findBooksByAuthor(author: 'author')), + ).thenAnswer((_) async => []), build: () => bookBloc, act: (bloc) => bloc.add(FoundBooksByAuthorEvent(author: 'author')), verify: (_) { @@ -151,8 +170,9 @@ void main() { blocTest( '10- Test if the FindBooksByAuthorEvent is a error state', - setUp: () => when((() => repository.findBooksByAuthor(author: 'author'))) - .thenThrow(const BookException('this is a error')), + setUp: () => when( + (() => repository.findBooksByAuthor(author: 'author')), + ).thenThrow(const RestClientException(RestClientErrorCode.notFound)), build: () => bookBloc, act: (bloc) => bloc.add(FoundBooksByAuthorEvent(author: 'author')), verify: (_) { @@ -160,20 +180,25 @@ void main() { }, expect: () => [ isA(), - isA(), + isA().having( + (state) => state.errorCode, + 'errorCode', + RestClientErrorCode.notFound, + ), ], ); blocTest( '11- Test if the FindBooksByCategoryEvent is not empty state', - setUp: () => - when((() => repository.findBooksByCategory(category: 'category'))) - .thenAnswer((_) async => booksMock), + setUp: () => when( + (() => repository.findBooksByCategory(category: 'category')), + ).thenAnswer((_) async => booksMock), build: () => bookBloc, act: (bloc) => bloc.add(FoundBooksByCategoryEvent(category: 'category')), verify: (_) { - verify(() => repository.findBooksByCategory(category: 'category')) - .called(1); + verify( + () => repository.findBooksByCategory(category: 'category'), + ).called(1); }, expect: () => [ isA(), @@ -183,14 +208,15 @@ void main() { blocTest( '12- Test if the FindBooksByCategoryEvent is empty state', - setUp: () => - when((() => repository.findBooksByCategory(category: 'category'))) - .thenAnswer((_) async => []), + setUp: () => when( + (() => repository.findBooksByCategory(category: 'category')), + ).thenAnswer((_) async => []), build: () => bookBloc, act: (bloc) => bloc.add(FoundBooksByCategoryEvent(category: 'category')), verify: (_) { - verify(() => repository.findBooksByCategory(category: 'category')) - .called(1); + verify( + () => repository.findBooksByCategory(category: 'category'), + ).called(1); }, expect: () => [ isA(), @@ -200,32 +226,38 @@ void main() { blocTest( '13- Test if the FindBooksByCategoryEvent is a error state', - setUp: () => - when((() => repository.findBooksByCategory(category: 'category'))) - .thenThrow(const BookException('this is a error')), + setUp: () => when( + (() => repository.findBooksByCategory(category: 'category')), + ).thenThrow(const RestClientException(RestClientErrorCode.notFound)), build: () => bookBloc, act: (bloc) => bloc.add(FoundBooksByCategoryEvent(category: 'category')), verify: (_) { - verify(() => repository.findBooksByCategory(category: 'category')) - .called(1); + verify( + () => repository.findBooksByCategory(category: 'category'), + ).called(1); }, expect: () => [ isA(), - isA(), + isA().having( + (state) => state.errorCode, + 'errorCode', + RestClientErrorCode.notFound, + ), ], ); blocTest( '14- Test if the FindBooksByPublisherEvent is not empty state', - setUp: () => - when((() => repository.findBooksByPublisher(publisher: 'publisher'))) - .thenAnswer((_) async => booksMock), + setUp: () => when( + (() => repository.findBooksByPublisher(publisher: 'publisher')), + ).thenAnswer((_) async => booksMock), build: () => bookBloc, act: (bloc) => bloc.add(FoundBooksByPublisherEvent(publisher: 'publisher')), verify: (_) { - verify(() => repository.findBooksByPublisher(publisher: 'publisher')) - .called(1); + verify( + () => repository.findBooksByPublisher(publisher: 'publisher'), + ).called(1); }, expect: () => [ isA(), @@ -235,15 +267,16 @@ void main() { blocTest( '15- Test if the FindBooksByPublisherEvent is empty state', - setUp: () => - when((() => repository.findBooksByPublisher(publisher: 'publisher'))) - .thenAnswer((_) async => []), + setUp: () => when( + (() => repository.findBooksByPublisher(publisher: 'publisher')), + ).thenAnswer((_) async => []), build: () => bookBloc, act: (bloc) => bloc.add(FoundBooksByPublisherEvent(publisher: 'publisher')), verify: (_) { - verify(() => repository.findBooksByPublisher(publisher: 'publisher')) - .called(1); + verify( + () => repository.findBooksByPublisher(publisher: 'publisher'), + ).called(1); }, expect: () => [ isA(), @@ -253,26 +286,32 @@ void main() { blocTest( '16- Test if the FindBooksByPublisherEvent is a error state', - setUp: () => - when((() => repository.findBooksByPublisher(publisher: 'publisher'))) - .thenThrow(const BookException('this is a error')), + setUp: () => when( + (() => repository.findBooksByPublisher(publisher: 'publisher')), + ).thenThrow(const RestClientException(RestClientErrorCode.notFound)), build: () => bookBloc, act: (bloc) => bloc.add(FoundBooksByPublisherEvent(publisher: 'publisher')), verify: (_) { - verify(() => repository.findBooksByPublisher(publisher: 'publisher')) - .called(1); + verify( + () => repository.findBooksByPublisher(publisher: 'publisher'), + ).called(1); }, expect: () => [ isA(), - isA(), + isA().having( + (state) => state.errorCode, + 'errorCode', + RestClientErrorCode.notFound, + ), ], ); blocTest( '17- Test if the FindBooksByTitleEvent is not empty state', - setUp: () => when((() => repository.findBooksByTitle(title: 'title'))) - .thenAnswer((_) async => booksMock), + setUp: () => when( + (() => repository.findBooksByTitle(title: 'title')), + ).thenAnswer((_) async => booksMock), build: () => bookBloc, act: (bloc) => bloc.add(FoundBooksByTitleEvent(title: 'title')), verify: (_) { @@ -286,8 +325,9 @@ void main() { blocTest( '18- Test if the FindBooksByTitleEvent is empty state', - setUp: () => when((() => repository.findBooksByTitle(title: 'title'))) - .thenAnswer((_) async => []), + setUp: () => when( + (() => repository.findBooksByTitle(title: 'title')), + ).thenAnswer((_) async => []), build: () => bookBloc, act: (bloc) => bloc.add(FoundBooksByTitleEvent(title: 'title')), verify: (_) { @@ -301,8 +341,9 @@ void main() { blocTest( '19- Test if the FindBooksByTitleEvent is a error state', - setUp: () => when((() => repository.findBooksByTitle(title: 'title'))) - .thenThrow(const BookException('this is a error')), + setUp: () => when( + (() => repository.findBooksByTitle(title: 'title')), + ).thenThrow(const RestClientException(RestClientErrorCode.notFound)), build: () => bookBloc, act: (bloc) => bloc.add(FoundBooksByTitleEvent(title: 'title')), verify: (_) { @@ -310,7 +351,11 @@ void main() { }, expect: () => [ isA(), - isA(), + isA().having( + (state) => state.errorCode, + 'errorCode', + RestClientErrorCode.notFound, + ), ], ); }); diff --git a/test/src/shared/cubits/user_logged_cubit/user_logged_cubit_test.dart b/test/src/shared/cubits/user_logged_cubit/user_logged_cubit_test.dart new file mode 100644 index 00000000..085fbdc1 --- /dev/null +++ b/test/src/shared/cubits/user_logged_cubit/user_logged_cubit_test.dart @@ -0,0 +1,105 @@ +import 'package:bloc_test/bloc_test.dart'; +import 'package:bookify/src/shared/enums/auth_error_code.dart'; +import 'package:bookify/src/core/errors/auth_exception/auth_exception.dart'; +import 'package:bookify/src/core/services/auth_service/auth_service.dart'; +import 'package:bookify/src/shared/cubits/user_logged_cubit/user_logged_cubit.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; + +class AuthServiceMock extends Mock implements AuthService {} + +void main() { + final authService = AuthServiceMock(); + late UserLoggedCubit userLoggedCubit; + + setUp(() { + userLoggedCubit = UserLoggedCubit( + authService, + ); + }); + + group('Test UserLogged Cubit', () { + blocTest( + 'Initial state is empty', + build: () => userLoggedCubit, + verify: (cubit) async => await cubit.close(), + expect: () => [], + ); + + blocTest( + 'Test checkAuthStatus function work when user is logged in', + build: () => userLoggedCubit, + setUp: () => + when( + () => authService.userIsLoggedIn(), + ).thenAnswer( + (_) async => true, + ), + act: (cubit) => cubit.checkAuthStatus(), + verify: (_) => verify( + () => authService.userIsLoggedIn(), + ).called(1), + expect: () => [ + isA(), + isA(), + ], + ); + + blocTest( + 'Test checkAuthStatus function work when user is NOT logged in', + build: () => userLoggedCubit, + setUp: () => + when( + () => authService.userIsLoggedIn(), + ).thenAnswer( + (_) async => false, + ), + act: (cubit) => cubit.checkAuthStatus(), + verify: (_) => verify( + () => authService.userIsLoggedIn(), + ).called(1), + expect: () => [ + isA(), + isA(), + ], + ); + + blocTest( + 'Test checkAuthStatus function work when throw AuthException', + build: () => userLoggedCubit, + setUp: () => + when( + () => authService.userIsLoggedIn(), + ).thenThrow( + const AuthException( + AuthErrorCode.internalError, + descriptionMessage: 'Error on Auth Service', + ), + ), + act: (cubit) => cubit.checkAuthStatus(), + verify: (_) => verify( + () => authService.userIsLoggedIn(), + ).called(1), + expect: () => [ + isA(), + isA(), + ], + ); + + blocTest( + 'Test checkAuthStatus function work when throw Generic Exception', + build: () => userLoggedCubit, + setUp: () => when( + () => authService.userIsLoggedIn(), + ).thenThrow(Exception('Generic Error')), + act: (cubit) => cubit.checkAuthStatus(), + verify: (_) => verify( + () => authService.userIsLoggedIn(), + ).called(1), + expect: () => [ + isA(), + isA(), + ], + ); + }); +} diff --git a/test/src/shared/cubits/user_notification_cubit/user_notification_cubit_test.dart b/test/src/shared/cubits/user_notification_cubit/user_notification_cubit_test.dart new file mode 100644 index 00000000..6395e6ad --- /dev/null +++ b/test/src/shared/cubits/user_notification_cubit/user_notification_cubit_test.dart @@ -0,0 +1,62 @@ +import 'package:bloc_test/bloc_test.dart'; +import 'package:bookify/src/core/services/app_services/notifications_service/notifications_service.dart'; +import 'package:bookify/src/shared/cubits/user_notification_cubit/user_notification_cubit.dart'; +import 'package:flutter_test/flutter_test.dart'; +import 'package:mocktail/mocktail.dart'; + +class NotificationsServiceMock extends Mock implements NotificationsService {} + +void main() { + final notificationsService = NotificationsServiceMock(); + late UserNotificationCubit userNotificationCubit; + + setUp(() { + userNotificationCubit = UserNotificationCubit( + notificationsService, + ); + }); + + group('Test UserNotification Cubit', () { + blocTest( + 'Initial state is empty', + build: () => userNotificationCubit, + verify: (cubit) async => await cubit.close(), + expect: () => [], + ); + + blocTest( + 'Test initializeNotifications function work', + build: () => userNotificationCubit, + setUp: () => + when( + () => notificationsService.checkForNotifications(), + ).thenAnswer( + (_) async {}, // Simula il completamento di Future + ), + act: (cubit) => cubit.initializeNotifications(), + verify: (_) => verify( + () => notificationsService.checkForNotifications(), + ).called(1), + expect: () => [ + isA(), + isA(), + ], + ); + + blocTest( + 'Test initializeNotifications function work when throw Generic Exception', + build: () => userNotificationCubit, + setUp: () => when( + () => notificationsService.checkForNotifications(), + ).thenThrow(Exception('Generic Error')), + act: (cubit) => cubit.initializeNotifications(), + verify: (_) => verify( + () => notificationsService.checkForNotifications(), + ).called(1), + expect: () => [ + isA(), + isA(), + ], + ); + }); +} diff --git a/test/src/shared/blocs/user_theme_cubit/user_theme_cubit_test.dart b/test/src/shared/cubits/user_theme_cubit/user_theme_cubit_test.dart similarity index 85% rename from test/src/shared/blocs/user_theme_cubit/user_theme_cubit_test.dart rename to test/src/shared/cubits/user_theme_cubit/user_theme_cubit_test.dart index 3b000ee4..f5c267ac 100644 --- a/test/src/shared/blocs/user_theme_cubit/user_theme_cubit_test.dart +++ b/test/src/shared/cubits/user_theme_cubit/user_theme_cubit_test.dart @@ -1,4 +1,5 @@ import 'package:bloc_test/bloc_test.dart'; +import 'package:bookify/src/shared/enums/storage_error_code.dart'; import 'package:bookify/src/core/errors/storage_exception/storage_exception.dart'; import 'package:bookify/src/core/repositories/user_theme_repository/user_theme_repository.dart'; import 'package:bookify/src/shared/cubits/user_theme_cubit/user_theme_cubit.dart'; @@ -29,11 +30,12 @@ void main() { blocTest( 'Test getTheme function work', build: () => userThemeCubit, - setUp: () => when( - () => userRepository.getThemeMode(), - ).thenAnswer( - (_) async => ThemeMode.light, - ), + setUp: () => + when( + () => userRepository.getThemeMode(), + ).thenAnswer( + (_) async => ThemeMode.light, + ), act: (cubit) => cubit.getTheme(), verify: (_) => verify( () => userRepository.getThemeMode(), @@ -74,9 +76,15 @@ void main() { blocTest( 'Test getTheme function work when throw StorageException', build: () => userThemeCubit, - setUp: () => when( - () => userRepository.getThemeMode(), - ).thenThrow(const StorageException('Error on storage Data')), + setUp: () => + when( + () => userRepository.getThemeMode(), + ).thenThrow( + const StorageException( + StorageErrorCode.invalidValue, + descriptionMessage: 'Error on storage Data', + ), + ), act: (cubit) => cubit.getTheme(), verify: (_) => verify( () => userRepository.getThemeMode(), @@ -142,9 +150,15 @@ void main() { blocTest( 'Test setTheme function work when throw StorageException', build: () => userThemeCubit, - setUp: () => when( - () => userRepository.setThemeMode(themeMode: ThemeMode.system), - ).thenThrow(const StorageException('Error on storage Data')), + setUp: () => + when( + () => userRepository.setThemeMode(themeMode: ThemeMode.system), + ).thenThrow( + const StorageException( + StorageErrorCode.invalidValue, + descriptionMessage: 'Error on storage Data', + ), + ), act: (cubit) => cubit.setTheme( themeMode: ThemeMode.system, ),