Skip to content

Commit f9e8aff

Browse files
authored
Merge pull request #37 from headlines-toolkit/feature_developement_entry_point
Feature developement entry point
2 parents 63f38a3 + 4c5192b commit f9e8aff

39 files changed

+1523
-1013
lines changed

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ Developed with best practices for a maintainable and scalable codebase:
4848
* **GoRouter:** Well-structured and powerful navigation.
4949
* **Benefit for you:** An easy-to-understand, extendable, and testable foundation for your project. 📈
5050

51+
#### ⚙️ **Flexible Environment Configuration**
52+
Easily switch between development (in-memory data or local API) and production environments with a simple code change. This empowers rapid prototyping, robust testing, and seamless deployment.
53+
* **Benefit for you:** Accelerate your development cycle and ensure your app is always ready for any deployment scenario. 🚀
54+
5155
#### 🌍 **Localization Ready**
5256
Fully internationalized with working English and Arabic localizations (`.arb` files). Adding more languages is straightforward.
5357
* **Benefit for you:** Easily adapt your application for a global audience. 🌐

lib/account/bloc/account_bloc.dart

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,14 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
1313
AccountBloc({
1414
required HtAuthRepository authenticationRepository,
1515
required HtDataRepository<UserContentPreferences>
16-
userContentPreferencesRepository,
17-
}) : _authenticationRepository = authenticationRepository,
18-
_userContentPreferencesRepository = userContentPreferencesRepository,
19-
super(const AccountState()) {
16+
userContentPreferencesRepository,
17+
}) : _authenticationRepository = authenticationRepository,
18+
_userContentPreferencesRepository = userContentPreferencesRepository,
19+
super(const AccountState()) {
2020
// Listen to user changes from HtAuthRepository
21-
_userSubscription =
22-
_authenticationRepository.authStateChanges.listen((user) {
21+
_userSubscription = _authenticationRepository.authStateChanges.listen((
22+
user,
23+
) {
2324
add(AccountUserChanged(user));
2425
});
2526

@@ -35,7 +36,7 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
3536

3637
final HtAuthRepository _authenticationRepository;
3738
final HtDataRepository<UserContentPreferences>
38-
_userContentPreferencesRepository;
39+
_userContentPreferencesRepository;
3940
late StreamSubscription<User?> _userSubscription;
4041

4142
Future<void> _onAccountUserChanged(
@@ -47,7 +48,9 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
4748
add(AccountLoadUserPreferences(userId: event.user!.id));
4849
} else {
4950
// Clear preferences if user is null (logged out)
50-
emit(state.copyWith(clearPreferences: true, status: AccountStatus.initial));
51+
emit(
52+
state.copyWith(clearPreferences: true, status: AccountStatus.initial),
53+
);
5154
}
5255
}
5356

@@ -113,8 +116,9 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
113116
emit(state.copyWith(status: AccountStatus.loading));
114117

115118
final currentPrefs = state.preferences!;
116-
final isCurrentlySaved =
117-
currentPrefs.savedHeadlines.any((h) => h.id == event.headline.id);
119+
final isCurrentlySaved = currentPrefs.savedHeadlines.any(
120+
(h) => h.id == event.headline.id,
121+
);
118122
final List<Headline> updatedSavedHeadlines;
119123

120124
if (isCurrentlySaved) {
@@ -125,8 +129,9 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
125129
..add(event.headline);
126130
}
127131

128-
final updatedPrefs =
129-
currentPrefs.copyWith(savedHeadlines: updatedSavedHeadlines);
132+
final updatedPrefs = currentPrefs.copyWith(
133+
savedHeadlines: updatedSavedHeadlines,
134+
);
130135

131136
try {
132137
await _userContentPreferencesRepository.update(
@@ -163,8 +168,9 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
163168
emit(state.copyWith(status: AccountStatus.loading));
164169

165170
final currentPrefs = state.preferences!;
166-
final isCurrentlyFollowed = currentPrefs.followedCategories
167-
.any((c) => c.id == event.category.id);
171+
final isCurrentlyFollowed = currentPrefs.followedCategories.any(
172+
(c) => c.id == event.category.id,
173+
);
168174
final List<Category> updatedFollowedCategories;
169175

170176
if (isCurrentlyFollowed) {
@@ -175,8 +181,9 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
175181
..add(event.category);
176182
}
177183

178-
final updatedPrefs =
179-
currentPrefs.copyWith(followedCategories: updatedFollowedCategories);
184+
final updatedPrefs = currentPrefs.copyWith(
185+
followedCategories: updatedFollowedCategories,
186+
);
180187

181188
try {
182189
await _userContentPreferencesRepository.update(
@@ -213,8 +220,9 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
213220
emit(state.copyWith(status: AccountStatus.loading));
214221

215222
final currentPrefs = state.preferences!;
216-
final isCurrentlyFollowed =
217-
currentPrefs.followedSources.any((s) => s.id == event.source.id);
223+
final isCurrentlyFollowed = currentPrefs.followedSources.any(
224+
(s) => s.id == event.source.id,
225+
);
218226
final List<Source> updatedFollowedSources;
219227

220228
if (isCurrentlyFollowed) {
@@ -225,8 +233,9 @@ class AccountBloc extends Bloc<AccountEvent, AccountState> {
225233
..add(event.source);
226234
}
227235

228-
final updatedPrefs =
229-
currentPrefs.copyWith(followedSources: updatedFollowedSources);
236+
final updatedPrefs = currentPrefs.copyWith(
237+
followedSources: updatedFollowedSources,
238+
);
230239

231240
try {
232241
await _userContentPreferencesRepository.update(

lib/account/bloc/account_event.dart

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,17 @@ abstract class AccountEvent extends Equatable {
77
List<Object?> get props => [];
88
}
99

10-
class AccountUserChanged extends AccountEvent { // Corrected name
10+
class AccountUserChanged extends AccountEvent {
11+
// Corrected name
1112
const AccountUserChanged(this.user);
1213
final User? user;
1314

1415
@override
1516
List<Object?> get props => [user];
1617
}
1718

18-
class AccountLoadUserPreferences extends AccountEvent { // Corrected name
19+
class AccountLoadUserPreferences extends AccountEvent {
20+
// Corrected name
1921
const AccountLoadUserPreferences({required this.userId});
2022
final String userId;
2123

lib/account/bloc/account_state.dart

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,7 @@ class AccountState extends Equatable {
2727
return AccountState(
2828
status: status ?? this.status,
2929
user: clearUser ? null : user ?? this.user,
30-
preferences:
31-
clearPreferences ? null : preferences ?? this.preferences,
30+
preferences: clearPreferences ? null : preferences ?? this.preferences,
3231
errorMessage:
3332
clearErrorMessage ? null : errorMessage ?? this.errorMessage,
3433
);

lib/account/view/account_page.dart

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,17 @@ class AccountPage extends StatelessWidget {
3535
),
3636
),
3737
body: ListView(
38-
padding: const EdgeInsets.all(AppSpacing.paddingMedium), // Adjusted padding
38+
padding: const EdgeInsets.all(
39+
AppSpacing.paddingMedium,
40+
), // Adjusted padding
3941
children: [
4042
_buildUserHeader(context, user, isAnonymous),
4143
const SizedBox(height: AppSpacing.lg), // Adjusted spacing
4244
ListTile(
43-
leading: Icon(Icons.tune_outlined, color: theme.colorScheme.primary),
45+
leading: Icon(
46+
Icons.tune_outlined,
47+
color: theme.colorScheme.primary,
48+
),
4449
title: Text(
4550
l10n.accountContentPreferencesTile,
4651
style: textTheme.titleMedium,
@@ -50,9 +55,15 @@ class AccountPage extends StatelessWidget {
5055
context.goNamed(Routes.manageFollowedItemsName);
5156
},
5257
),
53-
const Divider(indent: AppSpacing.paddingMedium, endIndent: AppSpacing.paddingMedium),
58+
const Divider(
59+
indent: AppSpacing.paddingMedium,
60+
endIndent: AppSpacing.paddingMedium,
61+
),
5462
ListTile(
55-
leading: Icon(Icons.bookmark_outline, color: theme.colorScheme.primary),
63+
leading: Icon(
64+
Icons.bookmark_outline,
65+
color: theme.colorScheme.primary,
66+
),
5667
title: Text(
5768
l10n.accountSavedHeadlinesTile,
5869
style: textTheme.titleMedium,
@@ -62,9 +73,15 @@ class AccountPage extends StatelessWidget {
6273
context.goNamed(Routes.accountSavedHeadlinesName);
6374
},
6475
),
65-
const Divider(indent: AppSpacing.paddingMedium, endIndent: AppSpacing.paddingMedium),
76+
const Divider(
77+
indent: AppSpacing.paddingMedium,
78+
endIndent: AppSpacing.paddingMedium,
79+
),
6680
_buildSettingsTile(context),
67-
const Divider(indent: AppSpacing.paddingMedium, endIndent: AppSpacing.paddingMedium),
81+
const Divider(
82+
indent: AppSpacing.paddingMedium,
83+
endIndent: AppSpacing.paddingMedium,
84+
),
6885
],
6986
),
7087
);
@@ -89,12 +106,14 @@ class AccountPage extends StatelessWidget {
89106
displayName = l10n.accountAnonymousUser;
90107
statusWidget = Padding(
91108
padding: const EdgeInsets.only(top: AppSpacing.md), // Increased padding
92-
child: ElevatedButton.icon( // Changed to ElevatedButton
109+
child: ElevatedButton.icon(
110+
// Changed to ElevatedButton
93111
icon: const Icon(Icons.link_outlined),
94112
label: Text(l10n.accountSignInPromptButton),
95113
style: ElevatedButton.styleFrom(
96114
padding: const EdgeInsets.symmetric(
97-
horizontal: AppSpacing.lg, vertical: AppSpacing.sm,
115+
horizontal: AppSpacing.lg,
116+
vertical: AppSpacing.sm,
98117
),
99118
textStyle: textTheme.labelLarge,
100119
),
@@ -111,7 +130,8 @@ class AccountPage extends StatelessWidget {
111130
statusWidget = Column(
112131
mainAxisSize: MainAxisSize.min, // To keep column tight
113132
children: [
114-
if (user?.role != null) ...[ // Show role only if available
133+
if (user?.role != null) ...[
134+
// Show role only if available
115135
const SizedBox(height: AppSpacing.xs),
116136
Text(
117137
l10n.accountRoleLabel(user!.role.name),
@@ -122,21 +142,23 @@ class AccountPage extends StatelessWidget {
122142
),
123143
],
124144
const SizedBox(height: AppSpacing.md), // Consistent spacing
125-
OutlinedButton.icon( // Changed to OutlinedButton.icon
145+
OutlinedButton.icon(
146+
// Changed to OutlinedButton.icon
126147
icon: Icon(Icons.logout, color: colorScheme.error),
127148
label: Text(l10n.accountSignOutTile),
128149
style: OutlinedButton.styleFrom(
129150
foregroundColor: colorScheme.error,
130151
side: BorderSide(color: colorScheme.error.withOpacity(0.5)),
131152
padding: const EdgeInsets.symmetric(
132-
horizontal: AppSpacing.lg, vertical: AppSpacing.sm,
153+
horizontal: AppSpacing.lg,
154+
vertical: AppSpacing.sm,
133155
),
134156
textStyle: textTheme.labelLarge,
135157
),
136158
onPressed: () {
137-
context
138-
.read<AuthenticationBloc>()
139-
.add(const AuthenticationSignOutRequested());
159+
context.read<AuthenticationBloc>().add(
160+
const AuthenticationSignOutRequested(),
161+
);
140162
},
141163
),
142164
],

0 commit comments

Comments
 (0)