diff --git a/assets/images/logo_white.png b/assets/images/logo_white.png new file mode 100644 index 0000000..d90c228 Binary files /dev/null and b/assets/images/logo_white.png differ diff --git a/lib/common/theme/app_color.dart b/lib/common/theme/app_color.dart index ab8f9b2..14ded10 100644 --- a/lib/common/theme/app_color.dart +++ b/lib/common/theme/app_color.dart @@ -39,6 +39,8 @@ class AppColor { static const Color white = Color(0xFFFFFFFF); static const Color black = Color(0xFF000000); + static const Color disabled = Color(0xFFC8D1E1); + // Gradient Colors static const List primaryGradient = [ Color(0xFF36175e), diff --git a/lib/injection.config.dart b/lib/injection.config.dart index 5c7f74e..f1ab702 100644 --- a/lib/injection.config.dart +++ b/lib/injection.config.dart @@ -9,6 +9,7 @@ // coverage:ignore-file // ignore_for_file: no_leading_underscores_for_library_prefixes +import 'package:apskel_pos_flutter_v2/application/auth/auth_bloc.dart' as _i343; import 'package:apskel_pos_flutter_v2/application/auth/bloc/login_form_bloc.dart' as _i185; import 'package:apskel_pos_flutter_v2/common/api/api_client.dart' as _i457; @@ -76,6 +77,9 @@ extension GetItInjectableX on _i174.GetIt { gh<_i204.AuthLocalDataProvider>(), ), ); + gh.factory<_i343.AuthBloc>( + () => _i343.AuthBloc(gh<_i776.IAuthRepository>()), + ); gh.factory<_i185.LoginFormBloc>( () => _i185.LoginFormBloc(gh<_i776.IAuthRepository>()), ); diff --git a/lib/presentation/app_widget.dart b/lib/presentation/app_widget.dart index 38ae400..5e26317 100644 --- a/lib/presentation/app_widget.dart +++ b/lib/presentation/app_widget.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import '../application/auth/auth_bloc.dart'; import '../common/theme/theme.dart'; import '../common/constant/app_constant.dart'; import '../injection.dart'; @@ -18,12 +20,15 @@ class _AppWidgetState extends State { @override Widget build(BuildContext context) { - return MaterialApp.router( - debugShowCheckedModeBanner: false, - title: AppConstant.appName, - theme: ThemeApp.theme, - routerConfig: _appRouter.config( - navigatorObservers: () => [AppRouteObserver()], + return BlocProvider( + create: (context) => getIt(), + child: MaterialApp.router( + debugShowCheckedModeBanner: false, + title: AppConstant.appName, + theme: ThemeApp.theme, + routerConfig: _appRouter.config( + navigatorObservers: () => [AppRouteObserver()], + ), ), ); } diff --git a/lib/presentation/components/assets/assets.gen.dart b/lib/presentation/components/assets/assets.gen.dart index c528e32..343ade5 100644 --- a/lib/presentation/components/assets/assets.gen.dart +++ b/lib/presentation/components/assets/assets.gen.dart @@ -17,8 +17,12 @@ class $AssetsImagesGen { /// File path: assets/images/logo.png AssetGenImage get logo => const AssetGenImage('assets/images/logo.png'); + /// File path: assets/images/logo_white.png + AssetGenImage get logoWhite => + const AssetGenImage('assets/images/logo_white.png'); + /// List of all assets - List get values => [logo]; + List get values => [logo, logoWhite]; } class Assets { diff --git a/lib/presentation/pages/auth/login/login_page.dart b/lib/presentation/pages/auth/login/login_page.dart index 304e63e..f9acde4 100644 --- a/lib/presentation/pages/auth/login/login_page.dart +++ b/lib/presentation/pages/auth/login/login_page.dart @@ -10,6 +10,7 @@ import '../../../components/assets/assets.gen.dart'; import '../../../components/button/button.dart'; import '../../../components/spaces/space.dart'; import '../../../components/toast/flushbar.dart'; +import '../../../router/app_router.gr.dart'; import 'widgets/email_field.dart'; import 'widgets/password_field.dart'; @@ -29,12 +30,8 @@ class LoginPage extends StatelessWidget implements AutoRouteWrapper { (f) => AppFlushbar.showAuthFailureToast(context, f), (data) { if (context.mounted) { - AppFlushbar.showSuccess( - context, - 'Login berhasil! Selamat datang, ${data.user.name}.', - ); // context.read().add(AuthEvent.fetchCurrentUser()); - // context.router.replace(const MainRoute()); + context.router.replace(const MainRoute()); } }, ), diff --git a/lib/presentation/pages/main/main_page.dart b/lib/presentation/pages/main/main_page.dart new file mode 100644 index 0000000..2fc6a61 --- /dev/null +++ b/lib/presentation/pages/main/main_page.dart @@ -0,0 +1,117 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; + +import '../../../common/theme/theme.dart'; +import '../../components/assets/assets.gen.dart'; +import '../../router/app_router.gr.dart'; + +@RoutePage() +class MainPage extends StatelessWidget { + const MainPage({super.key}); + + @override + Widget build(BuildContext context) { + return AutoTabsRouter( + routes: [ + HomeRoute(), + TableRoute(), + ReportRoute(), + CustomerRoute(), + SettingRoute(), + ], + builder: (context, child) { + final tabsRouter = AutoTabsRouter.of(context); + + return Scaffold( + body: Row( + children: [ + NavigationRail( + selectedIndex: tabsRouter.activeIndex, + onDestinationSelected: tabsRouter.setActiveIndex, + labelType: NavigationRailLabelType.none, + backgroundColor: AppColor.primary, + selectedIconTheme: const IconThemeData(color: Colors.white), + indicatorColor: AppColor.disabled.withOpacity(0.25), + indicatorShape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(8.0), + ), + minExtendedWidth: 56, + leading: Padding( + padding: EdgeInsets.all(8.0), + child: Assets.images.logoWhite.image( + width: 40, + height: 40, + fit: BoxFit.contain, + ), + ), + trailing: Expanded( + child: Align( + alignment: Alignment.bottomCenter, + child: Padding( + padding: const EdgeInsets.only(bottom: 16.0), + child: IconButton( + icon: const Icon( + Icons.logout, + color: AppColor.disabled, + ), + onPressed: () {}, + tooltip: 'Logout', + ), + ), + ), + ), + destinations: const [ + NavigationRailDestination( + icon: Icon(Icons.home_outlined, color: AppColor.disabled), + selectedIcon: Icon(Icons.home, color: AppColor.white), + label: Text('POS'), + padding: EdgeInsets.symmetric(vertical: 8), + ), + NavigationRailDestination( + icon: Icon( + Icons.table_bar_outlined, + color: AppColor.disabled, + ), + selectedIcon: Icon(Icons.person, color: AppColor.white), + label: Text('Meja'), + padding: EdgeInsets.symmetric(vertical: 8), + ), + NavigationRailDestination( + icon: Icon( + Icons.pie_chart_outline_outlined, + color: AppColor.disabled, + ), + selectedIcon: Icon(Icons.settings, color: AppColor.white), + label: Text('Laporan'), + padding: EdgeInsets.symmetric(vertical: 8), + ), + NavigationRailDestination( + icon: Icon( + Icons.person_2_outlined, + color: AppColor.disabled, + ), + selectedIcon: Icon(Icons.person_2, color: AppColor.white), + label: Text('Pelanggan'), + padding: EdgeInsets.symmetric(vertical: 8), + ), + NavigationRailDestination( + icon: Icon( + Icons.settings_outlined, + color: AppColor.disabled, + ), + selectedIcon: Icon(Icons.settings, color: AppColor.white), + label: Text('Pengaturan'), + padding: EdgeInsets.symmetric(vertical: 8), + ), + ], + ), + const VerticalDivider(thickness: 1, width: 1), + // Main content area + Expanded(child: child), + ], + ), + ); + }, + ); + } +} diff --git a/lib/presentation/pages/main/pages/customer/customer_page.dart b/lib/presentation/pages/main/pages/customer/customer_page.dart new file mode 100644 index 0000000..a93f8ee --- /dev/null +++ b/lib/presentation/pages/main/pages/customer/customer_page.dart @@ -0,0 +1,12 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; + +@RoutePage() +class CustomerPage extends StatelessWidget { + const CustomerPage({super.key}); + + @override + Widget build(BuildContext context) { + return const Placeholder(); + } +} diff --git a/lib/presentation/pages/main/pages/home/home_page.dart b/lib/presentation/pages/main/pages/home/home_page.dart new file mode 100644 index 0000000..edc555d --- /dev/null +++ b/lib/presentation/pages/main/pages/home/home_page.dart @@ -0,0 +1,12 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; + +@RoutePage() +class HomePage extends StatelessWidget { + const HomePage({super.key}); + + @override + Widget build(BuildContext context) { + return const Center(child: Text('Home Page')); + } +} diff --git a/lib/presentation/pages/main/pages/report/report_page.dart b/lib/presentation/pages/main/pages/report/report_page.dart new file mode 100644 index 0000000..04f367e --- /dev/null +++ b/lib/presentation/pages/main/pages/report/report_page.dart @@ -0,0 +1,12 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; + +@RoutePage() +class ReportPage extends StatelessWidget { + const ReportPage({super.key}); + + @override + Widget build(BuildContext context) { + return const Center(child: Text('Report Page')); + } +} diff --git a/lib/presentation/pages/main/pages/setting/setting_page.dart b/lib/presentation/pages/main/pages/setting/setting_page.dart new file mode 100644 index 0000000..be9d865 --- /dev/null +++ b/lib/presentation/pages/main/pages/setting/setting_page.dart @@ -0,0 +1,12 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; + +@RoutePage() +class SettingPage extends StatelessWidget { + const SettingPage({super.key}); + + @override + Widget build(BuildContext context) { + return const Center(child: Text('Setting Page')); + } +} diff --git a/lib/presentation/pages/main/pages/table/table_page.dart b/lib/presentation/pages/main/pages/table/table_page.dart new file mode 100644 index 0000000..1b93637 --- /dev/null +++ b/lib/presentation/pages/main/pages/table/table_page.dart @@ -0,0 +1,17 @@ +import 'package:auto_route/auto_route.dart'; +import 'package:flutter/material.dart'; + +@RoutePage() +class TablePage extends StatelessWidget { + const TablePage({super.key}); + + @override + Widget build(BuildContext context) { + return Center( + child: Text( + 'Table Page', + style: Theme.of(context).textTheme.headlineMedium, + ), + ); + } +} diff --git a/lib/presentation/router/app_router.dart b/lib/presentation/router/app_router.dart index e66c2f8..7ccc5c3 100644 --- a/lib/presentation/router/app_router.dart +++ b/lib/presentation/router/app_router.dart @@ -8,7 +8,19 @@ class AppRouter extends RootStackRouter { // Splash AutoRoute(page: SplashRoute.page, initial: true), - // Router + // Auth AutoRoute(page: LoginRoute.page), + + // Main + AutoRoute( + page: MainRoute.page, + children: [ + AutoRoute(page: HomeRoute.page, initial: true), + AutoRoute(page: TableRoute.page), + AutoRoute(page: ReportRoute.page), + AutoRoute(page: CustomerRoute.page), + AutoRoute(page: SettingRoute.page), + ], + ), ]; } diff --git a/lib/presentation/router/app_router.gr.dart b/lib/presentation/router/app_router.gr.dart index 1bec181..5914064 100644 --- a/lib/presentation/router/app_router.gr.dart +++ b/lib/presentation/router/app_router.gr.dart @@ -10,39 +10,147 @@ // ignore_for_file: no_leading_underscores_for_library_prefixes import 'package:apskel_pos_flutter_v2/presentation/pages/auth/login/login_page.dart' + as _i3; +import 'package:apskel_pos_flutter_v2/presentation/pages/main/main_page.dart' + as _i4; +import 'package:apskel_pos_flutter_v2/presentation/pages/main/pages/customer/customer_page.dart' as _i1; -import 'package:apskel_pos_flutter_v2/presentation/pages/splash/splash_page.dart' +import 'package:apskel_pos_flutter_v2/presentation/pages/main/pages/home/home_page.dart' as _i2; -import 'package:auto_route/auto_route.dart' as _i3; +import 'package:apskel_pos_flutter_v2/presentation/pages/main/pages/report/report_page.dart' + as _i5; +import 'package:apskel_pos_flutter_v2/presentation/pages/main/pages/setting/setting_page.dart' + as _i6; +import 'package:apskel_pos_flutter_v2/presentation/pages/main/pages/table/table_page.dart' + as _i8; +import 'package:apskel_pos_flutter_v2/presentation/pages/splash/splash_page.dart' + as _i7; +import 'package:auto_route/auto_route.dart' as _i9; /// generated route for -/// [_i1.LoginPage] -class LoginRoute extends _i3.PageRouteInfo { - const LoginRoute({List<_i3.PageRouteInfo>? children}) +/// [_i1.CustomerPage] +class CustomerRoute extends _i9.PageRouteInfo { + const CustomerRoute({List<_i9.PageRouteInfo>? children}) + : super(CustomerRoute.name, initialChildren: children); + + static const String name = 'CustomerRoute'; + + static _i9.PageInfo page = _i9.PageInfo( + name, + builder: (data) { + return const _i1.CustomerPage(); + }, + ); +} + +/// generated route for +/// [_i2.HomePage] +class HomeRoute extends _i9.PageRouteInfo { + const HomeRoute({List<_i9.PageRouteInfo>? children}) + : super(HomeRoute.name, initialChildren: children); + + static const String name = 'HomeRoute'; + + static _i9.PageInfo page = _i9.PageInfo( + name, + builder: (data) { + return const _i2.HomePage(); + }, + ); +} + +/// generated route for +/// [_i3.LoginPage] +class LoginRoute extends _i9.PageRouteInfo { + const LoginRoute({List<_i9.PageRouteInfo>? children}) : super(LoginRoute.name, initialChildren: children); static const String name = 'LoginRoute'; - static _i3.PageInfo page = _i3.PageInfo( + static _i9.PageInfo page = _i9.PageInfo( name, builder: (data) { - return const _i1.LoginPage(); + return _i9.WrappedRoute(child: const _i3.LoginPage()); }, ); } /// generated route for -/// [_i2.SplashPage] -class SplashRoute extends _i3.PageRouteInfo { - const SplashRoute({List<_i3.PageRouteInfo>? children}) +/// [_i4.MainPage] +class MainRoute extends _i9.PageRouteInfo { + const MainRoute({List<_i9.PageRouteInfo>? children}) + : super(MainRoute.name, initialChildren: children); + + static const String name = 'MainRoute'; + + static _i9.PageInfo page = _i9.PageInfo( + name, + builder: (data) { + return const _i4.MainPage(); + }, + ); +} + +/// generated route for +/// [_i5.ReportPage] +class ReportRoute extends _i9.PageRouteInfo { + const ReportRoute({List<_i9.PageRouteInfo>? children}) + : super(ReportRoute.name, initialChildren: children); + + static const String name = 'ReportRoute'; + + static _i9.PageInfo page = _i9.PageInfo( + name, + builder: (data) { + return const _i5.ReportPage(); + }, + ); +} + +/// generated route for +/// [_i6.SettingPage] +class SettingRoute extends _i9.PageRouteInfo { + const SettingRoute({List<_i9.PageRouteInfo>? children}) + : super(SettingRoute.name, initialChildren: children); + + static const String name = 'SettingRoute'; + + static _i9.PageInfo page = _i9.PageInfo( + name, + builder: (data) { + return const _i6.SettingPage(); + }, + ); +} + +/// generated route for +/// [_i7.SplashPage] +class SplashRoute extends _i9.PageRouteInfo { + const SplashRoute({List<_i9.PageRouteInfo>? children}) : super(SplashRoute.name, initialChildren: children); static const String name = 'SplashRoute'; - static _i3.PageInfo page = _i3.PageInfo( + static _i9.PageInfo page = _i9.PageInfo( name, builder: (data) { - return const _i2.SplashPage(); + return const _i7.SplashPage(); + }, + ); +} + +/// generated route for +/// [_i8.TablePage] +class TableRoute extends _i9.PageRouteInfo { + const TableRoute({List<_i9.PageRouteInfo>? children}) + : super(TableRoute.name, initialChildren: children); + + static const String name = 'TableRoute'; + + static _i9.PageInfo page = _i9.PageInfo( + name, + builder: (data) { + return const _i8.TablePage(); }, ); }