Skip to content

Commit 68ce42b

Browse files
authored
Merge pull request #1 from headlines-toolkit/chore_simplify_codebase
Chore simplify codebase
2 parents 99e636f + 1a02b19 commit 68ce42b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

57 files changed

+3316
-31
lines changed

analysis_options.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
analyzer:
2+
errors:
3+
avoid_print: ignore
14
include: package:very_good_analysis/analysis_options.9.0.0.yaml
25
linter:
36
rules:

lib/app/app.dart

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export 'view/app.dart';

lib/app/bloc/app_bloc.dart

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import 'dart:async';
2+
3+
import 'package:bloc/bloc.dart';
4+
import 'package:equatable/equatable.dart';
5+
import 'package:ht_auth_repository/ht_auth_repository.dart';
6+
import 'package:ht_data_repository/ht_data_repository.dart';
7+
import 'package:ht_dashboard/app/config/config.dart' as local_config;
8+
import 'package:ht_shared/ht_shared.dart';
9+
10+
part 'app_event.dart';
11+
part 'app_state.dart';
12+
13+
class AppBloc extends Bloc<AppEvent, AppState> {
14+
AppBloc({
15+
required HtAuthRepository authenticationRepository,
16+
required HtDataRepository<UserAppSettings> userAppSettingsRepository,
17+
required HtDataRepository<AppConfig> appConfigRepository,
18+
required local_config.AppEnvironment environment,
19+
}) : _authenticationRepository = authenticationRepository,
20+
_userAppSettingsRepository = userAppSettingsRepository,
21+
_appConfigRepository = appConfigRepository,
22+
_environment = environment,
23+
super(
24+
const AppState(
25+
user: null,
26+
status: AppStatus.initial,
27+
environment: null,
28+
),
29+
) {
30+
on<AppUserChanged>(_onAppUserChanged);
31+
on<AppLogoutRequested>(_onLogoutRequested);
32+
33+
_userSubscription = _authenticationRepository.authStateChanges.listen(
34+
(User? user) => add(AppUserChanged(user)),
35+
);
36+
}
37+
38+
final HtAuthRepository _authenticationRepository;
39+
final HtDataRepository<UserAppSettings> _userAppSettingsRepository;
40+
final HtDataRepository<AppConfig> _appConfigRepository;
41+
final local_config.AppEnvironment _environment;
42+
late final StreamSubscription<User?> _userSubscription;
43+
44+
/// Handles user changes and loads initial settings once user is available.
45+
Future<void> _onAppUserChanged(
46+
AppUserChanged event,
47+
Emitter<AppState> emit,
48+
) async {
49+
// Determine the AppStatus based on the user object and its role
50+
final AppStatus status;
51+
52+
switch (event.user?.role) {
53+
case null:
54+
status = AppStatus.unauthenticated;
55+
case UserRole.standardUser:
56+
status = AppStatus.authenticated;
57+
// ignore: no_default_cases
58+
default: // Fallback for any other roles not explicitly handled
59+
status = AppStatus.unauthenticated; // Treat other roles as unauthenticated for dashboard
60+
}
61+
62+
// Emit user and status update
63+
emit(state.copyWith(status: status, user: event.user));
64+
}
65+
66+
void _onLogoutRequested(AppLogoutRequested event, Emitter<AppState> emit) {
67+
unawaited(_authenticationRepository.signOut());
68+
}
69+
70+
@override
71+
Future<void> close() {
72+
_userSubscription.cancel();
73+
return super.close();
74+
}
75+
}

lib/app/bloc/app_event.dart

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
part of 'app_bloc.dart';
2+
3+
abstract class AppEvent extends Equatable {
4+
const AppEvent();
5+
6+
@override
7+
List<Object?> get props => [];
8+
}
9+
10+
class AppUserChanged extends AppEvent {
11+
const AppUserChanged(this.user);
12+
13+
final User? user;
14+
15+
@override
16+
List<Object?> get props => [user];
17+
}
18+
19+
/// {@template app_logout_requested}
20+
/// Event to request user logout.
21+
/// {@endtemplate}
22+
class AppLogoutRequested extends AppEvent {
23+
/// {@macro app_logout_requested}
24+
const AppLogoutRequested();
25+
}

lib/app/bloc/app_state.dart

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
part of 'app_bloc.dart';
2+
3+
/// Represents the application's authentication status.
4+
enum AppStatus {
5+
/// The application is initializing and the status is unknown.
6+
initial,
7+
8+
/// The user is authenticated.
9+
authenticated,
10+
11+
/// The user is unauthenticated.
12+
unauthenticated,
13+
14+
/// The user is anonymous (signed in using an anonymous provider).
15+
anonymous,
16+
}
17+
18+
class AppState extends Equatable {
19+
/// {@macro app_state}
20+
const AppState({
21+
this.status = AppStatus.initial,
22+
this.user,
23+
this.environment,
24+
});
25+
26+
/// The current authentication status of the application.
27+
final AppStatus status;
28+
29+
/// The current user details. Null if unauthenticated.
30+
final User? user;
31+
32+
/// The current application environment (e.g., production, development, demo).
33+
final local_config.AppEnvironment? environment;
34+
35+
/// Creates a copy of the current state with updated values.
36+
AppState copyWith({
37+
AppStatus? status,
38+
User? user,
39+
local_config.AppEnvironment? environment,
40+
bool clearEnvironment = false,
41+
}) {
42+
return AppState(
43+
status: status ?? this.status,
44+
user: user ?? this.user,
45+
environment: clearEnvironment ? null : environment ?? this.environment,
46+
);
47+
}
48+
49+
@override
50+
List<Object?> get props => [
51+
status,
52+
user,
53+
environment,
54+
];
55+
}

lib/app/config/app_config.dart

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import 'package:ht_dashboard/app/config/app_environment.dart';
2+
3+
class AppConfig {
4+
const AppConfig({
5+
required this.environment,
6+
required this.baseUrl,
7+
});
8+
9+
factory AppConfig.production() => const AppConfig(
10+
environment: AppEnvironment.production,
11+
baseUrl: 'http://api.yourproductiondomain.com',
12+
);
13+
14+
factory AppConfig.demo() => const AppConfig(
15+
environment: AppEnvironment.demo,
16+
baseUrl: '',
17+
);
18+
19+
factory AppConfig.development() => const AppConfig(
20+
environment: AppEnvironment.development,
21+
baseUrl: 'http://localhost:8080',
22+
);
23+
24+
final AppEnvironment environment;
25+
final String baseUrl;
26+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/// Defines the different application environments.
2+
enum AppEnvironment {
3+
/// Represents the production environment.
4+
///
5+
/// This environment is used for the live application, connecting to
6+
/// production backend services and configurations.
7+
production,
8+
9+
/// Represents a development environment connecting to a local API.
10+
///
11+
/// This environment is used during local development, typically connecting
12+
/// to a locally running Dart Frog backend API.
13+
development,
14+
15+
/// Represents a demonstration environment with in-memory data.
16+
///
17+
/// This environment is designed for showcasing the application's user
18+
/// interface and features without requiring any external backend services.
19+
/// All data operations are handled by mock data stored directly in memory,
20+
/// eliminating the need for API access.
21+
demo,
22+
23+
// Add other environments like staging, etc. as needed
24+
}

lib/app/config/config.dart

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
export 'app_config.dart';
2+
export 'app_environment.dart';

lib/app/view/app.dart

Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
//
2+
// ignore_for_file: deprecated_member_use
3+
4+
import 'package:flutter/material.dart';
5+
import 'package:flutter_bloc/flutter_bloc.dart';
6+
import 'package:go_router/go_router.dart';
7+
import 'package:ht_auth_repository/ht_auth_repository.dart';
8+
import 'package:ht_data_repository/ht_data_repository.dart';
9+
import 'package:ht_kv_storage_service/ht_kv_storage_service.dart';
10+
import 'package:ht_dashboard/app/bloc/app_bloc.dart';
11+
import 'package:ht_dashboard/app/config/app_environment.dart';
12+
import 'package:ht_dashboard/authentication/bloc/authentication_bloc.dart';
13+
import 'package:ht_dashboard/l10n/app_localizations.dart';
14+
import 'package:ht_dashboard/l10n/l10n.dart';
15+
import 'package:ht_dashboard/router/router.dart';
16+
import 'package:ht_shared/ht_shared.dart';
17+
18+
class App extends StatelessWidget {
19+
const App({
20+
required HtAuthRepository htAuthenticationRepository,
21+
required HtDataRepository<Headline> htHeadlinesRepository,
22+
required HtDataRepository<Category> htCategoriesRepository,
23+
required HtDataRepository<Country> htCountriesRepository,
24+
required HtDataRepository<Source> htSourcesRepository,
25+
required HtDataRepository<UserAppSettings> htUserAppSettingsRepository,
26+
required HtDataRepository<UserContentPreferences>
27+
htUserContentPreferencesRepository,
28+
required HtDataRepository<AppConfig> htAppConfigRepository,
29+
required HtKVStorageService kvStorageService,
30+
required AppEnvironment environment,
31+
super.key,
32+
}) : _htAuthenticationRepository = htAuthenticationRepository,
33+
_htHeadlinesRepository = htHeadlinesRepository,
34+
_htCategoriesRepository = htCategoriesRepository,
35+
_htCountriesRepository = htCountriesRepository,
36+
_htSourcesRepository = htSourcesRepository,
37+
_htUserAppSettingsRepository = htUserAppSettingsRepository,
38+
_htUserContentPreferencesRepository = htUserContentPreferencesRepository,
39+
_htAppConfigRepository = htAppConfigRepository,
40+
_kvStorageService = kvStorageService,
41+
_environment = environment;
42+
43+
final HtAuthRepository _htAuthenticationRepository;
44+
final HtDataRepository<Headline> _htHeadlinesRepository;
45+
final HtDataRepository<Category> _htCategoriesRepository;
46+
final HtDataRepository<Country> _htCountriesRepository;
47+
final HtDataRepository<Source> _htSourcesRepository;
48+
final HtDataRepository<UserAppSettings> _htUserAppSettingsRepository;
49+
final HtDataRepository<UserContentPreferences>
50+
_htUserContentPreferencesRepository;
51+
final HtDataRepository<AppConfig> _htAppConfigRepository;
52+
final HtKVStorageService _kvStorageService;
53+
final AppEnvironment _environment;
54+
55+
@override
56+
Widget build(BuildContext context) {
57+
return MultiRepositoryProvider(
58+
providers: [
59+
RepositoryProvider.value(value: _htAuthenticationRepository),
60+
RepositoryProvider.value(value: _htHeadlinesRepository),
61+
RepositoryProvider.value(value: _htCategoriesRepository),
62+
RepositoryProvider.value(value: _htCountriesRepository),
63+
RepositoryProvider.value(value: _htSourcesRepository),
64+
RepositoryProvider.value(value: _htUserAppSettingsRepository),
65+
RepositoryProvider.value(value: _htUserContentPreferencesRepository),
66+
RepositoryProvider.value(value: _htAppConfigRepository),
67+
RepositoryProvider.value(value: _kvStorageService),
68+
],
69+
child: MultiBlocProvider(
70+
providers: [
71+
BlocProvider(
72+
create: (context) => AppBloc(
73+
authenticationRepository: context.read<HtAuthRepository>(),
74+
userAppSettingsRepository:
75+
context.read<HtDataRepository<UserAppSettings>>(),
76+
appConfigRepository: context.read<HtDataRepository<AppConfig>>(),
77+
environment: _environment,
78+
),
79+
),
80+
BlocProvider(
81+
create: (context) => AuthenticationBloc(
82+
authenticationRepository: context.read<HtAuthRepository>(),
83+
),
84+
),
85+
],
86+
child: _AppView(
87+
htAuthenticationRepository: _htAuthenticationRepository,
88+
environment: _environment,
89+
),
90+
),
91+
);
92+
}
93+
}
94+
95+
class _AppView extends StatefulWidget {
96+
const _AppView({
97+
required this.htAuthenticationRepository,
98+
required this.environment,
99+
});
100+
101+
final HtAuthRepository htAuthenticationRepository;
102+
final AppEnvironment environment;
103+
104+
@override
105+
State<_AppView> createState() => _AppViewState();
106+
}
107+
108+
class _AppViewState extends State<_AppView> {
109+
late final GoRouter _router;
110+
late final ValueNotifier<AppStatus> _statusNotifier;
111+
112+
@override
113+
void initState() {
114+
super.initState();
115+
final appBloc = context.read<AppBloc>();
116+
_statusNotifier = ValueNotifier<AppStatus>(appBloc.state.status);
117+
_router = createRouter(
118+
authStatusNotifier: _statusNotifier,
119+
htAuthenticationRepository: widget.htAuthenticationRepository,
120+
environment: widget.environment,
121+
);
122+
}
123+
124+
@override
125+
void dispose() {
126+
_statusNotifier.dispose();
127+
super.dispose();
128+
}
129+
130+
@override
131+
Widget build(BuildContext context) {
132+
return BlocListener<AppBloc, AppState>(
133+
listenWhen: (previous, current) => previous.status != current.status,
134+
listener: (context, state) {
135+
_statusNotifier.value = state.status;
136+
},
137+
child: BlocBuilder<AppBloc, AppState>(
138+
builder: (context, state) {
139+
return MaterialApp.router(
140+
debugShowCheckedModeBanner: false,
141+
routerConfig: _router,
142+
localizationsDelegates: AppLocalizations.localizationsDelegates,
143+
supportedLocales: AppLocalizations.supportedLocales,
144+
);
145+
},
146+
),
147+
);
148+
}
149+
}

0 commit comments

Comments
 (0)