Babylonia-terminal/babylonia_terminal_launcher/lib/widgets/selectable_yaru_expansion_panel.dart
2024-06-03 20:14:53 +02:00

238 lines
6.7 KiB
Dart

// This file has been literally copied from https://github.com/ubuntu/yaru.dart/blob/main/lib/src/widgets/yaru_expansion_panel.dart
// and https://github.com/ubuntu/yaru.dart/blob/main/lib/src/widgets/yaru_expandable.dart
// Just want to make some change to it for specific needs instead of contributing to it, because I'm too lazy for that and I think they don't want these change
import 'package:flutter/material.dart';
import 'package:yaru/constants.dart';
import 'package:yaru/widgets.dart';
class SectionController extends ChangeNotifier {
int? selectedItem;
Function()? onChange;
SectionController({required this.selectedItem});
void updateSection(int? newSelectedItem) {
selectedItem = newSelectedItem;
notifyListeners();
if (onChange != null) {
onChange!();
}
}
}
class SelectableYaruExpansionPanel extends StatefulWidget {
const SelectableYaruExpansionPanel({
super.key,
required this.controller,
required this.children,
this.borderRadius =
const BorderRadius.all(Radius.circular(kYaruContainerRadius)),
this.border,
required this.headers,
this.width,
this.height,
this.padding,
this.margin,
this.expandIconPadding = const EdgeInsets.all(10),
this.headerPadding = const EdgeInsets.only(left: 20),
this.color,
this.placeDividers = true,
this.expandIcon,
this.shrinkWrap = true,
this.scrollPhysics = const ClampingScrollPhysics(),
this.collapseOnExpand = true,
}) : assert(headers.length == children.length);
final SectionController controller;
final List<Widget> children;
final List<Widget> headers;
final BorderRadius borderRadius;
final BoxBorder? border;
final double? width;
final double? height;
final EdgeInsetsGeometry? padding;
final EdgeInsetsGeometry? margin;
final EdgeInsetsGeometry expandIconPadding;
final EdgeInsetsGeometry headerPadding;
final Color? color;
final bool placeDividers;
final Widget? expandIcon;
final bool shrinkWrap;
final ScrollPhysics scrollPhysics;
final bool collapseOnExpand;
@override
State<SelectableYaruExpansionPanel> createState() =>
_SelectableYaruExpansionPanelState();
}
class _SelectableYaruExpansionPanelState
extends State<SelectableYaruExpansionPanel> {
late List<bool> _expandedStore;
@override
void initState() {
super.initState();
widget.controller.onChange = widget.collapseOnExpand
? () {
if (widget.controller.selectedItem != null) {
_expandedStore[widget.controller.selectedItem!];
for (var n = 0; n < _expandedStore.length; n++) {
if (_expandedStore[n]) {
setState(() => _expandedStore[n] = false);
}
}
} else {
for (var n = 0; n < _expandedStore.length; n++) {
setState(() => _expandedStore[n] = false);
}
}
}
: null;
_expandedStore =
List<bool>.generate(widget.children.length, (index) => false);
}
@override
Widget build(BuildContext context) {
assert(widget.children.length == widget.headers.length);
if (widget.controller.selectedItem != null) {
_expandedStore[widget.controller.selectedItem!] = true;
}
return YaruBorderContainer(
border: widget.border,
borderRadius: widget.borderRadius,
color: widget.color,
width: widget.width,
height: widget.height,
padding: widget.padding,
margin: widget.margin,
child: widget.placeDividers
? ListView.separated(
shrinkWrap: widget.shrinkWrap,
physics: widget.scrollPhysics,
itemCount: widget.children.length,
itemBuilder: _itemBuilder,
separatorBuilder: (context, index) {
if (index != widget.children.length - 1) {
return const Padding(
padding: EdgeInsets.symmetric(vertical: 1),
child: Divider(),
);
} else {
return const SizedBox.shrink();
}
},
)
: ListView.builder(
shrinkWrap: widget.shrinkWrap,
physics: widget.scrollPhysics,
itemCount: widget.children.length,
itemBuilder: _itemBuilder,
),
);
}
Widget? _itemBuilder(context, index) {
return YaruExpandable(
expandIconPadding: widget.expandIconPadding,
isExpanded: _expandedStore[index],
header: Padding(
padding: widget.headerPadding,
child: widget.headers[index],
),
child: widget.children[index],
);
}
}
const _kAnimationDuration = Duration(milliseconds: 250);
const _kAnimationCurve = Curves.easeInOutCubic;
class YaruExpandable extends StatefulWidget {
const YaruExpandable({
super.key,
required this.header,
this.expandIconPadding = EdgeInsets.zero,
required this.child,
this.collapsedChild,
this.gapHeight = 4.0,
this.isExpanded = false,
this.onChange,
});
final Widget header;
final EdgeInsetsGeometry expandIconPadding;
final Widget child;
final Widget? collapsedChild;
final double gapHeight;
final bool isExpanded;
final ValueChanged<bool>? onChange;
@override
State<YaruExpandable> createState() => _YaruExpandableState();
}
class _YaruExpandableState extends State<YaruExpandable> {
late bool _isExpanded;
@override
void initState() {
_isExpanded = widget.isExpanded;
super.initState();
}
@override
void didUpdateWidget(YaruExpandable oldWidget) {
super.didUpdateWidget(oldWidget);
if (oldWidget.isExpanded != widget.isExpanded) {
_isExpanded = widget.isExpanded;
}
}
@override
Widget build(BuildContext context) {
return Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
widget.header,
Padding(
padding: widget.expandIconPadding,
child: const SizedBox(
height: 36,
width: 36,
),
),
],
),
AnimatedCrossFade(
firstChild: _buildChild(widget.child),
secondChild: widget.collapsedChild != null
? _buildChild(widget.collapsedChild!)
: Container(),
crossFadeState: _isExpanded
? CrossFadeState.showFirst
: CrossFadeState.showSecond,
sizeCurve: _kAnimationCurve,
duration: _kAnimationDuration,
),
],
);
}
Widget _buildChild(Widget child) {
return Column(
children: [
SizedBox(height: widget.gapHeight),
child,
],
);
}
}