Skip to content

Commit 2bd8495

Browse files
Merge branch 'airqo-platform:staging' into NetManagerMapFunc
2 parents 041591c + 75924ef commit 2bd8495

File tree

7 files changed

+108
-90
lines changed

7 files changed

+108
-90
lines changed

mobile-v3/android/app/build.gradle

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,14 +39,14 @@ if (localPropertiesFile.exists()) {
3939
}
4040
}
4141

42-
def googleMapApiKey = appProperties.getProperty('google.maps.key')
42+
def googleMapApiKey = appProperties.getProperty('google.maps.key') ?: secrets.getProperty('MAPS_API_KEY')
4343
if (googleMapApiKey == null) {
44-
throw new GradleException("Google Maps Key not found. Define google.maps.key in the key.properties file.")
44+
throw new GradleException("Google Maps Key not found. Define either google.maps.key in key.properties or MAPS_API_KEY in secrets.properties")
4545
}
4646

47-
def googleMapApiKeyDev = appProperties.getProperty('google.maps.key.dev')
47+
def googleMapApiKeyDev = appProperties.getProperty('google.maps.key.dev') ?: secrets.getProperty('MAPS_API_KEY_DEV')
4848
if (googleMapApiKeyDev == null) {
49-
throw new GradleException("Google Maps Key not found. Define google.maps.key_dev in the key.properties file.")
49+
throw new GradleException("Google Maps Dev Key not found. Define either google.maps.key.dev in key.properties or MAPS_API_KEY_DEV in secrets.properties")
5050
}
5151

5252
def flutterVersionCode = localProperties.getProperty('flutter.versionCode')

mobile-v3/android/app/src/main/AndroidManifest.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,12 @@
1010

1111
<!-- TODO: Add your Google Maps API key here -->
1212
<meta-data android:name="com.google.android.geo.API_KEY"
13-
android:value="${MAPS_API_KEY}" />
13+
android:value="${googleMapsKey}" />
14+
15+
<!-- Google Places API key -->
16+
<meta-data
17+
android:name="com.google.android.places.API_KEY"
18+
android:value="${PLACES_API_KEY}" />
1419
<activity
1520
android:name=".MainActivity"
1621
android:exported="true"

mobile-v3/lib/src/app/auth/bloc/auth_bloc.dart

Lines changed: 19 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -9,65 +9,21 @@ import '../../shared/repository/hive_repository.dart';
99
part 'auth_event.dart';
1010
part 'auth_state.dart';
1111

12-
// class AuthBloc extends Bloc<AuthEvent, AuthState> {
13-
// final AuthRepository authRepository;
14-
// AuthBloc(this.authRepository) : super(AuthInitial()) {
15-
// on<AuthEvent>((event, emit) async {
16-
// if (event is LoginUser) {
17-
// try {
18-
// emit(AuthLoading());
19-
// await authRepository.loginWithEmailAndPassword(
20-
// event.username, event.password);
21-
//
22-
// emit(AuthLoaded(AuthPurpose.LOGIN));
23-
// } catch (e) {
24-
// debugPrint(e.toString());
25-
// emit(
26-
// AuthLoadingError(
27-
// e.toString(),
28-
// ),
29-
// );
30-
// }
31-
// } else if (event is RegisterUser) {
32-
// try {
33-
// emit(AuthLoading());
34-
//
35-
// await authRepository.registerWithEmailAndPassword(event.model);
36-
//
37-
// emit(AuthLoaded(AuthPurpose.REGISTER));
38-
// } catch (e) {
39-
// debugPrint(e.toString());
40-
// emit(
41-
// AuthLoadingError(
42-
// e.toString(),
43-
// ),
44-
// );
45-
// }
46-
// } else if (event is UseAsGuest) {
47-
// emit(GuestUser());
48-
// }
49-
// });
50-
// }
51-
// }
5212
class AuthBloc extends Bloc<AuthEvent, AuthState> {
5313
final AuthRepository authRepository;
5414

5515
AuthBloc(this.authRepository) : super(AuthInitial()) {
56-
//debugPrint("AuthBloc initialized");
57-
5816
on<AppStarted>(_onAppStarted);
5917

60-
6118
on<LoginUser>(_onLoginUser);
6219

63-
6420
on<RegisterUser>(_onRegisterUser);
6521

22+
on<LogoutUser>(_onLogoutUser);
6623

6724
on<UseAsGuest>((event, emit) => emit(GuestUser()));
6825
}
6926

70-
7127
Future<void> _onAppStarted(AppStarted event, Emitter<AuthState> emit) async {
7228
emit(AuthLoading());
7329
try {
@@ -85,15 +41,15 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
8541
}
8642
}
8743

88-
8944
Future<void> _onLoginUser(LoginUser event, Emitter<AuthState> emit) async {
9045
emit(AuthLoading());
9146
try {
92-
93-
final token = await authRepository.loginWithEmailAndPassword(event.username, event.password);
47+
final token = await authRepository.loginWithEmailAndPassword(
48+
event.username, event.password);
9449
await HiveRepository.saveData(HiveBoxNames.authBox, 'token', token);
9550
// Save token in Hive
96-
final savedToken = await HiveRepository.getData('token', HiveBoxNames.authBox);
51+
final savedToken =
52+
await HiveRepository.getData('token', HiveBoxNames.authBox);
9753
//debugPrint("Saved token: $savedToken");
9854

9955
emit(AuthLoaded(AuthPurpose.LOGIN));
@@ -103,8 +59,8 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
10359
}
10460
}
10561

106-
107-
Future<void> _onRegisterUser(RegisterUser event, Emitter<AuthState> emit) async {
62+
Future<void> _onRegisterUser(
63+
RegisterUser event, Emitter<AuthState> emit) async {
10864
emit(AuthLoading());
10965
try {
11066
await authRepository.registerWithEmailAndPassword(event.model);
@@ -116,6 +72,18 @@ class AuthBloc extends Bloc<AuthEvent, AuthState> {
11672
}
11773

11874

75+
Future<void> _onLogoutUser(LogoutUser event, Emitter<AuthState> emit) async {
76+
emit(AuthLoading());
77+
try {
78+
await HiveRepository.deleteData(
79+
'token', HiveBoxNames.authBox); // Remove token from Hive
80+
emit(GuestUser()); // Emit guest state after logout
81+
} catch (e) {
82+
debugPrint("Logout error: $e");
83+
emit(AuthLoadingError("Failed to log out. Please try again."));
84+
}
85+
}
86+
11987
String _extractErrorMessage(dynamic e) {
12088
if (e is Exception) {
12189
return e.toString().replaceAll("Exception:", "").trim();

mobile-v3/lib/src/app/auth/bloc/auth_event.dart

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,3 +26,7 @@ class RegisterUser extends AuthEvent {
2626
class UseAsGuest extends AuthEvent {
2727
const UseAsGuest();
2828
}
29+
30+
class LogoutUser extends AuthEvent {
31+
const LogoutUser();
32+
}

mobile-v3/lib/src/app/dashboard/pages/dashboard_page.dart

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -106,24 +106,24 @@ class _DashboardPageState extends State<DashboardPage> {
106106
),
107107
SizedBox(width: 8),
108108
GestureDetector(
109-
onTap: () {
110-
final authState = context.read<AuthBloc>().state;
111-
if (authState is GuestUser) {
109+
// onTap: () {
110+
// final authState = context.read<AuthBloc>().state;
111+
// if (authState is GuestUser) {
112112

113-
Navigator.of(context).push(
114-
MaterialPageRoute(
115-
builder: (context) => GuestProfilePage(),
116-
),
117-
);
118-
} else {
119-
// Navigate to the regular profile page
120-
Navigator.of(context).push(
121-
MaterialPageRoute(
122-
builder: (context) => ProfilePage(),
123-
),
124-
);
125-
}
126-
},
113+
// Navigator.of(context).push(
114+
// MaterialPageRoute(
115+
// builder: (context) => GuestProfilePage(),
116+
// ),
117+
// );
118+
// } else {
119+
// // Navigate to the regular profile page
120+
// Navigator.of(context).push(
121+
// MaterialPageRoute(
122+
// builder: (context) => ProfilePage(),
123+
// ),
124+
// );
125+
// }
126+
// },
127127
child: BlocBuilder<AuthBloc, AuthState>(
128128
builder: (context, authState) {
129129
if (authState is GuestUser) {

mobile-v3/lib/src/app/learn/pages/lesson_finished.dart

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,19 @@ class LessonFinishedWidget extends StatelessWidget {
1414
Text("👋🏼 Great Job !",
1515
style: TextStyle(fontSize: 20, fontWeight: FontWeight.w700)),
1616
Text(
17-
"You can invite your friends to learn a thing about Air Pollution",
17+
"You can now teach your friends to learn a thing about Air Pollution",
1818
textAlign: TextAlign.center,
1919
style: TextStyle(fontSize: 18, fontWeight: FontWeight.w500)),
2020
SizedBox(height: 64),
21-
SmallRoundedButton(
22-
label: "Share",
23-
imagePath: "assets/images/shared/share_icon.svg",
24-
),
25-
SizedBox(height: 16),
26-
SmallRoundedButton(
27-
label: "Rate the App",
28-
imagePath: "assets/images/shared/bookmark_icon.svg",
29-
),
21+
// SmallRoundedButton(
22+
// label: "Share",
23+
// imagePath: "assets/images/shared/share_icon.svg",
24+
// ),
25+
// SizedBox(height: 16),
26+
// SmallRoundedButton(
27+
// label: "Rate the App",
28+
// imagePath: "assets/images/shared/bookmark_icon.svg",
29+
// ),
3030
],
3131
),
3232
);

mobile-v3/lib/src/app/profile/pages/widgets/settings_widget.dart

Lines changed: 48 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import 'package:airqo/src/app/auth/pages/welcome_screen.dart';
2+
import 'package:flutter_bloc/flutter_bloc.dart';
3+
import 'package:airqo/src/app/auth/bloc/auth_bloc.dart';
14
import 'package:flutter/material.dart';
25
import 'package:airqo/src/app/profile/pages/widgets/settings_tile.dart';
36
import 'package:flutter_svg/svg.dart';
@@ -9,6 +12,7 @@ class SettingsWidget extends StatefulWidget {
912
@override
1013
State<SettingsWidget> createState() => _SettingsWidgetState();
1114
}
15+
1216
class _SettingsWidgetState extends State<SettingsWidget> {
1317
String _appVersion = '';
1418
bool _locationEnabled = true;
@@ -30,27 +34,64 @@ class _SettingsWidgetState extends State<SettingsWidget> {
3034
void _showLogoutConfirmation() {
3135
showDialog(
3236
context: context,
33-
builder: (context) => AlertDialog(
37+
builder: (dialogContext) => AlertDialog(
3438
title: const Text('Confirm Logout'),
3539
content: const Text('Are you sure you want to log out?'),
3640
actions: [
3741
TextButton(
38-
onPressed: () => Navigator.pop(context),
42+
onPressed: () => Navigator.pop(dialogContext),
3943
child: const Text('Cancel'),
4044
),
4145
ElevatedButton(
42-
onPressed: () {
43-
// TODO: Implement actual logout logic
44-
// e.g., clear user session, revoke tokens
45-
Navigator.of(context).pushReplacementNamed('/login');
46-
},
46+
onPressed: () => _handleLogout(dialogContext),
4747
child: const Text('Log Out'),
4848
),
4949
],
5050
),
5151
);
5252
}
5353

54+
Future<void> _handleLogout(BuildContext dialogContext) async {
55+
Navigator.pop(dialogContext); // Close confirmation dialog
56+
57+
showDialog(
58+
context: context,
59+
barrierDismissible: false,
60+
builder: (_) => const Center(child: CircularProgressIndicator()),
61+
);
62+
63+
try {
64+
context.read<AuthBloc>().add(LogoutUser());
65+
66+
await for (final state in context.read<AuthBloc>().stream) {
67+
if (state is GuestUser) {
68+
Navigator.pop(context);
69+
70+
await Navigator.pushAndRemoveUntil(
71+
context,
72+
MaterialPageRoute(builder: (_) => WelcomeScreen()),
73+
(route) => false,
74+
);
75+
break;
76+
} else if (state is AuthLoadingError) {
77+
Navigator.pop(context);
78+
79+
ScaffoldMessenger.of(context).showSnackBar(
80+
SnackBar(content: Text(state.message)),
81+
);
82+
break;
83+
}
84+
}
85+
} catch (e) {
86+
Navigator.pop(context);
87+
88+
ScaffoldMessenger.of(context).showSnackBar(
89+
const SnackBar(content: Text('An unexpected error occurred')),
90+
);
91+
}
92+
}
93+
94+
5495
void _showDeleteAccountDialog() {
5596
final TextEditingController passwordController = TextEditingController();
5697

0 commit comments

Comments
 (0)