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,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,
|
||||
);
|
||||
}
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user