Skip to content

Commit c3eae65

Browse files
committed
feat(account): Add category follow page
- Implemented UI for category selection - Integrates with AccountBloc - Shows followed categories
1 parent 1cc41ae commit c3eae65

File tree

1 file changed

+120
-0
lines changed

1 file changed

+120
-0
lines changed
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_bloc/flutter_bloc.dart';
3+
import 'package:ht_main/account/bloc/account_bloc.dart';
4+
import 'package:ht_main/headlines-feed/bloc/categories_filter_bloc.dart';
5+
import 'package:ht_main/l10n/l10n.dart';
6+
import 'package:ht_main/shared/constants/app_spacing.dart';
7+
import 'package:ht_main/shared/widgets/widgets.dart';
8+
import 'package:ht_shared/ht_shared.dart';
9+
import 'package:ht_data_repository/ht_data_repository.dart'; // Required for HtDataRepository
10+
11+
/// {@template add_category_to_follow_page}
12+
/// A page that allows users to browse and select categories to follow.
13+
/// {@endtemplate}
14+
class AddCategoryToFollowPage extends StatelessWidget {
15+
/// {@macro add_category_to_follow_page}
16+
const AddCategoryToFollowPage({super.key});
17+
18+
@override
19+
Widget build(BuildContext context) {
20+
final l10n = context.l10n;
21+
// It's better to provide CategoriesFilterBloc here if it's specific to this page
22+
// or ensure it's provided higher up if shared more broadly for "add" flows.
23+
// For now, creating a new instance.
24+
return BlocProvider(
25+
create: (context) => CategoriesFilterBloc(
26+
categoriesRepository: context.read<HtDataRepository<Category>>(),
27+
)..add(CategoriesFilterRequested()), // Removed const
28+
child: Scaffold(
29+
appBar: AppBar(
30+
title: Text(l10n.addCategoriesPageTitle),
31+
),
32+
body: BlocBuilder<CategoriesFilterBloc, CategoriesFilterState>(
33+
builder: (context, categoriesState) {
34+
if (categoriesState.status == CategoriesFilterStatus.loading) {
35+
return const Center(child: CircularProgressIndicator());
36+
}
37+
if (categoriesState.status == CategoriesFilterStatus.failure) {
38+
String errorMessage = l10n.categoryFilterError;
39+
if (categoriesState.error is HtHttpException) {
40+
errorMessage = (categoriesState.error as HtHttpException).message;
41+
} else if (categoriesState.error != null) {
42+
errorMessage = categoriesState.error.toString();
43+
}
44+
return FailureStateWidget(
45+
message: errorMessage,
46+
onRetry: () => context
47+
.read<CategoriesFilterBloc>()
48+
.add(CategoriesFilterRequested()), // Removed const
49+
);
50+
}
51+
if (categoriesState.categories.isEmpty) {
52+
return FailureStateWidget(
53+
message: l10n.categoryFilterEmptyHeadline,
54+
); // Re-use existing key
55+
}
56+
57+
// Use AccountBloc to check which categories are already followed
58+
return BlocBuilder<AccountBloc, AccountState>(
59+
builder: (context, accountState) {
60+
final followedCategories =
61+
accountState.preferences?.followedCategories ?? [];
62+
63+
return ListView.builder(
64+
padding: const EdgeInsets.all(AppSpacing.md),
65+
itemCount: categoriesState.categories.length,
66+
itemBuilder: (context, index) {
67+
final category = categoriesState.categories[index];
68+
final isFollowed = followedCategories
69+
.any((fc) => fc.id == category.id);
70+
71+
return Card(
72+
margin: const EdgeInsets.only(bottom: AppSpacing.sm),
73+
child: ListTile(
74+
leading: category.iconUrl != null &&
75+
Uri.tryParse(category.iconUrl!)?.isAbsolute ==
76+
true
77+
? SizedBox(
78+
width: 36,
79+
height: 36,
80+
child: Image.network(
81+
category.iconUrl!,
82+
fit: BoxFit.contain,
83+
errorBuilder:
84+
(context, error, stackTrace) =>
85+
const Icon(Icons.category_outlined),
86+
),
87+
)
88+
: const Icon(Icons.category_outlined),
89+
title: Text(category.name),
90+
trailing: IconButton(
91+
icon: isFollowed
92+
? Icon(
93+
Icons.check_circle,
94+
color: Theme.of(context).colorScheme.primary,
95+
)
96+
: const Icon(Icons.add_circle_outline),
97+
tooltip: isFollowed
98+
? l10n.unfollowCategoryTooltip(category.name)
99+
: l10n.followCategoryTooltip(category.name), // New
100+
onPressed: () {
101+
context.read<AccountBloc>().add(
102+
AccountFollowCategoryToggled(
103+
category: category,
104+
),
105+
);
106+
},
107+
),
108+
// Optional: onTap could also toggle
109+
),
110+
);
111+
},
112+
);
113+
},
114+
);
115+
},
116+
),
117+
),
118+
);
119+
}
120+
}

0 commit comments

Comments
 (0)