Refactor provider initialization to load only essential providers at startup. Introduce TabNavigationService for managing tab state and update screens to respond to tab changes. Clean up view models and navigation logic for improved performance and maintainability.
This commit is contained in:
@@ -1,12 +1,44 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import '../../../core/services/tab_navigation_service.dart';
|
||||
import '../../../core/utils/size_config.dart';
|
||||
import '../../../view_models/home_view_model.dart';
|
||||
import '../../shared/responsive_builder.dart';
|
||||
import '../widgets.dart';
|
||||
|
||||
class HomeScreen extends StatelessWidget {
|
||||
class HomeScreen extends StatefulWidget {
|
||||
const HomeScreen({super.key});
|
||||
|
||||
@override
|
||||
State<HomeScreen> createState() => _HomeScreenState();
|
||||
}
|
||||
|
||||
class _HomeScreenState extends State<HomeScreen> {
|
||||
late final HomeViewModel _viewModel;
|
||||
late final TabNavigationService _tabService;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_viewModel = context.read<HomeViewModel>();
|
||||
_tabService = context.read<TabNavigationService>();
|
||||
_tabService.addListener(_onTabChanged);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_tabService.removeListener(_onTabChanged);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onTabChanged() {
|
||||
// Tab index 0 is Home
|
||||
if (_tabService.currentTabIndex == 0 && mounted) {
|
||||
_viewModel.init();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
SizeConfig.init(context);
|
||||
|
||||
@@ -1,13 +1,45 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tm_app/core/services/tab_navigation_service.dart';
|
||||
import 'package:tm_app/core/utils/size_config.dart';
|
||||
import 'package:tm_app/view_models/notification_view_model.dart';
|
||||
import 'package:tm_app/views/notification/pages/d_notification_page.dart';
|
||||
import 'package:tm_app/views/notification/pages/m_notification_page.dart';
|
||||
import 'package:tm_app/views/notification/pages/t_notification_page.dart';
|
||||
import 'package:tm_app/views/shared/responsive_builder.dart';
|
||||
|
||||
class NotificationScreen extends StatelessWidget {
|
||||
class NotificationScreen extends StatefulWidget {
|
||||
const NotificationScreen({super.key});
|
||||
|
||||
@override
|
||||
State<NotificationScreen> createState() => _NotificationScreenState();
|
||||
}
|
||||
|
||||
class _NotificationScreenState extends State<NotificationScreen> {
|
||||
late final NotificationViewModel _viewModel;
|
||||
late final TabNavigationService _tabService;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_viewModel = context.read<NotificationViewModel>();
|
||||
_tabService = context.read<TabNavigationService>();
|
||||
_tabService.addListener(_onTabChanged);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_tabService.removeListener(_onTabChanged);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onTabChanged() {
|
||||
// Tab index 3 is Notification
|
||||
if (_tabService.currentTabIndex == 3 && mounted) {
|
||||
_viewModel.init();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
SizeConfig.init(context);
|
||||
|
||||
@@ -49,104 +49,124 @@ class _DesktopProfilePageState extends State<DesktopProfilePage> {
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: AppColors.backgroundColor,
|
||||
body: Consumer<ProfileViewModel>(
|
||||
builder: (context, viewModel, child) {
|
||||
if (viewModel.isLoading) {
|
||||
return const Center(
|
||||
child: CircularProgressIndicator(color: AppColors.secondary50),
|
||||
);
|
||||
}
|
||||
if (viewModel.errorMessage != null) {
|
||||
return Center(child: Text(viewModel.errorMessage!));
|
||||
}
|
||||
body: Column(
|
||||
children: [
|
||||
const DesktopNavigationWidget(
|
||||
currentIndex: 4, // Tenders index
|
||||
),
|
||||
Consumer<ProfileViewModel>(
|
||||
builder: (context, viewModel, child) {
|
||||
if (viewModel.isLoading) {
|
||||
return const Expanded(
|
||||
child: Center(
|
||||
child: CircularProgressIndicator(
|
||||
color: AppColors.secondary50,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
if (viewModel.errorMessage != null) {
|
||||
return Expanded(
|
||||
child: Center(child: Text(viewModel.errorMessage!)),
|
||||
);
|
||||
}
|
||||
|
||||
if (viewModel.companyProfileData == null) {
|
||||
return const Center(child: Text(CommonStrings.noData));
|
||||
}
|
||||
if (viewModel.companyProfileData == null) {
|
||||
return const Expanded(
|
||||
child: Center(child: Text(CommonStrings.noData)),
|
||||
);
|
||||
}
|
||||
|
||||
return SafeArea(
|
||||
child: Column(
|
||||
children: [
|
||||
const DesktopNavigationWidget(
|
||||
currentIndex: 4, // Tenders index
|
||||
),
|
||||
SizedBox(
|
||||
width: 740,
|
||||
return Expanded(
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(height: 36.0.h()),
|
||||
TitleDescription(
|
||||
title: ProfileStrings.companyName,
|
||||
description: viewModel.companyProfileData!.name!,
|
||||
),
|
||||
TitleDescription(
|
||||
title: ProfileStrings.nationalId,
|
||||
description: viewModel.companyProfileData!.id!,
|
||||
),
|
||||
TitleDescription(
|
||||
title: ProfileStrings.registrationNumber,
|
||||
description:
|
||||
viewModel.companyProfileData!.registrationNumber!,
|
||||
),
|
||||
const TitleDescription(
|
||||
title: ProfileStrings.businessType,
|
||||
description: '-',
|
||||
),
|
||||
TitleDescription(
|
||||
title: ProfileStrings.founded,
|
||||
description:
|
||||
viewModel.companyProfileData!.foundedYear!.toString(),
|
||||
),
|
||||
SizedBox(height: 24.0.h()),
|
||||
// Theme Toggle
|
||||
Align(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
child: Text(
|
||||
ProfileStrings.settings,
|
||||
style: TextStyle(
|
||||
fontSize: 20.0.sp(),
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.grey70,
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 36.0.h()),
|
||||
_themeChangeRow(),
|
||||
SizedBox(height: 24.0.h()),
|
||||
Divider(color: AppColors.dividerColor, thickness: 1),
|
||||
SizedBox(height: 24.0.h()),
|
||||
// Spacer(),
|
||||
Align(
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
child: InkWell(
|
||||
onTap: () => viewModel.logout(),
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
child: Container(
|
||||
width: 156,
|
||||
height: 56.0.h(),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.primary20,
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
SizedBox(
|
||||
width: 740,
|
||||
child: Column(
|
||||
children: [
|
||||
SizedBox(height: 36.0.h()),
|
||||
TitleDescription(
|
||||
title: ProfileStrings.companyName,
|
||||
description: viewModel.companyProfileData!.name!,
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
ProfileStrings.logout,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0.sp(),
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.primaryColor,
|
||||
TitleDescription(
|
||||
title: ProfileStrings.nationalId,
|
||||
description: viewModel.companyProfileData!.id!,
|
||||
),
|
||||
TitleDescription(
|
||||
title: ProfileStrings.registrationNumber,
|
||||
description:
|
||||
viewModel
|
||||
.companyProfileData!
|
||||
.registrationNumber!,
|
||||
),
|
||||
const TitleDescription(
|
||||
title: ProfileStrings.businessType,
|
||||
description: '-',
|
||||
),
|
||||
TitleDescription(
|
||||
title: ProfileStrings.founded,
|
||||
description:
|
||||
viewModel.companyProfileData!.foundedYear!
|
||||
.toString(),
|
||||
),
|
||||
SizedBox(height: 24.0.h()),
|
||||
// Theme Toggle
|
||||
Align(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
child: Text(
|
||||
ProfileStrings.settings,
|
||||
style: TextStyle(
|
||||
fontSize: 20.0.sp(),
|
||||
fontWeight: FontWeight.w600,
|
||||
color: AppColors.grey70,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
SizedBox(height: 36.0.h()),
|
||||
_themeChangeRow(),
|
||||
SizedBox(height: 24.0.h()),
|
||||
Divider(
|
||||
color: AppColors.dividerColor,
|
||||
thickness: 1,
|
||||
),
|
||||
SizedBox(height: 24.0.h()),
|
||||
// Spacer(),
|
||||
Align(
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
child: InkWell(
|
||||
onTap: () => viewModel.logout(),
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
child: Container(
|
||||
width: 156,
|
||||
height: 56.0.h(),
|
||||
decoration: BoxDecoration(
|
||||
color: AppColors.primary20,
|
||||
borderRadius: BorderRadius.circular(100),
|
||||
),
|
||||
alignment: Alignment.center,
|
||||
child: Text(
|
||||
ProfileStrings.logout,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0.sp(),
|
||||
fontWeight: FontWeight.w500,
|
||||
color: AppColors.primaryColor,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tm_app/core/services/tab_navigation_service.dart';
|
||||
import 'package:tm_app/core/utils/size_config.dart';
|
||||
import 'package:tm_app/view_models/profile_view_model.dart';
|
||||
import 'package:tm_app/views/shared/responsive_builder.dart';
|
||||
@@ -16,17 +17,34 @@ class ProfileScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _ProfileScreenState extends State<ProfileScreen> {
|
||||
late ProfileViewModel viewModel;
|
||||
late final ProfileViewModel _viewModel;
|
||||
late final TabNavigationService _tabService;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
viewModel = context.read<ProfileViewModel>();
|
||||
_viewModel = context.read<ProfileViewModel>();
|
||||
_tabService = context.read<TabNavigationService>();
|
||||
_tabService.addListener(_onTabChanged);
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
viewModel.getCompanyProfile();
|
||||
_viewModel.getCompanyProfile();
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_tabService.removeListener(_onTabChanged);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onTabChanged() {
|
||||
// Tab index 2 is Profile
|
||||
if (_tabService.currentTabIndex == 2 && mounted) {
|
||||
_viewModel.getCompanyProfile();
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
SizeConfig.init(context);
|
||||
|
||||
@@ -2,16 +2,15 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tm_app/core/constants/assets.dart';
|
||||
import 'package:tm_app/core/services/tab_navigation_service.dart';
|
||||
import 'package:tm_app/core/theme/colors.dart';
|
||||
import 'package:tm_app/core/utils/size_config.dart';
|
||||
import 'package:tm_app/view_models/home_view_model.dart';
|
||||
import 'package:tm_app/view_models/tenders_view_model.dart';
|
||||
import 'package:tm_app/data/services/notification_state_service.dart';
|
||||
import 'package:tm_app/views/home/strings/home_strings.dart';
|
||||
import 'package:tm_app/views/profile/strings/profile_strings.dart';
|
||||
import 'package:tm_app/views/tenders/strings/tenders_strings.dart';
|
||||
|
||||
import '../../core/routes/app_routes.dart';
|
||||
import '../../view_models/notification_view_model.dart';
|
||||
|
||||
class DesktopNavigationWidget extends StatelessWidget {
|
||||
const DesktopNavigationWidget({
|
||||
@@ -45,7 +44,7 @@ class DesktopNavigationWidget extends StatelessWidget {
|
||||
context,
|
||||
() => const HomeRouteData().go(context),
|
||||
);
|
||||
context.read<HomeViewModel>().init();
|
||||
context.read<TabNavigationService>().onTabSelected(0);
|
||||
}
|
||||
},
|
||||
child: SvgPicture.asset(AssetsManager.logoSmall),
|
||||
@@ -63,7 +62,7 @@ class DesktopNavigationWidget extends StatelessWidget {
|
||||
context,
|
||||
() => const HomeRouteData().go(context),
|
||||
);
|
||||
context.read<HomeViewModel>().init();
|
||||
context.read<TabNavigationService>().onTabSelected(0);
|
||||
}
|
||||
},
|
||||
iconPath: AssetsManager.home,
|
||||
@@ -75,16 +74,11 @@ class DesktopNavigationWidget extends StatelessWidget {
|
||||
text: TendersStrings.tendersTitle,
|
||||
isActive: currentIndex == 1,
|
||||
onTap: () {
|
||||
// if (currentIndex == 1) {
|
||||
// return;
|
||||
// } else
|
||||
{
|
||||
Router.neglect(
|
||||
context,
|
||||
() => const TendersRouteData().go(context),
|
||||
);
|
||||
context.read<TendersViewModel>().init(context);
|
||||
}
|
||||
Router.neglect(
|
||||
context,
|
||||
() => const TendersRouteData().go(context),
|
||||
);
|
||||
context.read<TabNavigationService>().onTabSelected(1);
|
||||
},
|
||||
iconPath: AssetsManager.tenders,
|
||||
activeIconPath: AssetsManager.tendersActive,
|
||||
@@ -118,7 +112,7 @@ class DesktopNavigationWidget extends StatelessWidget {
|
||||
context,
|
||||
() => const NotificationRouteData().go(context),
|
||||
);
|
||||
context.read<NotificationViewModel>().init();
|
||||
context.read<TabNavigationService>().onTabSelected(3);
|
||||
}
|
||||
},
|
||||
iconPath: AssetsManager.notify,
|
||||
@@ -171,7 +165,8 @@ class DesktopNavigationWidget extends StatelessWidget {
|
||||
required String iconPath,
|
||||
required String activeIconPath,
|
||||
}) {
|
||||
final hasUnread = context.watch<HomeViewModel>().hasUnreadNotification;
|
||||
final hasUnread =
|
||||
context.watch<NotificationStateService>().hasUnreadNotification;
|
||||
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
|
||||
@@ -3,16 +3,15 @@ import 'package:flutter_svg/svg.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tm_app/core/constants/assets.dart';
|
||||
import 'package:tm_app/core/services/tab_navigation_service.dart';
|
||||
import 'package:tm_app/core/theme/colors.dart';
|
||||
import 'package:tm_app/core/utils/size_config.dart';
|
||||
import 'package:tm_app/view_models/home_view_model.dart';
|
||||
import 'package:tm_app/view_models/tenders_view_model.dart';
|
||||
import 'package:tm_app/data/services/notification_state_service.dart';
|
||||
import 'package:tm_app/views/home/strings/home_strings.dart';
|
||||
import 'package:tm_app/views/profile/strings/profile_strings.dart';
|
||||
import 'package:tm_app/views/tenders/strings/tenders_strings.dart';
|
||||
|
||||
import '../../core/routes/app_routes.dart';
|
||||
import '../../view_models/notification_view_model.dart';
|
||||
|
||||
class TabletNavigationWidget extends StatelessWidget {
|
||||
const TabletNavigationWidget({required this.currentIndex, super.key});
|
||||
@@ -41,7 +40,7 @@ class TabletNavigationWidget extends StatelessWidget {
|
||||
context,
|
||||
() => const HomeRouteData().go(context),
|
||||
);
|
||||
context.read<HomeViewModel>().init();
|
||||
context.read<TabNavigationService>().onTabSelected(0);
|
||||
}
|
||||
},
|
||||
iconPath: AssetsManager.home,
|
||||
@@ -60,7 +59,7 @@ class TabletNavigationWidget extends StatelessWidget {
|
||||
context,
|
||||
() => const TendersRouteData().go(context),
|
||||
);
|
||||
context.read<TendersViewModel>().init(context);
|
||||
context.read<TabNavigationService>().onTabSelected(1);
|
||||
}
|
||||
},
|
||||
iconPath: AssetsManager.tenders,
|
||||
@@ -94,7 +93,7 @@ class TabletNavigationWidget extends StatelessWidget {
|
||||
context,
|
||||
() => const NotificationRouteData().go(context),
|
||||
);
|
||||
context.read<NotificationViewModel>().init();
|
||||
context.read<TabNavigationService>().onTabSelected(3);
|
||||
}
|
||||
},
|
||||
iconPath: AssetsManager.notify,
|
||||
@@ -131,7 +130,8 @@ class TabletNavigationWidget extends StatelessWidget {
|
||||
required String iconPath,
|
||||
required String activeIconPath,
|
||||
}) {
|
||||
final hasUnread = context.watch<HomeViewModel>().hasUnreadNotification;
|
||||
final hasUnread =
|
||||
context.watch<NotificationStateService>().hasUnreadNotification;
|
||||
|
||||
return InkWell(
|
||||
onTap: onTap,
|
||||
|
||||
@@ -6,7 +6,7 @@ import 'package:tm_app/core/theme/colors.dart';
|
||||
import 'package:tm_app/core/utils/size_config.dart';
|
||||
|
||||
import '../../core/routes/app_routes.dart';
|
||||
import '../../view_models/home_view_model.dart';
|
||||
import '../../core/services/tab_navigation_service.dart';
|
||||
|
||||
PreferredSizeWidget tenderMobileAppBar({required String title}) {
|
||||
return PreferredSize(
|
||||
@@ -87,7 +87,7 @@ PreferredSizeWidget tabletAppBar({
|
||||
borderRadius: BorderRadius.circular(50),
|
||||
onTap: () {
|
||||
Router.neglect(context, () => const HomeRouteData().go(context));
|
||||
context.read<HomeViewModel>().init();
|
||||
context.read<TabNavigationService>().onTabSelected(0);
|
||||
},
|
||||
child: SvgPicture.asset(AssetsManager.logoSmall),
|
||||
),
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:tm_app/core/services/tab_navigation_service.dart';
|
||||
import 'package:tm_app/core/utils/size_config.dart';
|
||||
import 'package:tm_app/views/shared/responsive_builder.dart';
|
||||
|
||||
@@ -16,15 +17,32 @@ class TendersScreen extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _TendersScreenState extends State<TendersScreen> {
|
||||
late final TendersViewModel viewModel;
|
||||
late final TendersViewModel _viewModel;
|
||||
late final TabNavigationService _tabService;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
viewModel = context.read<TendersViewModel>();
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
viewModel.init(context);
|
||||
});
|
||||
super.initState();
|
||||
_viewModel = context.read<TendersViewModel>();
|
||||
_tabService = context.read<TabNavigationService>();
|
||||
_tabService.addListener(_onTabChanged);
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
_viewModel.init(context);
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_tabService.removeListener(_onTabChanged);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void _onTabChanged() {
|
||||
// Tab index 1 is Tenders
|
||||
if (_tabService.currentTabIndex == 1 && mounted) {
|
||||
_viewModel.init(context);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
||||
@@ -27,9 +27,7 @@ class _YourTendersMobilePageState extends State<YourTendersMobilePage> {
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
viewModel.clearFilter();
|
||||
});
|
||||
viewModel.clearFilter();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user