From 356f7393ef1f3f62d681979e96ba46e54bcec835 Mon Sep 17 00:00:00 2001 From: fulleni Date: Fri, 1 Aug 2025 06:54:39 +0100 Subject: [PATCH 01/10] refactor(bloc): optimize search and repository calls - Replace restartable() transformer with droppable() for search events - Remove unnecessary line breaks in constructor initializers - Simplify filter conditions in repository calls - Merge language list update into a single line --- .../create_headline/create_headline_bloc.dart | 18 +++++++--------- .../create_source/create_source_bloc.dart | 21 ++++++++----------- .../edit_headline/edit_headline_bloc.dart | 17 +++++++-------- .../bloc/edit_source/edit_source_bloc.dart | 20 ++++++++---------- 4 files changed, 34 insertions(+), 42 deletions(-) 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 5b491ee..a587808 100644 --- a/lib/content_management/bloc/create_headline/create_headline_bloc.dart +++ b/lib/content_management/bloc/create_headline/create_headline_bloc.dart @@ -20,11 +20,11 @@ class CreateHeadlineBloc required DataRepository sourcesRepository, required DataRepository topicsRepository, required DataRepository countriesRepository, - }) : _headlinesRepository = headlinesRepository, - _sourcesRepository = sourcesRepository, - _topicsRepository = topicsRepository, - _countriesRepository = countriesRepository, - super(const CreateHeadlineState()) { + }) : _headlinesRepository = headlinesRepository, + _sourcesRepository = sourcesRepository, + _topicsRepository = topicsRepository, + _countriesRepository = countriesRepository, + super(const CreateHeadlineState()) { on(_onDataLoaded); on(_onTitleChanged); on(_onExcerptChanged); @@ -37,10 +37,9 @@ class CreateHeadlineBloc on(_onSubmitted); on( _onCountrySearchChanged, - transformer: restartable(), + transformer: droppable(), ); - on( - _onLoadMoreCountriesRequested); + on(_onLoadMoreCountriesRequested); } final DataRepository _headlinesRepository; @@ -204,8 +203,7 @@ class CreateHeadlineBloc emit(state.copyWith(countrySearchTerm: event.searchTerm)); try { final countriesResponse = await _countriesRepository.readAll( - filter: - event.searchTerm.isNotEmpty ? {'name': event.searchTerm} : null, + filter: event.searchTerm.isNotEmpty ? {'name': event.searchTerm} : null, sort: [const SortOption('name', SortOrder.asc)], ); 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 fe4e63b..24c2e23 100644 --- a/lib/content_management/bloc/create_source/create_source_bloc.dart +++ b/lib/content_management/bloc/create_source/create_source_bloc.dart @@ -18,10 +18,10 @@ class CreateSourceBloc extends Bloc { required DataRepository sourcesRepository, required DataRepository countriesRepository, required DataRepository languagesRepository, - }) : _sourcesRepository = sourcesRepository, - _countriesRepository = countriesRepository, - _languagesRepository = languagesRepository, - super(const CreateSourceState()) { + }) : _sourcesRepository = sourcesRepository, + _countriesRepository = countriesRepository, + _languagesRepository = languagesRepository, + super(const CreateSourceState()) { on(_onDataLoaded); on(_onNameChanged); on(_onDescriptionChanged); @@ -33,14 +33,14 @@ class CreateSourceBloc extends Bloc { on(_onSubmitted); on( _onCountrySearchChanged, - transformer: restartable(), + transformer: droppable(), ); on( _onLoadMoreCountriesRequested, ); on( _onLanguageSearchChanged, - transformer: restartable(), + transformer: droppable(), ); on( _onLoadMoreLanguagesRequested, @@ -194,8 +194,7 @@ class CreateSourceBloc extends Bloc { emit(state.copyWith(countrySearchTerm: event.searchTerm)); try { final countriesResponse = await _countriesRepository.readAll( - filter: - event.searchTerm.isNotEmpty ? {'name': event.searchTerm} : null, + filter: event.searchTerm.isNotEmpty ? {'name': event.searchTerm} : null, sort: [const SortOption('name', SortOrder.asc)], ); @@ -262,8 +261,7 @@ class CreateSourceBloc extends Bloc { emit(state.copyWith(languageSearchTerm: event.searchTerm)); try { final languagesResponse = await _languagesRepository.readAll( - filter: - event.searchTerm.isNotEmpty ? {'name': event.searchTerm} : null, + filter: event.searchTerm.isNotEmpty ? {'name': event.searchTerm} : null, sort: [const SortOption('name', SortOrder.asc)], ); @@ -305,8 +303,7 @@ class CreateSourceBloc extends Bloc { emit( state.copyWith( - languages: List.of(state.languages) - ..addAll(languagesResponse.items), + languages: List.of(state.languages)..addAll(languagesResponse.items), languagesCursor: languagesResponse.cursor, languagesHasMore: languagesResponse.hasMore, ), 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 412cde1..9eb2463 100644 --- a/lib/content_management/bloc/edit_headline/edit_headline_bloc.dart +++ b/lib/content_management/bloc/edit_headline/edit_headline_bloc.dart @@ -19,12 +19,12 @@ class EditHeadlineBloc extends Bloc { required DataRepository topicsRepository, required DataRepository countriesRepository, required String headlineId, - }) : _headlinesRepository = headlinesRepository, - _sourcesRepository = sourcesRepository, - _topicsRepository = topicsRepository, - _countriesRepository = countriesRepository, - _headlineId = headlineId, - super(const EditHeadlineState()) { + }) : _headlinesRepository = headlinesRepository, + _sourcesRepository = sourcesRepository, + _topicsRepository = topicsRepository, + _countriesRepository = countriesRepository, + _headlineId = headlineId, + super(const EditHeadlineState()) { on(_onLoaded); on(_onTitleChanged); on(_onExcerptChanged); @@ -37,7 +37,7 @@ class EditHeadlineBloc extends Bloc { on(_onSubmitted); on( _onCountrySearchChanged, - transformer: restartable(), + transformer: droppable(), ); on( _onLoadMoreCountriesRequested, @@ -253,8 +253,7 @@ class EditHeadlineBloc extends Bloc { emit(state.copyWith(countrySearchTerm: event.searchTerm)); try { final countriesResponse = await _countriesRepository.readAll( - filter: - event.searchTerm.isNotEmpty ? {'name': event.searchTerm} : null, + filter: event.searchTerm.isNotEmpty ? {'name': event.searchTerm} : null, sort: [const SortOption('name', SortOrder.asc)], ); 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 c8d8c7a..73c3777 100644 --- a/lib/content_management/bloc/edit_source/edit_source_bloc.dart +++ b/lib/content_management/bloc/edit_source/edit_source_bloc.dart @@ -18,11 +18,11 @@ class EditSourceBloc extends Bloc { required DataRepository countriesRepository, required DataRepository languagesRepository, required String sourceId, - }) : _sourcesRepository = sourcesRepository, - _countriesRepository = countriesRepository, - _languagesRepository = languagesRepository, - _sourceId = sourceId, - super(const EditSourceState()) { + }) : _sourcesRepository = sourcesRepository, + _countriesRepository = countriesRepository, + _languagesRepository = languagesRepository, + _sourceId = sourceId, + super(const EditSourceState()) { on(_onLoaded); on(_onNameChanged); on(_onDescriptionChanged); @@ -34,14 +34,14 @@ class EditSourceBloc extends Bloc { on(_onSubmitted); on( _onCountrySearchChanged, - transformer: restartable(), + transformer: droppable(), ); on( _onLoadMoreCountriesRequested, ); on( _onLanguageSearchChanged, - transformer: restartable(), + transformer: droppable(), ); on( _onLoadMoreLanguagesRequested, @@ -248,8 +248,7 @@ class EditSourceBloc extends Bloc { emit(state.copyWith(countrySearchTerm: event.searchTerm)); try { final countriesResponse = await _countriesRepository.readAll( - filter: - event.searchTerm.isNotEmpty ? {'name': event.searchTerm} : null, + filter: event.searchTerm.isNotEmpty ? {'name': event.searchTerm} : null, sort: [const SortOption('name', SortOrder.asc)], ); @@ -316,8 +315,7 @@ class EditSourceBloc extends Bloc { emit(state.copyWith(languageSearchTerm: event.searchTerm)); try { final languagesResponse = await _languagesRepository.readAll( - filter: - event.searchTerm.isNotEmpty ? {'name': event.searchTerm} : null, + filter: event.searchTerm.isNotEmpty ? {'name': event.searchTerm} : null, sort: [const SortOption('name', SortOrder.asc)], ); From a810921035c635a9d7ffc2178e54bd06befbfc16 Mon Sep 17 00:00:00 2001 From: fulleni Date: Fri, 1 Aug 2025 07:24:39 +0100 Subject: [PATCH 02/10] feat(content_management): add loading more state for countries - Add 'countriesIsLoadingMore' field to CreateHeadlineState - Update copyWith method to include new field - Modify state initialization to set default value for 'countriesIsLoadingMore' --- .../bloc/create_headline/create_headline_state.dart | 6 ++++++ 1 file changed, 6 insertions(+) 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 c914953..f4effd4 100644 --- a/lib/content_management/bloc/create_headline/create_headline_state.dart +++ b/lib/content_management/bloc/create_headline/create_headline_state.dart @@ -33,6 +33,7 @@ final class CreateHeadlineState extends Equatable { this.topics = const [], this.countries = const [], this.countriesHasMore = true, + this.countriesIsLoadingMore = false, this.countriesCursor, this.countrySearchTerm = '', this.contentStatus = ContentStatus.active, @@ -52,6 +53,7 @@ final class CreateHeadlineState extends Equatable { final List topics; final List countries; final bool countriesHasMore; + final bool countriesIsLoadingMore; final String? countriesCursor; final String countrySearchTerm; final ContentStatus contentStatus; @@ -81,6 +83,7 @@ final class CreateHeadlineState extends Equatable { List? topics, List? countries, bool? countriesHasMore, + bool? countriesIsLoadingMore, String? countriesCursor, String? countrySearchTerm, ContentStatus? contentStatus, @@ -100,6 +103,8 @@ final class CreateHeadlineState extends Equatable { topics: topics ?? this.topics, countries: countries ?? this.countries, countriesHasMore: countriesHasMore ?? this.countriesHasMore, + countriesIsLoadingMore: + countriesIsLoadingMore ?? this.countriesIsLoadingMore, countriesCursor: countriesCursor ?? this.countriesCursor, countrySearchTerm: countrySearchTerm ?? this.countrySearchTerm, contentStatus: contentStatus ?? this.contentStatus, @@ -122,6 +127,7 @@ final class CreateHeadlineState extends Equatable { topics, countries, countriesHasMore, + countriesIsLoadingMore, countriesCursor, countrySearchTerm, contentStatus, From c6b9c0847d91347ddb6e44ad16d8cdda5af09191 Mon Sep 17 00:00:00 2001 From: fulleni Date: Fri, 1 Aug 2025 07:32:48 +0100 Subject: [PATCH 03/10] fix(content_management): prevent multiple concurrent country load more requests - Add countriesIsLoadingMore flag to state - Check countriesIsLoadingMore before making new load more request - Update state with countriesIsLoadingMore: true at the start of the request - Reset countriesIsLoadingMore to false in both success and error cases --- .../bloc/create_headline/create_headline_bloc.dart | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) 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 a587808..456fb6a 100644 --- a/lib/content_management/bloc/create_headline/create_headline_bloc.dart +++ b/lib/content_management/bloc/create_headline/create_headline_bloc.dart @@ -230,7 +230,9 @@ class CreateHeadlineBloc CreateHeadlineLoadMoreCountriesRequested event, Emitter emit, ) async { - if (!state.countriesHasMore) return; + if (!state.countriesHasMore || state.countriesIsLoadingMore) return; + + emit(state.copyWith(countriesIsLoadingMore: true)); try { final countriesResponse = await _countriesRepository.readAll( @@ -248,15 +250,23 @@ class CreateHeadlineBloc countries: List.of(state.countries)..addAll(countriesResponse.items), countriesCursor: countriesResponse.cursor, countriesHasMore: countriesResponse.hasMore, + countriesIsLoadingMore: false, ), ); } on HttpException catch (e) { - emit(state.copyWith(status: CreateHeadlineStatus.failure, exception: e)); + emit( + state.copyWith( + status: CreateHeadlineStatus.failure, + exception: e, + countriesIsLoadingMore: false, + ), + ); } catch (e) { emit( state.copyWith( status: CreateHeadlineStatus.failure, exception: UnknownException('An unexpected error occurred: $e'), + countriesIsLoadingMore: false, ), ); } From 9699ad8a73b96b2fd9d9b8f969a3f23e25aab28a Mon Sep 17 00:00:00 2001 From: fulleni Date: Fri, 1 Aug 2025 07:37:37 +0100 Subject: [PATCH 04/10] fix(content_management): prevent multiple concurrent country load more requests - Add countriesIsLoadingMore flag to state - Check countriesIsLoadingMore before making new load more request - Update loading state in both success and error cases --- .../bloc/edit_headline/edit_headline_bloc.dart | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) 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 9eb2463..c1129e0 100644 --- a/lib/content_management/bloc/edit_headline/edit_headline_bloc.dart +++ b/lib/content_management/bloc/edit_headline/edit_headline_bloc.dart @@ -280,7 +280,9 @@ class EditHeadlineBloc extends Bloc { EditHeadlineLoadMoreCountriesRequested event, Emitter emit, ) async { - if (!state.countriesHasMore) return; + if (!state.countriesHasMore || state.countriesIsLoadingMore) return; + + emit(state.copyWith(countriesIsLoadingMore: true)); try { final countriesResponse = await _countriesRepository.readAll( @@ -298,15 +300,23 @@ class EditHeadlineBloc extends Bloc { countries: List.of(state.countries)..addAll(countriesResponse.items), countriesCursor: countriesResponse.cursor, countriesHasMore: countriesResponse.hasMore, + countriesIsLoadingMore: false, ), ); } on HttpException catch (e) { - emit(state.copyWith(status: EditHeadlineStatus.failure, exception: e)); + emit( + state.copyWith( + status: EditHeadlineStatus.failure, + exception: e, + countriesIsLoadingMore: false, + ), + ); } catch (e) { emit( state.copyWith( status: EditHeadlineStatus.failure, exception: UnknownException('An unexpected error occurred: $e'), + countriesIsLoadingMore: false, ), ); } From b639e2c848133c11af8f3f3a366037ae49b6400c Mon Sep 17 00:00:00 2001 From: fulleni Date: Fri, 1 Aug 2025 07:37:46 +0100 Subject: [PATCH 05/10] feat(content_management): add loading more state for countries - Add 'countriesIsLoadingMore' field to EditHeadlineState - Update constructor and copyWith method to include new field - Modify Equatable props to include 'countriesIsLoadingMore' --- .../bloc/edit_headline/edit_headline_state.dart | 6 ++++++ 1 file changed, 6 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 11e5b07..804e639 100644 --- a/lib/content_management/bloc/edit_headline/edit_headline_state.dart +++ b/lib/content_management/bloc/edit_headline/edit_headline_state.dart @@ -34,6 +34,7 @@ final class EditHeadlineState extends Equatable { this.topics = const [], this.countries = const [], this.countriesHasMore = true, + this.countriesIsLoadingMore = false, this.countriesCursor, this.countrySearchTerm = '', this.contentStatus = ContentStatus.active, @@ -54,6 +55,7 @@ final class EditHeadlineState extends Equatable { final List topics; final List countries; final bool countriesHasMore; + final bool countriesIsLoadingMore; final String? countriesCursor; final String countrySearchTerm; final ContentStatus contentStatus; @@ -84,6 +86,7 @@ final class EditHeadlineState extends Equatable { List? topics, List? countries, bool? countriesHasMore, + bool? countriesIsLoadingMore, String? countriesCursor, String? countrySearchTerm, ContentStatus? contentStatus, @@ -104,6 +107,8 @@ final class EditHeadlineState extends Equatable { topics: topics ?? this.topics, countries: countries ?? this.countries, countriesHasMore: countriesHasMore ?? this.countriesHasMore, + countriesIsLoadingMore: + countriesIsLoadingMore ?? this.countriesIsLoadingMore, countriesCursor: countriesCursor ?? this.countriesCursor, countrySearchTerm: countrySearchTerm ?? this.countrySearchTerm, contentStatus: contentStatus ?? this.contentStatus, @@ -127,6 +132,7 @@ final class EditHeadlineState extends Equatable { topics, countries, countriesHasMore, + countriesIsLoadingMore, countriesCursor, countrySearchTerm, contentStatus, From f1d1eeb165f7d154a35eb5982f007aa358290d81 Mon Sep 17 00:00:00 2001 From: fulleni Date: Fri, 1 Aug 2025 07:39:59 +0100 Subject: [PATCH 06/10] feat(content_management): add loading more indicators for countries and languages - Add countriesIsLoadingMore and languagesIsLoadingMore fields to CreateSourceState - Update constructor, copyWith method, and properties list to include new loading indicators - This change supports infinite scrolling functionality for country and language lists --- .../bloc/create_source/create_source_state.dart | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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 783a200..cc0aef6 100644 --- a/lib/content_management/bloc/create_source/create_source_state.dart +++ b/lib/content_management/bloc/create_source/create_source_state.dart @@ -31,10 +31,12 @@ final class CreateSourceState extends Equatable { this.headquarters, this.countries = const [], this.countriesHasMore = true, + this.countriesIsLoadingMore = false, this.countriesCursor, this.countrySearchTerm = '', this.languages = const [], this.languagesHasMore = true, + this.languagesIsLoadingMore = false, this.languagesCursor, this.languageSearchTerm = '', this.contentStatus = ContentStatus.active, @@ -51,10 +53,12 @@ final class CreateSourceState extends Equatable { final Country? headquarters; final List countries; final bool countriesHasMore; + final bool countriesIsLoadingMore; final String? countriesCursor; final String countrySearchTerm; final List languages; final bool languagesHasMore; + final bool languagesIsLoadingMore; final String? languagesCursor; final String languageSearchTerm; final ContentStatus contentStatus; @@ -80,10 +84,12 @@ final class CreateSourceState extends Equatable { ValueGetter? headquarters, List? countries, bool? countriesHasMore, + bool? countriesIsLoadingMore, String? countriesCursor, String? countrySearchTerm, List? languages, bool? languagesHasMore, + bool? languagesIsLoadingMore, String? languagesCursor, String? languageSearchTerm, ContentStatus? contentStatus, @@ -100,10 +106,14 @@ final class CreateSourceState extends Equatable { headquarters: headquarters != null ? headquarters() : this.headquarters, countries: countries ?? this.countries, countriesHasMore: countriesHasMore ?? this.countriesHasMore, + countriesIsLoadingMore: + countriesIsLoadingMore ?? this.countriesIsLoadingMore, countriesCursor: countriesCursor ?? this.countriesCursor, countrySearchTerm: countrySearchTerm ?? this.countrySearchTerm, languages: languages ?? this.languages, languagesHasMore: languagesHasMore ?? this.languagesHasMore, + languagesIsLoadingMore: + languagesIsLoadingMore ?? this.languagesIsLoadingMore, languagesCursor: languagesCursor ?? this.languagesCursor, languageSearchTerm: languageSearchTerm ?? this.languageSearchTerm, contentStatus: contentStatus ?? this.contentStatus, @@ -123,10 +133,12 @@ final class CreateSourceState extends Equatable { headquarters, countries, countriesHasMore, + countriesIsLoadingMore, countriesCursor, countrySearchTerm, languages, languagesHasMore, + languagesIsLoadingMore, languagesCursor, languageSearchTerm, contentStatus, From bc9c8a8d5df9559629770d815c9d45ee86a29935 Mon Sep 17 00:00:00 2001 From: fulleni Date: Fri, 1 Aug 2025 07:40:06 +0100 Subject: [PATCH 07/10] fix(content_management): prevent multiple concurrent loads for countries and languages - Add loading flags for countries and languages - Check loading flags before initiating new load requests - Update loading flags appropriately during and after API calls - Ensure proper UI feedback during loading states --- .../create_source/create_source_bloc.dart | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) 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 24c2e23..dda551c 100644 --- a/lib/content_management/bloc/create_source/create_source_bloc.dart +++ b/lib/content_management/bloc/create_source/create_source_bloc.dart @@ -221,7 +221,9 @@ class CreateSourceBloc extends Bloc { CreateSourceLoadMoreCountriesRequested event, Emitter emit, ) async { - if (!state.countriesHasMore) return; + if (!state.countriesHasMore || state.countriesIsLoadingMore) return; + + emit(state.copyWith(countriesIsLoadingMore: true)); try { final countriesResponse = await _countriesRepository.readAll( @@ -239,15 +241,23 @@ class CreateSourceBloc extends Bloc { countries: List.of(state.countries)..addAll(countriesResponse.items), countriesCursor: countriesResponse.cursor, countriesHasMore: countriesResponse.hasMore, + countriesIsLoadingMore: false, ), ); } on HttpException catch (e) { - emit(state.copyWith(status: CreateSourceStatus.failure, exception: e)); + emit( + state.copyWith( + status: CreateSourceStatus.failure, + exception: e, + countriesIsLoadingMore: false, + ), + ); } catch (e) { emit( state.copyWith( status: CreateSourceStatus.failure, exception: UnknownException('An unexpected error occurred: $e'), + countriesIsLoadingMore: false, ), ); } @@ -288,7 +298,9 @@ class CreateSourceBloc extends Bloc { CreateSourceLoadMoreLanguagesRequested event, Emitter emit, ) async { - if (!state.languagesHasMore) return; + if (!state.languagesHasMore || state.languagesIsLoadingMore) return; + + emit(state.copyWith(languagesIsLoadingMore: true)); try { final languagesResponse = await _languagesRepository.readAll( @@ -306,15 +318,23 @@ class CreateSourceBloc extends Bloc { languages: List.of(state.languages)..addAll(languagesResponse.items), languagesCursor: languagesResponse.cursor, languagesHasMore: languagesResponse.hasMore, + languagesIsLoadingMore: false, ), ); } on HttpException catch (e) { - emit(state.copyWith(status: CreateSourceStatus.failure, exception: e)); + emit( + state.copyWith( + status: CreateSourceStatus.failure, + exception: e, + languagesIsLoadingMore: false, + ), + ); } catch (e) { emit( state.copyWith( status: CreateSourceStatus.failure, exception: UnknownException('An unexpected error occurred: $e'), + languagesIsLoadingMore: false, ), ); } From b81c0836c73985639c16f909d71b1cab56a91f3f Mon Sep 17 00:00:00 2001 From: fulleni Date: Fri, 1 Aug 2025 07:45:24 +0100 Subject: [PATCH 08/10] fix(content_management): prevent multiple concurrent loads for countries and languages - Add loading flags for countries and languages - Check loading flags before initiating new load requests - Update loading flags appropriately during and after API calls - Ensure proper UI feedback while loads are in progress --- .../bloc/edit_source/edit_source_bloc.dart | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) 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 73c3777..5f886a0 100644 --- a/lib/content_management/bloc/edit_source/edit_source_bloc.dart +++ b/lib/content_management/bloc/edit_source/edit_source_bloc.dart @@ -275,7 +275,9 @@ class EditSourceBloc extends Bloc { EditSourceLoadMoreCountriesRequested event, Emitter emit, ) async { - if (!state.countriesHasMore) return; + if (!state.countriesHasMore || state.countriesIsLoadingMore) return; + + emit(state.copyWith(countriesIsLoadingMore: true)); try { final countriesResponse = await _countriesRepository.readAll( @@ -293,15 +295,23 @@ class EditSourceBloc extends Bloc { countries: List.of(state.countries)..addAll(countriesResponse.items), countriesCursor: countriesResponse.cursor, countriesHasMore: countriesResponse.hasMore, + countriesIsLoadingMore: false, ), ); } on HttpException catch (e) { - emit(state.copyWith(status: EditSourceStatus.failure, exception: e)); + emit( + state.copyWith( + status: EditSourceStatus.failure, + exception: e, + countriesIsLoadingMore: false, + ), + ); } catch (e) { emit( state.copyWith( status: EditSourceStatus.failure, exception: UnknownException('An unexpected error occurred: $e'), + countriesIsLoadingMore: false, ), ); } @@ -342,7 +352,9 @@ class EditSourceBloc extends Bloc { EditSourceLoadMoreLanguagesRequested event, Emitter emit, ) async { - if (!state.languagesHasMore) return; + if (!state.languagesHasMore || state.languagesIsLoadingMore) return; + + emit(state.copyWith(languagesIsLoadingMore: true)); try { final languagesResponse = await _languagesRepository.readAll( @@ -360,15 +372,23 @@ class EditSourceBloc extends Bloc { languages: List.of(state.languages)..addAll(languagesResponse.items), languagesCursor: languagesResponse.cursor, languagesHasMore: languagesResponse.hasMore, + languagesIsLoadingMore: false, ), ); } on HttpException catch (e) { - emit(state.copyWith(status: EditSourceStatus.failure, exception: e)); + emit( + state.copyWith( + status: EditSourceStatus.failure, + exception: e, + languagesIsLoadingMore: false, + ), + ); } catch (e) { emit( state.copyWith( status: EditSourceStatus.failure, exception: UnknownException('An unexpected error occurred: $e'), + languagesIsLoadingMore: false, ), ); } From 68d85bebf70fc586fe621ad62263961d04dee385 Mon Sep 17 00:00:00 2001 From: fulleni Date: Fri, 1 Aug 2025 07:45:35 +0100 Subject: [PATCH 09/10] feat(content_management): add loading more indicators for countries and languages - Add countriesIsLoadingMore and languagesIsLoadingMore fields to EditSourceState - Update constructor, copyWith method, and field list to include new loading indicators --- .../bloc/edit_source/edit_source_state.dart | 12 ++++++++++++ 1 file changed, 12 insertions(+) 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 f4e3281..82dda1c 100644 --- a/lib/content_management/bloc/edit_source/edit_source_state.dart +++ b/lib/content_management/bloc/edit_source/edit_source_state.dart @@ -31,10 +31,12 @@ final class EditSourceState extends Equatable { this.headquarters, this.countries = const [], this.countriesHasMore = true, + this.countriesIsLoadingMore = false, this.countriesCursor, this.countrySearchTerm = '', this.languages = const [], this.languagesHasMore = true, + this.languagesIsLoadingMore = false, this.languagesCursor, this.languageSearchTerm = '', this.contentStatus = ContentStatus.active, @@ -52,10 +54,12 @@ final class EditSourceState extends Equatable { final Country? headquarters; final List countries; final bool countriesHasMore; + final bool countriesIsLoadingMore; final String? countriesCursor; final String countrySearchTerm; final List languages; final bool languagesHasMore; + final bool languagesIsLoadingMore; final String? languagesCursor; final String languageSearchTerm; final ContentStatus contentStatus; @@ -82,10 +86,12 @@ final class EditSourceState extends Equatable { ValueGetter? headquarters, List? countries, bool? countriesHasMore, + bool? countriesIsLoadingMore, String? countriesCursor, String? countrySearchTerm, List? languages, bool? languagesHasMore, + bool? languagesIsLoadingMore, String? languagesCursor, String? languageSearchTerm, ContentStatus? contentStatus, @@ -103,10 +109,14 @@ final class EditSourceState extends Equatable { headquarters: headquarters != null ? headquarters() : this.headquarters, countries: countries ?? this.countries, countriesHasMore: countriesHasMore ?? this.countriesHasMore, + countriesIsLoadingMore: + countriesIsLoadingMore ?? this.countriesIsLoadingMore, countriesCursor: countriesCursor ?? this.countriesCursor, countrySearchTerm: countrySearchTerm ?? this.countrySearchTerm, languages: languages ?? this.languages, languagesHasMore: languagesHasMore ?? this.languagesHasMore, + languagesIsLoadingMore: + languagesIsLoadingMore ?? this.languagesIsLoadingMore, languagesCursor: languagesCursor ?? this.languagesCursor, languageSearchTerm: languageSearchTerm ?? this.languageSearchTerm, contentStatus: contentStatus ?? this.contentStatus, @@ -127,10 +137,12 @@ final class EditSourceState extends Equatable { headquarters, countries, countriesHasMore, + countriesIsLoadingMore, countriesCursor, countrySearchTerm, languages, languagesHasMore, + languagesIsLoadingMore, languagesCursor, languageSearchTerm, contentStatus, From 2109f44d13dcfc386ebf0337d75a88e11a71e689 Mon Sep 17 00:00:00 2001 From: fulleni Date: Fri, 1 Aug 2025 07:45:46 +0100 Subject: [PATCH 10/10] fix(shared): prevent loading more when reaching bottom while extracting - Add a check for loading state before triggering onLoadMore() - Extract isLoadingExtractor from widget to avoid redundant calls - Improve performance and prevent unnecessary API calls --- lib/shared/widgets/searchable_dropdown_form_field.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/shared/widgets/searchable_dropdown_form_field.dart b/lib/shared/widgets/searchable_dropdown_form_field.dart index e97b730..b7c1cc5 100644 --- a/lib/shared/widgets/searchable_dropdown_form_field.dart +++ b/lib/shared/widgets/searchable_dropdown_form_field.dart @@ -141,7 +141,8 @@ class _SearchableSelectionDialogState, S> } void _onScroll() { - if (_isBottom) { + final isLoading = widget.isLoadingExtractor(widget.bloc.state); + if (_isBottom && !isLoading) { widget.onLoadMore(); } } @@ -228,4 +229,4 @@ class _SearchableSelectionDialogState, S> }, ); } -} \ No newline at end of file +}