@@ -100,12 +100,17 @@ class _CategoryFilterPageState extends State<CategoryFilterPage> {
100100 Widget build (BuildContext context) {
101101 final l10n = context.l10n;
102102
103+ final theme = Theme .of (context); // Get theme
104+ final textTheme = theme.textTheme; // Get textTheme
105+ final colorScheme = theme.colorScheme; // Get colorScheme
106+
103107 return Scaffold (
104108 appBar: AppBar (
105- // Default back button will pop without result (cancelling)
106- title: Text (l10n.headlinesFeedFilterCategoryLabel),
109+ title: Text (
110+ l10n.headlinesFeedFilterCategoryLabel,
111+ style: textTheme.titleLarge, // Apply consistent title style
112+ ),
107113 actions: [
108- // Apply Button
109114 IconButton (
110115 icon: const Icon (Icons .check),
111116 tooltip: l10n.headlinesFeedFilterApplyButton,
@@ -129,6 +134,9 @@ class _CategoryFilterPageState extends State<CategoryFilterPage> {
129134 /// Builds the main content body based on the current [CategoriesFilterState] .
130135 Widget _buildBody (BuildContext context, CategoriesFilterState state) {
131136 final l10n = context.l10n;
137+ final theme = Theme .of (context); // Get theme
138+ final textTheme = theme.textTheme; // Get textTheme
139+ final colorScheme = theme.colorScheme; // Get colorScheme
132140
133141 // Handle initial loading state
134142 if (state.status == CategoriesFilterStatus .loading) {
@@ -140,53 +148,44 @@ class _CategoryFilterPageState extends State<CategoryFilterPage> {
140148 }
141149
142150 // Handle failure state (show error and retry button)
143- // Only show full error screen if not loading more (i.e., initial load failed)
144151 if (state.status == CategoriesFilterStatus .failure &&
145152 state.categories.isEmpty) {
146153 return FailureStateWidget (
147154 message: state.error? .toString () ?? l10n.unknownError,
148- onRetry:
149- () => context.read <CategoriesFilterBloc >().add (
150- CategoriesFilterRequested (),
151- ),
155+ onRetry: () =>
156+ context.read <CategoriesFilterBloc >().add (CategoriesFilterRequested ()),
152157 );
153158 }
154159
155160 // Handle empty state (after successful load but no categories found)
156161 if (state.status == CategoriesFilterStatus .success &&
157162 state.categories.isEmpty) {
158163 return InitialStateWidget (
159- icon: Icons .search_off,
164+ icon: Icons .search_off_outlined, // Use outlined version
160165 headline: l10n.categoryFilterEmptyHeadline,
161166 subheadline: l10n.categoryFilterEmptySubheadline,
162167 );
163168 }
164169
165170 // Handle loaded state (success or loading more)
166- // Show the list, potentially with a loading indicator at the bottom
167171 return ListView .builder (
168172 controller: _scrollController,
169- padding: const EdgeInsets .only (
170- bottom: AppSpacing .xxl, // Padding at the bottom for loader/content
171- ),
172- // Add 1 to item count if loading more or if failed during load more
173- itemCount:
174- state.categories.length +
173+ padding: const EdgeInsets .symmetric (vertical: AppSpacing .paddingSmall)
174+ .copyWith (bottom: AppSpacing .xxl), // Consistent vertical padding
175+ itemCount: state.categories.length +
175176 ((state.status == CategoriesFilterStatus .loadingMore ||
176177 (state.status == CategoriesFilterStatus .failure &&
177178 state.categories.isNotEmpty))
178179 ? 1
179180 : 0 ),
180181 itemBuilder: (context, index) {
181- // Check if we need to render the loading/error indicator at the end
182182 if (index >= state.categories.length) {
183183 if (state.status == CategoriesFilterStatus .loadingMore) {
184184 return const Padding (
185185 padding: EdgeInsets .symmetric (vertical: AppSpacing .lg),
186186 child: Center (child: CircularProgressIndicator ()),
187187 );
188188 } else if (state.status == CategoriesFilterStatus .failure) {
189- // Show a smaller error indicator at the bottom if load more failed
190189 return Padding (
191190 padding: const EdgeInsets .symmetric (
192191 vertical: AppSpacing .md,
@@ -195,51 +194,64 @@ class _CategoryFilterPageState extends State<CategoryFilterPage> {
195194 child: Center (
196195 child: Text (
197196 l10n.loadMoreError,
198- style: Theme .of (context).textTheme.bodySmall? .copyWith (
199- color: Theme .of (context).colorScheme.error,
200- ),
197+ style: textTheme.bodySmall
198+ ? .copyWith (color: colorScheme.error),
201199 ),
202200 ),
203201 );
204- } else {
205- return const SizedBox .shrink (); // Should not happen if hasMore is false
206202 }
203+ return const SizedBox .shrink ();
207204 }
208205
209- // Render the actual category item
210206 final category = state.categories[index];
211207 final isSelected = _pageSelectedCategories.contains (category);
212208
213209 return CheckboxListTile (
214- title: Text (category.name),
215- secondary:
216- category.iconUrl != null
217- ? SizedBox (
218- width: 40 ,
219- height: 40 ,
210+ title: Text (category.name, style: textTheme.titleMedium),
211+ secondary: category.iconUrl != null
212+ ? SizedBox (
213+ width: AppSpacing .xl + AppSpacing .sm, // 40 -> 32
214+ height: AppSpacing .xl + AppSpacing .sm,
215+ child: ClipRRect (
216+ borderRadius: BorderRadius .circular (AppSpacing .xs),
220217 child: Image .network (
221218 category.iconUrl! ,
222219 fit: BoxFit .contain,
223- errorBuilder:
224- (context, error, stackTrace) =>
225- const Icon (Icons .category), // Placeholder icon
220+ errorBuilder: (context, error, stackTrace) => Icon (
221+ Icons .category_outlined, // Use outlined
222+ color: colorScheme.onSurfaceVariant, // Theme color
223+ size: AppSpacing .xl,
224+ ),
225+ loadingBuilder: (context, child, loadingProgress) {
226+ if (loadingProgress == null ) return child;
227+ return Center (
228+ child: CircularProgressIndicator (
229+ strokeWidth: 2 ,
230+ value: loadingProgress.expectedTotalBytes != null
231+ ? loadingProgress.cumulativeBytesLoaded /
232+ loadingProgress.expectedTotalBytes!
233+ : null ,
234+ ),
235+ );
236+ },
226237 ),
227- )
228- : null ,
238+ ),
239+ )
240+ : null ,
229241 value: isSelected,
230242 onChanged: (bool ? value) {
231- // When a checkbox state changes, update the local selection set
232- // (`_pageSelectedCategories`) for this page.
233243 setState (() {
234244 if (value == true ) {
235- // Add the category if checked.
236245 _pageSelectedCategories.add (category);
237246 } else {
238- // Remove the category if unchecked.
239247 _pageSelectedCategories.remove (category);
240248 }
241249 });
242250 },
251+ controlAffinity: ListTileControlAffinity .leading,
252+ contentPadding: const EdgeInsets .symmetric (
253+ horizontal: AppSpacing .paddingMedium, // Standard padding
254+ ),
243255 );
244256 },
245257 );
0 commit comments