From 74bdfe397163529bfb65493a9ee3947b6d12a73c Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 17:12:59 +0100 Subject: [PATCH 01/28] refactor: Implement Timestamp Logic for Creation --- .../bloc/create_category/create_category_bloc.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/content_management/bloc/create_category/create_category_bloc.dart b/lib/content_management/bloc/create_category/create_category_bloc.dart index 845c2580..935acd29 100644 --- a/lib/content_management/bloc/create_category/create_category_bloc.dart +++ b/lib/content_management/bloc/create_category/create_category_bloc.dart @@ -79,11 +79,14 @@ class CreateCategoryBloc emit(state.copyWith(status: CreateCategoryStatus.submitting)); try { + final now = DateTime.now(); final newCategory = Category( name: state.name, description: state.description.isNotEmpty ? state.description : null, iconUrl: state.iconUrl.isNotEmpty ? state.iconUrl : null, status: state.contentStatus, + createdAt: now, + updatedAt: now, ); await _categoriesRepository.create(item: newCategory); From a83e29bc1f7af5696d8f9a88b508c22b924aca29 Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 17:13:27 +0100 Subject: [PATCH 02/28] refactor: Implement Timestamp Logic for Updates --- .../bloc/edit_category/edit_category_bloc.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/content_management/bloc/edit_category/edit_category_bloc.dart b/lib/content_management/bloc/edit_category/edit_category_bloc.dart index 3f67aa0b..41e535d1 100644 --- a/lib/content_management/bloc/edit_category/edit_category_bloc.dart +++ b/lib/content_management/bloc/edit_category/edit_category_bloc.dart @@ -135,6 +135,7 @@ class EditCategoryBloc extends Bloc { description: state.description.isNotEmpty ? state.description : null, iconUrl: state.iconUrl.isNotEmpty ? state.iconUrl : null, status: state.contentStatus, + updatedAt: DateTime.now(), ); await _categoriesRepository.update( From 6e7a503e1333fe4223d7d33f2b1485e504d79d52 Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 17:42:06 +0100 Subject: [PATCH 03/28] feat: added a new createdCategory property to the state. This will allow the CreateCategoryBloc to hold the newly created category object upon successful submission, which is the first step toward updating the main list locally instead of doing a full refresh. --- .../bloc/create_category/create_category_state.dart | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/content_management/bloc/create_category/create_category_state.dart b/lib/content_management/bloc/create_category/create_category_state.dart index 47884d57..ec6a272e 100644 --- a/lib/content_management/bloc/create_category/create_category_state.dart +++ b/lib/content_management/bloc/create_category/create_category_state.dart @@ -25,6 +25,7 @@ final class CreateCategoryState extends Equatable { this.iconUrl = '', this.contentStatus = ContentStatus.active, this.errorMessage, + this.createdCategory, }); final CreateCategoryStatus status; @@ -33,6 +34,7 @@ final class CreateCategoryState extends Equatable { final String iconUrl; final ContentStatus contentStatus; final String? errorMessage; + final Category? createdCategory; /// Returns true if the form is valid and can be submitted. /// Based on the Category model, only the name is required. @@ -45,6 +47,7 @@ final class CreateCategoryState extends Equatable { String? iconUrl, ContentStatus? contentStatus, String? errorMessage, + Category? createdCategory, }) { return CreateCategoryState( status: status ?? this.status, @@ -53,6 +56,7 @@ final class CreateCategoryState extends Equatable { iconUrl: iconUrl ?? this.iconUrl, contentStatus: contentStatus ?? this.contentStatus, errorMessage: errorMessage, + createdCategory: createdCategory ?? this.createdCategory, ); } @@ -64,5 +68,6 @@ final class CreateCategoryState extends Equatable { iconUrl, contentStatus, errorMessage, + createdCategory, ]; } From 53ebeb8b23fed9d2a9856ff85f438fef64b00c0a Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 17:44:27 +0100 Subject: [PATCH 04/28] feat: updated the _onSubmitted method in create_category_bloc.dart. When a category is successfully created, I'll emit the new Category object along with the success status. This makes the newly created item available in the BLoC's state, which is essential for the UI to perform a local update on the main content list later. --- .../bloc/create_category/create_category_bloc.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/content_management/bloc/create_category/create_category_bloc.dart b/lib/content_management/bloc/create_category/create_category_bloc.dart index 935acd29..773d6e34 100644 --- a/lib/content_management/bloc/create_category/create_category_bloc.dart +++ b/lib/content_management/bloc/create_category/create_category_bloc.dart @@ -90,7 +90,12 @@ class CreateCategoryBloc ); await _categoriesRepository.create(item: newCategory); - emit(state.copyWith(status: CreateCategoryStatus.success)); + emit( + state.copyWith( + status: CreateCategoryStatus.success, + createdCategory: newCategory, + ), + ); } on HtHttpException catch (e) { emit( state.copyWith( From cd02fb80a7da2dffaa606f46b75238d2d4576bad Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 17:45:31 +0100 Subject: [PATCH 05/28] feat: modify edit_category_state.dart. I'm adding an updatedCategory property. This will allow the EditCategoryBloc to hold the successfully updated category object, which is necessary for the UI to later perform a local update on the main content list. --- .../edit_category/edit_category_state.dart | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/lib/content_management/bloc/edit_category/edit_category_state.dart b/lib/content_management/bloc/edit_category/edit_category_state.dart index c38f0e28..0ec53432 100644 --- a/lib/content_management/bloc/edit_category/edit_category_state.dart +++ b/lib/content_management/bloc/edit_category/edit_category_state.dart @@ -28,6 +28,7 @@ final class EditCategoryState extends Equatable { this.iconUrl = '', this.contentStatus = ContentStatus.active, this.errorMessage, + this.updatedCategory, }); final EditCategoryStatus status; @@ -37,6 +38,7 @@ final class EditCategoryState extends Equatable { final String iconUrl; final ContentStatus contentStatus; final String? errorMessage; + final Category? updatedCategory; /// Returns true if the form is valid and can be submitted. bool get isFormValid => name.isNotEmpty; @@ -49,6 +51,7 @@ final class EditCategoryState extends Equatable { String? iconUrl, ContentStatus? contentStatus, String? errorMessage, + Category? updatedCategory, }) { return EditCategoryState( status: status ?? this.status, @@ -58,17 +61,19 @@ final class EditCategoryState extends Equatable { iconUrl: iconUrl ?? this.iconUrl, contentStatus: contentStatus ?? this.contentStatus, errorMessage: errorMessage ?? this.errorMessage, + updatedCategory: updatedCategory ?? this.updatedCategory, ); } @override List get props => [ - status, - initialCategory, - name, - description, - iconUrl, - contentStatus, - errorMessage, - ]; + status, + initialCategory, + name, + description, + iconUrl, + contentStatus, + errorMessage, + updatedCategory, + ]; } From 229919aa88d4a65b6fdfcb8492f3530089f6c978 Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 17:46:37 +0100 Subject: [PATCH 06/28] feat: modified the _onSubmitted method in edit_category_bloc.dart. When a category is successfully updated, I'll emit the updatedCategory object along with the success status. This makes the updated item available in the BLoC's state, which is crucial for the UI to perform a local update on the main content list. --- .../bloc/edit_category/edit_category_bloc.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/content_management/bloc/edit_category/edit_category_bloc.dart b/lib/content_management/bloc/edit_category/edit_category_bloc.dart index 41e535d1..04d08ca6 100644 --- a/lib/content_management/bloc/edit_category/edit_category_bloc.dart +++ b/lib/content_management/bloc/edit_category/edit_category_bloc.dart @@ -142,7 +142,12 @@ class EditCategoryBloc extends Bloc { id: _categoryId, item: updatedCategory, ); - emit(state.copyWith(status: EditCategoryStatus.success)); + emit( + state.copyWith( + status: EditCategoryStatus.success, + updatedCategory: updatedCategory, + ), + ); } on HtHttpException catch (e) { emit( state.copyWith( From cd46a81b0d9ace0500412d89378619c236e45246 Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 17:52:10 +0100 Subject: [PATCH 07/28] refactor(content_management): add createdHeadline to CreateHeadlineState --- .../bloc/create_headline/create_headline_state.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/content_management/bloc/create_headline/create_headline_state.dart b/lib/content_management/bloc/create_headline/create_headline_state.dart index f809b6e3..605b078e 100644 --- a/lib/content_management/bloc/create_headline/create_headline_state.dart +++ b/lib/content_management/bloc/create_headline/create_headline_state.dart @@ -32,6 +32,7 @@ final class CreateHeadlineState extends Equatable { this.categories = const [], this.contentStatus = ContentStatus.active, this.errorMessage, + this.createdHeadline, }); final CreateHeadlineStatus status; @@ -45,6 +46,7 @@ final class CreateHeadlineState extends Equatable { final List categories; final ContentStatus contentStatus; final String? errorMessage; + final Headline? createdHeadline; /// Returns true if the form is valid and can be submitted. bool get isFormValid => title.isNotEmpty; @@ -61,6 +63,7 @@ final class CreateHeadlineState extends Equatable { List? categories, ContentStatus? contentStatus, String? errorMessage, + Headline? createdHeadline, }) { return CreateHeadlineState( status: status ?? this.status, @@ -73,7 +76,8 @@ final class CreateHeadlineState extends Equatable { sources: sources ?? this.sources, categories: categories ?? this.categories, contentStatus: contentStatus ?? this.contentStatus, - errorMessage: errorMessage ?? this.errorMessage, + errorMessage: errorMessage, + createdHeadline: createdHeadline ?? this.createdHeadline, ); } @@ -90,5 +94,6 @@ final class CreateHeadlineState extends Equatable { categories, contentStatus, errorMessage, + createdHeadline, ]; } From d87412d4db852613bcad42c3a66f25ac16a74a62 Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 17:53:49 +0100 Subject: [PATCH 08/28] refactor(content_management): emit created headline object on success --- .../bloc/create_headline/create_headline_bloc.dart | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/lib/content_management/bloc/create_headline/create_headline_bloc.dart b/lib/content_management/bloc/create_headline/create_headline_bloc.dart index 412416bd..45f029dd 100644 --- a/lib/content_management/bloc/create_headline/create_headline_bloc.dart +++ b/lib/content_management/bloc/create_headline/create_headline_bloc.dart @@ -135,18 +135,27 @@ class CreateHeadlineBloc emit(state.copyWith(status: CreateHeadlineStatus.submitting)); try { + final now = DateTime.now(); final newHeadline = Headline( title: state.title, description: state.description.isNotEmpty ? state.description : null, url: state.url.isNotEmpty ? state.url : null, imageUrl: state.imageUrl.isNotEmpty ? state.imageUrl : null, source: state.source, + publishedAt: now, + createdAt: now, + updatedAt: now, category: state.category, status: state.contentStatus, ); await _headlinesRepository.create(item: newHeadline); - emit(state.copyWith(status: CreateHeadlineStatus.success)); + emit( + state.copyWith( + status: CreateHeadlineStatus.success, + createdHeadline: newHeadline, + ), + ); } on HtHttpException catch (e) { emit( state.copyWith( From 2e0fbad91db6888938eed519efeda8cc7aca80eb Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 17:55:36 +0100 Subject: [PATCH 09/28] refactor(content_management): add updatedHeadline to EditHeadlineState --- .../bloc/edit_headline/edit_headline_state.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/content_management/bloc/edit_headline/edit_headline_state.dart b/lib/content_management/bloc/edit_headline/edit_headline_state.dart index 5bbb617a..54e9ada7 100644 --- a/lib/content_management/bloc/edit_headline/edit_headline_state.dart +++ b/lib/content_management/bloc/edit_headline/edit_headline_state.dart @@ -47,6 +47,7 @@ final class EditHeadlineState extends Equatable { final List categories; final ContentStatus contentStatus; final String? errorMessage; + final Headline? updatedHeadline; /// Returns true if the form is valid and can be submitted. bool get isFormValid => title.isNotEmpty; @@ -64,6 +65,7 @@ final class EditHeadlineState extends Equatable { List? categories, ContentStatus? contentStatus, String? errorMessage, + Headline? updatedHeadline, }) { return EditHeadlineState( status: status ?? this.status, @@ -77,7 +79,8 @@ final class EditHeadlineState extends Equatable { sources: sources ?? this.sources, categories: categories ?? this.categories, contentStatus: contentStatus ?? this.contentStatus, - errorMessage: errorMessage ?? this.errorMessage, + errorMessage: errorMessage, + updatedHeadline: updatedHeadline ?? this.updatedHeadline, ); } @@ -95,5 +98,6 @@ final class EditHeadlineState extends Equatable { categories, contentStatus, errorMessage, + updatedHeadline, ]; } From 170727189396ab6a4e833c79b1caa45976b0ac9d Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 17:57:54 +0100 Subject: [PATCH 10/28] fix(content_management): add updatedHeadline property to EditHeadlineState --- .../bloc/edit_headline/edit_headline_state.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/content_management/bloc/edit_headline/edit_headline_state.dart b/lib/content_management/bloc/edit_headline/edit_headline_state.dart index 54e9ada7..97c1e024 100644 --- a/lib/content_management/bloc/edit_headline/edit_headline_state.dart +++ b/lib/content_management/bloc/edit_headline/edit_headline_state.dart @@ -33,6 +33,8 @@ final class EditHeadlineState extends Equatable { this.categories = const [], this.contentStatus = ContentStatus.active, this.errorMessage, + this.updatedHeadline, + }); final EditHeadlineStatus status; From 36dea0fbd8335d5ce9058b61516ada4768f9f8ce Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 18:00:02 +0100 Subject: [PATCH 11/28] refactor(content_management): emit updated headline object on success --- .../bloc/edit_headline/edit_headline_bloc.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/content_management/bloc/edit_headline/edit_headline_bloc.dart b/lib/content_management/bloc/edit_headline/edit_headline_bloc.dart index b8f12f5b..c2951e74 100644 --- a/lib/content_management/bloc/edit_headline/edit_headline_bloc.dart +++ b/lib/content_management/bloc/edit_headline/edit_headline_bloc.dart @@ -192,10 +192,16 @@ class EditHeadlineBloc extends Bloc { source: state.source, category: state.category, status: state.contentStatus, + updatedAt: DateTime.now(), ); await _headlinesRepository.update(id: _headlineId, item: updatedHeadline); - emit(state.copyWith(status: EditHeadlineStatus.success)); + emit( + state.copyWith( + status: EditHeadlineStatus.success, + updatedHeadline: updatedHeadline, + ), + ); } on HtHttpException catch (e) { emit( state.copyWith( From 669f86088af25e3a0a2cafa8b38676f7a11323f9 Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 18:01:26 +0100 Subject: [PATCH 12/28] refactor(content_management): add createdSource to CreateSourceState --- .../bloc/create_source/create_source_state.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/content_management/bloc/create_source/create_source_state.dart b/lib/content_management/bloc/create_source/create_source_state.dart index 8a6f8374..1818cb52 100644 --- a/lib/content_management/bloc/create_source/create_source_state.dart +++ b/lib/content_management/bloc/create_source/create_source_state.dart @@ -32,6 +32,7 @@ final class CreateSourceState extends Equatable { this.countries = const [], this.contentStatus = ContentStatus.active, this.errorMessage, + this.createdSource, }); final CreateSourceStatus status; @@ -43,8 +44,8 @@ final class CreateSourceState extends Equatable { final Country? headquarters; final List countries; final ContentStatus contentStatus; - final String? errorMessage; + final Source? createdSource; /// Returns true if the form is valid and can be submitted. bool get isFormValid => name.isNotEmpty; @@ -59,8 +60,8 @@ final class CreateSourceState extends Equatable { ValueGetter? headquarters, List? countries, ContentStatus? contentStatus, - String? errorMessage, + Source? createdSource, }) { return CreateSourceState( status: status ?? this.status, @@ -72,8 +73,8 @@ final class CreateSourceState extends Equatable { headquarters: headquarters != null ? headquarters() : this.headquarters, countries: countries ?? this.countries, contentStatus: contentStatus ?? this.contentStatus, - errorMessage: errorMessage, + createdSource: createdSource ?? this.createdSource, ); } @@ -89,5 +90,6 @@ final class CreateSourceState extends Equatable { countries, contentStatus, errorMessage, + createdSource, ]; } From 88f354144d06975aa261839666a4c2de9024bdd3 Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 18:02:44 +0100 Subject: [PATCH 13/28] refactor(content_management): emit created source object on success --- .../bloc/create_source/create_source_bloc.dart | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/content_management/bloc/create_source/create_source_bloc.dart b/lib/content_management/bloc/create_source/create_source_bloc.dart index 533dff1d..40b85e0c 100644 --- a/lib/content_management/bloc/create_source/create_source_bloc.dart +++ b/lib/content_management/bloc/create_source/create_source_bloc.dart @@ -124,18 +124,26 @@ class CreateSourceBloc extends Bloc { emit(state.copyWith(status: CreateSourceStatus.submitting)); try { + final now = DateTime.now(); final newSource = Source( name: state.name, description: state.description.isNotEmpty ? state.description : null, url: state.url.isNotEmpty ? state.url : null, sourceType: state.sourceType, language: state.language.isNotEmpty ? state.language : null, + createdAt: now, + updatedAt: now, headquarters: state.headquarters, status: state.contentStatus, ); await _sourcesRepository.create(item: newSource); - emit(state.copyWith(status: CreateSourceStatus.success)); + emit( + state.copyWith( + status: CreateSourceStatus.success, + createdSource: newSource, + ), + ); } on HtHttpException catch (e) { emit( state.copyWith( From 61dfa2b395236fa34835a8bf7ccd8b73e998ac51 Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 18:04:18 +0100 Subject: [PATCH 14/28] refactor(content_management): add an updatedSource property to the state. This will allow the EditSourceBloc to hold the successfully updated source object, which is the final piece needed before we can refactor the main ContentManagementBloc to handle local updates --- .../bloc/edit_source/edit_source_state.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/content_management/bloc/edit_source/edit_source_state.dart b/lib/content_management/bloc/edit_source/edit_source_state.dart index 85908857..52bd59be 100644 --- a/lib/content_management/bloc/edit_source/edit_source_state.dart +++ b/lib/content_management/bloc/edit_source/edit_source_state.dart @@ -32,6 +32,7 @@ final class EditSourceState extends Equatable { this.countries = const [], this.contentStatus = ContentStatus.active, this.errorMessage, + this.updatedSource, }); final EditSourceStatus status; @@ -45,6 +46,7 @@ final class EditSourceState extends Equatable { final List countries; final ContentStatus contentStatus; final String? errorMessage; + final Source? updatedSource; /// Returns true if the form is valid and can be submitted. bool get isFormValid => name.isNotEmpty; @@ -61,6 +63,7 @@ final class EditSourceState extends Equatable { List? countries, ContentStatus? contentStatus, String? errorMessage, + Source? updatedSource, }) { return EditSourceState( status: status ?? this.status, @@ -73,7 +76,8 @@ final class EditSourceState extends Equatable { headquarters: headquarters != null ? headquarters() : this.headquarters, countries: countries ?? this.countries, contentStatus: contentStatus ?? this.contentStatus, - errorMessage: errorMessage ?? this.errorMessage, + errorMessage: errorMessage, + updatedSource: updatedSource ?? this.updatedSource, ); } @@ -90,5 +94,6 @@ final class EditSourceState extends Equatable { countries, contentStatus, errorMessage, + updatedSource, ]; } From 690d35a6489bee3227f2987d670cd97ba2563809 Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 18:06:08 +0100 Subject: [PATCH 15/28] refactor(content_management): update the _onSubmitted method in edit_source_bloc.dart. When a source is successfully updated, I'll set the updatedAt timestamp and then emit the complete updatedSource object along with the success status. This makes the updated item available in the BLoC's state, which is the final piece required before we can move on to updating the main ContentManagementBloc. --- .../bloc/edit_source/edit_source_bloc.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/content_management/bloc/edit_source/edit_source_bloc.dart b/lib/content_management/bloc/edit_source/edit_source_bloc.dart index 73e7a3de..094a1838 100644 --- a/lib/content_management/bloc/edit_source/edit_source_bloc.dart +++ b/lib/content_management/bloc/edit_source/edit_source_bloc.dart @@ -180,10 +180,16 @@ class EditSourceBloc extends Bloc { language: state.language.isNotEmpty ? state.language : null, headquarters: state.headquarters, status: state.contentStatus, + updatedAt: DateTime.now(), ); await _sourcesRepository.update(id: _sourceId, item: updatedSource); - emit(state.copyWith(status: EditSourceStatus.success)); + emit( + state.copyWith( + status: EditSourceStatus.success, + updatedSource: updatedSource, + ), + ); } on HtHttpException catch (e) { emit( state.copyWith( From c89a9c61dec80c860638ec85b5a2802218553005 Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 18:21:05 +0100 Subject: [PATCH 16/28] refactor(content_management): introducing new, specific events for adding and updating items (HeadlineAdded, HeadlineUpdated, etc.). These events will carry the actual object, allowing the BLoC to update its list locally without a full refresh. I am also removing the old Create...Requested and Update...Requested events as they are now obsolete. --- .../bloc/content_management_event.dart | 87 +++++++++---------- 1 file changed, 39 insertions(+), 48 deletions(-) diff --git a/lib/content_management/bloc/content_management_event.dart b/lib/content_management/bloc/content_management_event.dart index 3debb974..0fff533d 100644 --- a/lib/content_management/bloc/content_management_event.dart +++ b/lib/content_management/bloc/content_management_event.dart @@ -38,35 +38,32 @@ final class LoadHeadlinesRequested extends ContentManagementEvent { List get props => [startAfterId, limit]; } -/// {@template create_headline_requested} -/// Event to request creation of a new headline. +/// {@template headline_added} +/// Event to add a new headline to the local state. /// {@endtemplate} -final class CreateHeadlineRequested extends ContentManagementEvent { - /// {@macro create_headline_requested} - const CreateHeadlineRequested(this.headline); +final class HeadlineAdded extends ContentManagementEvent { + /// {@macro headline_added} + const HeadlineAdded(this.headline); - /// The headline to create. + /// The headline that was added. final Headline headline; @override List get props => [headline]; } -/// {@template update_headline_requested} -/// Event to request update of an existing headline. +/// {@template headline_updated} +/// Event to update an existing headline in the local state. /// {@endtemplate} -final class UpdateHeadlineRequested extends ContentManagementEvent { - /// {@macro update_headline_requested} - const UpdateHeadlineRequested({required this.id, required this.headline}); +final class HeadlineUpdated extends ContentManagementEvent { + /// {@macro headline_updated} + const HeadlineUpdated(this.headline); - /// The ID of the headline to update. - final String id; - - /// The updated headline data. + /// The headline that was updated. final Headline headline; @override - List get props => [id, headline]; + List get props => [headline]; } /// {@template delete_headline_requested} @@ -100,35 +97,32 @@ final class LoadCategoriesRequested extends ContentManagementEvent { List get props => [startAfterId, limit]; } -/// {@template create_category_requested} -/// Event to request creation of a new category. +/// {@template category_added} +/// Event to add a new category to the local state. /// {@endtemplate} -final class CreateCategoryRequested extends ContentManagementEvent { - /// {@macro create_category_requested} - const CreateCategoryRequested(this.category); +final class CategoryAdded extends ContentManagementEvent { + /// {@macro category_added} + const CategoryAdded(this.category); - /// The category to create. + /// The category that was added. final Category category; @override List get props => [category]; } -/// {@template update_category_requested} -/// Event to request update of an existing category. +/// {@template category_updated} +/// Event to update an existing category in the local state. /// {@endtemplate} -final class UpdateCategoryRequested extends ContentManagementEvent { - /// {@macro update_category_requested} - const UpdateCategoryRequested({required this.id, required this.category}); - - /// The ID of the category to update. - final String id; +final class CategoryUpdated extends ContentManagementEvent { + /// {@macro category_updated} + const CategoryUpdated(this.category); - /// The updated category data. + /// The category that was updated. final Category category; @override - List get props => [id, category]; + List get props => [category]; } /// {@template delete_category_requested} @@ -162,35 +156,32 @@ final class LoadSourcesRequested extends ContentManagementEvent { List get props => [startAfterId, limit]; } -/// {@template create_source_requested} -/// Event to request creation of a new source. +/// {@template source_added} +/// Event to add a new source to the local state. /// {@endtemplate} -final class CreateSourceRequested extends ContentManagementEvent { - /// {@macro create_source_requested} - const CreateSourceRequested(this.source); +final class SourceAdded extends ContentManagementEvent { + /// {@macro source_added} + const SourceAdded(this.source); - /// The source to create. + /// The source that was added. final Source source; @override List get props => [source]; } -/// {@template update_source_requested} -/// Event to request update of an existing source. +/// {@template source_updated} +/// Event to update an existing source in the local state. /// {@endtemplate} -final class UpdateSourceRequested extends ContentManagementEvent { - /// {@macro update_source_requested} - const UpdateSourceRequested({required this.id, required this.source}); - - /// The ID of the source to update. - final String id; +final class SourceUpdated extends ContentManagementEvent { + /// {@macro source_updated} + const SourceUpdated(this.source); - /// The updated source data. + /// The source that was updated. final Source source; @override - List get props => [id, source]; + List get props => [source]; } /// {@template delete_source_requested} From 28bfafeb3389fdc7d814ec001dfdfa9af27de33c Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 18:25:19 +0100 Subject: [PATCH 17/28] refactor(content_management): handle the new local update events. I will remove the old, inefficient event handlers that triggered a full data reload and replace them with new handlers that perform fast, local list manipulations (adding, updating, and deleting items directly in the state). This is the core change that will fix the "N/A" timestamp issue and make the UI much more responsive. --- .../bloc/content_management_bloc.dart | 235 +++++------------- 1 file changed, 65 insertions(+), 170 deletions(-) diff --git a/lib/content_management/bloc/content_management_bloc.dart b/lib/content_management/bloc/content_management_bloc.dart index ff0bf34d..60b74797 100644 --- a/lib/content_management/bloc/content_management_bloc.dart +++ b/lib/content_management/bloc/content_management_bloc.dart @@ -31,16 +31,16 @@ class ContentManagementBloc super(const ContentManagementState()) { on(_onContentManagementTabChanged); on(_onLoadHeadlinesRequested); - on(_onCreateHeadlineRequested); - on(_onUpdateHeadlineRequested); + on(_onHeadlineAdded); + on(_onHeadlineUpdated); on(_onDeleteHeadlineRequested); on(_onLoadCategoriesRequested); - on(_onCreateCategoryRequested); - on(_onUpdateCategoryRequested); + on(_onCategoryAdded); + on(_onCategoryUpdated); on(_onDeleteCategoryRequested); on(_onLoadSourcesRequested); - on(_onCreateSourceRequested); - on(_onUpdateSourceRequested); + on(_onSourceAdded); + on(_onSourceUpdated); on(_onOnDeleteSourceRequested); } @@ -93,59 +93,25 @@ class ContentManagementBloc } } - Future _onCreateHeadlineRequested( - CreateHeadlineRequested event, - Emitter emit, - ) async { - emit(state.copyWith(headlinesStatus: ContentManagementStatus.loading)); - try { - await _headlinesRepository.create(item: event.headline); - // Reload headlines after creation - add( - const LoadHeadlinesRequested(limit: kDefaultRowsPerPage), - ); - } on HtHttpException catch (e) { - emit( - state.copyWith( - headlinesStatus: ContentManagementStatus.failure, - errorMessage: e.message, - ), - ); - } catch (e) { - emit( - state.copyWith( - headlinesStatus: ContentManagementStatus.failure, - errorMessage: e.toString(), - ), - ); - } + void _onHeadlineAdded(HeadlineAdded event, Emitter emit) { + final updatedHeadlines = [event.headline, ...state.headlines]; + emit( + state.copyWith( + headlines: updatedHeadlines, + headlinesStatus: ContentManagementStatus.success, + ), + ); } - Future _onUpdateHeadlineRequested( - UpdateHeadlineRequested event, + void _onHeadlineUpdated( + HeadlineUpdated event, Emitter emit, - ) async { - emit(state.copyWith(headlinesStatus: ContentManagementStatus.loading)); - try { - await _headlinesRepository.update(id: event.id, item: event.headline); - // Reload headlines after update - add( - const LoadHeadlinesRequested(limit: kDefaultRowsPerPage), - ); - } on HtHttpException catch (e) { - emit( - state.copyWith( - headlinesStatus: ContentManagementStatus.failure, - errorMessage: e.message, - ), - ); - } catch (e) { - emit( - state.copyWith( - headlinesStatus: ContentManagementStatus.failure, - errorMessage: e.toString(), - ), - ); + ) { + final updatedHeadlines = List.from(state.headlines); + final index = updatedHeadlines.indexWhere((h) => h.id == event.headline.id); + if (index != -1) { + updatedHeadlines[index] = event.headline; + emit(state.copyWith(headlines: updatedHeadlines)); } } @@ -153,13 +119,11 @@ class ContentManagementBloc DeleteHeadlineRequested event, Emitter emit, ) async { - emit(state.copyWith(headlinesStatus: ContentManagementStatus.loading)); try { await _headlinesRepository.delete(id: event.id); - // Reload headlines after deletion - add( - const LoadHeadlinesRequested(limit: kDefaultRowsPerPage), - ); + final updatedHeadlines = + state.headlines.where((h) => h.id != event.id).toList(); + emit(state.copyWith(headlines: updatedHeadlines)); } on HtHttpException catch (e) { emit( state.copyWith( @@ -215,59 +179,28 @@ class ContentManagementBloc } } - Future _onCreateCategoryRequested( - CreateCategoryRequested event, + void _onCategoryAdded( + CategoryAdded event, Emitter emit, - ) async { - emit(state.copyWith(categoriesStatus: ContentManagementStatus.loading)); - try { - await _categoriesRepository.create(item: event.category); - // Reload categories after creation - add( - const LoadCategoriesRequested(limit: kDefaultRowsPerPage), - ); - } on HtHttpException catch (e) { - emit( - state.copyWith( - categoriesStatus: ContentManagementStatus.failure, - errorMessage: e.message, - ), - ); - } catch (e) { - emit( - state.copyWith( - categoriesStatus: ContentManagementStatus.failure, - errorMessage: e.toString(), - ), - ); - } + ) { + final updatedCategories = [event.category, ...state.categories]; + emit( + state.copyWith( + categories: updatedCategories, + categoriesStatus: ContentManagementStatus.success, + ), + ); } - Future _onUpdateCategoryRequested( - UpdateCategoryRequested event, + void _onCategoryUpdated( + CategoryUpdated event, Emitter emit, - ) async { - emit(state.copyWith(categoriesStatus: ContentManagementStatus.loading)); - try { - await _categoriesRepository.update(id: event.id, item: event.category); - // Reload categories after update - add( - const LoadCategoriesRequested(limit: kDefaultRowsPerPage), - ); - } on HtHttpException catch (e) { - emit( - state.copyWith( - categoriesStatus: ContentManagementStatus.failure, - errorMessage: e.message, - ), - ); - } catch (e) { - emit( - state.copyWith( - categoriesStatus: ContentManagementStatus.failure, - errorMessage: e.toString(), - ), - ); + ) { + final updatedCategories = List.from(state.categories); + final index = updatedCategories.indexWhere((c) => c.id == event.category.id); + if (index != -1) { + updatedCategories[index] = event.category; + emit(state.copyWith(categories: updatedCategories)); } } @@ -275,13 +208,11 @@ class ContentManagementBloc DeleteCategoryRequested event, Emitter emit, ) async { - emit(state.copyWith(categoriesStatus: ContentManagementStatus.loading)); try { await _categoriesRepository.delete(id: event.id); - // Reload categories after deletion - add( - const LoadCategoriesRequested(limit: kDefaultRowsPerPage), - ); + final updatedCategories = + state.categories.where((c) => c.id != event.id).toList(); + emit(state.copyWith(categories: updatedCategories)); } on HtHttpException catch (e) { emit( state.copyWith( @@ -337,59 +268,25 @@ class ContentManagementBloc } } - Future _onCreateSourceRequested( - CreateSourceRequested event, - Emitter emit, - ) async { - emit(state.copyWith(sourcesStatus: ContentManagementStatus.loading)); - try { - await _sourcesRepository.create(item: event.source); - // Reload sources after creation - add( - const LoadSourcesRequested(limit: kDefaultRowsPerPage), - ); - } on HtHttpException catch (e) { - emit( - state.copyWith( - sourcesStatus: ContentManagementStatus.failure, - errorMessage: e.message, - ), - ); - } catch (e) { - emit( - state.copyWith( - sourcesStatus: ContentManagementStatus.failure, - errorMessage: e.toString(), - ), - ); - } + void _onSourceAdded(SourceAdded event, Emitter emit) { + final updatedSources = [event.source, ...state.sources]; + emit( + state.copyWith( + sources: updatedSources, + sourcesStatus: ContentManagementStatus.success, + ), + ); } - Future _onUpdateSourceRequested( - UpdateSourceRequested event, + void _onSourceUpdated( + SourceUpdated event, Emitter emit, - ) async { - emit(state.copyWith(sourcesStatus: ContentManagementStatus.loading)); - try { - await _sourcesRepository.update(id: event.id, item: event.source); - // Reload sources after update - add( - const LoadSourcesRequested(limit: kDefaultRowsPerPage), - ); - } on HtHttpException catch (e) { - emit( - state.copyWith( - sourcesStatus: ContentManagementStatus.failure, - errorMessage: e.message, - ), - ); - } catch (e) { - emit( - state.copyWith( - sourcesStatus: ContentManagementStatus.failure, - errorMessage: e.toString(), - ), - ); + ) { + final updatedSources = List.from(state.sources); + final index = updatedSources.indexWhere((s) => s.id == event.source.id); + if (index != -1) { + updatedSources[index] = event.source; + emit(state.copyWith(sources: updatedSources)); } } @@ -397,13 +294,11 @@ class ContentManagementBloc DeleteSourceRequested event, Emitter emit, ) async { - emit(state.copyWith(sourcesStatus: ContentManagementStatus.loading)); try { await _sourcesRepository.delete(id: event.id); - // Reload sources after deletion - add( - const LoadSourcesRequested(limit: kDefaultRowsPerPage), - ); + final updatedSources = + state.sources.where((s) => s.id != event.id).toList(); + emit(state.copyWith(sources: updatedSources)); } on HtHttpException catch (e) { emit( state.copyWith( From 5de9fb52e1c8bd54e006ac6c2010b7c627937f9c Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 18:27:40 +0100 Subject: [PATCH 18/28] refactor(content_management): update the BlocListener in create_category_page.dart. Instead of dispatching the old LoadCategoriesRequested event (which caused a full reload), it will now dispatch the new CategoryAdded event. This event carries the newly created category object directly to the ContentManagementBloc, which will add it to the list locally for an instant UI update. --- lib/content_management/view/create_category_page.dart | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/content_management/view/create_category_page.dart b/lib/content_management/view/create_category_page.dart index 470ca996..67b327a8 100644 --- a/lib/content_management/view/create_category_page.dart +++ b/lib/content_management/view/create_category_page.dart @@ -75,19 +75,16 @@ class _CreateCategoryViewState extends State<_CreateCategoryView> { listenWhen: (previous, current) => previous.status != current.status, listener: (context, state) { if (state.status == CreateCategoryStatus.success && + state.createdCategory != null && ModalRoute.of(context)!.isCurrent) { ScaffoldMessenger.of(context) ..hideCurrentSnackBar() ..showSnackBar( - SnackBar( - content: Text(l10n.categoryCreatedSuccessfully), - ), + SnackBar(content: Text(l10n.categoryCreatedSuccessfully)), ); context.read().add( - const LoadCategoriesRequested( - limit: kDefaultRowsPerPage, - ), - ); + CategoryAdded(state.createdCategory!), + ); context.pop(); } if (state.status == CreateCategoryStatus.failure) { From f5ad54a9cb345657e1147d9710f8334a897196ce Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 18:29:09 +0100 Subject: [PATCH 19/28] refactor(content_management): update the BlocListener in edit_category_page.dart. When an edit is successful, it will now dispatch the new CategoryUpdated event, passing the updated category object directly to the ContentManagementBloc. This allows the main list to update the specific item locally, which is much more efficient than reloading the entire list. --- lib/content_management/view/edit_category_page.dart | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/content_management/view/edit_category_page.dart b/lib/content_management/view/edit_category_page.dart index 42b7184c..39fba1ef 100644 --- a/lib/content_management/view/edit_category_page.dart +++ b/lib/content_management/view/edit_category_page.dart @@ -101,7 +101,7 @@ class _EditCategoryViewState extends State<_EditCategoryView> { previous.initialCategory != current.initialCategory, listener: (context, state) { if (state.status == EditCategoryStatus.success && - state.initialCategory != null && + state.updatedCategory != null && ModalRoute.of(context)!.isCurrent) { ScaffoldMessenger.of(context) ..hideCurrentSnackBar() @@ -110,10 +110,8 @@ class _EditCategoryViewState extends State<_EditCategoryView> { const SnackBar(content: Text('Category updated successfully.')), ); context.read().add( - const LoadCategoriesRequested( - limit: kDefaultRowsPerPage, - ), - ); + CategoryUpdated(state.updatedCategory!), + ); context.pop(); } if (state.status == EditCategoryStatus.failure) { From a9801e889a1c69f64e70106137fa4a001a241644 Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 18:30:42 +0100 Subject: [PATCH 20/28] refactor(content_management): update the BlocListener in create_headline_page.dart. Instead of triggering a full data reload, it will now dispatch the new HeadlineAdded event. This event passes the newly created headline object directly to the ContentManagementBloc, which will add it to the list locally for an immediate and efficient UI update. --- lib/content_management/view/create_headline_page.dart | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/content_management/view/create_headline_page.dart b/lib/content_management/view/create_headline_page.dart index 06a79b71..3fb4ce26 100644 --- a/lib/content_management/view/create_headline_page.dart +++ b/lib/content_management/view/create_headline_page.dart @@ -77,19 +77,16 @@ class _CreateHeadlineViewState extends State<_CreateHeadlineView> { listenWhen: (previous, current) => previous.status != current.status, listener: (context, state) { if (state.status == CreateHeadlineStatus.success && + state.createdHeadline != null && ModalRoute.of(context)!.isCurrent) { ScaffoldMessenger.of(context) ..hideCurrentSnackBar() ..showSnackBar( - SnackBar( - content: Text(l10n.headlineCreatedSuccessfully), - ), + SnackBar(content: Text(l10n.headlineCreatedSuccessfully)), ); context.read().add( - const LoadHeadlinesRequested( - limit: kDefaultRowsPerPage, - ), - ); + HeadlineAdded(state.createdHeadline!), + ); context.pop(); } if (state.status == CreateHeadlineStatus.failure) { From 63d0304c97361a31164c524c42055de994685c53 Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 18:33:05 +0100 Subject: [PATCH 21/28] refactor(content_management): update the BlocListener in edit_headline_page.dart. When an edit is successful, it will now dispatch the new HeadlineUpdated event, passing the updated headline object directly to the ContentManagementBloc. This allows the main list to update the specific item locally, which is much more efficient than reloading the entire list. --- lib/content_management/view/edit_headline_page.dart | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/lib/content_management/view/edit_headline_page.dart b/lib/content_management/view/edit_headline_page.dart index 7f1215bd..cd676564 100644 --- a/lib/content_management/view/edit_headline_page.dart +++ b/lib/content_management/view/edit_headline_page.dart @@ -106,7 +106,7 @@ class _EditHeadlineViewState extends State<_EditHeadlineView> { previous.initialHeadline != current.initialHeadline, listener: (context, state) { if (state.status == EditHeadlineStatus.success && - state.initialHeadline != null && + state.updatedHeadline != null && ModalRoute.of(context)!.isCurrent) { ScaffoldMessenger.of(context) ..hideCurrentSnackBar() @@ -116,10 +116,8 @@ class _EditHeadlineViewState extends State<_EditHeadlineView> { ), ); context.read().add( - const LoadHeadlinesRequested( - limit: kDefaultRowsPerPage, - ), - ); + HeadlineUpdated(state.updatedHeadline!), + ); context.pop(); } if (state.status == EditHeadlineStatus.failure) { From 5e328e5da29c62e8281ed80872eafb72f2aa3c11 Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 18:34:55 +0100 Subject: [PATCH 22/28] refactor(content_management): update the BlocListener in create_source_page.dart. Instead of triggering a full data reload, it will now dispatch the new SourceAdded event. This event passes the newly created source object directly to the ContentManagementBloc, which will add it to the list locally for an immediate and efficient UI update. --- lib/content_management/view/create_source_page.dart | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/content_management/view/create_source_page.dart b/lib/content_management/view/create_source_page.dart index b91c5227..3fcece75 100644 --- a/lib/content_management/view/create_source_page.dart +++ b/lib/content_management/view/create_source_page.dart @@ -77,17 +77,16 @@ class _CreateSourceViewState extends State<_CreateSourceView> { listenWhen: (previous, current) => previous.status != current.status, listener: (context, state) { if (state.status == CreateSourceStatus.success && + state.createdSource != null && ModalRoute.of(context)!.isCurrent) { ScaffoldMessenger.of(context) ..hideCurrentSnackBar() ..showSnackBar( SnackBar(content: Text(l10n.sourceCreatedSuccessfully)), ); - context.read().add( - const LoadSourcesRequested( - limit: kDefaultRowsPerPage, - ), - ); + context + .read() + .add(SourceAdded(state.createdSource!)); context.pop(); } if (state.status == CreateSourceStatus.failure) { From cb7b8ad50de18d84b8703cb1dcdbb064d9b5f491 Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 18:36:35 +0100 Subject: [PATCH 23/28] refactor(content_management): update the BlocListener in edit_source_page.dart. When an edit is successful, it will dispatch the SourceUpdated event, passing the updated source object directly to the ContentManagementBloc. This completes our UI refactoring, ensuring all create and edit operations result in an efficient local list update rather than a full reload. --- lib/content_management/view/edit_source_page.dart | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/lib/content_management/view/edit_source_page.dart b/lib/content_management/view/edit_source_page.dart index 738e9d44..d2e8c594 100644 --- a/lib/content_management/view/edit_source_page.dart +++ b/lib/content_management/view/edit_source_page.dart @@ -105,18 +105,16 @@ class _EditSourceViewState extends State<_EditSourceView> { previous.initialSource != current.initialSource, listener: (context, state) { if (state.status == EditSourceStatus.success && - state.initialSource != null && + state.updatedSource != null && ModalRoute.of(context)!.isCurrent) { ScaffoldMessenger.of(context) ..hideCurrentSnackBar() ..showSnackBar( SnackBar(content: Text(l10n.sourceUpdatedSuccessfully)), ); - context.read().add( - const LoadSourcesRequested( - limit: kDefaultRowsPerPage, - ), - ); + context + .read() + .add(SourceUpdated(state.updatedSource!)); context.pop(); } if (state.status == EditSourceStatus.failure) { From 2c6fe24eae52c3d3f878808a61e96b5555d07a72 Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 18:38:34 +0100 Subject: [PATCH 24/28] feat(content_management): format updatedAt timestamp in categories table --- lib/content_management/view/categories_page.dart | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/content_management/view/categories_page.dart b/lib/content_management/view/categories_page.dart index b0b9b693..096d499e 100644 --- a/lib/content_management/view/categories_page.dart +++ b/lib/content_management/view/categories_page.dart @@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dart'; import 'package:ht_dashboard/l10n/app_localizations.dart'; +import 'package:intl/intl.dart'; import 'package:ht_dashboard/l10n/l10n.dart'; import 'package:ht_dashboard/router/routes.dart'; import 'package:ht_dashboard/shared/constants/pagination_constants.dart'; @@ -162,7 +163,14 @@ class _CategoriesDataSource extends DataTableSource { cells: [ DataCell(Text(category.name)), DataCell(Text(category.status.l10n(context))), - DataCell(Text(category.updatedAt?.toLocal().toString() ?? l10n.notAvailable)), + DataCell( + Text( + category.updatedAt != null + // TODO(fulleni): Make date format configurable by admin. + ? DateFormat('dd-MM-yyyy').format(category.updatedAt!.toLocal()) + : l10n.notAvailable, + ), + ), DataCell( Row( children: [ From 5ba9a3831460d4a43e0897dbd99f44f65aacf3b7 Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 18:40:51 +0100 Subject: [PATCH 25/28] feat(content_management): format updatedAt timestamp in headlines table --- lib/content_management/view/headlines_page.dart | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/content_management/view/headlines_page.dart b/lib/content_management/view/headlines_page.dart index 5dcd47f5..e791b2ec 100644 --- a/lib/content_management/view/headlines_page.dart +++ b/lib/content_management/view/headlines_page.dart @@ -3,6 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dart'; +import 'package:intl/intl.dart'; import 'package:ht_dashboard/l10n/app_localizations.dart'; // Corrected import import 'package:ht_dashboard/l10n/l10n.dart'; import 'package:ht_dashboard/router/routes.dart'; @@ -171,7 +172,13 @@ class _HeadlinesDataSource extends DataTableSource { DataCell(Text(headline.source?.name ?? l10n.unknown)), DataCell(Text(headline.status.l10n(context))), DataCell( - Text(headline.updatedAt?.toLocal().toString() ?? l10n.notAvailable), + Text( + headline.updatedAt != null + // TODO(fulleni): Make date format configurable by admin. + ? DateFormat('dd-MM-yyyy') + .format(headline.updatedAt!.toLocal()) + : l10n.notAvailable, + ), ), DataCell( Row( From 90d00c045e53d27d1063fbf85214edc98a50b07c Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 18:42:17 +0100 Subject: [PATCH 26/28] feat(content_management): format updatedAt timestamp in sources table --- lib/content_management/view/sources_page.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/content_management/view/sources_page.dart b/lib/content_management/view/sources_page.dart index ace07dfc..e426a597 100644 --- a/lib/content_management/view/sources_page.dart +++ b/lib/content_management/view/sources_page.dart @@ -4,6 +4,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dart'; import 'package:ht_dashboard/content_management/bloc/edit_source/edit_source_bloc.dart'; +import 'package:intl/intl.dart'; import 'package:ht_dashboard/l10n/app_localizations.dart'; import 'package:ht_dashboard/shared/extensions/content_status_l10n.dart'; import 'package:ht_dashboard/l10n/l10n.dart'; @@ -170,7 +171,12 @@ class _SourcesDataSource extends DataTableSource { DataCell(Text(source.sourceType?.localizedName(l10n) ?? l10n.unknown)), DataCell(Text(source.status.l10n(context))), DataCell( - Text(source.updatedAt?.toLocal().toString() ?? l10n.notAvailable), + Text( + source.updatedAt != null + // TODO(fulleni): Make date format configurable by admin. + ? DateFormat('dd-MM-yyyy').format(source.updatedAt!.toLocal()) + : l10n.notAvailable, + ), ), DataCell( Row( From 4f84cef80d80cb94454032812c5d5ca2018da373 Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 18:43:52 +0100 Subject: [PATCH 27/28] style: format --- .../bloc/content_management_bloc.dart | 24 +++++++++----- .../bloc/content_management_state.dart | 31 +++++++++---------- .../edit_headline/edit_headline_state.dart | 3 +- .../view/categories_page.dart | 12 +++++-- .../view/content_management_page.dart | 6 ++-- .../view/create_category_page.dart | 10 +++--- .../view/create_headline_page.dart | 4 +-- .../view/create_source_page.dart | 6 ++-- .../view/edit_category_page.dart | 4 +-- .../view/edit_headline_page.dart | 4 +-- .../view/edit_source_page.dart | 6 ++-- .../view/headlines_page.dart | 3 +- .../extensions/content_status_l10n.dart | 2 +- 13 files changed, 64 insertions(+), 51 deletions(-) diff --git a/lib/content_management/bloc/content_management_bloc.dart b/lib/content_management/bloc/content_management_bloc.dart index 60b74797..6beb2b63 100644 --- a/lib/content_management/bloc/content_management_bloc.dart +++ b/lib/content_management/bloc/content_management_bloc.dart @@ -93,7 +93,10 @@ class ContentManagementBloc } } - void _onHeadlineAdded(HeadlineAdded event, Emitter emit) { + void _onHeadlineAdded( + HeadlineAdded event, + Emitter emit, + ) { final updatedHeadlines = [event.headline, ...state.headlines]; emit( state.copyWith( @@ -121,8 +124,9 @@ class ContentManagementBloc ) async { try { await _headlinesRepository.delete(id: event.id); - final updatedHeadlines = - state.headlines.where((h) => h.id != event.id).toList(); + final updatedHeadlines = state.headlines + .where((h) => h.id != event.id) + .toList(); emit(state.copyWith(headlines: updatedHeadlines)); } on HtHttpException catch (e) { emit( @@ -197,7 +201,9 @@ class ContentManagementBloc Emitter emit, ) { final updatedCategories = List.from(state.categories); - final index = updatedCategories.indexWhere((c) => c.id == event.category.id); + final index = updatedCategories.indexWhere( + (c) => c.id == event.category.id, + ); if (index != -1) { updatedCategories[index] = event.category; emit(state.copyWith(categories: updatedCategories)); @@ -210,8 +216,9 @@ class ContentManagementBloc ) async { try { await _categoriesRepository.delete(id: event.id); - final updatedCategories = - state.categories.where((c) => c.id != event.id).toList(); + final updatedCategories = state.categories + .where((c) => c.id != event.id) + .toList(); emit(state.copyWith(categories: updatedCategories)); } on HtHttpException catch (e) { emit( @@ -296,8 +303,9 @@ class ContentManagementBloc ) async { try { await _sourcesRepository.delete(id: event.id); - final updatedSources = - state.sources.where((s) => s.id != event.id).toList(); + final updatedSources = state.sources + .where((s) => s.id != event.id) + .toList(); emit(state.copyWith(sources: updatedSources)); } on HtHttpException catch (e) { emit( diff --git a/lib/content_management/bloc/content_management_state.dart b/lib/content_management/bloc/content_management_state.dart index f6031937..d566cc63 100644 --- a/lib/content_management/bloc/content_management_state.dart +++ b/lib/content_management/bloc/content_management_state.dart @@ -1,6 +1,5 @@ part of 'content_management_bloc.dart'; - /// Represents the status of content loading and operations. enum ContentManagementStatus { /// The operation is in its initial state. @@ -115,19 +114,19 @@ class ContentManagementState extends Equatable { @override List get props => [ - activeTab, - headlinesStatus, - headlines, - headlinesCursor, - headlinesHasMore, - categoriesStatus, - categories, - categoriesCursor, - categoriesHasMore, - sourcesStatus, - sources, - sourcesCursor, - sourcesHasMore, - errorMessage, - ]; + activeTab, + headlinesStatus, + headlines, + headlinesCursor, + headlinesHasMore, + categoriesStatus, + categories, + categoriesCursor, + categoriesHasMore, + sourcesStatus, + sources, + sourcesCursor, + sourcesHasMore, + errorMessage, + ]; } diff --git a/lib/content_management/bloc/edit_headline/edit_headline_state.dart b/lib/content_management/bloc/edit_headline/edit_headline_state.dart index 97c1e024..5cd017f2 100644 --- a/lib/content_management/bloc/edit_headline/edit_headline_state.dart +++ b/lib/content_management/bloc/edit_headline/edit_headline_state.dart @@ -33,8 +33,7 @@ final class EditHeadlineState extends Equatable { this.categories = const [], this.contentStatus = ContentStatus.active, this.errorMessage, - this.updatedHeadline, - + this.updatedHeadline, }); final EditHeadlineStatus status; diff --git a/lib/content_management/view/categories_page.dart b/lib/content_management/view/categories_page.dart index 096d499e..a8da96a5 100644 --- a/lib/content_management/view/categories_page.dart +++ b/lib/content_management/view/categories_page.dart @@ -89,7 +89,8 @@ class _CategoriesPageState extends State { source: _CategoriesDataSource( context: context, categories: state.categories, - isLoading: state.categoriesStatus == ContentManagementStatus.loading, + isLoading: + state.categoriesStatus == ContentManagementStatus.loading, hasMore: state.categoriesHasMore, l10n: l10n, ), @@ -157,7 +158,10 @@ class _CategoriesDataSource extends DataTableSource { return DataRow2( onSelectChanged: (selected) { if (selected ?? false) { - context.goNamed(Routes.editCategoryName, pathParameters: {'id': category.id}); + context.goNamed( + Routes.editCategoryName, + pathParameters: {'id': category.id}, + ); } }, cells: [ @@ -211,7 +215,9 @@ class _CategoriesDataSource extends DataTableSource { if (hasMore) { // When loading, we show an extra row for the spinner. // Otherwise, we just indicate that there are more rows. - return isLoading ? categories.length + 1 : categories.length + kDefaultRowsPerPage; + return isLoading + ? categories.length + 1 + : categories.length + kDefaultRowsPerPage; } return categories.length; } diff --git a/lib/content_management/view/content_management_page.dart b/lib/content_management/view/content_management_page.dart index 3f9749f9..d4f0305c 100644 --- a/lib/content_management/view/content_management_page.dart +++ b/lib/content_management/view/content_management_page.dart @@ -96,8 +96,10 @@ class _ContentManagementPageState extends State icon: const Icon(Icons.add), tooltip: 'Add New Item', // Consider localizing this tooltip onPressed: () { - final currentTab = - context.read().state.activeTab; + final currentTab = context + .read() + .state + .activeTab; switch (currentTab) { case ContentManagementTab.headlines: context.goNamed(Routes.createHeadlineName); diff --git a/lib/content_management/view/create_category_page.dart b/lib/content_management/view/create_category_page.dart index 67b327a8..f3e39a4b 100644 --- a/lib/content_management/view/create_category_page.dart +++ b/lib/content_management/view/create_category_page.dart @@ -83,8 +83,8 @@ class _CreateCategoryViewState extends State<_CreateCategoryView> { SnackBar(content: Text(l10n.categoryCreatedSuccessfully)), ); context.read().add( - CategoryAdded(state.createdCategory!), - ); + CategoryAdded(state.createdCategory!), + ); context.pop(); } if (state.status == CreateCategoryStatus.failure) { @@ -155,9 +155,9 @@ class _CreateCategoryViewState extends State<_CreateCategoryView> { }).toList(), onChanged: (value) { if (value == null) return; - context - .read() - .add(CreateCategoryStatusChanged(value)); + context.read().add( + CreateCategoryStatusChanged(value), + ); }, ), ], diff --git a/lib/content_management/view/create_headline_page.dart b/lib/content_management/view/create_headline_page.dart index 3fb4ce26..20d64e07 100644 --- a/lib/content_management/view/create_headline_page.dart +++ b/lib/content_management/view/create_headline_page.dart @@ -85,8 +85,8 @@ class _CreateHeadlineViewState extends State<_CreateHeadlineView> { SnackBar(content: Text(l10n.headlineCreatedSuccessfully)), ); context.read().add( - HeadlineAdded(state.createdHeadline!), - ); + HeadlineAdded(state.createdHeadline!), + ); context.pop(); } if (state.status == CreateHeadlineStatus.failure) { diff --git a/lib/content_management/view/create_source_page.dart b/lib/content_management/view/create_source_page.dart index 3fcece75..8a514694 100644 --- a/lib/content_management/view/create_source_page.dart +++ b/lib/content_management/view/create_source_page.dart @@ -84,9 +84,9 @@ class _CreateSourceViewState extends State<_CreateSourceView> { ..showSnackBar( SnackBar(content: Text(l10n.sourceCreatedSuccessfully)), ); - context - .read() - .add(SourceAdded(state.createdSource!)); + context.read().add( + SourceAdded(state.createdSource!), + ); context.pop(); } if (state.status == CreateSourceStatus.failure) { diff --git a/lib/content_management/view/edit_category_page.dart b/lib/content_management/view/edit_category_page.dart index 39fba1ef..28680f76 100644 --- a/lib/content_management/view/edit_category_page.dart +++ b/lib/content_management/view/edit_category_page.dart @@ -110,8 +110,8 @@ class _EditCategoryViewState extends State<_EditCategoryView> { const SnackBar(content: Text('Category updated successfully.')), ); context.read().add( - CategoryUpdated(state.updatedCategory!), - ); + CategoryUpdated(state.updatedCategory!), + ); context.pop(); } if (state.status == EditCategoryStatus.failure) { diff --git a/lib/content_management/view/edit_headline_page.dart b/lib/content_management/view/edit_headline_page.dart index cd676564..e49d8c4b 100644 --- a/lib/content_management/view/edit_headline_page.dart +++ b/lib/content_management/view/edit_headline_page.dart @@ -116,8 +116,8 @@ class _EditHeadlineViewState extends State<_EditHeadlineView> { ), ); context.read().add( - HeadlineUpdated(state.updatedHeadline!), - ); + HeadlineUpdated(state.updatedHeadline!), + ); context.pop(); } if (state.status == EditHeadlineStatus.failure) { diff --git a/lib/content_management/view/edit_source_page.dart b/lib/content_management/view/edit_source_page.dart index d2e8c594..735173bd 100644 --- a/lib/content_management/view/edit_source_page.dart +++ b/lib/content_management/view/edit_source_page.dart @@ -112,9 +112,9 @@ class _EditSourceViewState extends State<_EditSourceView> { ..showSnackBar( SnackBar(content: Text(l10n.sourceUpdatedSuccessfully)), ); - context - .read() - .add(SourceUpdated(state.updatedSource!)); + context.read().add( + SourceUpdated(state.updatedSource!), + ); context.pop(); } if (state.status == EditSourceStatus.failure) { diff --git a/lib/content_management/view/headlines_page.dart b/lib/content_management/view/headlines_page.dart index e791b2ec..46078a8a 100644 --- a/lib/content_management/view/headlines_page.dart +++ b/lib/content_management/view/headlines_page.dart @@ -175,8 +175,7 @@ class _HeadlinesDataSource extends DataTableSource { Text( headline.updatedAt != null // TODO(fulleni): Make date format configurable by admin. - ? DateFormat('dd-MM-yyyy') - .format(headline.updatedAt!.toLocal()) + ? DateFormat('dd-MM-yyyy').format(headline.updatedAt!.toLocal()) : l10n.notAvailable, ), ), diff --git a/lib/shared/extensions/content_status_l10n.dart b/lib/shared/extensions/content_status_l10n.dart index c2f9b6cf..3e52c83a 100644 --- a/lib/shared/extensions/content_status_l10n.dart +++ b/lib/shared/extensions/content_status_l10n.dart @@ -16,4 +16,4 @@ extension ContentStatusL10n on ContentStatus { return l10n.contentStatusDraft; } } -} \ No newline at end of file +} From 6426aa7a19d9a287633871f4d02d97755df491cf Mon Sep 17 00:00:00 2001 From: fulleni Date: Thu, 3 Jul 2025 18:44:33 +0100 Subject: [PATCH 28/28] lint: misc --- lib/content_management/bloc/content_management_bloc.dart | 1 - .../bloc/create_source/create_source_bloc.dart | 2 +- .../bloc/edit_source/edit_source_bloc.dart | 2 -- lib/content_management/view/categories_page.dart | 6 +----- lib/content_management/view/create_category_page.dart | 2 -- lib/content_management/view/create_headline_page.dart | 2 -- lib/content_management/view/create_source_page.dart | 2 -- lib/content_management/view/edit_category_page.dart | 2 -- lib/content_management/view/edit_headline_page.dart | 2 -- lib/content_management/view/edit_source_page.dart | 2 -- lib/content_management/view/headlines_page.dart | 4 ++-- lib/content_management/view/sources_page.dart | 6 +++--- 12 files changed, 7 insertions(+), 26 deletions(-) diff --git a/lib/content_management/bloc/content_management_bloc.dart b/lib/content_management/bloc/content_management_bloc.dart index 6beb2b63..41af4a16 100644 --- a/lib/content_management/bloc/content_management_bloc.dart +++ b/lib/content_management/bloc/content_management_bloc.dart @@ -1,7 +1,6 @@ import 'package:bloc/bloc.dart'; import 'package:equatable/equatable.dart'; import 'package:ht_data_repository/ht_data_repository.dart'; -import 'package:ht_dashboard/shared/constants/pagination_constants.dart'; import 'package:ht_shared/ht_shared.dart'; part 'content_management_event.dart'; diff --git a/lib/content_management/bloc/create_source/create_source_bloc.dart b/lib/content_management/bloc/create_source/create_source_bloc.dart index 40b85e0c..18db57ff 100644 --- a/lib/content_management/bloc/create_source/create_source_bloc.dart +++ b/lib/content_management/bloc/create_source/create_source_bloc.dart @@ -37,7 +37,7 @@ class CreateSourceBloc extends Bloc { emit(state.copyWith(status: CreateSourceStatus.loading)); try { final countriesResponse = await _countriesRepository.readAll(); - final countries = (countriesResponse as PaginatedResponse).items; + final countries = countriesResponse.items; emit( state.copyWith( diff --git a/lib/content_management/bloc/edit_source/edit_source_bloc.dart b/lib/content_management/bloc/edit_source/edit_source_bloc.dart index 094a1838..6da5cb83 100644 --- a/lib/content_management/bloc/edit_source/edit_source_bloc.dart +++ b/lib/content_management/bloc/edit_source/edit_source_bloc.dart @@ -3,9 +3,7 @@ import 'package:equatable/equatable.dart'; import 'package:flutter/foundation.dart'; import 'package:ht_dashboard/l10n/app_localizations.dart'; import 'package:ht_data_repository/ht_data_repository.dart'; -import 'package:ht_http_client/ht_http_client.dart'; import 'package:ht_shared/ht_shared.dart'; -import 'package:ht_dashboard/l10n/l10n.dart'; part 'edit_source_event.dart'; part 'edit_source_state.dart'; diff --git a/lib/content_management/view/categories_page.dart b/lib/content_management/view/categories_page.dart index a8da96a5..13cf504f 100644 --- a/lib/content_management/view/categories_page.dart +++ b/lib/content_management/view/categories_page.dart @@ -4,16 +4,12 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dart'; import 'package:ht_dashboard/l10n/app_localizations.dart'; -import 'package:intl/intl.dart'; import 'package:ht_dashboard/l10n/l10n.dart'; import 'package:ht_dashboard/router/routes.dart'; import 'package:ht_dashboard/shared/constants/pagination_constants.dart'; -import 'package:ht_dashboard/shared/constants/app_spacing.dart'; import 'package:ht_dashboard/shared/shared.dart'; -import 'package:ht_dashboard/shared/widgets/failure_state_widget.dart'; -import 'package:ht_dashboard/shared/widgets/loading_state_widget.dart'; import 'package:ht_shared/ht_shared.dart'; -import 'package:ht_dashboard/shared/extensions/content_status_l10n.dart'; +import 'package:intl/intl.dart'; /// {@template categories_page} /// A page for displaying and managing Categories in a tabular format. diff --git a/lib/content_management/view/create_category_page.dart b/lib/content_management/view/create_category_page.dart index f3e39a4b..dc043a24 100644 --- a/lib/content_management/view/create_category_page.dart +++ b/lib/content_management/view/create_category_page.dart @@ -4,8 +4,6 @@ import 'package:go_router/go_router.dart'; import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dart'; import 'package:ht_dashboard/content_management/bloc/create_category/create_category_bloc.dart'; import 'package:ht_dashboard/l10n/l10n.dart'; -import 'package:ht_dashboard/shared/constants/pagination_constants.dart'; -import 'package:ht_dashboard/shared/extensions/content_status_l10n.dart'; import 'package:ht_dashboard/shared/shared.dart'; import 'package:ht_data_repository/ht_data_repository.dart'; import 'package:ht_shared/ht_shared.dart'; diff --git a/lib/content_management/view/create_headline_page.dart b/lib/content_management/view/create_headline_page.dart index 20d64e07..075d2a4d 100644 --- a/lib/content_management/view/create_headline_page.dart +++ b/lib/content_management/view/create_headline_page.dart @@ -3,9 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dart'; import 'package:ht_dashboard/content_management/bloc/create_headline/create_headline_bloc.dart'; -import 'package:ht_dashboard/shared/extensions/content_status_l10n.dart'; import 'package:ht_dashboard/l10n/l10n.dart'; -import 'package:ht_dashboard/shared/constants/pagination_constants.dart'; import 'package:ht_dashboard/shared/shared.dart'; import 'package:ht_data_repository/ht_data_repository.dart'; import 'package:ht_shared/ht_shared.dart'; diff --git a/lib/content_management/view/create_source_page.dart b/lib/content_management/view/create_source_page.dart index 8a514694..652b6896 100644 --- a/lib/content_management/view/create_source_page.dart +++ b/lib/content_management/view/create_source_page.dart @@ -4,9 +4,7 @@ import 'package:go_router/go_router.dart'; import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dart'; import 'package:ht_dashboard/content_management/bloc/create_source/create_source_bloc.dart'; import 'package:ht_dashboard/content_management/bloc/edit_source/edit_source_bloc.dart'; -import 'package:ht_dashboard/shared/extensions/content_status_l10n.dart'; import 'package:ht_dashboard/l10n/l10n.dart'; -import 'package:ht_dashboard/shared/constants/pagination_constants.dart'; import 'package:ht_dashboard/shared/shared.dart'; import 'package:ht_data_repository/ht_data_repository.dart'; import 'package:ht_shared/ht_shared.dart'; diff --git a/lib/content_management/view/edit_category_page.dart b/lib/content_management/view/edit_category_page.dart index 28680f76..2a888969 100644 --- a/lib/content_management/view/edit_category_page.dart +++ b/lib/content_management/view/edit_category_page.dart @@ -4,8 +4,6 @@ import 'package:go_router/go_router.dart'; import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dart'; import 'package:ht_dashboard/content_management/bloc/edit_category/edit_category_bloc.dart'; import 'package:ht_dashboard/l10n/l10n.dart'; -import 'package:ht_dashboard/shared/extensions/content_status_l10n.dart'; -import 'package:ht_dashboard/shared/constants/pagination_constants.dart'; import 'package:ht_dashboard/shared/shared.dart'; import 'package:ht_data_repository/ht_data_repository.dart'; import 'package:ht_shared/ht_shared.dart'; diff --git a/lib/content_management/view/edit_headline_page.dart b/lib/content_management/view/edit_headline_page.dart index e49d8c4b..3f90c5b1 100644 --- a/lib/content_management/view/edit_headline_page.dart +++ b/lib/content_management/view/edit_headline_page.dart @@ -3,9 +3,7 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dart'; import 'package:ht_dashboard/content_management/bloc/edit_headline/edit_headline_bloc.dart'; -import 'package:ht_dashboard/shared/extensions/content_status_l10n.dart'; import 'package:ht_dashboard/l10n/l10n.dart'; -import 'package:ht_dashboard/shared/constants/pagination_constants.dart'; import 'package:ht_dashboard/shared/shared.dart'; import 'package:ht_data_repository/ht_data_repository.dart'; import 'package:ht_shared/ht_shared.dart'; diff --git a/lib/content_management/view/edit_source_page.dart b/lib/content_management/view/edit_source_page.dart index 735173bd..469bbd59 100644 --- a/lib/content_management/view/edit_source_page.dart +++ b/lib/content_management/view/edit_source_page.dart @@ -4,8 +4,6 @@ import 'package:go_router/go_router.dart'; import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dart'; import 'package:ht_dashboard/content_management/bloc/edit_source/edit_source_bloc.dart'; import 'package:ht_dashboard/l10n/l10n.dart'; -import 'package:ht_dashboard/shared/extensions/content_status_l10n.dart'; -import 'package:ht_dashboard/shared/constants/pagination_constants.dart'; import 'package:ht_dashboard/shared/shared.dart'; import 'package:ht_data_repository/ht_data_repository.dart'; import 'package:ht_shared/ht_shared.dart'; diff --git a/lib/content_management/view/headlines_page.dart b/lib/content_management/view/headlines_page.dart index 46078a8a..55beb513 100644 --- a/lib/content_management/view/headlines_page.dart +++ b/lib/content_management/view/headlines_page.dart @@ -3,16 +3,16 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dart'; -import 'package:intl/intl.dart'; import 'package:ht_dashboard/l10n/app_localizations.dart'; // Corrected import import 'package:ht_dashboard/l10n/l10n.dart'; import 'package:ht_dashboard/router/routes.dart'; import 'package:ht_dashboard/shared/constants/app_spacing.dart'; +import 'package:ht_dashboard/shared/constants/pagination_constants.dart'; import 'package:ht_dashboard/shared/extensions/content_status_l10n.dart'; import 'package:ht_dashboard/shared/widgets/failure_state_widget.dart'; import 'package:ht_dashboard/shared/widgets/loading_state_widget.dart'; import 'package:ht_shared/ht_shared.dart'; -import 'package:ht_dashboard/shared/constants/pagination_constants.dart'; +import 'package:intl/intl.dart'; /// {@template headlines_page} /// A page for displaying and managing Headlines in a tabular format. diff --git a/lib/content_management/view/sources_page.dart b/lib/content_management/view/sources_page.dart index e426a597..2cbf184c 100644 --- a/lib/content_management/view/sources_page.dart +++ b/lib/content_management/view/sources_page.dart @@ -4,16 +4,16 @@ import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:go_router/go_router.dart'; import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dart'; import 'package:ht_dashboard/content_management/bloc/edit_source/edit_source_bloc.dart'; -import 'package:intl/intl.dart'; import 'package:ht_dashboard/l10n/app_localizations.dart'; -import 'package:ht_dashboard/shared/extensions/content_status_l10n.dart'; import 'package:ht_dashboard/l10n/l10n.dart'; import 'package:ht_dashboard/router/routes.dart'; -import 'package:ht_dashboard/shared/constants/pagination_constants.dart'; import 'package:ht_dashboard/shared/constants/app_spacing.dart'; +import 'package:ht_dashboard/shared/constants/pagination_constants.dart'; +import 'package:ht_dashboard/shared/extensions/content_status_l10n.dart'; import 'package:ht_dashboard/shared/widgets/failure_state_widget.dart'; import 'package:ht_dashboard/shared/widgets/loading_state_widget.dart'; import 'package:ht_shared/ht_shared.dart'; +import 'package:intl/intl.dart'; /// {@template sources_page} /// A page for displaying and managing Sources in a tabular format.