mangayomi/lib/modules/widgets/custom_draggable_tabbar.dart
2024-12-20 10:15:15 +01:00

191 lines
7 KiB
Dart

import 'dart:io';
import 'package:draggable_menu/draggable_menu.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:mangayomi/router/router.dart';
import 'package:mangayomi/utils/extensions/build_context_extensions.dart';
class MeasureWidgetSize extends StatefulWidget {
final Function(Size? size) onCalculateSize;
final Widget child;
const MeasureWidgetSize(
{super.key, required this.onCalculateSize, required this.child});
@override
State<MeasureWidgetSize> createState() => _MeasureWidgetSizeState();
}
class _MeasureWidgetSizeState extends State<MeasureWidgetSize> {
final _key = GlobalKey();
@override
initState() {
WidgetsBinding.instance.addPostFrameCallback(
(_) => widget.onCalculateSize(_key.currentContext?.size));
super.initState();
}
@override
Widget build(BuildContext context) {
return Container(key: _key, child: widget.child);
}
}
Future<void> customDraggableTabBar(
{required List<Widget> tabs,
required List<Widget> children,
required BuildContext context,
required TickerProvider vsync,
bool fullWidth = false,
Widget? moreWidget}) async {
final controller = DraggableMenuController();
late TabController tabBarController;
tabBarController = TabController(length: tabs.length, vsync: vsync);
final maxHeight = context.height(0.8);
int index = 0;
List<Map<String, dynamic>> widgetsHeight = [];
void refresh() {
controller.animateTo(
widgetsHeight.indexWhere((element) => element["index"] == index));
}
tabBarController.animation!.addListener(() {
final currentIndex = tabBarController.animation!.value.round();
index = tabBarController.index;
if (index != currentIndex) {
index = currentIndex;
refresh();
} else {
refresh();
}
});
await showDialog(
context: context,
builder: (context) {
return Material(
child: Column(
children: [
for (var i = 0; i < children.length; i++) ...[
MeasureWidgetSize(
onCalculateSize: (size) {
final additionnalHeight =
((List.generate(10000, (index) => index * 0.0001))
..shuffle())
.first;
double newHeight = size!.height + 52.0 + additionnalHeight;
if (!(newHeight <= maxHeight)) {
newHeight = maxHeight + additionnalHeight;
}
widgetsHeight.add({"index": i, "height": newHeight});
if (widgetsHeight.length == children.length) {
Navigator.pop(context);
}
},
child: children[i])
]
],
),
);
},
);
widgetsHeight
.sort((a, b) => (a["height"] as double).compareTo(b["height"] as double));
if (context.mounted) {
await DraggableMenu.open(
context,
DraggableMenu(
curve: Curves.linearToEaseOut,
controller: controller,
levels: widgetsHeight
.map((e) => e["height"])
.map((e) => DraggableMenuLevel(height: e))
.toList(),
customUi: Consumer(builder: (context, ref, child) {
final location =
ref.watch(routerCurrentLocationStateProvider(context));
final width = context.isTablet && !fullWidth
? switch (location) {
null => 100,
!= '/MangaLibrary' &&
!= '/AnimeLibrary' &&
!= '/history' &&
!= '/browse' &&
!= '/more' =>
0,
_ => 100,
}
: 0;
return Scaffold(
backgroundColor: Platform.isLinux ? null : Colors.transparent,
body: Container(
width: context.width(1) - width,
decoration: BoxDecoration(
borderRadius: const BorderRadius.only(
topLeft: Radius.circular(20),
topRight: Radius.circular(20)),
color: Theme.of(context).scaffoldBackgroundColor),
child: DefaultTabController(
length: tabs.length,
child: Column(children: [
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Flexible(
flex: 9,
child: TabBar(
unselectedLabelStyle: const TextStyle(
fontWeight: FontWeight.w500),
labelStyle: const TextStyle(
fontWeight: FontWeight.bold),
dividerColor: context.isLight
? Colors.black
: Colors.grey,
dividerHeight: 0.4,
controller: tabBarController,
tabs: tabs),
),
if (moreWidget != null)
Flexible(
flex: 1,
child: Column(
children: [
moreWidget,
const SizedBox(height: 2),
Row(
children: [
Flexible(
child: Container(
color: context.isLight
? Colors.black
: Colors.grey,
height: 0.4),
),
],
)
],
),
)
],
),
Flexible(
child: TabBarView(
controller: tabBarController,
children: children
.map((e) => SingleChildScrollView(
child: MeasureWidgetSize(
onCalculateSize: (_) => refresh(),
child: e)))
.toList()))
]),
),
),
);
}),
child: const SizedBox.shrink()));
}
}