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:
amirrezaghabeli
2025-10-06 14:12:40 +03:30
parent 645247183b
commit b43ebf885b
24 changed files with 839 additions and 218 deletions
+18 -67
View File
@@ -1,6 +1,7 @@
import 'package:provider/provider.dart';
import 'package:provider/single_child_widget.dart';
import 'package:tm_app/core/network/network_manager.dart';
import 'package:tm_app/core/services/tab_navigation_service.dart';
import 'package:tm_app/core/theme/theme_provider.dart';
import 'package:tm_app/data/repositories/home_repository.dart';
import 'package:tm_app/data/repositories/liked_tenders_repository.dart';
@@ -15,12 +16,6 @@ import 'package:tm_app/data/services/notification_service.dart';
import 'package:tm_app/data/services/notification_state_service.dart';
import 'package:tm_app/data/services/tender_detail_service.dart';
import 'package:tm_app/data/services/your_tenders_service.dart';
import 'package:tm_app/view_models/final_completion_of_documents_view_model.dart';
import 'package:tm_app/view_models/liked_tenders_view_model.dart';
import 'package:tm_app/view_models/notification_view_model.dart';
import 'package:tm_app/view_models/tender_detail_view_model.dart';
import 'package:tm_app/view_models/tenders_view_model.dart';
import 'package:tm_app/view_models/your_tenders_view_model.dart';
import '../../data/repositories/auth_repository.dart';
import '../../data/repositories/profile_repository.dart';
@@ -28,11 +23,17 @@ import '../../data/services/auth_service.dart';
import '../../data/services/profile_service.dart';
import '../../data/services/tenders_service.dart';
import '../../view_models/auth_view_model.dart';
import '../../view_models/home_view_model.dart';
import '../../view_models/profile_view_model.dart';
List<SingleChildWidget> get providersRemote {
return [...cores, ...apiClients, ...repositories, ...services, ...viewModels];
/// Essential providers loaded at app startup
/// Only includes infrastructure and auth
List<SingleChildWidget> get essentialProviders {
return [
...cores,
...apiClients,
...repositories,
...services,
...authProvider,
];
}
List<SingleChildWidget> get cores {
@@ -43,6 +44,10 @@ List<SingleChildWidget> get cores {
create: (context) => NotificationStateService(),
lazy: true,
),
ChangeNotifierProvider(
create: (context) => TabNavigationService(),
lazy: true,
),
];
}
@@ -147,66 +152,12 @@ List<SingleChildWidget> get services {
];
}
List<SingleChildWidget> get viewModels {
/// Auth ViewModel - only essential ViewModel loaded at startup
List<SingleChildWidget> get authProvider {
return [
ChangeNotifierProvider(
create: (context) => AuthViewModel(authRepository: context.read()),
lazy: true,
),
ChangeNotifierProvider(
create:
(context) => HomeViewModel(
homeRepository: context.read(),
notificationStateService: context.read(),
),
lazy: true,
),
ChangeNotifierProvider(
create: (context) => TendersViewModel(tendersRepository: context.read()),
lazy: true,
),
ChangeNotifierProvider(
create:
(context) => TenderDetailViewModel(
tenderDetailRepository: context.read(),
tendersRepository: context.read(),
),
lazy: true,
),
ChangeNotifierProvider(
create:
(context) =>
YourTendersViewModel(yourTendersRepository: context.read()),
lazy: true,
),
ChangeNotifierProvider(
create:
(context) => LikedTendersViewModel(
likedTendersRepository: context.read(),
tendersRepository: context.read(),
),
lazy: true,
),
ChangeNotifierProvider(
create:
(context) => ProfileViewModel(
profileRepository: context.read(),
authRepository: context.read(),
),
lazy: true,
),
ChangeNotifierProvider(
create: (context) => FinalCompletionOfDocumentsViewModel(),
lazy: true,
),
ChangeNotifierProvider(
create:
(context) => NotificationViewModel(
notificationsRepository: context.read(),
notificationStateService: context.read(),
notificationCheckService: context.read(),
),
lazy: true,
lazy: false, // Load immediately for auth state checks
),
];
}
@@ -0,0 +1,13 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../view_models/final_completion_of_documents_view_model.dart';
/// Lazy FinalCompletionOfDocumentsViewModel provider
/// Wraps screens that need FinalCompletionOfDocumentsViewModel
Widget finalCompletionProvider({required Widget child}) {
return ChangeNotifierProvider(
create: (context) => FinalCompletionOfDocumentsViewModel(),
child: child,
);
}
+19
View File
@@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../data/repositories/home_repository.dart';
import '../../data/services/notification_state_service.dart';
import '../../view_models/home_view_model.dart';
/// Lazy HomeViewModel provider
/// Wraps screens that need HomeViewModel
Widget homeProvider({required Widget child}) {
return ChangeNotifierProvider(
create:
(context) => HomeViewModel(
homeRepository: context.read<HomeRepository>(),
notificationStateService: context.read<NotificationStateService>(),
),
child: child,
);
}
@@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../data/repositories/liked_tenders_repository.dart';
import '../../data/repositories/tenders_repository.dart';
import '../../view_models/liked_tenders_view_model.dart';
/// Lazy LikedTendersViewModel provider
/// Wraps screens that need LikedTendersViewModel
Widget likedTendersProvider({required Widget child}) {
return ChangeNotifierProvider(
create:
(context) => LikedTendersViewModel(
likedTendersRepository: context.read<LikedTendersRepository>(),
tendersRepository: context.read<TendersRepository>(),
),
child: child,
);
}
@@ -0,0 +1,21 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../data/repositories/notification_repository.dart';
import '../../data/services/notification_check_service.dart';
import '../../data/services/notification_state_service.dart';
import '../../view_models/notification_view_model.dart';
/// Lazy NotificationViewModel provider
/// Wraps screens that need NotificationViewModel
Widget notificationProvider({required Widget child}) {
return ChangeNotifierProvider(
create:
(context) => NotificationViewModel(
notificationsRepository: context.read<NotificationsRepository>(),
notificationStateService: context.read<NotificationStateService>(),
notificationCheckService: context.read<NotificationCheckService>(),
),
child: child,
);
}
+19
View File
@@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../data/repositories/auth_repository.dart';
import '../../data/repositories/profile_repository.dart';
import '../../view_models/profile_view_model.dart';
/// Lazy ProfileViewModel provider
/// Wraps screens that need ProfileViewModel
Widget profileProvider({required Widget child}) {
return ChangeNotifierProvider(
create:
(context) => ProfileViewModel(
profileRepository: context.read<ProfileRepository>(),
authRepository: context.read<AuthRepository>(),
),
child: child,
);
}
@@ -0,0 +1,19 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../data/repositories/tender_detail_repository.dart';
import '../../data/repositories/tenders_repository.dart';
import '../../view_models/tender_detail_view_model.dart';
/// Lazy TenderDetailViewModel provider
/// Wraps screens that need TenderDetailViewModel
Widget tenderDetailProvider({required Widget child}) {
return ChangeNotifierProvider(
create:
(context) => TenderDetailViewModel(
tenderDetailRepository: context.read<TenderDetailRepository>(),
tendersRepository: context.read<TendersRepository>(),
),
child: child,
);
}
+17
View File
@@ -0,0 +1,17 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../data/repositories/tenders_repository.dart';
import '../../view_models/tenders_view_model.dart';
/// Lazy TendersViewModel provider
/// Wraps screens that need TendersViewModel
Widget tendersProvider({required Widget child}) {
return ChangeNotifierProvider(
create:
(context) => TendersViewModel(
tendersRepository: context.read<TendersRepository>(),
),
child: child,
);
}
@@ -0,0 +1,17 @@
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import '../../data/repositories/your_tenders_repository.dart';
import '../../view_models/your_tenders_view_model.dart';
/// Lazy YourTendersViewModel provider
/// Wraps screens that need YourTendersViewModel
Widget yourTendersProvider({required Widget child}) {
return ChangeNotifierProvider(
create:
(context) => YourTendersViewModel(
yourTendersRepository: context.read<YourTendersRepository>(),
),
child: child,
);
}
+21 -9
View File
@@ -17,6 +17,14 @@ import '../../views/profile/pages/profile_screen.dart';
import '../../views/splash/pages/splash_screen.dart';
import '../../views/tenders/pages/tenders_screen.dart';
import '../../views/your_tenders/pages/your_tenders_screen.dart';
import '../providers/final_completion_provider.dart';
import '../providers/home_provider.dart';
import '../providers/liked_tenders_provider.dart';
import '../providers/notification_provider.dart';
import '../providers/profile_provider.dart';
import '../providers/tender_detail_provider.dart';
import '../providers/tenders_provider.dart';
import '../providers/your_tenders_provider.dart';
import 'app_shell/app_shell_screen.dart';
part 'app_routes.g.dart';
@@ -147,7 +155,7 @@ class HomeRouteData extends GoRouteData with _$HomeRouteData {
@override
Widget build(BuildContext context, GoRouterState state) {
return const HomeScreen();
return homeProvider(child: const HomeScreen());
}
// @override
@@ -177,7 +185,7 @@ class TendersRouteData extends GoRouteData with _$TendersRouteData {
@override
Widget build(BuildContext context, GoRouterState state) {
return const TendersScreen();
return tendersProvider(child: const TendersScreen());
}
}
@@ -186,7 +194,7 @@ class ProfileRouteData extends GoRouteData with _$ProfileRouteData {
@override
Widget build(BuildContext context, GoRouterState state) {
return const ProfileScreen();
return profileProvider(child: const ProfileScreen());
}
}
@@ -195,7 +203,7 @@ class NotificationRouteData extends GoRouteData with _$NotificationRouteData {
@override
Widget build(BuildContext context, GoRouterState state) {
return const NotificationScreen();
return notificationProvider(child: const NotificationScreen());
}
}
@@ -205,7 +213,7 @@ class YourTendersRouteData extends GoRouteData with _$YourTendersRouteData {
@override
Widget build(BuildContext context, GoRouterState state) {
return const YourTendersScreen();
return yourTendersProvider(child: const YourTendersScreen());
}
}
@@ -218,7 +226,9 @@ class FinalCompletionOfDocumentsRouteData extends GoRouteData
@override
Widget build(BuildContext context, GoRouterState state) {
return const FinalCompletionOfDocumentsScreen();
return finalCompletionProvider(
child: const FinalCompletionOfDocumentsScreen(),
);
}
}
@@ -228,7 +238,7 @@ class LikedTendersRouteData extends GoRouteData with _$LikedTendersRouteData {
@override
Widget build(BuildContext context, GoRouterState state) {
return const LikedTendersScreen();
return likedTendersProvider(child: const LikedTendersScreen());
}
}
@@ -241,7 +251,9 @@ class CompletionOfDocumentsMobileRouteData extends GoRouteData
@override
Widget build(BuildContext context, GoRouterState state) {
return const CompletionOfDocumentsMobilePage();
return finalCompletionProvider(
child: const CompletionOfDocumentsMobilePage(),
);
}
}
@@ -252,7 +264,7 @@ class TenderDetailRouteData extends GoRouteData with _$TenderDetailRouteData {
@override
Widget build(BuildContext context, GoRouterState state) {
return TenderDetailScreen(tenderId: tenderId);
return tenderDetailProvider(child: TenderDetailScreen(tenderId: tenderId));
}
}
@@ -5,11 +5,9 @@ import 'package:tm_app/core/routes/app_shell/desktop_shell_page.dart';
import 'package:tm_app/core/routes/app_shell/mobile_shell_page.dart';
import 'package:tm_app/core/routes/app_shell/tablet_shell_page.dart';
import 'package:tm_app/data/services/notification_check_service.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/views/shared/responsive_builder.dart';
import '../../../view_models/notification_view_model.dart';
import '../../services/tab_navigation_service.dart';
class AppShellScreen extends StatefulWidget {
const AppShellScreen({required this.navigationShell, super.key});
@@ -35,24 +33,14 @@ class _AppShellScreenState extends State<AppShellScreen> {
return;
}
// Navigate first
// Navigate to the selected branch
widget.navigationShell.goBranch(
index,
initialLocation: index == widget.navigationShell.currentIndex,
);
// Then trigger data loading after navigation is complete
WidgetsBinding.instance.addPostFrameCallback((_) {
if (index == 0) {
context.read<HomeViewModel>().init();
}
if (index == 1) {
context.read<TendersViewModel>().init(context);
}
if (index == 3) {
context.read<NotificationViewModel>().init();
}
});
// Notify that tab has changed so screens can refresh
context.read<TabNavigationService>().onTabSelected(index);
}
@override
@@ -0,0 +1,17 @@
import 'package:flutter/foundation.dart';
/// Service to broadcast tab navigation events
/// Allows screens to refresh when their tab becomes active
class TabNavigationService extends ChangeNotifier {
int _currentTabIndex = 0;
int get currentTabIndex => _currentTabIndex;
/// Notify listeners that a tab has been selected
void onTabSelected(int index) {
if (_currentTabIndex != index) {
_currentTabIndex = index;
notifyListeners();
}
}
}
+1 -1
View File
@@ -38,7 +38,7 @@ void main() async {
List<SingleChildWidget> providers = [
Provider(create: (context) => prefs),
...providersRemote,
...essentialProviders, // Only load essential providers at startup
];
// Configure web URL strategy if running on web
configureWebUrlStrategy();
+33 -1
View File
@@ -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);
+106 -86
View File
@@ -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,
),
),
),
),
),
],
),
),
],
),
),
],
),
);
},
);
},
),
],
),
);
}
+21 -3
View File
@@ -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);
+12 -17
View File
@@ -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,
+2 -2
View File
@@ -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),
),
+23 -5
View File
@@ -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();
}