6177214e-ce7c-49e3-99de-ff9721b26f63 — Commit d644ff40
Changed files
comwell_key_app/assets/translations/da-DK.json | 5 +- comwell_key_app/assets/translations/en-US.json | 5 +- .../authentication/authentication_repository.dart | 43 ++++++- .../authentication/bloc/authentication_bloc.dart | 69 +---------- .../authentication/bloc/authentication_event.dart | 2 + .../authentication/bloc/authentication_state.dart | 19 +-- .../authentication/enum/authentication_status.dart | 3 +- comwell_key_app/lib/comwell_app.dart | 17 +-- .../lib/login/components/azure_b2c_widget.dart | 11 +- comwell_key_app/lib/login/login_page.dart | 68 +++++----- .../lib/profile/cubit/profile_cubit.dart | 20 ++- comwell_key_app/lib/profile/profile_page.dart | 137 +++++++++++++++++++-- .../profile_settings/profile_settings_page.dart | 6 +- comwell_key_app/lib/routing/app_router.dart | 37 ++++-- .../interceptors/response_handle_interceptor.dart | 46 ++++--- comwell_key_app/lib/utils/locator.dart | 1 + .../lib/utils/stream_to_listenable.dart | 11 ++ 17 files changed, 327 insertions(+), 173 deletions(-)
Diff
diff --git a/comwell_key_app/assets/translations/da-DK.json b/comwell_key_app/assets/translations/da-DK.json
index 13b6f328..f504185e 100644
--- a/comwell_key_app/assets/translations/da-DK.json
+++ b/comwell_key_app/assets/translations/da-DK.json
@@ -238,5 +238,8 @@
"total_charge": "I alt til betaling",
"early_checkin": "Tidlig check-in",
"payed": "BETALT",
- "total_charge_value": "{} kr."
+ "total_charge_value": "{} kr.",
+ "generic_error_profile_page": "Der skete en fejl. Prøv igen senere. Eller log ud og prøv igen.",
+ "profile_error_name": "Fejl ved indlæsning af profiloplysninger",
+ "error": "Fejl"
}
\ No newline at end of file
diff --git a/comwell_key_app/assets/translations/en-US.json b/comwell_key_app/assets/translations/en-US.json
index ecc67286..0e35b884 100644
--- a/comwell_key_app/assets/translations/en-US.json
+++ b/comwell_key_app/assets/translations/en-US.json
@@ -238,5 +238,8 @@
"total_charge": "Total charge",
"early_checkin": "Early check-in",
"payed": "PAYED",
- "total_charge_value": "{} kr."
+ "total_charge_value": "{} kr.",
+ "generic_error_profile_page": "An error occurred. Please try again later. Or logout and try again.",
+ "profile_error_name": "Failed to load profile information",
+ "error": "Error"
}
diff --git a/comwell_key_app/lib/authentication/authentication_repository.dart b/comwell_key_app/lib/authentication/authentication_repository.dart
index d0cfa02c..a603adf5 100644
--- a/comwell_key_app/lib/authentication/authentication_repository.dart
+++ b/comwell_key_app/lib/authentication/authentication_repository.dart
@@ -3,8 +3,10 @@ import 'dart:async';
import 'package:comwell_key_app/authentication/enum/authentication_status.dart';
import 'package:comwell_key_app/database/comwell_db.dart';
import 'package:comwell_key_app/services/api.dart';
+import 'package:comwell_key_app/tracking/comwell_tracking.dart';
import 'package:comwell_key_app/utils/secure_storage.dart';
import 'package:comwell_key_app/common/const.dart' as constants;
+import 'package:firebase_analytics/firebase_analytics.dart';
import 'package:flutter/foundation.dart';
import '../utils/locator.dart';
@@ -13,12 +15,30 @@ import '../utils/seos_repository.dart';
class AuthenticationRepository {
final SecureStorage secureStorage = SecureStorage();
final _controller = StreamController<AuthenticationStatus>.broadcast();
+ late final broadcast = _controller.stream.asBroadcastStream();
+ AuthenticationStatus statusBuffer = AuthenticationStatus.unknown;
final seos = locator<SeosRepository>();
final database = locator<ComwellDatabase>();
final api = Api();
+ AuthenticationRepository() {
+ broadcast.listen((status) {
+ print('status $status');
+ statusBuffer = status;
+ });
+
+ _controller.sink.add(AuthenticationStatus.unknown);
+
+
+ FirebaseAnalytics.instance.setUserProperty(
+ name: 'login_status',
+ value: 'false',
+
+ );
+ }
+
Stream<AuthenticationStatus> get status async* {
- yield* _controller.stream.map((status) {
+ yield* broadcast.map((status) {
_onAuthResult(status);
return status;
});
@@ -36,12 +56,29 @@ class AuthenticationRepository {
Future<void> logIn() async {
_controller.sink.add(AuthenticationStatus.authenticated);
+ await FirebaseAnalytics.instance.logLogin();
+ await FirebaseAnalytics.instance.setUserProperty(
+ name: 'login_status',
+ value: 'true',
+ );
}
- Future<void> logOut() async {
+ Future<void> logOut({bool forced = false}) async {
+ print('logOut $forced');
await secureStorage.deleteAll();
await database.deleteDatabase();
- _controller.sink.add(AuthenticationStatus.unauthenticated);
+
+ //TODO: Should we differentiate between forced and unauthenticated in the tracking event?
+ locator<ComwellTracking>().trackEvent('logout');
+ await FirebaseAnalytics.instance.setUserProperty(
+ name: 'login_status',
+ value: 'false',
+ );
+ if (forced) {
+ _controller.sink.add(AuthenticationStatus.forcedUnauthenticated);
+ } else {
+ _controller.sink.add(AuthenticationStatus.unauthenticated);
+ }
}
void dispose() => _controller.close();
diff --git a/comwell_key_app/lib/authentication/bloc/authentication_bloc.dart b/comwell_key_app/lib/authentication/bloc/authentication_bloc.dart
index d5e94721..653cf955 100644
--- a/comwell_key_app/lib/authentication/bloc/authentication_bloc.dart
+++ b/comwell_key_app/lib/authentication/bloc/authentication_bloc.dart
@@ -1,10 +1,7 @@
import 'package:bloc/bloc.dart';
import 'package:comwell_key_app/authentication/authentication_repository.dart';
import 'package:comwell_key_app/authentication/enum/authentication_status.dart';
-import 'package:comwell_key_app/tracking/comwell_tracking.dart';
-import 'package:comwell_key_app/utils/locator.dart';
import 'package:equatable/equatable.dart';
-import 'package:firebase_analytics/firebase_analytics.dart';
part 'authentication_event.dart';
@@ -16,74 +13,12 @@ class AuthenticationBloc
AuthenticationBloc({
required this.authenticationRepository,
- }) : super(const AuthenticationState.unknown()) {
- on<AuthenticationSubscriptionRequested>(_onSubscriptionRequested);
- on<AuthenticationLogoutPressed>(_onLogoutPressed);
- on<AuthenticationLoginPressed>(_onLoginPressed);
- on<AuthenticationRequestFailed>(_loginErrorFromAzureB2C);
+ }) : super(const AuthenticationState.unknown()) {
add(AuthenticationSubscriptionRequested());
}
- void _onLogoutPressed(
- AuthenticationLogoutPressed event,
- Emitter<AuthenticationState> emit,
- ) {
- locator<ComwellTracking>().trackEvent(
- 'logout');
- authenticationRepository.logOut();
- }
- Future<void> _onSubscriptionRequested(
- AuthenticationSubscriptionRequested event,
- Emitter<AuthenticationState> emit,
- ) {
- return emit.onEach(
- authenticationRepository.status.asBroadcastStream(),
- onData: (status) async {
- switch (status) {
- case AuthenticationStatus.unauthenticated:
- await FirebaseAnalytics.instance.setUserProperty(
- name: 'login_status',
- value: 'false',
- );
- return emit(const AuthenticationState.unauthenticated());
- case AuthenticationStatus.authenticated:
- await FirebaseAnalytics.instance.logLogin();
- await FirebaseAnalytics.instance.setUserProperty(
- name: 'login_status',
- value: 'true',
- );
- return emit(const AuthenticationState.authenticated());
- case AuthenticationStatus.unknown:
- await FirebaseAnalytics.instance.setUserProperty(
- name: 'login_status',
- value: 'false',
- );
- return emit(const AuthenticationState.unknown());
- }
- },
- onError: addError,
- );
- }
- void _onLoginPressed(
- AuthenticationLoginPressed event,
- Emitter<AuthenticationState> emit,
- ) {
- try {
- // Call the login method from the authenticationRepository
- authenticationRepository.logIn();
- emit(const AuthenticationState.authenticated());
- } catch (e) {
- emit(const AuthenticationState.unauthenticated());
- }
- }
- void _loginErrorFromAzureB2C(
- AuthenticationRequestFailed event,
- Emitter<AuthenticationState> emit,
- ) {
- emit(const AuthenticationState.unauthenticated());
- authenticationRepository.logOut();
- }
+
}
diff --git a/comwell_key_app/lib/authentication/bloc/authentication_event.dart b/comwell_key_app/lib/authentication/bloc/authentication_event.dart
index b44a83e1..8cf05445 100644
--- a/comwell_key_app/lib/authentication/bloc/authentication_event.dart
+++ b/comwell_key_app/lib/authentication/bloc/authentication_event.dart
@@ -13,6 +13,8 @@ final class AuthenticationSubscriptionNotValid extends AuthenticationEvent {}
final class AuthenticationLogoutPressed extends AuthenticationEvent {}
+final class Unauthenticated extends AuthenticationEvent {}
+
final class AuthenticationLoginPressed extends AuthenticationEvent {}
final class AuthenticationRequestFailed extends AuthenticationEvent {}
diff --git a/comwell_key_app/lib/authentication/bloc/authentication_state.dart b/comwell_key_app/lib/authentication/bloc/authentication_state.dart
index 34b4be35..09b1c4cf 100644
--- a/comwell_key_app/lib/authentication/bloc/authentication_state.dart
+++ b/comwell_key_app/lib/authentication/bloc/authentication_state.dart
@@ -1,19 +1,24 @@
part of 'authentication_bloc.dart';
class AuthenticationState extends Equatable {
+ final bool forced;
+ final AuthenticationStatus status;
const AuthenticationState._({
this.status = AuthenticationStatus.unknown,
+ this.forced = false,
});
-
-const AuthenticationState.unknown() : this._();
-const AuthenticationState.authenticated() : this._(status: AuthenticationStatus.authenticated);
+ const AuthenticationState.unknown() : this._();
-const AuthenticationState.unauthenticated() : this._(status: AuthenticationStatus.unauthenticated);
+ const AuthenticationState.authenticated()
+ : this._(status: AuthenticationStatus.authenticated);
-final AuthenticationStatus status;
+ const AuthenticationState.unauthenticated({bool forced = false})
+ : this._(status: AuthenticationStatus.unauthenticated, forced: forced);
+ const AuthenticationState.forcedUnauthenticated()
+ : this._(status: AuthenticationStatus.forcedUnauthenticated);
-@override
-List<Object> get props => [status];
+ @override
+ List<Object> get props => [status];
}
diff --git a/comwell_key_app/lib/authentication/enum/authentication_status.dart b/comwell_key_app/lib/authentication/enum/authentication_status.dart
index b2f12eaf..23ed5370 100644
--- a/comwell_key_app/lib/authentication/enum/authentication_status.dart
+++ b/comwell_key_app/lib/authentication/enum/authentication_status.dart
@@ -2,6 +2,5 @@ enum AuthenticationStatus {
unknown,
authenticated,
unauthenticated,
+ forcedUnauthenticated,
}
-
-
diff --git a/comwell_key_app/lib/comwell_app.dart b/comwell_key_app/lib/comwell_app.dart
index a259b023..623e102b 100644
--- a/comwell_key_app/lib/comwell_app.dart
+++ b/comwell_key_app/lib/comwell_app.dart
@@ -20,27 +20,22 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class ComwellApp extends StatelessWidget {
- final AuthenticationBloc authBloc = AuthenticationBloc(
- authenticationRepository: locator<AuthenticationRepository>());
- ComwellApp({super.key});
+ const ComwellApp({super.key});
@override
Widget build(BuildContext context) {
- return BlocProvider<AuthenticationBloc>(
- create: (context) => authBloc,
- child: MultiBlocProvider(
- providers: blocProviderList,
+ return MultiBlocProvider(
+ providers: blocProviderList,
child: MaterialApp.router(
title: 'Comwell Key App',
- routerConfig: goRouter(authBloc),
+ routerConfig: goRouter(),
localizationsDelegates: context.localizationDelegates,
supportedLocales: context.supportedLocales,
locale: context.locale,
theme: lightTheme,
darkTheme: darkTheme,
- themeMode: ThemeMode.system,
- ),
+ themeMode: ThemeMode.system,
),
);
}
@@ -62,7 +57,7 @@ final List<BlocProvider> blocProviderList = [
BlocProvider<ProfileCubit>(
lazy: false,
create: (BuildContext context) =>
- ProfileCubit(profileRepository: locator<ProfileRepository>()),
+ ProfileCubit(profileRepository: locator<ProfileRepository>(), authenticationRepository: locator<AuthenticationRepository>()),
),
BlocProvider<ProfileSettingsCubit>(
lazy: false,
diff --git a/comwell_key_app/lib/login/components/azure_b2c_widget.dart b/comwell_key_app/lib/login/components/azure_b2c_widget.dart
index 78184cd4..2b7ecf24 100644
--- a/comwell_key_app/lib/login/components/azure_b2c_widget.dart
+++ b/comwell_key_app/lib/login/components/azure_b2c_widget.dart
@@ -1,4 +1,5 @@
import 'package:aad_b2c_webview/aad_b2c_webview.dart';
+import 'package:comwell_key_app/authentication/authentication_repository.dart';
import 'package:comwell_key_app/authentication/bloc/authentication_bloc.dart';
import 'package:comwell_key_app/login/auth.dart';
import 'package:comwell_key_app/tracking/comwell_tracking.dart';
@@ -14,11 +15,11 @@ class AzureB2CWidget extends StatelessWidget {
final Auth authEnum;
final SecureStorage secureStorage = SecureStorage();
// final LoginCubit loginCubit = LoginCubit(authenticationRepository: AuthenticationRepository());
- final AuthenticationBloc authBloc;
+ final AuthenticationRepository authenticationRepository;
final _tracking = locator<ComwellTracking>();
AzureB2CWidget({
- required this.authBloc,
required this.authEnum,
+ required this.authenticationRepository,
super.key,
});
@@ -43,14 +44,14 @@ class AzureB2CWidget extends StatelessWidget {
debugPrint(JwtDecoder.decode(token.value).toString());
},
onAccessToken: (Token token) {
-
+
},
onRefreshToken: (Token token) {
secureStorage.write(constants.refreshToken, token.value);
debugPrint('refresh_token: ${token.value}');
- authBloc.add(AuthenticationLoginPressed());
+ authenticationRepository.logIn();
},
- onErrorOrCancel: (context) => authBloc.add(AuthenticationRequestFailed()),
+ onErrorOrCancel: (context) => authenticationRepository.logOut(forced: true),
optionalParameters: const [],
webViewBackgroundColor: sandColor[40]!,
);
diff --git a/comwell_key_app/lib/login/login_page.dart b/comwell_key_app/lib/login/login_page.dart
index 79d50764..f67603f9 100644
--- a/comwell_key_app/lib/login/login_page.dart
+++ b/comwell_key_app/lib/login/login_page.dart
@@ -1,4 +1,4 @@
-import 'package:comwell_key_app/authentication/bloc/authentication_bloc.dart';
+import 'package:comwell_key_app/authentication/authentication_repository.dart';
import 'package:comwell_key_app/login/auth.dart';
import 'package:comwell_key_app/login/components/create_user_button.dart';
import 'package:comwell_key_app/login/components/login_button.dart';
@@ -7,16 +7,17 @@ import 'package:comwell_key_app/tracking/comwell_tracking.dart';
import 'package:comwell_key_app/utils/locator.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
-import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
class LoginPage extends StatelessWidget {
+ final bool forced;
- const LoginPage({super.key});
+ const LoginPage({super.key, required this.forced});
@override
Widget build(BuildContext context) {
final tracking = locator<ComwellTracking>();
+
return Scaffold(
body: Container(
constraints: const BoxConstraints.expand(),
@@ -26,40 +27,43 @@ class LoginPage extends StatelessWidget {
fit: BoxFit.cover,
),
),
- child: SafeArea(child: Column(
- mainAxisAlignment: MainAxisAlignment.center,
- children: [
- // Logo
- Expanded(
- flex: 3,
- child:
- Image.asset('assets/images/Logo.png', width: 175, height: 50),
- ),
- const SizedBox(height: 32),
- // Login Button
- LoginButton(
- onPressed: () {
+ child: SafeArea(
+ child: Column(
+ mainAxisAlignment: MainAxisAlignment.center,
+ children: [
+ if (forced)
+ Text('forced $forced', style: TextStyle(color: Colors.red, fontSize: 50),),
+ // Logo
+ Expanded(
+ flex: 3,
+ child: Image.asset('assets/images/Logo.png',
+ width: 175, height: 50),
+ ),
+ const SizedBox(height: 32),
+ // Login Button
+ LoginButton(onPressed: () {
tracking.trackScreenView('Login - Form', '/login/form');
- openModal(context, Auth.login);}
- ),
+ openModal(context, Auth.login);
+ }),
- const SizedBox(height: 10),
- // Create New User Button
- CreateUserButton(
- onPressed: () {
- tracking.trackScreenView('Create User - Form', '/create-user/form');
- openModal(context, Auth.createUser);}
- ),
- const SizedBox(height: 20),
- ],
+ const SizedBox(height: 10),
+ // Create New User Button
+ CreateUserButton(onPressed: () {
+ tracking.trackScreenView(
+ 'Create User - Form', '/create-user/form');
+ openModal(context, Auth.createUser);
+ }),
+ const SizedBox(height: 20),
+ ],
+ ),
),
),
- ),);
+ );
}
Future<dynamic> openModal(BuildContext context, Auth authEnum) {
return showCupertinoModalBottomSheet(
- enableDrag: false,
+ enableDrag: false,
backgroundColor: Colors.orange,
topRadius: const Radius.circular(30),
elevation: 5,
@@ -74,10 +78,12 @@ class LoginPage extends StatelessWidget {
child: SizedBox(
height: 700,
width: 400,
- child: AzureB2CWidget(authEnum: authEnum, authBloc: context.read<AuthenticationBloc>()),
+ child: AzureB2CWidget(
+ authEnum: authEnum,
+ authenticationRepository: locator<AuthenticationRepository>()),
),
),
);
});
}
-}
\ No newline at end of file
+}
diff --git a/comwell_key_app/lib/profile/cubit/profile_cubit.dart b/comwell_key_app/lib/profile/cubit/profile_cubit.dart
index a1b3e26d..71612715 100644
--- a/comwell_key_app/lib/profile/cubit/profile_cubit.dart
+++ b/comwell_key_app/lib/profile/cubit/profile_cubit.dart
@@ -1,4 +1,5 @@
import 'package:bloc/bloc.dart';
+import 'package:comwell_key_app/authentication/authentication_repository.dart';
import 'package:comwell_key_app/profile/profile_repository.dart';
import 'package:comwell_key_app/profile_settings/model/user.dart';
import 'package:equatable/equatable.dart';
@@ -9,9 +10,17 @@ part 'profile_state.dart';
class ProfileCubit extends Cubit<ProfileState> {
final ProfileRepository profileRepository;
- ProfileCubit({required this.profileRepository})
- : super(const ProfileState(isLoading: false, user: null, error: null, isToSAccepted: false, isNewsletterAccepted: false));
-
+ final AuthenticationRepository authenticationRepository;
+
+ ProfileCubit({
+ required this.profileRepository,
+ required this.authenticationRepository,
+ }) : super(const ProfileState(
+ isLoading: false,
+ user: null,
+ error: null,
+ isToSAccepted: false,
+ isNewsletterAccepted: false));
void sendPageViewEvent() async {
await FirebaseAnalytics.instance.logScreenView(
screenName: 'Profile',
@@ -25,6 +34,11 @@ class ProfileCubit extends Cubit<ProfileState> {
return packageInfo.version;
}
+ void logOutPressed() {
+ authenticationRepository.logOut();
+ emit(const ProfileState(isLoading: false, user: null, error: null, isToSAccepted: false, isNewsletterAccepted: false));
+ }
+
void deleteAllInfoOnLogOut() async {
emit(const ProfileState(isLoading: false, user: null, error: null, isToSAccepted: false, isNewsletterAccepted: false));
}
diff --git a/comwell_key_app/lib/profile/profile_page.dart b/comwell_key_app/lib/profile/profile_page.dart
index c7b40d8b..fcc64a78 100644
--- a/comwell_key_app/lib/profile/profile_page.dart
+++ b/comwell_key_app/lib/profile/profile_page.dart
@@ -32,11 +32,7 @@ class ProfilePage extends StatelessWidget {
if (state.isLoading) {
return const Center(child: CircularProgressIndicator());
} else if (state.error != null) {
- return Center(
- child: Text(
- "generic_error".tr(),
- ),
- );
+ return _buildErrorPage(context);
} else {
return _buildProfilePage(cubit, context);
}
@@ -45,9 +41,79 @@ class ProfilePage extends StatelessWidget {
);
}
+ Widget _buildErrorPage(BuildContext context) {
+ final theme = Theme.of(context);
+ return SafeArea(
+ child: Column(
+ children: [
+ Padding(
+ padding: const EdgeInsets.only(top: 20),
+ child: Container(
+ alignment: Alignment.centerRight,
+ child: RoundIconButton(
+ icon: "assets/icons/close-icon.svg",
+ color: Colors.white,
+ onPressed: () {
+ context.pop();
+ }),
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Column(
+ children: [
+ ComwellCard(
+ content: getEmptyCardContent(context),
+ backgroundColor: sandColor[10]!),
+ ],
+ ),
+ ),
+ const SizedBox(height: 10),
+ Expanded(
+ child: Container(
+ color: Colors.white,
+ child: Column(
+ children: [
+ const SizedBox(height: 20),
+ Center(
+ child: OutlinedButton(
+ style: OutlinedButton.styleFrom(
+ side: const BorderSide(color: colorDivider),
+ ),
+ onPressed: () {
+ showLogoutDialog(context);
+ },
+ child: Text(
+ 'logout_profile_menu'.tr(),
+ style: TextStyle(color: Colors.grey[600]),
+ ),
+ ),
+ ),
+ const SizedBox(height: 16),
+ FutureBuilder<String>(
+ future: context.read<ProfileCubit>().getVersion(),
+ builder: (context, snapshot) {
+ if (snapshot.hasData) {
+ return Text(snapshot.data!,
+ style: TextStyle(color: Colors.grey[500]));
+ }
+ return const SizedBox.shrink();
+ },
+ ),
+ const SizedBox(height: 20),
+ const Spacer(),
+ ],
+ ),
+ ),
+ ),
+ ],
+ ),
+ );
+ }
+
Widget _buildProfilePage(ProfileCubit cubit, BuildContext context) {
final user = cubit.state.user;
- final isActive = cubit.state.user!.clubLevel != 'L1';
+ final isActive = cubit.state.user!.clubLevel != '';
return SafeArea(
child: Column(
@@ -101,7 +167,8 @@ class ProfilePage extends StatelessWidget {
isScrollControlled: true,
backgroundColor: Colors.white,
builder: (context) =>
- ComwellClubSignupBottomSheet(user: user!),
+ ComwellClubSignupBottomSheet(
+ user: user!),
);
cubit.init();
},
@@ -233,6 +300,8 @@ class ProfilePage extends StatelessWidget {
}
Future<AlertDialog?> showLogoutDialog(BuildContext context) {
+ final cubit = context.read<ProfileCubit>();
+
return showDialog<AlertDialog>(
context: context,
builder: (BuildContext context) {
@@ -263,9 +332,7 @@ class ProfilePage extends StatelessWidget {
padding: const EdgeInsets.symmetric(vertical: 16),
),
onPressed: () {
- context
- .read<AuthenticationBloc>()
- .add(AuthenticationLogoutPressed());
+ cubit.logOutPressed();
},
child: Text(
"logout_profile_menu".tr(),
@@ -305,6 +372,56 @@ class ProfilePage extends StatelessWidget {
});
}
+ Widget getEmptyCardContent(
+ BuildContext context) {
+ final theme = Theme.of(context);
+
+ return SizedBox(
+ width: double.infinity,
+ height: double.infinity,
+ child: Stack(
+ children: [
+ Positioned(
+ top: 20,
+ left: 20,
+ child: Container(
+ padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 6),
+ decoration: BoxDecoration(
+ color: Colors.white,
+ borderRadius: BorderRadius.circular(32),
+ ),
+ child: Text(
+ 'error'.tr(),
+ style: theme.textTheme.bodySmall!.copyWith(
+ color: Colors.black,
+ fontWeight: FontWeight.w600,
+ ),
+ ),
+ ),
+ ),
+ Positioned(
+ bottom: 20,
+ left: 20,
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ Text(
+ 'profile_error_name'.tr(),
+ style: theme.textTheme.bodySmall!.copyWith(
+ color: Colors.black,
+ fontSize: 16,
+ fontWeight: FontWeight.w600,
+ ),
+ ),
+ ],
+ ),
+ ),
+
+ ],
+ ),
+ );
+ }
+
Widget getCardContent(
BuildContext context, ProfileCubit cubit, bool isActive) {
final theme = Theme.of(context);
diff --git a/comwell_key_app/lib/profile_settings/profile_settings_page.dart b/comwell_key_app/lib/profile_settings/profile_settings_page.dart
index b0779df1..4bdacb23 100644
--- a/comwell_key_app/lib/profile_settings/profile_settings_page.dart
+++ b/comwell_key_app/lib/profile_settings/profile_settings_page.dart
@@ -1,17 +1,17 @@
- import 'package:comwell_key_app/authentication/bloc/authentication_bloc.dart';
+ import 'package:comwell_key_app/authentication/authentication_repository.dart';
import 'package:comwell_key_app/common/components/comwell_app_bar.dart';
import 'package:comwell_key_app/common/components/generic_dialog.dart';
import 'package:comwell_key_app/login/auth.dart';
import 'package:comwell_key_app/login/components/azure_b2c_widget.dart';
import 'package:comwell_key_app/profile_settings/components/address_bottom_sheet.dart';
import 'package:comwell_key_app/profile_settings/components/comwell_text_field.dart';
-import 'package:comwell_key_app/profile_settings/components/date_time_picker.dart';
import 'package:comwell_key_app/profile_settings/components/intl_phone_field.dart';
import 'package:comwell_key_app/profile_settings/components/text_field_with_trailing_icon.dart';
import 'package:comwell_key_app/profile_settings/cubit/profile_settings_cubit.dart';
import 'package:comwell_key_app/profile_settings/model/address.dart';
import 'package:comwell_key_app/profile_settings/model/user.dart';
import 'package:comwell_key_app/themes/light_theme.dart';
+import 'package:comwell_key_app/utils/locator.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
@@ -229,7 +229,7 @@ class ProfileSettingsPage extends StatelessWidget {
child: SizedBox(
height: 700,
width: 400,
- child: AzureB2CWidget(authEnum: authEnum, authBloc: context.read<AuthenticationBloc>()),
+ child: AzureB2CWidget(authEnum: authEnum, authenticationRepository: locator<AuthenticationRepository>()),
),
),
);
diff --git a/comwell_key_app/lib/routing/app_router.dart b/comwell_key_app/lib/routing/app_router.dart
index c259cf67..4dbc0399 100644
--- a/comwell_key_app/lib/routing/app_router.dart
+++ b/comwell_key_app/lib/routing/app_router.dart
@@ -1,5 +1,5 @@
import 'package:comwell_key_app/authentication/authentication_repository.dart';
-import 'package:comwell_key_app/authentication/bloc/authentication_bloc.dart';
+import 'package:comwell_key_app/authentication/enum/authentication_status.dart';
import 'package:comwell_key_app/check_in/bloc/check_in_cubit.dart';
import 'package:comwell_key_app/check_in/check_in_page.dart';
import 'package:comwell_key_app/check_out/bloc/check_out_cubit.dart';
@@ -20,7 +20,6 @@ import 'package:comwell_key_app/my_booking/cubit/my_booking_cubit.dart';
import 'package:comwell_key_app/my_booking/my_booking_page.dart';
import 'package:comwell_key_app/my_booking/my_booking_repository.dart';
import 'package:comwell_key_app/notifications/cubit/notifications_cubit.dart';
-import 'package:comwell_key_app/notifications/models/notification_permission.dart';
import 'package:comwell_key_app/notifications/notifications_page.dart';
import 'package:comwell_key_app/notifications/notifications_repository.dart';
import 'package:comwell_key_app/overview/models/booking.dart';
@@ -36,7 +35,6 @@ import 'package:comwell_key_app/profile/profile_page.dart';
import 'package:comwell_key_app/profile/profile_repository.dart';
import 'package:comwell_key_app/profile_settings/components/change_password_modal.dart';
import 'package:comwell_key_app/profile_settings/cubit/profile_settings_cubit.dart';
-import 'package:comwell_key_app/profile_settings/model/user.dart';
import 'package:comwell_key_app/profile_settings/profile_settings_page.dart';
import 'package:comwell_key_app/profile_settings/repostiory/profile_settings_repository.dart';
import 'package:comwell_key_app/redeem_debug/redeem_page.dart';
@@ -61,31 +59,37 @@ import '../booking_details/booking_details_repository.dart';
final _rootNavigatorKey = GlobalKey<NavigatorState>();
final _shellNavigatorKey = GlobalKey<NavigatorState>();
-GoRouter goRouter(AuthenticationBloc authBloc) {
+GoRouter goRouter() {
+ final authRepo = locator<AuthenticationRepository>();
+
return GoRouter(
initialLocation: '/login',
navigatorKey: _rootNavigatorKey,
debugLogDiagnostics: true,
observers: [GoRouterObserver()],
refreshListenable:
- StreamToListenable([authBloc.stream.asBroadcastStream()]),
+ StreamToListenable([authRepo.broadcast]),
redirect: (context, state) async {
+ final status = authRepo.statusBuffer;
+ print('status $status');
final isAuthenticated =
- authBloc.state == const AuthenticationState.authenticated();
+ status == AuthenticationStatus.authenticated;
final isUnAuthenticated =
- authBloc.state == const AuthenticationState.unauthenticated();
- final authRepo = authBloc.authenticationRepository;
+ status == AuthenticationStatus.unauthenticated || status == AuthenticationStatus.forcedUnauthenticated;
+
- if (authBloc.state == const AuthenticationState.unknown()) {
+ if (status == AuthenticationStatus.unknown) {
bool doesTokenExist = await authRepo.doesTokenExist();
if (doesTokenExist) {
- authBloc.add(AuthenticationLoginPressed());
+ authRepo.logIn();
}
}
// Redirect to the login page if the user is not authenticated, and if authenticated, do not show the login page
if (isUnAuthenticated && !state.matchedLocation.contains("/login")) {
- return "/login";
+ final forced = status == AuthenticationStatus.forcedUnauthenticated;
+
+ return "/login?forced=$forced";
}
// Redirect to the booking_details page if the user is authenticated
else if (isAuthenticated && state.matchedLocation.contains("/login")) {
@@ -204,7 +208,9 @@ GoRouter goRouter(AuthenticationBloc authBloc) {
builder: (context, state) {
return BlocProvider<ProfileCubit>(
create: (BuildContext context) => ProfileCubit(
- profileRepository: locator<ProfileRepository>())
+ profileRepository: locator<ProfileRepository>(),
+ authenticationRepository:
+ locator<AuthenticationRepository>())
..init(),
child: ProfilePage(), //mobileKey: key);
);
@@ -292,7 +298,12 @@ GoRouter goRouter(AuthenticationBloc authBloc) {
GoRoute(
path: "/login",
name: AppRoutes.login.name,
- builder: (context, state) => const LoginPage(),
+ builder: (context, state) {
+ final queryForced = state.uri.queryParameters['forced'] ?? 'false';
+ final forced = bool.parse(queryForced);
+ print('forced $forced');
+ return LoginPage(forced: forced);
+ },
),
GoRoute(
path: "/redeem",
diff --git a/comwell_key_app/lib/services/interceptors/response_handle_interceptor.dart b/comwell_key_app/lib/services/interceptors/response_handle_interceptor.dart
index 2107488f..aba7f6b9 100644
--- a/comwell_key_app/lib/services/interceptors/response_handle_interceptor.dart
+++ b/comwell_key_app/lib/services/interceptors/response_handle_interceptor.dart
@@ -1,6 +1,7 @@
+import 'package:comwell_key_app/authentication/authentication_repository.dart';
import 'package:comwell_key_app/services/token_error_type.dart';
+import 'package:comwell_key_app/utils/locator.dart';
import 'package:dio/dio.dart';
-import 'package:flutter/foundation.dart';
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:comwell_key_app/common/const.dart' as constants;
@@ -10,6 +11,10 @@ class ResponseHandleInterceptor extends Interceptor {
final FlutterSecureStorage _secureStorageService =
const FlutterSecureStorage();
+ final AuthenticationRepository _authenticationRepository =
+ locator<AuthenticationRepository>();
+ int retryCount = 0;
+
ResponseHandleInterceptor(this._dio);
@override
@@ -33,7 +38,7 @@ class ResponseHandleInterceptor extends Interceptor {
return handler.reject(error);
}
options.headers.addAll({
- 'Authorization': accessToken,
+ 'Authorization': 'accessToken',
'Ocp-Apim-Subscription-Key': dotenv.env['OCP_APIM_SUBSCRIPTION_KEY']!,
});
return handler.next(options);
@@ -45,6 +50,7 @@ class ResponseHandleInterceptor extends Interceptor {
ErrorInterceptorHandler handler,
) async {
final response = err.response;
+
if (response == null) {
return handler.next(DioException(
message: "Missing response",
@@ -58,20 +64,28 @@ class ResponseHandleInterceptor extends Interceptor {
requestOptions: response.requestOptions, error: 'Not found');
handler.next(err);
} else if (statusCode == 401) {
- final newToken = await _refreshToken();
- if (newToken != null) {
- // Retry the original request with the new token
- final options = response.requestOptions;
- options.headers['Authorization'] = newToken;
- final opts = Options(
- method: response.requestOptions.method,
- headers: response.requestOptions.headers);
- final retryRequest = await _dio.request<dynamic>(
- response.requestOptions.path,
- options: opts,
- data: response.requestOptions.data,
- queryParameters: response.requestOptions.queryParameters);
- return handler.resolve(retryRequest);
+ retryCount++;
+ if (retryCount < 10) {
+ final newToken = await _refreshToken();
+ if (newToken != null) {
+ // Retry the original request with the new token
+ final options = response.requestOptions;
+ options.headers['Authorization'] = newToken;
+ final opts = Options(
+ method: response.requestOptions.method,
+ headers: response.requestOptions.headers);
+ final retryRequest = await _dio.request<dynamic>(
+ response.requestOptions.path,
+ options: opts,
+ data: response.requestOptions.data,
+ queryParameters: response.requestOptions.queryParameters);
+
+ return handler.resolve(retryRequest);
+ }
+ } else {
+ retryCount = 0;
+ _authenticationRepository.logOut(forced: true);
+ return handler.reject(err);
}
} else {
final err = DioException(
diff --git a/comwell_key_app/lib/utils/locator.dart b/comwell_key_app/lib/utils/locator.dart
index 08489893..17829734 100644
--- a/comwell_key_app/lib/utils/locator.dart
+++ b/comwell_key_app/lib/utils/locator.dart
@@ -1,4 +1,5 @@
import 'package:comwell_key_app/authentication/authentication_repository.dart';
+import 'package:comwell_key_app/authentication/bloc/authentication_bloc.dart';
import 'package:comwell_key_app/database/comwell_db.dart';
import 'package:comwell_key_app/hotel_information/repository/hotel_information_repository.dart';
import 'package:comwell_key_app/key/repository/key_repository.dart';
diff --git a/comwell_key_app/lib/utils/stream_to_listenable.dart b/comwell_key_app/lib/utils/stream_to_listenable.dart
index 35de3b66..4dd38aa6 100644
--- a/comwell_key_app/lib/utils/stream_to_listenable.dart
+++ b/comwell_key_app/lib/utils/stream_to_listenable.dart
@@ -7,11 +7,22 @@ class StreamToListenable extends ChangeNotifier {
late final List<StreamSubscription<dynamic>> subscriptions;
StreamToListenable(List<Stream<dynamic>> streams) {
+
subscriptions = [];
+
+ print('streams $streams');
+ print('streams length ${streams.length}');
+
+
for (var e in streams) {
var s = e.asBroadcastStream().listen(_tt);
subscriptions.add(s);
}
+
+ print('subscriptions $subscriptions');
+ streams.first.single.then((value) {
+ print('value $value');
+ });
notifyListeners();
}