diff --git a/lib/bloc_observer.dart b/lib/bloc_observer.dart index 97afcf4..0439dac 100644 --- a/lib/bloc_observer.dart +++ b/lib/bloc_observer.dart @@ -9,11 +9,13 @@ class AppBlocObserver extends BlocObserver { void onChange(BlocBase bloc, Change change) { super.onChange(bloc, change); log('onChange(${bloc.runtimeType}, $change)'); + print('onChange(${bloc.runtimeType}, $change)'); } @override void onError(BlocBase bloc, Object error, StackTrace stackTrace) { log('onError(${bloc.runtimeType}, $error, $stackTrace)'); + print('onError(${bloc.runtimeType}, $error, $stackTrace)'); super.onError(bloc, error, stackTrace); } } 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 164e459..845c258 100644 --- a/lib/content_management/bloc/create_category/create_category_bloc.dart +++ b/lib/content_management/bloc/create_category/create_category_bloc.dart @@ -17,6 +17,7 @@ class CreateCategoryBloc on(_onNameChanged); on(_onDescriptionChanged); on(_onIconUrlChanged); + on(_onStatusChanged); on(_onSubmitted); } @@ -58,6 +59,18 @@ class CreateCategoryBloc ); } + void _onStatusChanged( + CreateCategoryStatusChanged event, + Emitter emit, + ) { + emit( + state.copyWith( + contentStatus: event.status, + status: CreateCategoryStatus.initial, + ), + ); + } + Future _onSubmitted( CreateCategorySubmitted event, Emitter emit, @@ -70,6 +83,7 @@ class CreateCategoryBloc name: state.name, description: state.description.isNotEmpty ? state.description : null, iconUrl: state.iconUrl.isNotEmpty ? state.iconUrl : null, + status: state.contentStatus, ); await _categoriesRepository.create(item: newCategory); diff --git a/lib/content_management/bloc/create_category/create_category_event.dart b/lib/content_management/bloc/create_category/create_category_event.dart index e159d37..591e570 100644 --- a/lib/content_management/bloc/create_category/create_category_event.dart +++ b/lib/content_management/bloc/create_category/create_category_event.dart @@ -5,7 +5,7 @@ sealed class CreateCategoryEvent extends Equatable { const CreateCategoryEvent(); @override - List get props => []; + List get props => []; } /// Event for when the category's name is changed. @@ -13,7 +13,7 @@ final class CreateCategoryNameChanged extends CreateCategoryEvent { const CreateCategoryNameChanged(this.name); final String name; @override - List get props => [name]; + List get props => [name]; } /// Event for when the category's description is changed. @@ -21,7 +21,7 @@ final class CreateCategoryDescriptionChanged extends CreateCategoryEvent { const CreateCategoryDescriptionChanged(this.description); final String description; @override - List get props => [description]; + List get props => [description]; } /// Event for when the category's icon URL is changed. @@ -29,7 +29,16 @@ final class CreateCategoryIconUrlChanged extends CreateCategoryEvent { const CreateCategoryIconUrlChanged(this.iconUrl); final String iconUrl; @override - List get props => [iconUrl]; + List get props => [iconUrl]; +} + +/// Event for when the category's status is changed. +final class CreateCategoryStatusChanged extends CreateCategoryEvent { + const CreateCategoryStatusChanged(this.status); + + final ContentStatus status; + @override + List get props => [status]; } /// Event to signal that the form should be submitted. 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 7c4fdee..47884d5 100644 --- a/lib/content_management/bloc/create_category/create_category_state.dart +++ b/lib/content_management/bloc/create_category/create_category_state.dart @@ -23,6 +23,7 @@ final class CreateCategoryState extends Equatable { this.name = '', this.description = '', this.iconUrl = '', + this.contentStatus = ContentStatus.active, this.errorMessage, }); @@ -30,6 +31,7 @@ final class CreateCategoryState extends Equatable { final String name; final String description; final String iconUrl; + final ContentStatus contentStatus; final String? errorMessage; /// Returns true if the form is valid and can be submitted. @@ -41,6 +43,7 @@ final class CreateCategoryState extends Equatable { String? name, String? description, String? iconUrl, + ContentStatus? contentStatus, String? errorMessage, }) { return CreateCategoryState( @@ -48,10 +51,18 @@ final class CreateCategoryState extends Equatable { name: name ?? this.name, description: description ?? this.description, iconUrl: iconUrl ?? this.iconUrl, + contentStatus: contentStatus ?? this.contentStatus, errorMessage: errorMessage, ); } @override - List get props => [status, name, description, iconUrl, errorMessage]; + List get props => [ + status, + name, + description, + iconUrl, + contentStatus, + errorMessage, + ]; } 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 8d03524..412416b 100644 --- a/lib/content_management/bloc/create_headline/create_headline_bloc.dart +++ b/lib/content_management/bloc/create_headline/create_headline_bloc.dart @@ -26,6 +26,7 @@ class CreateHeadlineBloc on(_onImageUrlChanged); on(_onSourceChanged); on(_onCategoryChanged); + on(_onStatusChanged); on(_onSubmitted); } @@ -114,6 +115,18 @@ class CreateHeadlineBloc emit(state.copyWith(category: () => event.category)); } + void _onStatusChanged( + CreateHeadlineStatusChanged event, + Emitter emit, + ) { + emit( + state.copyWith( + contentStatus: event.status, + status: CreateHeadlineStatus.initial, + ), + ); + } + Future _onSubmitted( CreateHeadlineSubmitted event, Emitter emit, @@ -129,6 +142,7 @@ class CreateHeadlineBloc imageUrl: state.imageUrl.isNotEmpty ? state.imageUrl : null, source: state.source, category: state.category, + status: state.contentStatus, ); await _headlinesRepository.create(item: newHeadline); diff --git a/lib/content_management/bloc/create_headline/create_headline_event.dart b/lib/content_management/bloc/create_headline/create_headline_event.dart index de06564..63d04c1 100644 --- a/lib/content_management/bloc/create_headline/create_headline_event.dart +++ b/lib/content_management/bloc/create_headline/create_headline_event.dart @@ -1,7 +1,7 @@ part of 'create_headline_bloc.dart'; /// Base class for all events related to the [CreateHeadlineBloc]. -abstract class CreateHeadlineEvent extends Equatable { +sealed class CreateHeadlineEvent extends Equatable { const CreateHeadlineEvent(); @override @@ -9,44 +9,44 @@ abstract class CreateHeadlineEvent extends Equatable { } /// Event to signal that the data for dropdowns should be loaded. -class CreateHeadlineDataLoaded extends CreateHeadlineEvent { +final class CreateHeadlineDataLoaded extends CreateHeadlineEvent { const CreateHeadlineDataLoaded(); } /// Event for when the headline's title is changed. -class CreateHeadlineTitleChanged extends CreateHeadlineEvent { +final class CreateHeadlineTitleChanged extends CreateHeadlineEvent { const CreateHeadlineTitleChanged(this.title); final String title; @override - List get props => [title]; + List get props => [title]; } /// Event for when the headline's description is changed. -class CreateHeadlineDescriptionChanged extends CreateHeadlineEvent { +final class CreateHeadlineDescriptionChanged extends CreateHeadlineEvent { const CreateHeadlineDescriptionChanged(this.description); final String description; @override - List get props => [description]; + List get props => [description]; } /// Event for when the headline's URL is changed. -class CreateHeadlineUrlChanged extends CreateHeadlineEvent { +final class CreateHeadlineUrlChanged extends CreateHeadlineEvent { const CreateHeadlineUrlChanged(this.url); final String url; @override - List get props => [url]; + List get props => [url]; } /// Event for when the headline's image URL is changed. -class CreateHeadlineImageUrlChanged extends CreateHeadlineEvent { +final class CreateHeadlineImageUrlChanged extends CreateHeadlineEvent { const CreateHeadlineImageUrlChanged(this.imageUrl); final String imageUrl; @override - List get props => [imageUrl]; + List get props => [imageUrl]; } /// Event for when the headline's source is changed. -class CreateHeadlineSourceChanged extends CreateHeadlineEvent { +final class CreateHeadlineSourceChanged extends CreateHeadlineEvent { const CreateHeadlineSourceChanged(this.source); final Source? source; @override @@ -54,15 +54,24 @@ class CreateHeadlineSourceChanged extends CreateHeadlineEvent { } /// Event for when the headline's category is changed. -class CreateHeadlineCategoryChanged extends CreateHeadlineEvent { +final class CreateHeadlineCategoryChanged extends CreateHeadlineEvent { const CreateHeadlineCategoryChanged(this.category); final Category? category; @override List get props => [category]; } +/// Event for when the headline's status is changed. +final class CreateHeadlineStatusChanged extends CreateHeadlineEvent { + const CreateHeadlineStatusChanged(this.status); + + final ContentStatus status; + + @override + List get props => [status]; +} + /// Event to signal that the form should be submitted. -class CreateHeadlineSubmitted extends CreateHeadlineEvent { +final class CreateHeadlineSubmitted extends CreateHeadlineEvent { const CreateHeadlineSubmitted(); } - 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 c0ed1ae..f809b6e 100644 --- a/lib/content_management/bloc/create_headline/create_headline_state.dart +++ b/lib/content_management/bloc/create_headline/create_headline_state.dart @@ -30,6 +30,7 @@ final class CreateHeadlineState extends Equatable { this.category, this.sources = const [], this.categories = const [], + this.contentStatus = ContentStatus.active, this.errorMessage, }); @@ -42,6 +43,7 @@ final class CreateHeadlineState extends Equatable { final Category? category; final List sources; final List categories; + final ContentStatus contentStatus; final String? errorMessage; /// Returns true if the form is valid and can be submitted. @@ -57,6 +59,7 @@ final class CreateHeadlineState extends Equatable { ValueGetter? category, List? sources, List? categories, + ContentStatus? contentStatus, String? errorMessage, }) { return CreateHeadlineState( @@ -69,22 +72,23 @@ final class CreateHeadlineState extends Equatable { category: category != null ? category() : this.category, sources: sources ?? this.sources, categories: categories ?? this.categories, + contentStatus: contentStatus ?? this.contentStatus, errorMessage: errorMessage ?? this.errorMessage, ); } @override List get props => [ - status, - title, - description, - url, - imageUrl, - source, - category, - sources, - categories, - errorMessage, - ]; + status, + title, + description, + url, + imageUrl, + source, + category, + sources, + categories, + contentStatus, + errorMessage, + ]; } - 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 4448de9..533dff1 100644 --- a/lib/content_management/bloc/create_source/create_source_bloc.dart +++ b/lib/content_management/bloc/create_source/create_source_bloc.dart @@ -23,6 +23,7 @@ class CreateSourceBloc extends Bloc { on(_onSourceTypeChanged); on(_onLanguageChanged); on(_onHeadquartersChanged); + on(_onStatusChanged); on(_onSubmitted); } @@ -103,6 +104,18 @@ class CreateSourceBloc extends Bloc { emit(state.copyWith(headquarters: () => event.headquarters)); } + void _onStatusChanged( + CreateSourceStatusChanged event, + Emitter emit, + ) { + emit( + state.copyWith( + contentStatus: event.status, + status: CreateSourceStatus.initial, + ), + ); + } + Future _onSubmitted( CreateSourceSubmitted event, Emitter emit, @@ -118,6 +131,7 @@ class CreateSourceBloc extends Bloc { sourceType: state.sourceType, language: state.language.isNotEmpty ? state.language : null, headquarters: state.headquarters, + status: state.contentStatus, ); await _sourcesRepository.create(item: newSource); diff --git a/lib/content_management/bloc/create_source/create_source_event.dart b/lib/content_management/bloc/create_source/create_source_event.dart index 055ebf7..8838dd6 100644 --- a/lib/content_management/bloc/create_source/create_source_event.dart +++ b/lib/content_management/bloc/create_source/create_source_event.dart @@ -18,7 +18,7 @@ final class CreateSourceNameChanged extends CreateSourceEvent { const CreateSourceNameChanged(this.name); final String name; @override - List get props => [name]; + List get props => [name]; } /// Event for when the source's description is changed. @@ -26,7 +26,7 @@ final class CreateSourceDescriptionChanged extends CreateSourceEvent { const CreateSourceDescriptionChanged(this.description); final String description; @override - List get props => [description]; + List get props => [description]; } /// Event for when the source's URL is changed. @@ -34,7 +34,7 @@ final class CreateSourceUrlChanged extends CreateSourceEvent { const CreateSourceUrlChanged(this.url); final String url; @override - List get props => [url]; + List get props => [url]; } /// Event for when the source's type is changed. @@ -50,7 +50,7 @@ final class CreateSourceLanguageChanged extends CreateSourceEvent { const CreateSourceLanguageChanged(this.language); final String language; @override - List get props => [language]; + List get props => [language]; } /// Event for when the source's headquarters is changed. @@ -61,6 +61,16 @@ final class CreateSourceHeadquartersChanged extends CreateSourceEvent { List get props => [headquarters]; } +/// Event for when the source's status is changed. +final class CreateSourceStatusChanged extends CreateSourceEvent { + const CreateSourceStatusChanged(this.status); + + final ContentStatus status; + + @override + List get props => [status]; +} + /// Event to signal that the form should be submitted. final class CreateSourceSubmitted extends CreateSourceEvent { const CreateSourceSubmitted(); 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 469d3ea..8a6f837 100644 --- a/lib/content_management/bloc/create_source/create_source_state.dart +++ b/lib/content_management/bloc/create_source/create_source_state.dart @@ -30,6 +30,7 @@ final class CreateSourceState extends Equatable { this.language = '', this.headquarters, this.countries = const [], + this.contentStatus = ContentStatus.active, this.errorMessage, }); @@ -41,6 +42,8 @@ final class CreateSourceState extends Equatable { final String language; final Country? headquarters; final List countries; + final ContentStatus contentStatus; + final String? errorMessage; /// Returns true if the form is valid and can be submitted. @@ -55,6 +58,8 @@ final class CreateSourceState extends Equatable { String? language, ValueGetter? headquarters, List? countries, + ContentStatus? contentStatus, + String? errorMessage, }) { return CreateSourceState( @@ -66,6 +71,8 @@ final class CreateSourceState extends Equatable { language: language ?? this.language, headquarters: headquarters != null ? headquarters() : this.headquarters, countries: countries ?? this.countries, + contentStatus: contentStatus ?? this.contentStatus, + errorMessage: errorMessage, ); } @@ -80,6 +87,7 @@ final class CreateSourceState extends Equatable { language, headquarters, countries, + contentStatus, errorMessage, ]; } 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 6266e16..3f67aa0 100644 --- a/lib/content_management/bloc/edit_category/edit_category_bloc.dart +++ b/lib/content_management/bloc/edit_category/edit_category_bloc.dart @@ -19,6 +19,7 @@ class EditCategoryBloc extends Bloc { on(_onNameChanged); on(_onDescriptionChanged); on(_onIconUrlChanged); + on(_onStatusChanged); on(_onSubmitted); } @@ -39,6 +40,7 @@ class EditCategoryBloc extends Bloc { name: category.name, description: category.description ?? '', iconUrl: category.iconUrl ?? '', + contentStatus: category.status, ), ); } on HtHttpException catch (e) { @@ -95,6 +97,18 @@ class EditCategoryBloc extends Bloc { ); } + void _onStatusChanged( + EditCategoryStatusChanged event, + Emitter emit, + ) { + emit( + state.copyWith( + contentStatus: event.status, + status: EditCategoryStatus.initial, + ), + ); + } + Future _onSubmitted( EditCategorySubmitted event, Emitter emit, @@ -120,6 +134,7 @@ class EditCategoryBloc extends Bloc { name: state.name, description: state.description.isNotEmpty ? state.description : null, iconUrl: state.iconUrl.isNotEmpty ? state.iconUrl : null, + status: state.contentStatus, ); await _categoriesRepository.update( diff --git a/lib/content_management/bloc/edit_category/edit_category_event.dart b/lib/content_management/bloc/edit_category/edit_category_event.dart index cea54d4..f830195 100644 --- a/lib/content_management/bloc/edit_category/edit_category_event.dart +++ b/lib/content_management/bloc/edit_category/edit_category_event.dart @@ -5,7 +5,7 @@ sealed class EditCategoryEvent extends Equatable { const EditCategoryEvent(); @override - List get props => []; + List get props => []; } /// Event to load the initial category data for editing. @@ -20,7 +20,7 @@ final class EditCategoryNameChanged extends EditCategoryEvent { final String name; @override - List get props => [name]; + List get props => [name]; } /// Event triggered when the category description input changes. @@ -30,7 +30,7 @@ final class EditCategoryDescriptionChanged extends EditCategoryEvent { final String description; @override - List get props => [description]; + List get props => [description]; } /// Event triggered when the category icon URL input changes. @@ -40,7 +40,17 @@ final class EditCategoryIconUrlChanged extends EditCategoryEvent { final String iconUrl; @override - List get props => [iconUrl]; + List get props => [iconUrl]; +} + +/// Event for when the category's status is changed. +final class EditCategoryStatusChanged extends EditCategoryEvent { + const EditCategoryStatusChanged(this.status); + + final ContentStatus status; + + @override + List get props => [status]; } /// Event to submit the edited category data. 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 9f6537f..c38f0e2 100644 --- a/lib/content_management/bloc/edit_category/edit_category_state.dart +++ b/lib/content_management/bloc/edit_category/edit_category_state.dart @@ -26,6 +26,7 @@ final class EditCategoryState extends Equatable { this.name = '', this.description = '', this.iconUrl = '', + this.contentStatus = ContentStatus.active, this.errorMessage, }); @@ -34,6 +35,7 @@ final class EditCategoryState extends Equatable { final String name; final String description; final String iconUrl; + final ContentStatus contentStatus; final String? errorMessage; /// Returns true if the form is valid and can be submitted. @@ -45,6 +47,7 @@ final class EditCategoryState extends Equatable { String? name, String? description, String? iconUrl, + ContentStatus? contentStatus, String? errorMessage, }) { return EditCategoryState( @@ -53,12 +56,19 @@ final class EditCategoryState extends Equatable { name: name ?? this.name, description: description ?? this.description, iconUrl: iconUrl ?? this.iconUrl, + contentStatus: contentStatus ?? this.contentStatus, errorMessage: errorMessage ?? this.errorMessage, ); } @override - List get props => - [status, initialCategory, name, description, iconUrl, errorMessage]; + List get props => [ + status, + initialCategory, + name, + description, + iconUrl, + contentStatus, + errorMessage, + ]; } - 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 da2fee1..b8f12f5 100644 --- a/lib/content_management/bloc/edit_headline/edit_headline_bloc.dart +++ b/lib/content_management/bloc/edit_headline/edit_headline_bloc.dart @@ -27,6 +27,7 @@ class EditHeadlineBloc extends Bloc { on(_onImageUrlChanged); on(_onSourceChanged); on(_onCategoryChanged); + on(_onStatusChanged); on(_onSubmitted); } @@ -68,6 +69,7 @@ class EditHeadlineBloc extends Bloc { category: () => headline.category, sources: sources, categories: categories, + contentStatus: headline.status, ), ); } on HtHttpException catch (e) { @@ -151,6 +153,18 @@ class EditHeadlineBloc extends Bloc { ); } + void _onStatusChanged( + EditHeadlineStatusChanged event, + Emitter emit, + ) { + emit( + state.copyWith( + contentStatus: event.status, + status: EditHeadlineStatus.initial, + ), + ); + } + Future _onSubmitted( EditHeadlineSubmitted event, Emitter emit, @@ -177,6 +191,7 @@ class EditHeadlineBloc extends Bloc { imageUrl: state.imageUrl.isNotEmpty ? state.imageUrl : null, source: state.source, category: state.category, + status: state.contentStatus, ); await _headlinesRepository.update(id: _headlineId, item: updatedHeadline); diff --git a/lib/content_management/bloc/edit_headline/edit_headline_event.dart b/lib/content_management/bloc/edit_headline/edit_headline_event.dart index 8b71944..44e4e81 100644 --- a/lib/content_management/bloc/edit_headline/edit_headline_event.dart +++ b/lib/content_management/bloc/edit_headline/edit_headline_event.dart @@ -1,7 +1,7 @@ part of 'edit_headline_bloc.dart'; /// Base class for all events related to the [EditHeadlineBloc]. -abstract class EditHeadlineEvent extends Equatable { +sealed class EditHeadlineEvent extends Equatable { const EditHeadlineEvent(); @override @@ -9,44 +9,44 @@ abstract class EditHeadlineEvent extends Equatable { } /// Event to signal that the headline data should be loaded. -class EditHeadlineLoaded extends EditHeadlineEvent { +final class EditHeadlineLoaded extends EditHeadlineEvent { const EditHeadlineLoaded(); } /// Event for when the headline's title is changed. -class EditHeadlineTitleChanged extends EditHeadlineEvent { +final class EditHeadlineTitleChanged extends EditHeadlineEvent { const EditHeadlineTitleChanged(this.title); final String title; @override - List get props => [title]; + List get props => [title]; } /// Event for when the headline's description is changed. -class EditHeadlineDescriptionChanged extends EditHeadlineEvent { +final class EditHeadlineDescriptionChanged extends EditHeadlineEvent { const EditHeadlineDescriptionChanged(this.description); final String description; @override - List get props => [description]; + List get props => [description]; } /// Event for when the headline's URL is changed. -class EditHeadlineUrlChanged extends EditHeadlineEvent { +final class EditHeadlineUrlChanged extends EditHeadlineEvent { const EditHeadlineUrlChanged(this.url); final String url; @override - List get props => [url]; + List get props => [url]; } /// Event for when the headline's image URL is changed. -class EditHeadlineImageUrlChanged extends EditHeadlineEvent { +final class EditHeadlineImageUrlChanged extends EditHeadlineEvent { const EditHeadlineImageUrlChanged(this.imageUrl); final String imageUrl; @override - List get props => [imageUrl]; + List get props => [imageUrl]; } /// Event for when the headline's source is changed. -class EditHeadlineSourceChanged extends EditHeadlineEvent { +final class EditHeadlineSourceChanged extends EditHeadlineEvent { const EditHeadlineSourceChanged(this.source); final Source? source; @override @@ -54,15 +54,24 @@ class EditHeadlineSourceChanged extends EditHeadlineEvent { } /// Event for when the headline's category is changed. -class EditHeadlineCategoryChanged extends EditHeadlineEvent { +final class EditHeadlineCategoryChanged extends EditHeadlineEvent { const EditHeadlineCategoryChanged(this.category); final Category? category; @override List get props => [category]; } +/// Event for when the headline's status is changed. +final class EditHeadlineStatusChanged extends EditHeadlineEvent { + const EditHeadlineStatusChanged(this.status); + + final ContentStatus status; + + @override + List get props => [status]; +} + /// Event to signal that the form should be submitted. -class EditHeadlineSubmitted extends EditHeadlineEvent { +final class EditHeadlineSubmitted extends EditHeadlineEvent { const EditHeadlineSubmitted(); } - 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 c2463c7..5bbb617 100644 --- a/lib/content_management/bloc/edit_headline/edit_headline_state.dart +++ b/lib/content_management/bloc/edit_headline/edit_headline_state.dart @@ -31,6 +31,7 @@ final class EditHeadlineState extends Equatable { this.category, this.sources = const [], this.categories = const [], + this.contentStatus = ContentStatus.active, this.errorMessage, }); @@ -44,6 +45,7 @@ final class EditHeadlineState extends Equatable { final Category? category; final List sources; final List categories; + final ContentStatus contentStatus; final String? errorMessage; /// Returns true if the form is valid and can be submitted. @@ -60,6 +62,7 @@ final class EditHeadlineState extends Equatable { ValueGetter? category, List? sources, List? categories, + ContentStatus? contentStatus, String? errorMessage, }) { return EditHeadlineState( @@ -73,22 +76,24 @@ final class EditHeadlineState extends Equatable { category: category != null ? category() : this.category, sources: sources ?? this.sources, categories: categories ?? this.categories, + contentStatus: contentStatus ?? this.contentStatus, errorMessage: errorMessage ?? this.errorMessage, ); } @override List get props => [ - status, - initialHeadline, - title, - description, - url, - imageUrl, - source, - category, - sources, - categories, - errorMessage, - ]; + status, + initialHeadline, + title, + description, + url, + imageUrl, + source, + category, + sources, + categories, + contentStatus, + errorMessage, + ]; } 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 f00cf3c..73e7a3d 100644 --- a/lib/content_management/bloc/edit_source/edit_source_bloc.dart +++ b/lib/content_management/bloc/edit_source/edit_source_bloc.dart @@ -28,6 +28,7 @@ class EditSourceBloc extends Bloc { on(_onSourceTypeChanged); on(_onLanguageChanged); on(_onHeadquartersChanged); + on(_onStatusChanged); on(_onSubmitted); } @@ -57,6 +58,7 @@ class EditSourceBloc extends Bloc { sourceType: () => source.sourceType, language: source.language ?? '', headquarters: () => source.headquarters, + contentStatus: source.status, countries: countries, ), ); @@ -139,6 +141,18 @@ class EditSourceBloc extends Bloc { ); } + void _onStatusChanged( + EditSourceStatusChanged event, + Emitter emit, + ) { + emit( + state.copyWith( + contentStatus: event.status, + status: EditSourceStatus.initial, + ), + ); + } + Future _onSubmitted( EditSourceSubmitted event, Emitter emit, @@ -165,6 +179,7 @@ class EditSourceBloc extends Bloc { sourceType: state.sourceType, language: state.language.isNotEmpty ? state.language : null, headquarters: state.headquarters, + status: state.contentStatus, ); await _sourcesRepository.update(id: _sourceId, item: updatedSource); diff --git a/lib/content_management/bloc/edit_source/edit_source_event.dart b/lib/content_management/bloc/edit_source/edit_source_event.dart index 678e4ef..6a7246a 100644 --- a/lib/content_management/bloc/edit_source/edit_source_event.dart +++ b/lib/content_management/bloc/edit_source/edit_source_event.dart @@ -20,7 +20,7 @@ final class EditSourceNameChanged extends EditSourceEvent { final String name; @override - List get props => [name]; + List get props => [name]; } /// Event triggered when the source description input changes. @@ -30,7 +30,7 @@ final class EditSourceDescriptionChanged extends EditSourceEvent { final String description; @override - List get props => [description]; + List get props => [description]; } /// Event triggered when the source URL input changes. @@ -40,7 +40,7 @@ final class EditSourceUrlChanged extends EditSourceEvent { final String url; @override - List get props => [url]; + List get props => [url]; } /// Event triggered when the source type input changes. @@ -60,7 +60,7 @@ final class EditSourceLanguageChanged extends EditSourceEvent { final String language; @override - List get props => [language]; + List get props => [language]; } /// Event triggered when the source headquarters input changes. @@ -73,6 +73,16 @@ final class EditSourceHeadquartersChanged extends EditSourceEvent { List get props => [headquarters]; } +/// Event for when the source's status is changed. +final class EditSourceStatusChanged extends EditSourceEvent { + const EditSourceStatusChanged(this.status); + + final ContentStatus status; + + @override + List get props => [status]; +} + /// Event to submit the edited source data. final class EditSourceSubmitted extends EditSourceEvent { const EditSourceSubmitted(); 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 950cb29..8590885 100644 --- a/lib/content_management/bloc/edit_source/edit_source_state.dart +++ b/lib/content_management/bloc/edit_source/edit_source_state.dart @@ -30,6 +30,7 @@ final class EditSourceState extends Equatable { this.language = '', this.headquarters, this.countries = const [], + this.contentStatus = ContentStatus.active, this.errorMessage, }); @@ -42,6 +43,7 @@ final class EditSourceState extends Equatable { final String language; final Country? headquarters; final List countries; + final ContentStatus contentStatus; final String? errorMessage; /// Returns true if the form is valid and can be submitted. @@ -57,6 +59,7 @@ final class EditSourceState extends Equatable { String? language, ValueGetter? headquarters, List? countries, + ContentStatus? contentStatus, String? errorMessage, }) { return EditSourceState( @@ -69,6 +72,7 @@ final class EditSourceState extends Equatable { language: language ?? this.language, headquarters: headquarters != null ? headquarters() : this.headquarters, countries: countries ?? this.countries, + contentStatus: contentStatus ?? this.contentStatus, errorMessage: errorMessage ?? this.errorMessage, ); } @@ -84,6 +88,7 @@ final class EditSourceState extends Equatable { language, headquarters, countries, + contentStatus, errorMessage, ]; } diff --git a/lib/content_management/view/categories_page.dart b/lib/content_management/view/categories_page.dart index 4cfc6cc..b0b9b69 100644 --- a/lib/content_management/view/categories_page.dart +++ b/lib/content_management/view/categories_page.dart @@ -8,9 +8,11 @@ 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'; /// {@template categories_page} /// A page for displaying and managing Categories in a tabular format. @@ -70,12 +72,17 @@ class _CategoriesPageState extends State { size: ColumnSize.L, ), DataColumn2( - label: Text(l10n.description), + label: Text(l10n.status), + size: ColumnSize.S, + ), + DataColumn2( + label: Text(l10n.lastUpdated), size: ColumnSize.M, ), DataColumn2( label: Text(l10n.actions), size: ColumnSize.S, + fixedWidth: 120, ), ], source: _CategoriesDataSource( @@ -137,16 +144,25 @@ class _CategoriesDataSource extends DataTableSource { // If we are loading, show a spinner. Otherwise, we've reached the end. if (isLoading) { return DataRow2( - cells: List.generate(3, (_) => const DataCell(Center(child: CircularProgressIndicator()))), + cells: List.generate( + 4, + (_) => const DataCell(Center(child: CircularProgressIndicator())), + ), ); } return null; } final category = categories[index]; return DataRow2( + onSelectChanged: (selected) { + if (selected ?? false) { + context.goNamed(Routes.editCategoryName, pathParameters: {'id': category.id}); + } + }, cells: [ DataCell(Text(category.name)), - DataCell(Text(category.description ?? l10n.notAvailable)), + DataCell(Text(category.status.l10n(context))), + DataCell(Text(category.updatedAt?.toLocal().toString() ?? l10n.notAvailable)), DataCell( Row( children: [ diff --git a/lib/content_management/view/create_category_page.dart b/lib/content_management/view/create_category_page.dart index f2e2e77..470ca99 100644 --- a/lib/content_management/view/create_category_page.dart +++ b/lib/content_management/view/create_category_page.dart @@ -5,6 +5,7 @@ import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dar 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'; @@ -83,9 +84,9 @@ class _CreateCategoryViewState extends State<_CreateCategoryView> { ), ); context.read().add( - const LoadCategoriesRequested( - limit: kDefaultRowsPerPage, - ), + const LoadCategoriesRequested( + limit: kDefaultRowsPerPage, + ), ); context.pop(); } @@ -142,6 +143,26 @@ class _CreateCategoryViewState extends State<_CreateCategoryView> { .read() .add(CreateCategoryIconUrlChanged(value)), ), + const SizedBox(height: AppSpacing.lg), + DropdownButtonFormField( + value: state.contentStatus, + decoration: InputDecoration( + labelText: l10n.status, + border: const OutlineInputBorder(), + ), + items: ContentStatus.values.map((status) { + return DropdownMenuItem( + value: status, + child: Text(status.l10n(context)), + ); + }).toList(), + onChanged: (value) { + if (value == null) return; + 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 cfbd1ae..06a79b7 100644 --- a/lib/content_management/view/create_headline_page.dart +++ b/lib/content_management/view/create_headline_page.dart @@ -3,6 +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'; @@ -85,9 +86,9 @@ class _CreateHeadlineViewState extends State<_CreateHeadlineView> { ), ); context.read().add( - const LoadHeadlinesRequested( - limit: kDefaultRowsPerPage, - ), + const LoadHeadlinesRequested( + limit: kDefaultRowsPerPage, + ), ); context.pop(); } @@ -214,6 +215,26 @@ class _CreateHeadlineViewState extends State<_CreateHeadlineView> { .read() .add(CreateHeadlineCategoryChanged(value)), ), + const SizedBox(height: AppSpacing.lg), + DropdownButtonFormField( + value: state.contentStatus, + decoration: InputDecoration( + labelText: l10n.status, + border: const OutlineInputBorder(), + ), + items: ContentStatus.values.map((status) { + return DropdownMenuItem( + value: status, + child: Text(status.l10n(context)), + ); + }).toList(), + onChanged: (value) { + if (value == null) return; + context.read().add( + CreateHeadlineStatusChanged(value), + ); + }, + ), ], ), ), diff --git a/lib/content_management/view/create_source_page.dart b/lib/content_management/view/create_source_page.dart index 1239b33..b91c522 100644 --- a/lib/content_management/view/create_source_page.dart +++ b/lib/content_management/view/create_source_page.dart @@ -4,6 +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'; @@ -211,6 +212,26 @@ class _CreateSourceViewState extends State<_CreateSourceView> { .read() .add(CreateSourceHeadquartersChanged(value)), ), + const SizedBox(height: AppSpacing.lg), + DropdownButtonFormField( + value: state.contentStatus, + decoration: InputDecoration( + labelText: l10n.status, + border: const OutlineInputBorder(), + ), + items: ContentStatus.values.map((status) { + return DropdownMenuItem( + value: status, + child: Text(status.l10n(context)), + ); + }).toList(), + onChanged: (value) { + if (value == null) return; + context.read().add( + CreateSourceStatusChanged(value), + ); + }, + ), ], ), ), diff --git a/lib/content_management/view/edit_category_page.dart b/lib/content_management/view/edit_category_page.dart index 902b4e0..42b7184 100644 --- a/lib/content_management/view/edit_category_page.dart +++ b/lib/content_management/view/edit_category_page.dart @@ -4,6 +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/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'; @@ -109,9 +110,9 @@ class _EditCategoryViewState extends State<_EditCategoryView> { const SnackBar(content: Text('Category updated successfully.')), ); context.read().add( - const LoadCategoriesRequested( - limit: kDefaultRowsPerPage, - ), + const LoadCategoriesRequested( + limit: kDefaultRowsPerPage, + ), ); context.pop(); } @@ -192,6 +193,26 @@ class _EditCategoryViewState extends State<_EditCategoryView> { .read() .add(EditCategoryIconUrlChanged(value)), ), + const SizedBox(height: AppSpacing.lg), + DropdownButtonFormField( + value: state.contentStatus, + decoration: InputDecoration( + labelText: l10n.status, + border: const OutlineInputBorder(), + ), + items: ContentStatus.values.map((status) { + return DropdownMenuItem( + value: status, + child: Text(status.l10n(context)), + ); + }).toList(), + onChanged: (value) { + if (value == null) return; + context.read().add( + EditCategoryStatusChanged(value), + ); + }, + ), ], ), ), diff --git a/lib/content_management/view/edit_headline_page.dart b/lib/content_management/view/edit_headline_page.dart index 83922ce..7f1215b 100644 --- a/lib/content_management/view/edit_headline_page.dart +++ b/lib/content_management/view/edit_headline_page.dart @@ -3,6 +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'; @@ -273,6 +274,26 @@ class _EditHeadlineViewState extends State<_EditHeadlineView> { .read() .add(EditHeadlineCategoryChanged(value)), ), + const SizedBox(height: AppSpacing.lg), + DropdownButtonFormField( + value: state.contentStatus, + decoration: InputDecoration( + labelText: l10n.status, + border: const OutlineInputBorder(), + ), + items: ContentStatus.values.map((status) { + return DropdownMenuItem( + value: status, + child: Text(status.l10n(context)), + ); + }).toList(), + onChanged: (value) { + if (value == null) return; + context.read().add( + EditHeadlineStatusChanged(value), + ); + }, + ), ], ), ), diff --git a/lib/content_management/view/edit_source_page.dart b/lib/content_management/view/edit_source_page.dart index db148b7..738e9d4 100644 --- a/lib/content_management/view/edit_source_page.dart +++ b/lib/content_management/view/edit_source_page.dart @@ -4,6 +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/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'; @@ -112,9 +113,9 @@ class _EditSourceViewState extends State<_EditSourceView> { SnackBar(content: Text(l10n.sourceUpdatedSuccessfully)), ); context.read().add( - const LoadSourcesRequested( - limit: kDefaultRowsPerPage, - ), + const LoadSourcesRequested( + limit: kDefaultRowsPerPage, + ), ); context.pop(); } @@ -258,6 +259,26 @@ class _EditSourceViewState extends State<_EditSourceView> { EditSourceHeadquartersChanged(value), ), ), + const SizedBox(height: AppSpacing.lg), + DropdownButtonFormField( + value: state.contentStatus, + decoration: InputDecoration( + labelText: l10n.status, + border: const OutlineInputBorder(), + ), + items: ContentStatus.values.map((status) { + return DropdownMenuItem( + value: status, + child: Text(status.l10n(context)), + ); + }).toList(), + onChanged: (value) { + if (value == null) return; + context.read().add( + EditSourceStatusChanged(value), + ); + }, + ), ], ), ), diff --git a/lib/content_management/view/headlines_page.dart b/lib/content_management/view/headlines_page.dart index e9d3cc7..5dcd47f 100644 --- a/lib/content_management/view/headlines_page.dart +++ b/lib/content_management/view/headlines_page.dart @@ -6,12 +6,12 @@ import 'package:ht_dashboard/content_management/bloc/content_management_bloc.dar 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/pagination_constants.dart'; import 'package:ht_dashboard/shared/constants/app_spacing.dart'; -import 'package:ht_dashboard/shared/utils/date_formatter.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'; /// {@template headlines_page} /// A page for displaying and managing Headlines in a tabular format. @@ -75,18 +75,24 @@ class _HeadlinesPageState extends State { size: ColumnSize.M, ), DataColumn2( - label: Text(l10n.publishedAt), + label: Text(l10n.status), size: ColumnSize.S, ), + DataColumn2( + label: Text(l10n.lastUpdated), + size: ColumnSize.M, + ), DataColumn2( label: Text(l10n.actions), size: ColumnSize.S, + fixedWidth: 120, ), ], source: _HeadlinesDataSource( context: context, headlines: state.headlines, - isLoading: state.headlinesStatus == ContentManagementStatus.loading, + isLoading: + state.headlinesStatus == ContentManagementStatus.loading, hasMore: state.headlinesHasMore, l10n: l10n, ), @@ -142,22 +148,30 @@ class _HeadlinesDataSource extends DataTableSource { // If we are loading, show a spinner. Otherwise, we've reached the end. if (isLoading) { return DataRow2( - cells: List.generate(4, (_) => const DataCell(Center(child: CircularProgressIndicator()))), + cells: List.generate( + 5, + (_) => const DataCell(Center(child: CircularProgressIndicator())), + ), ); } return null; } final headline = headlines[index]; return DataRow2( + onSelectChanged: (selected) { + if (selected ?? false) { + context.goNamed( + Routes.editHeadlineName, + pathParameters: {'id': headline.id}, + ); + } + }, cells: [ DataCell(Text(headline.title)), DataCell(Text(headline.source?.name ?? l10n.unknown)), + DataCell(Text(headline.status.l10n(context))), DataCell( - Text( - headline.publishedAt != null - ? DateFormatter.formatDate(headline.publishedAt!) - : l10n.unknown, - ), + Text(headline.updatedAt?.toLocal().toString() ?? l10n.notAvailable), ), DataCell( Row( @@ -199,7 +213,9 @@ class _HeadlinesDataSource 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 ? headlines.length + 1 : headlines.length + kDefaultRowsPerPage; + return isLoading + ? headlines.length + 1 + : headlines.length + kDefaultRowsPerPage; } return headlines.length; } diff --git a/lib/content_management/view/sources_page.dart b/lib/content_management/view/sources_page.dart index e3d42c1..ace07df 100644 --- a/lib/content_management/view/sources_page.dart +++ b/lib/content_management/view/sources_page.dart @@ -3,7 +3,9 @@ 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:ht_dashboard/content_management/bloc/edit_source/edit_source_bloc.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'; @@ -74,12 +76,17 @@ class _SourcesPageState extends State { size: ColumnSize.M, ), DataColumn2( - label: Text(l10n.language), + label: Text(l10n.status), size: ColumnSize.S, ), + DataColumn2( + label: Text(l10n.lastUpdated), + size: ColumnSize.M, + ), DataColumn2( label: Text(l10n.actions), size: ColumnSize.S, + fixedWidth: 120, ), ], source: _SourcesDataSource( @@ -141,20 +148,30 @@ class _SourcesDataSource extends DataTableSource { // If we are loading, show a spinner. Otherwise, we've reached the end. if (isLoading) { return DataRow2( - cells: List.generate( - 4, - (_) => const DataCell(Center(child: CircularProgressIndicator())), - ), + cells: List.generate(5, (_) { + return const DataCell(Center(child: CircularProgressIndicator())); + }), ); } return null; } final source = sources[index]; return DataRow2( + onSelectChanged: (selected) { + if (selected ?? false) { + context.goNamed( + Routes.editSourceName, + pathParameters: {'id': source.id}, + ); + } + }, cells: [ DataCell(Text(source.name)), - DataCell(Text(source.sourceType?.name ?? l10n.unknown)), - DataCell(Text(source.language ?? l10n.unknown)), + DataCell(Text(source.sourceType?.localizedName(l10n) ?? l10n.unknown)), + DataCell(Text(source.status.l10n(context))), + DataCell( + Text(source.updatedAt?.toLocal().toString() ?? l10n.notAvailable), + ), DataCell( Row( children: [ diff --git a/lib/l10n/app_localizations.dart b/lib/l10n/app_localizations.dart index ed2ae68..16076a4 100644 --- a/lib/l10n/app_localizations.dart +++ b/lib/l10n/app_localizations.dart @@ -1285,6 +1285,36 @@ abstract class AppLocalizations { /// In en, this message translates to: /// **'Source created successfully.'** String get sourceCreatedSuccessfully; + + /// No description provided for @status. + /// + /// In en, this message translates to: + /// **'Status'** + String get status; + + /// No description provided for @lastUpdated. + /// + /// In en, this message translates to: + /// **'Last Updated'** + String get lastUpdated; + + /// No description provided for @contentStatusActive. + /// + /// In en, this message translates to: + /// **'Active'** + String get contentStatusActive; + + /// No description provided for @contentStatusArchived. + /// + /// In en, this message translates to: + /// **'Archived'** + String get contentStatusArchived; + + /// No description provided for @contentStatusDraft. + /// + /// In en, this message translates to: + /// **'Draft'** + String get contentStatusDraft; } class _AppLocalizationsDelegate diff --git a/lib/l10n/app_localizations_ar.dart b/lib/l10n/app_localizations_ar.dart index 6509b2e..c98a7e1 100644 --- a/lib/l10n/app_localizations_ar.dart +++ b/lib/l10n/app_localizations_ar.dart @@ -671,4 +671,19 @@ class AppLocalizationsAr extends AppLocalizations { @override String get sourceCreatedSuccessfully => 'تم إنشاء المصدر بنجاح.'; + + @override + String get status => 'الحالة'; + + @override + String get lastUpdated => 'آخر تحديث'; + + @override + String get contentStatusActive => 'نشط'; + + @override + String get contentStatusArchived => 'مؤرشف'; + + @override + String get contentStatusDraft => 'مسودة'; } diff --git a/lib/l10n/app_localizations_en.dart b/lib/l10n/app_localizations_en.dart index f4767b1..f34b3fb 100644 --- a/lib/l10n/app_localizations_en.dart +++ b/lib/l10n/app_localizations_en.dart @@ -669,4 +669,19 @@ class AppLocalizationsEn extends AppLocalizations { @override String get sourceCreatedSuccessfully => 'Source created successfully.'; + + @override + String get status => 'Status'; + + @override + String get lastUpdated => 'Last Updated'; + + @override + String get contentStatusActive => 'Active'; + + @override + String get contentStatusArchived => 'Archived'; + + @override + String get contentStatusDraft => 'Draft'; } diff --git a/lib/l10n/arb/app_ar.arb b/lib/l10n/arb/app_ar.arb index d00ab8d..889328f 100644 --- a/lib/l10n/arb/app_ar.arb +++ b/lib/l10n/arb/app_ar.arb @@ -815,5 +815,15 @@ "sourceCreatedSuccessfully": "تم إنشاء المصدر بنجاح.", "@sourceCreatedSuccessfully": { "description": "رسالة تُعرض عند إنشاء المصدر بنجاح" - } + }, + "status": "الحالة", + "@status": {}, + "lastUpdated": "آخر تحديث", + "@lastUpdated": {}, + "contentStatusActive": "نشط", + "@contentStatusActive": {}, + "contentStatusArchived": "مؤرشف", + "@contentStatusArchived": {}, + "contentStatusDraft": "مسودة", + "@contentStatusDraft": {} } \ No newline at end of file diff --git a/lib/l10n/arb/app_en.arb b/lib/l10n/arb/app_en.arb index 14b6501..a7b6143 100644 --- a/lib/l10n/arb/app_en.arb +++ b/lib/l10n/arb/app_en.arb @@ -815,5 +815,15 @@ "sourceCreatedSuccessfully": "Source created successfully.", "@sourceCreatedSuccessfully": { "description": "Message displayed when a source is created successfully" - } + }, + "status": "Status", + "@status": {}, + "lastUpdated": "Last Updated", + "@lastUpdated": {}, + "contentStatusActive": "Active", + "@contentStatusActive": {}, + "contentStatusArchived": "Archived", + "@contentStatusArchived": {}, + "contentStatusDraft": "Draft", + "@contentStatusDraft": {} } \ No newline at end of file diff --git a/lib/shared/extensions/content_status_l10n.dart b/lib/shared/extensions/content_status_l10n.dart new file mode 100644 index 0000000..c2f9b6c --- /dev/null +++ b/lib/shared/extensions/content_status_l10n.dart @@ -0,0 +1,19 @@ +import 'package:flutter/widgets.dart'; +import 'package:ht_dashboard/l10n/l10n.dart'; +import 'package:ht_shared/ht_shared.dart'; + +/// Provides a localized string representation for [ContentStatus]. +extension ContentStatusL10n on ContentStatus { + /// Returns the localized string for the status. + String l10n(BuildContext context) { + final l10n = context.l10n; + switch (this) { + case ContentStatus.active: + return l10n.contentStatusActive; + case ContentStatus.archived: + return l10n.contentStatusArchived; + case ContentStatus.draft: + return l10n.contentStatusDraft; + } + } +} \ No newline at end of file diff --git a/lib/shared/extensions/extensions.dart b/lib/shared/extensions/extensions.dart new file mode 100644 index 0000000..ad4d418 --- /dev/null +++ b/lib/shared/extensions/extensions.dart @@ -0,0 +1 @@ +export 'content_status_l10n.dart'; diff --git a/lib/shared/shared.dart b/lib/shared/shared.dart index a0f4b74..e7c04f2 100644 --- a/lib/shared/shared.dart +++ b/lib/shared/shared.dart @@ -5,6 +5,7 @@ library; export 'constants/constants.dart'; +export 'extensions/extensions.dart'; export 'theme/theme.dart'; export 'utils/utils.dart'; export 'widgets/widgets.dart'; diff --git a/pubspec.lock b/pubspec.lock index 9d67c2f..e166c2b 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -69,18 +69,18 @@ packages: dependency: transitive description: name: device_frame - sha256: a58796a9a2efc0fd8a7903cee0eed2e2d111f4a7d81fa2319ab89430b020f624 + sha256: "7b2ebb2a09d6cc0f086b51bd1412d7be83e0170056a7290349169be41164c86a" url: "https://pub.dev" source: hosted - version: "1.3.0" + version: "1.4.0" device_preview: dependency: "direct main" description: name: device_preview - sha256: a694acdd3894b4c7d600f4ee413afc4ff917f76026b97ab06575fe886429ef19 + sha256: "88aa1cc73ee9a8ec771b309dcbc4000cc66b5d8456b825980997640ab1195bf5" url: "https://pub.dev" source: hosted - version: "1.2.0" + version: "1.3.1" dio: dependency: transitive description: @@ -180,18 +180,18 @@ packages: dependency: transitive description: name: freezed_annotation - sha256: c2e2d632dd9b8a2b7751117abcfc2b4888ecfe181bd9fca7170d9ef02e595fe2 + sha256: "7294967ff0a6d98638e7acb774aac3af2550777accd8149c90af5b014e6d44d8" url: "https://pub.dev" source: hosted - version: "2.4.4" + version: "3.1.0" go_router: dependency: "direct main" description: name: go_router - sha256: ac294be30ba841830cfa146e5a3b22bb09f8dc5a0fdd9ca9332b04b0bde99ebf + sha256: c489908a54ce2131f1d1b7cc631af9c1a06fac5ca7c449e959192089f9489431 url: "https://pub.dev" source: hosted - version: "15.2.4" + version: "16.0.0" google_fonts: dependency: "direct main" description: @@ -304,7 +304,7 @@ packages: description: path: "." ref: HEAD - resolved-ref: "096ceed8957af0935e950818b657617510b9a9ba" + resolved-ref: "9e771623f5745113d346fd4bfdb1abccf7e75049" url: "https://github.com/headlines-toolkit/ht-shared.git" source: git version: "0.0.0" @@ -611,4 +611,4 @@ packages: version: "1.1.0" sdks: dart: ">=3.8.0 <4.0.0" - flutter: ">=3.29.0" + flutter: ">=3.32.0" diff --git a/pubspec.yaml b/pubspec.yaml index d37f220..8534f3d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -19,7 +19,7 @@ dependencies: flutter_bloc: ^9.1.1 flutter_localizations: sdk: flutter - go_router: ^15.2.4 + go_router: ^16.0.0 google_fonts: ^6.2.1 ht_auth_api: git: