birzha_mobile/lib/components/tabview.dart

219 lines
7.1 KiB
Dart

import 'package:birzha/constants.dart';
import 'package:birzha/core/adaptix/adaptix.dart';
import 'package:flutter/material.dart';
import 'package:google_nav_bar/google_nav_bar.dart';
import 'package:provider/provider.dart';
class TabView extends StatefulWidget {
TabView({required this.items});
final List<TabConfigs> items;
@override
_TabViewState createState() => _TabViewState();
}
class _TabViewState extends State<TabView> {
late final List<GlobalKey<NavigatorState>> navigatorKeys;
late final PageController controller;
Future<bool> pop(BuildContext cntxt) async {
final tabnavigator = Provider.of<Tabnavigator>(cntxt, listen: false);
bool canPop = await navigatorKeys[tabnavigator.index].currentState?.maybePop() ?? true;
if (canPop) {
return false;
} else if (tabnavigator.stack.length > 1) {
setState(() {
tabnavigator._removefromStack();
changePage(tabnavigator.stack.last);
});
return false;
} else if (tabnavigator.stack.length == 1 && tabnavigator.index != 0) {
setState(() {
tabnavigator._removefromStack();
changePage(0);
});
return false;
}
return true;
}
void changePage(int index) {
controller.jumpToPage(index);
}
void onPageChange(BuildContext cntxt, int index) {
Provider.of<Tabnavigator>(cntxt, listen: false)._setIndex(index);
}
@override
void initState() {
navigatorKeys = [for (var item in widget.items) LabeledGlobalKey<NavigatorState>(item.initialRouteName)];
controller = PageController();
super.initState();
}
@override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => Tabnavigator(
currentRouteName: (index) {
return widget.items[index].initialRouteName;
},
changePage: changePage,
pop: pop,
rootNavContext: context),
builder: (context, _) => WillPopScope(
onWillPop: () => pop(context),
child: Consumer<Tabnavigator>(
builder: (context, tabnav, __) {
return Scaffold(
bottomNavigationBar: Container(
color: Theme.of(context).bottomNavigationBarTheme.backgroundColor ?? Colors.white,
padding: EdgeInsets.symmetric(horizontal: AppConstants.horizontalPadding(context) / 2).copyWith(bottom: Adaptix.systemPadding.bottom),
child: GNav(
tabBorderRadius: 20.adaptedPx(),
curve: Curves.easeInCubic,
duration: Duration(milliseconds: 280),
selectedIndex: tabnav.index,
backgroundColor: Colors.transparent,
gap: 10.adaptedPx(),
color: Theme.of(context).accentColor,
activeColor: Theme.of(context).accentColor,
iconSize: 18.7.adaptedPx(),
textStyle: Theme.of(context).textTheme.headline2?.copyWith(
color: Theme.of(context).accentColor,
fontSize: AppConstants.h2FontSize * 0.93,
// body text uly headlinedan kichi
fontWeight: FontWeight.w500,
height: 1.3),
tabBackgroundColor: Theme.of(context).bottomNavigationBarTheme.selectedItemColor ?? Colors.grey.shade300,
tabMargin: EdgeInsets.symmetric(vertical: 8.adaptedPx()),
padding: EdgeInsets.symmetric(horizontal: 10.adaptedPx(), vertical: 13.2.adaptedPx()),
onTabChange: (index) {
onPageChange(context, index);
changePage(index);
},
tabs: <GButton>[
for (var item in widget.items)
/// those items are integrated from each single tabconfig from widget.items
GButton(
icon: item.iconData,
text: item.routeLabel,
active: true,
),
],
),
),
body: Column(
children: [
//will create as much Navigators as the length of widget.items.length
Expanded(
child: PageView.builder(
itemCount: widget.items.length,
onPageChanged: (newPageIndex) {
onPageChange(context, newPageIndex);
},
controller: controller,
itemBuilder: (_, index) => Navigator(
initialRoute: widget.items[index].initialRouteName,
key: navigatorKeys[index],
onGenerateInitialRoutes: (_, __) {
return [
//each first screen of each item in widget.items
MaterialPageRoute(builder: widget.items[index].firstScreen),
];
},
),
),
),
],
),
);
},
),
),
);
}
}
///describes each gbutton, each tab and e.t.c -> creaet list of items in [TabView] constructor
class TabConfigs {
final int index;
final Widget Function(BuildContext) firstScreen;
final String routeLabel;
final IconData iconData;
final String initialRouteName;
TabConfigs({
required this.index,
required this.firstScreen,
required this.routeLabel,
required this.iconData,
required this.initialRouteName,
});
}
class Tabnavigator extends ChangeNotifier {
int index = 0;
Set<int> stack = <int>{0};
late final Future<bool> Function(BuildContext cntxt) pop;
late final String Function(int) currentRouteName;
late final void Function(int) _changePage;
late final BuildContext rootNavContext;
Tabnavigator({required void Function(int) changePage, required this.currentRouteName, required this.pop, required this.rootNavContext}) {
_changePage = changePage;
}
Map<int, dynamic> _routeSettingsTable = {};
void changePage(int page, [dynamic payload]) {
_routeSettingsTable[page] = payload;
_changePage(page);
notifyListeners();
}
dynamic getPayloadOf(int page) {
return _routeSettingsTable[page];
}
void _setIndex(int i) {
index = i;
stack.remove(i);
stack.add(i);
notifyListeners();
}
void _removefromStack() {
_routeSettingsTable.remove(stack.last);
var listFromStack = [...stack]..removeLast();
stack = {...listFromStack};
index = stack.last;
notifyListeners();
}
static Tabnavigator? maybeOf(BuildContext context) {
try {
return Provider.of<Tabnavigator>(context, listen: false);
} catch (e) {}
}
static backDispatcher(BuildContext context) {
if (Tabnavigator.maybeOf(context) == null)
Navigator.of(context).pop();
else
Tabnavigator.maybeOf(context)!.pop(context);
}
static String currentRoute(BuildContext context) {
var nav = Tabnavigator.maybeOf(context);
if (nav == null) {
return '/root';
} else {
return nav.currentRouteName(nav.index);
}
}
}