-
Notifications
You must be signed in to change notification settings - Fork 0
Fix countrries and languages uncomplete list in the con,tent managment #43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix countrries and languages uncomplete list in the con,tent managment #43
Conversation
- Add HttpException handling to provide more specific error information - Introduce UnknownException for unexpected errors - Update state.copyWith calls to include exception details
Refactors `CreateHeadlineState` and `EditHeadlineState` to support paginated loading of countries.
Introduces new events to `CreateHeadlineBloc` and `EditHeadlineBloc` to support paginated and searchable country dropdowns. - `CountrySearchChanged`: Dispatched when the user types in the search field for countries. - `LoadMoreCountriesRequested`: Dispatched when the user scrolls to the end of the country list, requesting the next page of data.
- Add debounce functionality for country search - Implement load more countries functionality - Refactor country data loading process - Import bloc_concurrency package for concurrency management
- Implement country search functionality in CreateHeadlineBloc - Add pagination support for loading more countries - Update CreateHeadlineState to include country search term, cursor, and hasMore flag
…management - Add bloc_concurrency package to improve handling of concurrent events
Refactors `CreateHeadlineBloc` and `EditHeadlineBloc` to support paginated and searchable country data fetching. - Updates `_onDataLoaded` and `_onLoaded` to fetch only the first page of countries initially. - Implements `_onCountrySearchChanged` to fetch a new list of countries based on a search term, with a debounce to prevent excessive API calls. - Implements `_onLoadMoreCountriesRequested` to fetch and append the next page of countries to the existing list. - Updates state with pagination cursor and `hasMore` flag from the repository response.
Introduces a new reusable `SearchableDropdownFormField` widget. This generic component provides a user-friendly and performant way to select an item from a large, paginated data set. - Displays a form field that, when tapped, opens a modal dialog. - The modal contains a search input to filter the list. - The list is paginated, fetching more items as the user scrolls. - The widget is generic (`<T>`) and uses builder functions for items, making it adaptable for various data types (e.g., Country, Language).
Replaces the standard `CountryDropdownFormField` with the new `SearchableDropdownFormField` in both the `CreateHeadlinePage` and `EditHeadlinePage`. This change connects the UI to the new pagination and search logic in the `CreateHeadlineBloc` and `EditHeadlineBloc`, allowing users to efficiently search and load countries from a large dataset. The dropdown now displays the country's flag alongside its name for an improved user experience.
Refactors `CreateSourceState` and `EditSourceState` to support paginated loading of both countries and languages. Replaces the simple lists with a set of fields to manage pagination state for each entity: `hasMore`, `cursor`, and `searchTerm`. This is the first step towards implementing searchable, paginated dropdowns for country and language selection in the source forms.
Introduces new events to `CreateSourceBloc` and `EditSourceBloc` to support paginated and searchable dropdowns for both countries and languages. - `CountrySearchChanged` / `LanguageSearchChanged`: Dispatched when the user types in the search field. - `LoadMoreCountriesRequested` / `LoadMoreLanguagesRequested`: Dispatched when the user scrolls to the end of the list, requesting the next page.
Refactors `CreateSourceBloc` to support paginated and searchable data fetching for both countries and languages. - Updates `_onDataLoaded` to fetch only the first page of data. - Implements handlers for searching and loading more data for both countries and languages, with a debounce for search inputs. - Updates state with pagination cursors and `hasMore` flags from the repository responses.
Refactors `EditSourceBloc` to support paginated and searchable data fetching for both countries and languages. - Updates `_onLoaded` to fetch only the first page of data for dropdowns. - Implements handlers for searching and loading more data for both countries and languages, with a debounce for search inputs. - Updates state with pagination cursors and `hasMore` flags from the repository responses.
Replaces the standard `CountryDropdownFormField` and `LanguageDropdownFormField` with the new `SearchableDropdownFormField` in both the `CreateSourcePage` and `EditSourcePage`. This change connects the UI to the new pagination and search logic in the `CreateSourceBloc` and `EditSourceBloc`, allowing users to efficiently search and load countries and languages from large datasets.
Deletes the `CountryDropdownFormField` and `LanguageDropdownFormField` widgets as they have been fully replaced by the new, more capable `SearchableDropdownFormField` across the application. Updates the shared widgets barrel file to remove the exports for the deleted files.
Replaces the incorrect `debounce` transformer with the correct `restartable` transformer from `bloc_concurrency` in all form BLoCs. This fixes the runtime error and correctly implements a debounce for search fields. Also completes the implementation for the language search and load-more handlers in `CreateSourceBloc` and `EditSourceBloc`, which were previously left incomplete. This includes adding proper error handling.
- Remove exports for 'country_dropdown_form_field.dart' and 'language_dropdown_form_field.dart' - Keep export for 'searchable_dropdown_form_field.dart'
- Update country search logic to handle empty search terms - Refine pagination handling when fetching more countries - Remove unnecessary type casting from repository responses
- Refactor initial data loading to use typed responses - Enhance country and language search to handle empty search terms - Add null safety checks for pagination options - Simplify response handling in various repository calls
- Enhance country filter to only apply when search term is not empty - Refine pagination logic for country list retrieval - Simplify response handling in Future.wait
- Use explicit type casting for repository responses - Simplify variable assignments and type inference - Remove unnecessary comments
Corrects multiple errors in `EditSourceBloc`: - Fixes type inference for `Future.wait` by explicitly handling the returned list of dynamic objects. - Replaces incorrect syntax for finding the selected language with a robust `try-catch` block around `firstWhere`. - Correctly passes pagination parameters by wrapping the cursor in a `PaginationOptions` object. - Refines search logic to prevent sending filters with empty search terms. - Removes unnecessary casts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Summary of Changes
Hello @fulleni, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!
This pull request significantly enhances the user experience in content management by introducing robust search and pagination capabilities for country and language selection fields. It refactors the underlying BLoC logic and introduces a new generic UI component to support dynamic data loading, ensuring users can efficiently find and select items from potentially large datasets.
Highlights
- Searchable & Paginated Dropdowns: Implemented search and pagination for country and language selection across content management forms (Create/Edit Headline, Create/Edit Source) to address incomplete lists.
- New UI Component: Introduced a new generic
SearchableDropdownFormField
widget (lib/shared/widgets/searchable_dropdown_form_field.dart
) that provides a reusable UI for searchable and paginated dropdowns, replacing the previous staticCountryDropdownFormField
andLanguageDropdownFormField
. - BLoC Logic Updates: Updated the BLoC layers (
CreateHeadlineBloc
,CreateSourceBloc
,EditHeadlineBloc
,EditSourceBloc
) to manage search terms, pagination cursors, and 'hasMore' flags for countries and languages. New events and handlers were added to support dynamic fetching, searching, and infinite scrolling of these lists. - Dependency Update: Added
bloc_concurrency
to manage event processing, specifically usingrestartable()
transformer for search events to debounce and cancel previous searches.
Using Gemini Code Assist
The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.
Invoking Gemini
You can request assistance from Gemini at any point in your pull request via creating an issue comment (i.e. comment on the pull request page) using either /gemini <command>
or @gemini-code-assist <command>
. Below is a summary of the supported commands.
Feature | Command | Description |
---|---|---|
Code Review | /gemini review |
Performs a code review for the current pull request in its current state. |
Pull Request Summary | /gemini summary |
Provides a summary of the current pull request in its current state. |
Comment | @gemini-code-assist | Responds in comments when explicitly tagged, both in issue comments and review comments. |
Help | /gemini help |
Displays a list of available commands. |
Customization
To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/
folder in the base of the repository. Detailed instructions can be found here.
Limitations & Feedback
Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments or fill out our survey to provide feedback.
You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.
Footnotes
-
Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution. ↩
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a significant improvement by replacing standard dropdowns with a new searchable and paginated component for selecting countries and languages. This will greatly enhance the user experience, especially for long lists. My review focuses on improving the implementation within the BLoCs that support this new UI, suggesting debounce
for search, safer Future.wait
handling, removing legacy code, and highlighting areas of code duplication.
final responses = await Future.wait([ | ||
_countriesRepository.readAll( | ||
sort: [const SortOption('name', SortOrder.asc)], | ||
), | ||
_languagesRepository.readAll( | ||
sort: [const SortOption('name', SortOrder.asc)], | ||
), | ||
]); | ||
|
||
final countries = (countriesResponse as PaginatedResponse<Country>).items; | ||
final languages = (languagesResponse as PaginatedResponse<Language>).items; | ||
|
||
final countriesPaginated = responses[0] as PaginatedResponse<Country>; | ||
final languagesPaginated = responses[1] as PaginatedResponse<Language>; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Accessing results from Future.wait
by index is brittle. If the order of futures changes, this will lead to runtime errors that are hard to debug. It's safer to use destructuring with a pattern, which also makes the code more readable.
final [countriesResponse, languagesResponse] = await Future.wait([
_countriesRepository.readAll(
sort: [const SortOption('name', SortOrder.asc)],
),
_languagesRepository.readAll(
sort: [const SortOption('name', SortOrder.asc)],
),
]);
final countriesPaginated = countriesResponse as PaginatedResponse<Country>;
final languagesPaginated = languagesResponse as PaginatedResponse<Language>;
final responses = await Future.wait([ | ||
_headlinesRepository.read(id: _headlineId), | ||
_sourcesRepository.readAll( | ||
sort: [const SortOption('updatedAt', SortOrder.desc)], | ||
), | ||
_topicsRepository.readAll( | ||
sort: [const SortOption('updatedAt', SortOrder.desc)], | ||
), | ||
_countriesRepository.readAll( | ||
sort: [const SortOption('name', SortOrder.asc)], | ||
), | ||
]); | ||
|
||
final headline = headlineResponse as Headline; | ||
final sources = (sourcesResponse as PaginatedResponse<Source>).items; | ||
final topics = (topicsResponse as PaginatedResponse<Topic>).items; | ||
final countries = (countriesResponse as PaginatedResponse<Country>).items; | ||
final headline = responses[0] as Headline; | ||
final sources = (responses[1] as PaginatedResponse<Source>).items; | ||
final topics = (responses[2] as PaginatedResponse<Topic>).items; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Accessing results from Future.wait
by index is brittle. If the order of futures changes, this will lead to runtime errors. It's safer to use destructuring with a pattern, which also makes the code more readable.
final [headlineResponse, sourcesResponse, topicsResponse] =
await Future.wait([
_headlinesRepository.read(id: _headlineId),
_sourcesRepository.readAll(
sort: [const SortOption('updatedAt', SortOrder.desc)],
),
_topicsRepository.readAll(
sort: [const SortOption('updatedAt', SortOrder.desc)],
),
]);
final headline = headlineResponse as Headline;
final sources = (sourcesResponse as PaginatedResponse<Source>).items;
final topics = (topicsResponse as PaginatedResponse<Topic>).items;
CreateSourceLanguageSearchChanged event, | ||
Emitter<CreateSourceState> emit, | ||
) async { | ||
await Future<void>.delayed(_searchDebounceDuration); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
on<CreateSourceLanguageSearchChanged>( | ||
_onLanguageSearchChanged, | ||
transformer: restartable(), | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
on<CreateSourceCountrySearchChanged>( | ||
_onCountrySearchChanged, | ||
transformer: restartable(), | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For handling search input with a delay, bloc_concurrency
provides a debounce
transformer that is more idiomatic for this use case than restartable()
combined with a manual Future.delayed
. Using debounce
will make the intent clearer and the event handler code cleaner.
on<CreateSourceCountrySearchChanged>(
_onCountrySearchChanged,
transformer: debounce(_searchDebounceDuration),
);
on<EditSourceCountrySearchChanged>( | ||
_onCountrySearchChanged, | ||
transformer: restartable(), | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For handling search input with a delay, bloc_concurrency
provides a debounce
transformer that is more idiomatic for this use case than restartable()
combined with a manual Future.delayed
. Using debounce
will make the intent clearer and the event handler code cleaner.
on<EditSourceCountrySearchChanged>(
_onCountrySearchChanged,
transformer: debounce(_searchDebounceDuration),
);
on<EditSourceLanguageSearchChanged>( | ||
_onLanguageSearchChanged, | ||
transformer: restartable(), | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Language? selectedLanguage; | ||
try { | ||
// Find the equivalent language object from the full list. | ||
// This ensures the DropdownButton can identify it by reference. | ||
selectedLanguage = languagesPaginated.items.firstWhere( | ||
(listLanguage) => listLanguage.id == source.language?.id, | ||
); | ||
} catch (_) { | ||
selectedLanguage = source.language; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This logic to find selectedLanguage
from the languagesPaginated.items
list appears to be a leftover from when a standard DropdownButtonFormField
was used. The new SearchableDropdownFormField
does not require the initialValue
to be an instance from the items
list. You can simplify this by directly assigning source.language
.
final selectedLanguage = source.language;
EditSourceCountrySearchChanged event, | ||
Emitter<EditSourceState> emit, | ||
) async { | ||
await Future<void>.delayed(_searchDebounceDuration); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EditSourceLanguageSearchChanged event, | ||
Emitter<EditSourceState> emit, | ||
) async { | ||
await Future<void>.delayed(_searchDebounceDuration); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Status
READY/IN DEVELOPMENT/HOLD
Description
Type of Change