Skip to content

Commit d18b74b

Browse files
committed
feat(country_filter): improve UI/UX country filter
- Apply theme to text styles - Add loading indicator to flag images - Improve flag image sizing - Add padding to list items
1 parent 40546b2 commit d18b74b

File tree

1 file changed

+55
-37
lines changed

1 file changed

+55
-37
lines changed

lib/headlines-feed/view/country_filter_page.dart

Lines changed: 55 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,15 @@ class _CountryFilterPageState extends State<CountryFilterPage> {
9898
@override
9999
Widget build(BuildContext context) {
100100
final l10n = context.l10n;
101+
final theme = Theme.of(context); // Get theme
102+
final textTheme = theme.textTheme; // Get textTheme
101103

102104
return Scaffold(
103105
appBar: AppBar(
104-
title: Text(l10n.headlinesFeedFilterEventCountryLabel),
106+
title: Text(
107+
l10n.headlinesFeedFilterEventCountryLabel,
108+
style: textTheme.titleLarge, // Apply consistent title style
109+
),
105110
actions: [
106111
IconButton(
107112
icon: const Icon(Icons.check),
@@ -126,46 +131,45 @@ class _CountryFilterPageState extends State<CountryFilterPage> {
126131
/// Builds the main content body based on the current [CountriesFilterState].
127132
Widget _buildBody(BuildContext context, CountriesFilterState state) {
128133
final l10n = context.l10n;
134+
final theme = Theme.of(context); // Get theme
135+
final textTheme = theme.textTheme; // Get textTheme
136+
final colorScheme = theme.colorScheme; // Get colorScheme
129137

130138
// Handle initial loading state
131139
if (state.status == CountriesFilterStatus.loading) {
132140
return LoadingStateWidget(
133-
icon: Icons.public_outlined, // Changed icon
134-
headline: l10n.countryFilterLoadingHeadline, // Assumes this exists
135-
subheadline:
136-
l10n.countryFilterLoadingSubheadline, // Assumes this exists
141+
icon: Icons.public_outlined,
142+
headline: l10n.countryFilterLoadingHeadline,
143+
subheadline: l10n.countryFilterLoadingSubheadline,
137144
);
138145
}
139146

140147
// Handle failure state (show error and retry button)
141148
if (state.status == CountriesFilterStatus.failure &&
142149
state.countries.isEmpty) {
143150
return FailureStateWidget(
144-
message:
145-
state.error?.toString() ?? l10n.unknownError, // Assumes this exists
146-
onRetry:
147-
() => context.read<CountriesFilterBloc>().add(
148-
CountriesFilterRequested(),
149-
),
151+
message: state.error?.toString() ?? l10n.unknownError,
152+
onRetry: () =>
153+
context.read<CountriesFilterBloc>().add(CountriesFilterRequested()),
150154
);
151155
}
152156

153157
// Handle empty state (after successful load but no countries found)
154158
if (state.status == CountriesFilterStatus.success &&
155159
state.countries.isEmpty) {
156160
return InitialStateWidget(
157-
icon: Icons.search_off,
158-
headline: l10n.countryFilterEmptyHeadline, // Assumes this exists
159-
subheadline: l10n.countryFilterEmptySubheadline, // Assumes this exists
161+
icon: Icons.flag_circle_outlined, // More relevant icon
162+
headline: l10n.countryFilterEmptyHeadline,
163+
subheadline: l10n.countryFilterEmptySubheadline,
160164
);
161165
}
162166

163167
// Handle loaded state (success or loading more)
164168
return ListView.builder(
165169
controller: _scrollController,
166-
padding: const EdgeInsets.only(bottom: AppSpacing.xxl),
167-
itemCount:
168-
state.countries.length +
170+
padding: const EdgeInsets.symmetric(vertical: AppSpacing.paddingSmall)
171+
.copyWith(bottom: AppSpacing.xxl), // Consistent vertical padding
172+
itemCount: state.countries.length +
169173
((state.status == CountriesFilterStatus.loadingMore ||
170174
(state.status == CountriesFilterStatus.failure &&
171175
state.countries.isNotEmpty))
@@ -186,49 +190,63 @@ class _CountryFilterPageState extends State<CountryFilterPage> {
186190
),
187191
child: Center(
188192
child: Text(
189-
l10n.loadMoreError, // Assumes this exists
190-
style: Theme.of(context).textTheme.bodySmall?.copyWith(
191-
color: Theme.of(context).colorScheme.error,
192-
),
193+
l10n.loadMoreError,
194+
style: textTheme.bodySmall
195+
?.copyWith(color: colorScheme.error),
193196
),
194197
),
195198
);
196-
} else {
197-
return const SizedBox.shrink();
198199
}
200+
return const SizedBox.shrink();
199201
}
200202

201203
final country = state.countries[index];
202204
final isSelected = _pageSelectedCountries.contains(country);
203205

204206
return CheckboxListTile(
205-
title: Text(country.name),
207+
title: Text(country.name, style: textTheme.titleMedium),
206208
secondary: SizedBox(
207-
// Use SizedBox for consistent flag size
208-
width: 40,
209-
height: 30, // Adjust height for flag aspect ratio if needed
210-
child: Image.network(
211-
country.flagUrl,
212-
fit: BoxFit.contain,
213-
errorBuilder:
214-
(context, error, stackTrace) =>
215-
const Icon(Icons.flag_outlined), // Placeholder icon
209+
width: AppSpacing.xl + AppSpacing.xs, // Standardized width (36)
210+
height: AppSpacing.lg + AppSpacing.sm, // Standardized height (24)
211+
child: ClipRRect( // Clip the image for rounded corners if desired
212+
borderRadius: BorderRadius.circular(AppSpacing.xs / 2),
213+
child: Image.network(
214+
country.flagUrl,
215+
fit: BoxFit.cover, // Use cover for better filling
216+
errorBuilder: (context, error, stackTrace) => Icon(
217+
Icons.flag_outlined,
218+
color: colorScheme.onSurfaceVariant,
219+
size: AppSpacing.lg, // Adjust size as needed
220+
),
221+
loadingBuilder: (context, child, loadingProgress) {
222+
if (loadingProgress == null) return child;
223+
return Center(
224+
child: CircularProgressIndicator(
225+
strokeWidth: 2,
226+
value: loadingProgress.expectedTotalBytes != null
227+
? loadingProgress.cumulativeBytesLoaded /
228+
loadingProgress.expectedTotalBytes!
229+
: null,
230+
),
231+
);
232+
},
233+
),
216234
),
217235
),
218236
value: isSelected,
219237
onChanged: (bool? value) {
220-
// When a checkbox state changes, update the local selection set
221-
// (`_pageSelectedCountries`) for this page.
222238
setState(() {
223239
if (value == true) {
224-
// Add the country if checked.
225240
_pageSelectedCountries.add(country);
226241
} else {
227-
// Remove the country if unchecked.
228242
_pageSelectedCountries.remove(country);
229243
}
230244
});
231245
},
246+
controlAffinity: ListTileControlAffinity.leading,
247+
contentPadding: const EdgeInsets.symmetric(
248+
horizontal: AppSpacing.paddingMedium,
249+
),
232250
);
233251
},
234252
);

0 commit comments

Comments
 (0)