Skip to content

Commit 3d81f4f

Browse files
committed
Refactor book status handling and improve notification service
- Introduced BookStatusExtension to encapsulate color and label logic for book statuses. - Updated BookDetailBloc to use the new label method for error messages. - Refactored BookStateWidget to utilize the new extension for color and label. - Enhanced NotificationsServiceImpl to use named parameters for better readability. - Modified PlayAlarmSoundService to make dispose method asynchronous. - Cleaned up SnackbarService by removing unnecessary toString method. - Updated BookcaseInsertionPage to support both create and edit modes with factory constructors. - Improved route handling for BookcaseInsertionPage to differentiate between create and edit. - Fixed various error handling and widget building issues across multiple files. - Updated pubspec.yaml and pubspec.lock for dependency upgrades and version changes.
1 parent 4b7b044 commit 3d81f4f

File tree

16 files changed

+366
-299
lines changed

16 files changed

+366
-299
lines changed

coverage/lcov.info

Lines changed: 196 additions & 189 deletions
Large diffs are not rendered by default.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import 'package:bookify/src/core/models/book_model.dart';
2+
import 'package:bookify/src/shared/theme/colors.dart';
3+
import 'package:flutter/material.dart';
4+
import 'package:localization/localization.dart';
5+
6+
extension BookStatusExtension on BookStatus {
7+
Color get color {
8+
return switch (this) {
9+
BookStatus.library => AppColor.bookifyBookLibraryColor,
10+
BookStatus.reading => AppColor.bookifyBookReadingColor,
11+
BookStatus.loaned => AppColor.bookifyBookLoanedColor,
12+
};
13+
}
14+
15+
String get label {
16+
return switch (this) {
17+
BookStatus.library => 'book-on-the-bookcase-label'.i18n(),
18+
BookStatus.reading => 'book-on-reading-label'.i18n(),
19+
BookStatus.loaned => 'book-on-loan-label'.i18n(),
20+
};
21+
}
22+
}

lib/src/core/services/app_services/notifications_service/notifications_service_impl.dart

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ class NotificationsServiceImpl implements NotificationsService {
6262
);
6363

6464
await _notifications.initialize(
65-
initializationSettings,
65+
settings: initializationSettings,
6666
onDidReceiveNotificationResponse: _onTapOnNotification,
6767
);
6868
tz.initializeTimeZones();
@@ -113,14 +113,14 @@ class NotificationsServiceImpl implements NotificationsService {
113113
CustomNotificationModel notification,
114114
) async {
115115
await _notifications.zonedSchedule(
116-
notification.id,
117-
notification.title,
118-
notification.body,
119-
tz.TZDateTime.from(
116+
id: notification.id,
117+
title: notification.title,
118+
body: notification.body,
119+
scheduledDate: tz.TZDateTime.from(
120120
notification.scheduledDate,
121121
tz.local,
122122
),
123-
_getNotificationDetails(
123+
notificationDetails: _getNotificationDetails(
124124
notification.notificationChannel,
125125
notification.body,
126126
),
@@ -144,14 +144,14 @@ class NotificationsServiceImpl implements NotificationsService {
144144
};
145145

146146
await _notifications.zonedSchedule(
147-
id,
148-
title,
149-
body,
150-
tz.TZDateTime.from(
147+
id: id,
148+
title: title,
149+
body: body,
150+
scheduledDate: tz.TZDateTime.from(
151151
scheduledDate,
152152
tz.local,
153153
),
154-
_getNotificationDetails(
154+
notificationDetails: _getNotificationDetails(
155155
notificationChannel,
156156
body,
157157
),
@@ -162,7 +162,7 @@ class NotificationsServiceImpl implements NotificationsService {
162162

163163
@override
164164
Future<void> cancelNotificationById({required int id}) async {
165-
await _notifications.cancel(id);
165+
await _notifications.cancel(id: id);
166166
}
167167

168168
@override

lib/src/core/services/app_services/play_alarm_sound_service/play_alarm_sound_service.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,8 @@ class PlayAlarmSoundService {
4141
await player.stop();
4242
}
4343

44-
void dispose() {
45-
player.dispose();
44+
Future<void> dispose() async {
45+
await player.dispose();
4646
}
4747

4848
Future<void> _playSound(double volume) async {

lib/src/core/services/app_services/snackbar_service/snackbar_service.dart

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,16 +24,6 @@ enum SnackBarType {
2424
SnackBarType.success => AppColor.bookifySuccessColor,
2525
};
2626
}
27-
28-
@override
29-
String toString() {
30-
return switch (this) {
31-
SnackBarType.info => 'Informação',
32-
SnackBarType.warning => 'Atenção',
33-
SnackBarType.error => 'Erro',
34-
SnackBarType.success => 'Sucesso',
35-
};
36-
}
3727
}
3828

3929
class SnackbarService {

lib/src/features/book_detail/bloc/book_detail_bloc.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import 'package:bookify/src/core/errors/local_database_exception/local_database_exception.dart';
2+
import 'package:bookify/src/core/helpers/book_status/book_status_extension.dart';
23
import 'package:bookify/src/core/models/book_model.dart';
34
import 'package:flutter_bloc/flutter_bloc.dart';
45

@@ -81,7 +82,7 @@ class BookDetailBloc extends Bloc<BookDetailEvent, BookDetailState> {
8182
emit(
8283
BookDetailErrorState(
8384
errorMessage:
84-
'Impossível remover o livro porque está ${bookStatus.toString()}.',
85+
'Impossível remover o livro porque está ${bookStatus.label}.',
8586
),
8687
);
8788
return;

lib/src/features/book_on_bookcase_detail/views/widgets/book_state_widget.dart

Lines changed: 3 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
1+
import 'package:bookify/src/core/helpers/book_status/book_status_extension.dart';
12
import 'package:bookify/src/core/models/book_model.dart';
2-
import 'package:bookify/src/shared/theme/colors.dart';
33
import 'package:flutter/material.dart';
4-
import 'package:localization/localization.dart';
54

65
class BookStateWidget extends StatelessWidget {
76
final BookStatus bookStatus;
@@ -11,32 +10,16 @@ class BookStateWidget extends StatelessWidget {
1110
required this.bookStatus,
1211
});
1312

14-
Color _getColor() {
15-
return switch (bookStatus) {
16-
BookStatus.library => AppColor.bookifyBookLibraryColor,
17-
BookStatus.reading => AppColor.bookifyBookReadingColor,
18-
BookStatus.loaned => AppColor.bookifyBookLoanedColor,
19-
};
20-
}
21-
22-
String _getBookStatusToString() {
23-
return switch (bookStatus) {
24-
BookStatus.library => 'book-on-the-bookcase-label'.i18n(),
25-
BookStatus.reading => 'book-on-reading-label'.i18n(),
26-
BookStatus.loaned => 'book-on-loan-label'.i18n(),
27-
};
28-
}
29-
3013
@override
3114
Widget build(BuildContext context) {
3215
return Container(
3316
padding: const EdgeInsets.all(8.0),
3417
decoration: BoxDecoration(
35-
color: _getColor(),
18+
color: bookStatus.color,
3619
borderRadius: BorderRadius.circular(22),
3720
),
3821
child: Text(
39-
_getBookStatusToString(),
22+
bookStatus.label,
4023
textAlign: TextAlign.center,
4124
overflow: TextOverflow.ellipsis,
4225
textScaler: TextScaler.noScaling,

lib/src/features/bookcase_detail/views/bookcase_detail_page.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -152,13 +152,13 @@ class _BookcaseDetailPageState extends State<BookcaseDetailPage> {
152152

153153
Future<void> _popupMenuOnSelected(String value, BuildContext context) async {
154154
if (value == _popupMenuItemsSet.first) {
155-
var bookcaseList = await Navigator.pushNamed(
155+
final result = await Navigator.pushNamed(
156156
context,
157157
BookcaseInsertionPage.routeName,
158158
arguments: _actualBookcase,
159159
) as List<Object?>?;
160160

161-
final bookcaseUpdated = bookcaseList?[1] as BookcaseModel?;
161+
final bookcaseUpdated = result?[1] as BookcaseModel?;
162162

163163
if (bookcaseUpdated != null) {
164164
setState(() {

lib/src/features/bookcase_insertion/views/bookcase_insertion_page.dart

Lines changed: 62 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,58 @@ import 'package:flutter_bloc/flutter_bloc.dart';
99
import 'package:localization/localization.dart';
1010
import 'package:validatorless/validatorless.dart';
1111

12+
/// Page for creating or updating a [BookcaseModel].
13+
///
14+
/// This page provides a form to input bookcase details such as name, description,
15+
/// and color. It supports two modes:
16+
/// - **Create mode**: For adding a new bookcase (see [newBookcase])
17+
/// - **Edit mode**: For modifying an existing bookcase (see [updateBookcase])
18+
///
19+
/// The page returns a list containing:
20+
/// - `result[0]`: A boolean indicating success
21+
/// - `result[1]`: The updated or newly created [BookcaseModel]
1222
class BookcaseInsertionPage extends StatefulWidget {
1323
/// The Route Name = '/bookcase_insertion'
1424
static const routeName = '/bookcase_insertion';
1525

26+
/// The bookcase model to edit, or `null` if creating a new bookcase.
1627
final BookcaseModel? bookcaseModel;
1728

18-
const BookcaseInsertionPage({
29+
/// Private constructor for internal use only.
30+
///
31+
/// Use [newBookcase] or [updateBookcase] factory constructors instead.
32+
const BookcaseInsertionPage._({
1933
super.key,
20-
this.bookcaseModel,
34+
required this.bookcaseModel,
2135
});
2236

37+
/// Creates a new bookcase insertion page in create mode.
38+
///
39+
/// Returns a page where the user can create a new bookcase with an empty form.
40+
factory BookcaseInsertionPage.newBookcase({Key? key}) {
41+
return BookcaseInsertionPage._(
42+
key: key,
43+
bookcaseModel: null,
44+
);
45+
}
46+
47+
/// Creates a new bookcase insertion page in edit mode.
48+
///
49+
/// The form will be pre-populated with the [bookcaseModel] data.
50+
///
51+
/// Parameters:
52+
/// - [bookcaseModel]: The bookcase to edit (required)
53+
/// - [key]: Optional widget key
54+
factory BookcaseInsertionPage.updateBookcase({
55+
required BookcaseModel bookcaseModel,
56+
Key? key,
57+
}) {
58+
return BookcaseInsertionPage._(
59+
key: key,
60+
bookcaseModel: bookcaseModel,
61+
);
62+
}
63+
2364
@override
2465
State<BookcaseInsertionPage> createState() => _BookcaseInsertionPageState();
2566
}
@@ -54,6 +95,9 @@ class _BookcaseInsertionPageState extends State<BookcaseInsertionPage> {
5495
super.dispose();
5596
}
5697

98+
/// Clears all text fields and resets the color to white.
99+
///
100+
/// This resets the form to its initial state, useful for the user to start over.
57101
void _clearAllTextField() {
58102
_formKey.currentState!.reset();
59103
_bookcaseNameEC.clear();
@@ -64,11 +108,23 @@ class _BookcaseInsertionPageState extends State<BookcaseInsertionPage> {
64108
});
65109
}
66110

111+
/// Validates the form and processes the bookcase insertion or update.
112+
///
113+
/// In **create mode**: Emits an [InsertedBookcaseEvent] to add a new bookcase.
114+
/// In **edit mode**: Emits an [UpdatedBookcaseEvent] to modify the existing bookcase.
115+
///
116+
/// The [bookcaseUpdated] will be populated with the updated bookcase data in edit mode,
117+
/// which is then passed back through the navigation result.
118+
///
119+
/// Sets [_canPopPage] to `false` to indicate the form is being processed
120+
67121
/// Checks whether all fields are valid,
68122
/// then enters the new or update bookcase.
69-
void _onPressedButton(BookcaseModel? bookcaseModel) {
123+
void _onPressedButton() {
70124
if (_formKey.currentState!.validate()) {
71-
if (bookcaseModel == null) {
125+
final isEditMode = widget.bookcaseModel != null;
126+
127+
if (!isEditMode) {
72128
_bloc.add(
73129
InsertedBookcaseEvent(
74130
name: _bookcaseNameEC.value.text,
@@ -79,6 +135,7 @@ class _BookcaseInsertionPageState extends State<BookcaseInsertionPage> {
79135
),
80136
);
81137
} else {
138+
final bookcaseModel = widget.bookcaseModel!;
82139
_bloc.add(
83140
UpdatedBookcaseEvent(
84141
id: bookcaseModel.id!,
@@ -274,7 +331,7 @@ class _BookcaseInsertionPageState extends State<BookcaseInsertionPage> {
274331
BookifyOutlinedButton.expanded(
275332
key: const Key('ConfirmBookcaseInsertionButton'),
276333
text: 'confirm-button-normal'.i18n(),
277-
onPressed: () => _onPressedButton(bookcaseModel),
334+
onPressed: _onPressedButton,
278335
),
279336
],
280337
),

lib/src/features/profile/views/widgets/user_circle_avatar.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class UserCircleAvatar extends StatelessWidget {
3535
);
3636
},
3737
placeholder: (context, _) => const CenterCircularProgressIndicator(),
38-
errorWidget: (_, __, ___) => Icon(
38+
errorWidget: (_, _, _) => Icon(
3939
Icons.error_rounded,
4040
color: Theme.of(context).colorScheme.error,
4141
),

0 commit comments

Comments
 (0)