diff --git a/assets/icons/qr_scan.png b/assets/icons/qr_scan.png deleted file mode 100644 index 7228c7b..0000000 Binary files a/assets/icons/qr_scan.png and /dev/null differ diff --git a/assets/icons/qr_scan.svg b/assets/icons/qr_scan.svg deleted file mode 100644 index ba9e926..0000000 --- a/assets/icons/qr_scan.svg +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - - - - - - diff --git a/lib/features/app_layout/bloc/nav_cubit.dart b/lib/features/app_layout/bloc/nav_cubit.dart index bb00d0d..87a1967 100644 --- a/lib/features/app_layout/bloc/nav_cubit.dart +++ b/lib/features/app_layout/bloc/nav_cubit.dart @@ -33,14 +33,14 @@ class NavCubit extends Cubit { ), ], 'Devices': [ - IconButton( - icon: Image.asset( - Assets.iconsFilter, - height: 20, - width: 20, - ), - onPressed: () {}, - ), + // IconButton( + // icon: Image.asset( + // Assets.iconsFilter, + // height: 20, + // width: 20, + // ), + // onPressed: () {}, + // ), IconButton( icon: const Icon( Icons.add, @@ -65,14 +65,14 @@ class NavCubit extends Cubit { ), ], 'Routine': [ - IconButton( - icon: Image.asset( - Assets.iconsFilter, - height: 20, - width: 20, - ), - onPressed: () {}, - ), + // IconButton( + // icon: Image.asset( + // Assets.iconsFilter, + // height: 20, + // width: 20, + // ), + // onPressed: () {}, + // ), IconButton( icon: const Icon( Icons.add, @@ -98,16 +98,8 @@ class NavCubit extends Cubit { ], 'Menu': [ IconButton( - icon: Image.asset( - Assets.iconsQrScan, - height: 20, - width: 20, - ), - onPressed: () {}, - ), - IconButton( - icon: Image.asset( - Assets.iconsSettings, + icon: SvgPicture.asset( + Assets.iconsScan, height: 20, width: 20, ), @@ -151,6 +143,7 @@ class NavCubit extends Cubit { void updatePageIndex(int index) { pageIndex = index; + print('index: $index'); pageController.animateToPage(index, duration: const Duration(milliseconds: 150), curve: Curves.easeIn); emit(NavChangePage()); diff --git a/lib/features/app_layout/view/widgets/app_body.dart b/lib/features/app_layout/view/widgets/app_body.dart index a3335a4..e98fa87 100644 --- a/lib/features/app_layout/view/widgets/app_body.dart +++ b/lib/features/app_layout/view/widgets/app_body.dart @@ -26,9 +26,7 @@ class AppBody extends StatelessWidget { ), ), child: PageView( - onPageChanged: (int index) { - NavCubit.of(context).updatePageIndex(index); - }, + physics: const NeverScrollableScrollPhysics(), controller: NavCubit.of(context).pageController, children: NavCubit.of(context).pages, ) diff --git a/lib/features/app_layout/view/widgets/default_nav_bar.dart b/lib/features/app_layout/view/widgets/default_nav_bar.dart index 2db04ff..92515db 100644 --- a/lib/features/app_layout/view/widgets/default_nav_bar.dart +++ b/lib/features/app_layout/view/widgets/default_nav_bar.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:syncrow_app/features/app_layout/bloc/nav_cubit.dart'; +import 'package:syncrow_app/features/app_layout/bloc/spaces_cubit.dart'; import 'package:syncrow_app/features/devices/bloc/devices_cubit.dart'; import 'package:syncrow_app/utils/resource_manager/color_manager.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; @@ -24,6 +25,9 @@ class DefaultNavBar extends StatelessWidget { if (DevicesCubit.get(context).chosenCategoryView != null) { DevicesCubit().clearCategoriesSelection(context); } + if (SpacesCubit.get(context).selectedRoom != null) { + SpacesCubit.get(context).unselectRoom(); + } }, currentIndex: NavCubit.pageIndex, selectedItemColor: ColorsManager.primaryColor, diff --git a/lib/features/auth/bloc/auth_cubit.dart b/lib/features/auth/bloc/auth_cubit.dart index e82e3d3..95d6115 100644 --- a/lib/features/auth/bloc/auth_cubit.dart +++ b/lib/features/auth/bloc/auth_cubit.dart @@ -2,11 +2,13 @@ import 'package:dio/dio.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:syncrow_app/features/auth/model/login_with_email_model.dart'; import 'package:syncrow_app/features/auth/model/token.dart'; import 'package:syncrow_app/features/auth/model/user_model.dart'; import 'package:syncrow_app/services/api/authentication_api.dart'; import 'package:syncrow_app/services/api/network_exception.dart'; +import 'package:syncrow_app/utils/resource_manager/constants.dart'; part 'auth_state.dart'; @@ -50,7 +52,10 @@ class AuthCubit extends Cubit { ); if (token.accessTokenIsNotEmpty) { - //Map dictionary + FlutterSecureStorage storage = const FlutterSecureStorage(); + await storage.write( + key: Constants.tokenAccessKey, value: token.accessToken); + user = UserModel.fromToken(token); emit(AuthSuccess()); } else { @@ -60,4 +65,15 @@ class AuthCubit extends Cubit { throw ServerFailure.fromDioError(e); } } + + logout() async { + emit(AuthLoading()); + try { + FlutterSecureStorage storage = const FlutterSecureStorage(); + await storage.delete(key: Constants.tokenAccessKey); + emit(AuthLoggedOut()); + } on DioException catch (e) { + throw ServerFailure.fromDioError(e); + } + } } diff --git a/lib/features/auth/bloc/auth_state.dart b/lib/features/auth/bloc/auth_state.dart index a48552c..8a370b0 100644 --- a/lib/features/auth/bloc/auth_state.dart +++ b/lib/features/auth/bloc/auth_state.dart @@ -16,6 +16,8 @@ class AuthError extends AuthState { class AuthSuccess extends AuthState {} +class AuthLoggedOut extends AuthState {} + class AuthPasswordVisibilityChanged extends AuthState {} class AuthAgreeToTermsChanged extends AuthState {} diff --git a/lib/features/auth/model/user_model.dart b/lib/features/auth/model/user_model.dart index baf44af..4d003a5 100644 --- a/lib/features/auth/model/user_model.dart +++ b/lib/features/auth/model/user_model.dart @@ -49,7 +49,7 @@ class UserModel { Map tempJson = token.decodeToken(); return UserModel( - id: tempJson['userId'].toString(), + id: tempJson['uuid'].toString(), email: tempJson['email'], name: null, photoUrl: null, diff --git a/lib/features/devices/view/widgets/devices_view_body.dart b/lib/features/devices/view/widgets/devices_view_body.dart index 7b53425..35858b7 100644 --- a/lib/features/devices/view/widgets/devices_view_body.dart +++ b/lib/features/devices/view/widgets/devices_view_body.dart @@ -65,12 +65,10 @@ class DevicesViewBody extends StatelessWidget { SpacesCubit.get(context).devicesPageController, count: 3, effect: const WormEffect( + paintStyle: PaintingStyle.stroke, dotHeight: 8, dotWidth: 8, ), - onDotClicked: (index) { - SpacesCubit.get(context).unselectRoom(); - }, ), ), ], diff --git a/lib/features/devices/view/widgets/rooms_slider.dart b/lib/features/devices/view/widgets/rooms_slider.dart index 5e9c3d9..8941e6c 100644 --- a/lib/features/devices/view/widgets/rooms_slider.dart +++ b/lib/features/devices/view/widgets/rooms_slider.dart @@ -67,58 +67,6 @@ class RoomsSlider extends StatelessWidget { ], ), ); - - // SingleChildScrollView( - // controller: SpacesCubit.get(context).roomsScrollController, - // scrollDirection: Axis.horizontal, - // child: Row( - // mainAxisAlignment: MainAxisAlignment.start, - // children: [ - // Padding( - // padding: const EdgeInsets.symmetric(horizontal: 15), - // child: InkWell( - // onTap: () { - // SpacesCubit.get(context).unselectRoom(); - // }, - // child: TitleMedium( - // text: StringsManager.wizard, - // style: context.titleMedium.copyWith( - // fontSize: 25, - // color: SpacesCubit.get(context).selectedRoom == null - // ? ColorsManager.textPrimaryColor - // : ColorsManager.textPrimaryColor.withOpacity(.2), - // ), - // ), - // ), - // ), - // ...SpacesCubit.get(context).selectedSpace.rooms.map( - // (room) => Padding( - // padding: const EdgeInsets.symmetric(horizontal: 15), - // child: InkWell( - // onTap: () { - // SpacesCubit.get(context).selectRoom(room); - // }, - // child: TitleMedium( - // text: room.name, - // style: context.titleMedium.copyWith( - // fontSize: 25, - // color: SpacesCubit.get(context).selectedRoomIndex == - // SpacesCubit.get(context) - // .selectedSpace - // .rooms - // .indexOf(room) + - // 1 - // ? ColorsManager.textPrimaryColor - // : ColorsManager.textPrimaryColor - // .withOpacity(.2), - // ), - // ), - // ), - // ), - // ) - // ], - // ), - // ); }, ); } diff --git a/lib/features/menu/view/menu_view.dart b/lib/features/menu/view/menu_view.dart index 2a491dc..1c55a36 100644 --- a/lib/features/menu/view/menu_view.dart +++ b/lib/features/menu/view/menu_view.dart @@ -1,8 +1,13 @@ import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:syncrow_app/features/auth/bloc/auth_cubit.dart'; import 'package:syncrow_app/features/menu/bloc/menu_cubit.dart'; import 'package:syncrow_app/features/menu/view/widgets/menu_list.dart'; import 'package:syncrow_app/features/menu/view/widgets/profile_tab.dart'; +import 'package:syncrow_app/features/shared_widgets/default_container.dart'; +import 'package:syncrow_app/features/shared_widgets/text_widgets/body_large.dart'; +import 'package:syncrow_app/navigation/routing_constants.dart'; +import 'package:syncrow_app/utils/context_extension.dart'; import 'package:syncrow_app/utils/resource_manager/constants.dart'; class MenuView extends StatelessWidget { @@ -14,26 +19,56 @@ class MenuView extends StatelessWidget { create: (BuildContext context) => MenuCubit(), child: BlocBuilder( builder: (context, state) { - return Padding( - padding: EdgeInsets.only( - top: Constants.appBarHeight, - bottom: Constants.bottomNavBarHeight, - left: Constants.defaultPadding, - right: Constants.defaultPadding, - ), - child: SingleChildScrollView( - physics: const BouncingScrollPhysics(), - child: Column( - children: [ - const ProfileTab(), - ...MenuCubit.of(context).menuLists.map( - (list) => MenuList( - listModel: list, - ), + return BlocBuilder( + builder: (context, state) { + return Padding( + padding: EdgeInsets.only( + top: Constants.appBarHeight, + bottom: Constants.bottomNavBarHeight, + left: Constants.defaultPadding, + right: Constants.defaultPadding, + ), + child: SingleChildScrollView( + physics: const BouncingScrollPhysics(), + child: Column( + children: [ + const ProfileTab(), + ...MenuCubit.of(context).menuLists.map( + (list) => MenuList( + listModel: list, + ), + ), + const SizedBox( + height: 15, ), - ], - ), - ), + InkWell( + onTap: () { + AuthCubit.get(context).logout(); + Navigator.of(context).pushNamedAndRemoveUntil( + Routes.authLogin, (route) => false); + }, + child: Row( + children: [ + Expanded( + child: DefaultContainer( + child: Center( + child: BodyLarge( + text: 'Logout', + style: context.bodyLarge.copyWith( + color: Colors.red, + ), + ), + ), + ), + ), + ], + ), + ) + ], + ), + ), + ); + }, ); }, ), diff --git a/lib/features/shared_widgets/default_button.dart b/lib/features/shared_widgets/default_button.dart index cbb70ce..05bcf7d 100644 --- a/lib/features/shared_widgets/default_button.dart +++ b/lib/features/shared_widgets/default_button.dart @@ -13,6 +13,8 @@ class DefaultButton extends StatelessWidget { this.isDone = false, this.customTextStyle, this.customButtonStyle, + this.backgroundColor, + this.foregroundColor, }); final void Function()? onPressed; @@ -29,6 +31,10 @@ class DefaultButton extends StatelessWidget { final ButtonStyle? customButtonStyle; + final Color? backgroundColor; + + final Color? foregroundColor; + @override Widget build(BuildContext context) { return ElevatedButton( @@ -41,17 +47,22 @@ class DefaultButton extends StatelessWidget { customTextStyle ?? context.bodyMedium.copyWith( fontSize: 16, + color: foregroundColor, ), ), foregroundColor: MaterialStateProperty.all( isSecondary ? Colors.black : enabled - ? Colors.white + ? foregroundColor ?? Colors.white : Colors.black, ), - backgroundColor: MaterialStateProperty.all( - enabled ? ColorsManager.primaryColor : Colors.grey), + backgroundColor: MaterialStateProperty.resolveWith( + (Set states) { + return enabled + ? backgroundColor ?? ColorsManager.primaryColor + : Colors.grey; + }), shape: MaterialStateProperty.all( RoundedRectangleBorder( borderRadius: BorderRadius.circular(20), diff --git a/lib/features/splash/view/splash_view.dart b/lib/features/splash/view/splash_view.dart index 218bc63..d36745f 100644 --- a/lib/features/splash/view/splash_view.dart +++ b/lib/features/splash/view/splash_view.dart @@ -1,7 +1,9 @@ import 'package:flutter/material.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:syncrow_app/generated/assets.dart'; import 'package:syncrow_app/navigation/routing_constants.dart'; +import 'package:syncrow_app/utils/resource_manager/constants.dart'; class SplashView extends StatelessWidget { const SplashView({super.key}); @@ -9,15 +11,16 @@ class SplashView extends StatelessWidget { @override Widget build(BuildContext context) { //TODO remove this delay - Future.delayed( - const Duration(seconds: 5), - () { - Navigator.popAndPushNamed( - context, - Routes.authLogin, - ); - }, - ); + Future.value().then((value) async { + var isLoggedIn = await const FlutterSecureStorage() + .read(key: Constants.tokenAccessKey) != + null; + if (isLoggedIn) { + Navigator.pushReplacementNamed(context, Routes.homeRoute); + } else { + Navigator.pushReplacementNamed(context, Routes.authLogin); + } + }); return Scaffold( body: Stack( alignment: Alignment.center, diff --git a/lib/generated/assets.dart b/lib/generated/assets.dart index 8237caa..b3da647 100644 --- a/lib/generated/assets.dart +++ b/lib/generated/assets.dart @@ -2,7 +2,6 @@ class Assets { Assets._(); - static const String assetsIconsQrScan = 'assets/icons/qr_scan.svg'; static const String assetsIconsSettings = 'assets/icons/settings.svg'; static const String fontsAftikaRegular = 'assets/fonts/AftikaRegular.ttf'; static const String iconsAC = 'assets/icons/AC.svg'; @@ -38,9 +37,9 @@ class Assets { static const String iconsMenuFill = 'assets/icons/Menu-fill.svg'; static const String iconsMinus = 'assets/icons/minus.svg'; static const String iconsPlus = 'assets/icons/plus.svg'; - static const String iconsQrScan = 'assets/icons/qr_scan.png'; static const String iconsRoutines = 'assets/icons/Routines.svg'; static const String iconsRoutinesFill = 'assets/icons/Routines-fill.svg'; + static const String iconsScan = 'assets/icons/Scan.svg'; static const String iconsScreen = 'assets/icons/Screen.svg'; static const String iconsSettings = 'assets/icons/settings.png'; static const String iconsSummer = 'assets/icons/Summer.svg'; diff --git a/lib/main.dart b/lib/main.dart index edb3229..2fa8e01 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -2,9 +2,11 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:syncrow_app/services/locator.dart'; import 'package:syncrow_app/utils/bloc_observer.dart'; import 'package:syncrow_app/utils/helpers/localization_helpers.dart'; +import 'package:syncrow_app/utils/resource_manager/constants.dart'; import 'my_app.dart'; @@ -32,6 +34,13 @@ void main() { //to initialize the locator initialSetup(); + //final SharedPreferences prefs = await SharedPreferences.getInstance(); + // var isLoggedIn = (prefs.getBool('isLoggedIn') == null) ? false : prefs.getBool('isLoggedIn'); + // + var storage = const FlutterSecureStorage(); + bool isLoggedIn = + await (storage.read(key: Constants.tokenAccessKey)) != null; + //to save the locale in the shared preferences await LocalizationService.saveLocale(const Locale("en", "AE")); final savedLocale = await LocalizationService.savedLocale(); diff --git a/lib/utils/resource_manager/constants.dart b/lib/utils/resource_manager/constants.dart index b185b28..6327b1b 100644 --- a/lib/utils/resource_manager/constants.dart +++ b/lib/utils/resource_manager/constants.dart @@ -11,7 +11,7 @@ abstract class Constants { static const double defaultPadding = 16; - static const String tokenKey = 'userToken'; + static const String tokenAccessKey = 'access_token'; } enum DeviceType {