Skip to content

Commit be28f8f

Browse files
authored
Enhancement/bloc use example (#110)
* refactor auth service and auth cubit logic * improve loading screen * fix copilot suggestions
1 parent 3aecefe commit be28f8f

File tree

12 files changed

+87
-239
lines changed

12 files changed

+87
-239
lines changed

.github/pull_request_template.md

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,3 @@
99

1010
#### Notes:
1111
[extra note or considerations]
12-
13-
@rs-gpt-review Describe the changes in this PR. Recommend improvements (including code improvements), possible memory leaks, and best practices.

.github/workflows/rs-gpt-review.yml

Lines changed: 0 additions & 37 deletions
This file was deleted.
Lines changed: 11 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,26 @@
11
import 'package:flutter/material.dart';
22

33
class LoadingScreen extends StatelessWidget {
4-
final bool isLoading;
54
final Color? color;
65

76
const LoadingScreen({
87
super.key,
9-
required this.isLoading,
108
this.color,
119
});
1210

1311
@override
1412
Widget build(BuildContext context) {
15-
return Positioned.fill(
16-
child: isLoading
17-
? Container(
18-
color: Colors.transparent,
19-
child: Center(
20-
child: SizedBox(
21-
width: 24,
22-
height: 24,
23-
child: CircularProgressIndicator(
24-
color: color,
25-
),
26-
),
27-
),
28-
)
29-
: const SizedBox.shrink(),
13+
return Container(
14+
color: Theme.of(context).colorScheme.primaryContainer.withAlpha(50),
15+
child: Center(
16+
child: SizedBox(
17+
width: 24,
18+
height: 24,
19+
child: CircularProgressIndicator(
20+
color: color,
21+
),
22+
),
23+
),
3024
);
3125
}
3226
}

app/lib/presentation/ui/pages/home/home_view.dart

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import 'package:app/main/init.dart';
2-
import 'package:domain/services/auth_service.dart';
2+
import 'package:domain/bloc/auth/auth_cubit.dart';
33
import 'package:flutter/material.dart';
44
import 'package:app/presentation/ui/custom/app_theme_switch.dart';
55

66
class HomeView extends StatelessWidget {
7-
AuthService get _authService => getIt();
7+
/// Given this is a global cubit, we can access it directly from getIt
8+
/// otherwise use context.read<AuthCubit>() to read the Cubit under that context
9+
AuthCubit get _authCubit => getIt();
810

911
const HomeView({super.key});
1012

@@ -14,7 +16,7 @@ class HomeView extends StatelessWidget {
1416
appBar: AppBar(
1517
actions: [
1618
IconButton(
17-
onPressed: () => _authService.onLogout(),
19+
onPressed: () => _authCubit.logOut(),
1820
icon: const Icon(Icons.logout),
1921
),
2022
const AppThemeSwitch(),

app/lib/presentation/ui/pages/login/login_page.dart

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,23 @@ import 'package:app/presentation/ui/custom/app_theme_switch.dart';
55
import 'package:app/presentation/ui/custom/loading_screen.dart';
66
import 'package:common/core/resource.dart';
77
import 'package:domain/bloc/auth/auth_cubit.dart';
8-
import 'package:domain/services/auth_service.dart';
98
import 'package:flutter/foundation.dart';
109
import 'package:flutter/material.dart';
1110
import 'package:flutter_bloc/flutter_bloc.dart';
1211

1312
import '../../custom/environment_selector.dart';
1413

1514
class LoginPage extends StatelessWidget {
16-
AuthService get _authService => getIt();
17-
1815
const LoginPage({super.key});
1916

17+
AuthCubit get _authCubit => getIt();
18+
2019
@override
2120
Widget build(BuildContext context) {
22-
return Stack(
23-
children: [
24-
Scaffold(
25-
appBar: AppBar(),
26-
backgroundColor: context.theme.colorScheme.surface,
27-
body: Padding(
21+
return Scaffold(
22+
body: Stack(
23+
children: [
24+
Padding(
2825
padding: EdgeInsets.all(spacing.m),
2926
child: Column(
3027
mainAxisAlignment: MainAxisAlignment.center,
@@ -36,7 +33,7 @@ class LoginPage extends StatelessWidget {
3633
child: ElevatedButton(
3734
child: const Text('Login'),
3835
onPressed: () {
39-
_authService.logInWithCredentials(
36+
_authCubit.login(
4037
'Rootstrap',
4138
'12345678',
4239
);
@@ -50,9 +47,9 @@ class LoginPage extends StatelessWidget {
5047
],
5148
),
5249
),
53-
),
54-
const _Loading(),
55-
],
50+
const _Loading(),
51+
],
52+
),
5653
);
5754
}
5855
}
@@ -64,8 +61,15 @@ class _Loading extends StatelessWidget {
6461
Widget build(BuildContext context) {
6562
return BlocBuilder<AuthCubit, Resource>(
6663
builder: (context, state) {
67-
return LoadingScreen(
68-
isLoading: state is RLoading,
64+
if (state is! RLoading) {
65+
return const SizedBox.shrink();
66+
}
67+
68+
return Container(
69+
color: Colors.black.withAlpha(50),
70+
width: double.maxFinite,
71+
height: double.maxFinite,
72+
child: const LoadingScreen(),
6973
);
7074
},
7175
);

app/lib/presentation/ui/pages/splash/splash_page.dart

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import 'package:app/main/init.dart';
2-
import 'package:domain/services/auth_service.dart';
2+
import 'package:domain/bloc/auth/auth_cubit.dart';
33
import 'package:flutter/material.dart';
44

55
class SplashPage extends StatefulWidget {
@@ -10,12 +10,19 @@ class SplashPage extends StatefulWidget {
1010
}
1111

1212
class _SplashPageState extends State<SplashPage> {
13-
AuthService get _authService => getIt();
13+
/// Given this is a global cubit, we can access it directly from getIt
14+
/// otherwise use context.read<AuthCubit>() to read the Cubit under that context
15+
AuthCubit get _authCubit => getIt();
1416

1517
@override
1618
void initState() {
1719
super.initState();
18-
_authService.onValidate();
20+
21+
/// Add post frame callback to avoid calling bloc methods during build
22+
WidgetsBinding.instance.addPostFrameCallback((_) async {
23+
await Future.delayed(const Duration(seconds: 1));
24+
_authCubit.onValidate();
25+
});
1926
}
2027

2128
@override

melos.yaml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@ packages:
55
- modules/*
66

77
scripts:
8+
run:web:
9+
description: Run the app in development mode for web.
10+
run: melos exec --scope="app" -- \
11+
flutter run -t lib/main.dart --dart-define-from-file=env/.dev -d chrome
812
lint:all:
913
run: melos run analyze && melos run format
1014
description: Run all static analysis checks.
@@ -38,4 +42,4 @@ scripts:
3842
description: Run `dart doctor` in selected or all packages. Includes prompt for packages.
3943
packageFilters:
4044
dirExists:
41-
- lib
45+
- lib

modules/domain/lib/bloc/auth/auth_cubit.dart

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,35 @@
11
import 'package:common/core/resource.dart';
2+
import 'package:common/core/result_type.dart';
23
import 'package:domain/bloc/base_cubit.dart';
34
import 'package:domain/bloc/auth/auth_state.dart';
5+
import 'package:domain/services/auth_service.dart';
46

57
class AuthCubit extends BaseCubit<AuthState> {
6-
AuthCubit() : super(RSuccess(data: AuthStateUnknown()));
8+
final AuthService _authService;
9+
AuthCubit(this._authService) : super(RSuccess(data: AuthStateUnknown()));
10+
11+
Future<void> login(String username, String password) async {
12+
isLoading();
13+
final authResult =
14+
await _authService.logInWithCredentials(username, password);
15+
16+
authResult
17+
..mapSuccess((_) => isLogin())
18+
..mapError((failure) => isError(failure));
19+
}
20+
21+
Future<void> onValidate() async {
22+
if (_authService.isLoggedIn()) {
23+
isLogin();
24+
} else {
25+
isLogOut();
26+
}
27+
}
28+
29+
Future<void> logOut() async {
30+
await _authService.onLogout();
31+
isLogOut();
32+
}
733

834
void isLogin() => isSuccess(AuthStateAuthenticated());
935

modules/domain/lib/init.dart

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,11 @@ import 'package:get_it/get_it.dart';
55

66
class DomainInit {
77
static Future<void> initialize(GetIt getIt) async {
8-
//Cubits
9-
getIt.registerSingleton(AppCubit(getIt()));
10-
getIt.registerSingleton(AuthCubit());
11-
128
//Services
13-
getIt.registerLazySingleton(() => AuthService(getIt(), getIt()));
9+
getIt.registerLazySingleton(() => AuthService(getIt()));
10+
11+
//Global Cubits
12+
getIt.registerSingleton(AppCubit(getIt()));
13+
getIt.registerSingleton(AuthCubit(getIt()));
1414
}
1515
}
Lines changed: 5 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,18 @@
11
import 'package:common/core/result_type.dart';
2-
import 'package:domain/bloc/auth/auth_cubit.dart';
32
import 'package:domain/repositories/auth_repository.dart';
43

54
class AuthService {
65
final AuthRepository _authRepository;
7-
final AuthCubit _sessionCubit;
86

9-
AuthService(this._authRepository, this._sessionCubit);
7+
AuthService(this._authRepository);
108

11-
Future<void> logInWithCredentials(String username, String password) async {
12-
_sessionCubit.isLoading();
13-
final result = await _authRepository.login(username, password);
14-
switch (result) {
15-
case TSuccess<void> _:
16-
_sessionCubit.isLogin();
17-
case TError<void> _:
18-
_sessionCubit.isError(result.error);
19-
}
20-
}
9+
Future<ResultType<void>> logInWithCredentials(
10+
String username, String password) =>
11+
_authRepository.login(username, password);
2112

22-
void onValidate() {
23-
if (_authRepository.isLoggedIn()) {
24-
_sessionCubit.isLogin();
25-
} else {
26-
_sessionCubit.isLogOut();
27-
}
28-
}
13+
bool isLoggedIn() => _authRepository.isLoggedIn();
2914

3015
Future<void> onLogout() async {
3116
await _authRepository.logout();
32-
_sessionCubit.isLogOut();
3317
}
3418
}

0 commit comments

Comments
 (0)