mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-11-05 20:07:44 +00:00
183 lines
5.1 KiB
Dart
183 lines
5.1 KiB
Dart
|
import 'package:flutter/material.dart';
|
||
|
import 'package:stackwallet/utilities/constants.dart';
|
||
|
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||
|
|
||
|
enum Expandable2State {
|
||
|
collapsed,
|
||
|
expanded,
|
||
|
}
|
||
|
|
||
|
class Expandable2Controller {
|
||
|
VoidCallback? toggle;
|
||
|
Expandable2State state = Expandable2State.collapsed;
|
||
|
}
|
||
|
|
||
|
class Expandable2 extends StatefulWidget {
|
||
|
const Expandable2({
|
||
|
Key? key,
|
||
|
required this.header,
|
||
|
required this.children,
|
||
|
this.background = Colors.white,
|
||
|
this.border = Colors.black,
|
||
|
this.animationController,
|
||
|
this.animation,
|
||
|
this.animationDurationMultiplier = 1.0,
|
||
|
this.onExpandWillChange,
|
||
|
this.onExpandChanged,
|
||
|
this.controller,
|
||
|
this.expandOverride,
|
||
|
}) : super(key: key);
|
||
|
|
||
|
final Widget header;
|
||
|
final List<Widget> children;
|
||
|
final Color background;
|
||
|
final Color border;
|
||
|
final AnimationController? animationController;
|
||
|
final Animation<double>? animation;
|
||
|
final double animationDurationMultiplier;
|
||
|
final void Function(Expandable2State)? onExpandWillChange;
|
||
|
final void Function(Expandable2State)? onExpandChanged;
|
||
|
final Expandable2Controller? controller;
|
||
|
final VoidCallback? expandOverride;
|
||
|
|
||
|
@override
|
||
|
State<Expandable2> createState() => _Expandable2State();
|
||
|
}
|
||
|
|
||
|
class _Expandable2State extends State<Expandable2>
|
||
|
with TickerProviderStateMixin {
|
||
|
final _key = GlobalKey();
|
||
|
|
||
|
late final AnimationController animationController;
|
||
|
late final Animation<double> animation;
|
||
|
late final Duration duration;
|
||
|
late final Expandable2Controller? controller;
|
||
|
|
||
|
Expandable2State _toggleState = Expandable2State.collapsed;
|
||
|
|
||
|
void toggle() {
|
||
|
if (animation.isDismissed) {
|
||
|
_toggleState = Expandable2State.expanded;
|
||
|
widget.onExpandWillChange?.call(_toggleState);
|
||
|
animationController
|
||
|
.forward()
|
||
|
.then((_) => widget.onExpandChanged?.call(_toggleState));
|
||
|
} else if (animation.isCompleted) {
|
||
|
_toggleState = Expandable2State.collapsed;
|
||
|
widget.onExpandWillChange?.call(_toggleState);
|
||
|
animationController
|
||
|
.reverse()
|
||
|
.then((_) => widget.onExpandChanged?.call(_toggleState));
|
||
|
}
|
||
|
controller?.state = _toggleState;
|
||
|
setState(() {});
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
void initState() {
|
||
|
controller = widget.controller;
|
||
|
controller?.toggle = toggle;
|
||
|
|
||
|
duration = Duration(
|
||
|
milliseconds: (500 * widget.animationDurationMultiplier).toInt(),
|
||
|
);
|
||
|
animationController = widget.animationController ??
|
||
|
AnimationController(
|
||
|
vsync: this,
|
||
|
duration: duration,
|
||
|
);
|
||
|
animation = widget.animation ??
|
||
|
Tween<double>(begin: 0.0, end: 1.0).animate(
|
||
|
CurvedAnimation(
|
||
|
curve: Curves.easeInOut,
|
||
|
parent: animationController,
|
||
|
),
|
||
|
);
|
||
|
super.initState();
|
||
|
}
|
||
|
|
||
|
double _top = 0;
|
||
|
|
||
|
void getHeaderHeight() {
|
||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||
|
if (_key.currentContext?.size?.height != null &&
|
||
|
_top != _key.currentContext!.size!.height) {
|
||
|
setState(() {
|
||
|
_top = _key.currentContext!.size!.height;
|
||
|
});
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
void dispose() {
|
||
|
animationController.dispose();
|
||
|
super.dispose();
|
||
|
}
|
||
|
|
||
|
@override
|
||
|
Widget build(BuildContext context) {
|
||
|
getHeaderHeight();
|
||
|
|
||
|
return AnimatedContainer(
|
||
|
duration: duration,
|
||
|
decoration: _toggleState == Expandable2State.expanded
|
||
|
? BoxDecoration(
|
||
|
color: widget.background,
|
||
|
borderRadius: BorderRadius.circular(
|
||
|
Constants.size.circularBorderRadius,
|
||
|
),
|
||
|
border: Border.all(color: widget.border),
|
||
|
boxShadow: [
|
||
|
Theme.of(context).extension<StackColors>()!.standardBoxShadow,
|
||
|
],
|
||
|
)
|
||
|
: BoxDecoration(
|
||
|
color: widget.background,
|
||
|
borderRadius: BorderRadius.circular(
|
||
|
Constants.size.circularBorderRadius,
|
||
|
),
|
||
|
border: Border.all(color: widget.border),
|
||
|
),
|
||
|
child: Stack(
|
||
|
children: [
|
||
|
Padding(
|
||
|
padding: EdgeInsets.only(top: _top),
|
||
|
child: SizeTransition(
|
||
|
sizeFactor: animation,
|
||
|
axisAlignment: 1.0,
|
||
|
child: Column(
|
||
|
children: widget.children
|
||
|
.map(
|
||
|
(e) => Column(
|
||
|
children: [
|
||
|
Container(
|
||
|
height: 1,
|
||
|
width: double.infinity,
|
||
|
color: widget.border,
|
||
|
),
|
||
|
e,
|
||
|
],
|
||
|
),
|
||
|
)
|
||
|
.toList(),
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
MouseRegion(
|
||
|
key: _key,
|
||
|
cursor: SystemMouseCursors.click,
|
||
|
child: GestureDetector(
|
||
|
onTap: widget.expandOverride ?? toggle,
|
||
|
child: Container(
|
||
|
color: Colors.transparent,
|
||
|
child: widget.header,
|
||
|
),
|
||
|
),
|
||
|
),
|
||
|
],
|
||
|
),
|
||
|
);
|
||
|
}
|
||
|
}
|