animated main menu

This commit is contained in:
julian 2022-11-28 13:50:55 -06:00
parent 66ff5a437d
commit 221e654dd6
2 changed files with 174 additions and 37 deletions

View file

@ -38,6 +38,9 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
static const expandedWidth = 225.0; static const expandedWidth = 225.0;
static const minimizedWidth = 72.0; static const minimizedWidth = 72.0;
final Duration duration = const Duration(milliseconds: 250);
late final List<DMIController> controllers;
double _width = expandedWidth; double _width = expandedWidth;
void updateSelectedMenuItem(DesktopMenuItemId idKey) { void updateSelectedMenuItem(DesktopMenuItemId idKey) {
@ -49,26 +52,58 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
} }
void toggleMinimize() { void toggleMinimize() {
final expanded = _width == expandedWidth;
for (var e in controllers) {
e.toggle?.call();
}
setState(() { setState(() {
_width = _width == expandedWidth ? minimizedWidth : expandedWidth; _width = expanded ? minimizedWidth : expandedWidth;
}); });
} }
@override
void initState() {
controllers = [
DMIController(),
DMIController(),
DMIController(),
DMIController(),
DMIController(),
DMIController(),
DMIController(),
DMIController(),
];
super.initState();
}
@override
void dispose() {
for (var e in controllers) {
e.dispose();
}
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Material( return Material(
color: Theme.of(context).extension<StackColors>()!.popupBG, color: Theme.of(context).extension<StackColors>()!.popupBG,
child: SizedBox( child: AnimatedContainer(
width: _width, width: _width,
duration: duration,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.center, crossAxisAlignment: CrossAxisAlignment.center,
children: [ children: [
SizedBox( const SizedBox(
height: _width == expandedWidth ? 22 : 25, height: 25,
), ),
SizedBox( AnimatedContainer(
duration: duration,
width: _width == expandedWidth ? 70 : 32, width: _width == expandedWidth ? 70 : 32,
height: _width == expandedWidth ? 70 : 32, height: 70, //_width == expandedWidth ? 70 : 32,
child: SvgPicture.asset( child: SvgPicture.asset(
Assets.svg.stackIcon(context), Assets.svg.stackIcon(context),
), ),
@ -76,18 +111,26 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
const SizedBox( const SizedBox(
height: 10, height: 10,
), ),
Text( AnimatedOpacity(
_width == expandedWidth ? "Stack Wallet" : "", duration: duration,
opacity: _width == expandedWidth ? 1 : 0,
child: SizedBox(
height: 28,
child: Text(
"Stack Wallet",
style: STextStyles.desktopH2(context).copyWith( style: STextStyles.desktopH2(context).copyWith(
fontSize: 18, fontSize: 18,
height: 23.4 / 18, height: 23.4 / 18,
), ),
), ),
),
),
const SizedBox( const SizedBox(
height: 60, height: 60,
), ),
Expanded( Expanded(
child: SizedBox( child: AnimatedContainer(
duration: duration,
width: _width == expandedWidth width: _width == expandedWidth
? _width - 32 // 16 padding on either side ? _width - 32 // 16 padding on either side
: _width - 16, // 8 padding on either side : _width - 16, // 8 padding on either side
@ -95,6 +138,7 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
DesktopMenuItem( DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset( icon: SvgPicture.asset(
Assets.svg.walletDesktop, Assets.svg.walletDesktop,
width: 20, width: 20,
@ -116,12 +160,13 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
group: group:
ref.watch(currentDesktopMenuItemProvider.state).state, ref.watch(currentDesktopMenuItemProvider.state).state,
onChanged: updateSelectedMenuItem, onChanged: updateSelectedMenuItem,
iconOnly: _width == minimizedWidth, controller: controllers[0],
), ),
const SizedBox( const SizedBox(
height: 2, height: 2,
), ),
DesktopMenuItem( DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset( icon: SvgPicture.asset(
Assets.svg.exchangeDesktop, Assets.svg.exchangeDesktop,
width: 20, width: 20,
@ -143,12 +188,13 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
group: group:
ref.watch(currentDesktopMenuItemProvider.state).state, ref.watch(currentDesktopMenuItemProvider.state).state,
onChanged: updateSelectedMenuItem, onChanged: updateSelectedMenuItem,
iconOnly: _width == minimizedWidth, controller: controllers[1],
), ),
const SizedBox( const SizedBox(
height: 2, height: 2,
), ),
DesktopMenuItem( DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset( icon: SvgPicture.asset(
ref.watch(notificationsProvider.select( ref.watch(notificationsProvider.select(
(value) => value.hasUnreadNotifications)) (value) => value.hasUnreadNotifications))
@ -177,12 +223,13 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
group: group:
ref.watch(currentDesktopMenuItemProvider.state).state, ref.watch(currentDesktopMenuItemProvider.state).state,
onChanged: updateSelectedMenuItem, onChanged: updateSelectedMenuItem,
iconOnly: _width == minimizedWidth, controller: controllers[2],
), ),
const SizedBox( const SizedBox(
height: 2, height: 2,
), ),
DesktopMenuItem( DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset( icon: SvgPicture.asset(
Assets.svg.addressBookDesktop, Assets.svg.addressBookDesktop,
width: 20, width: 20,
@ -204,12 +251,13 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
group: group:
ref.watch(currentDesktopMenuItemProvider.state).state, ref.watch(currentDesktopMenuItemProvider.state).state,
onChanged: updateSelectedMenuItem, onChanged: updateSelectedMenuItem,
iconOnly: _width == minimizedWidth, controller: controllers[3],
), ),
const SizedBox( const SizedBox(
height: 2, height: 2,
), ),
DesktopMenuItem( DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset( icon: SvgPicture.asset(
Assets.svg.gear, Assets.svg.gear,
width: 20, width: 20,
@ -231,12 +279,13 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
group: group:
ref.watch(currentDesktopMenuItemProvider.state).state, ref.watch(currentDesktopMenuItemProvider.state).state,
onChanged: updateSelectedMenuItem, onChanged: updateSelectedMenuItem,
iconOnly: _width == minimizedWidth, controller: controllers[4],
), ),
const SizedBox( const SizedBox(
height: 2, height: 2,
), ),
DesktopMenuItem( DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset( icon: SvgPicture.asset(
Assets.svg.messageQuestion, Assets.svg.messageQuestion,
width: 20, width: 20,
@ -258,12 +307,13 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
group: group:
ref.watch(currentDesktopMenuItemProvider.state).state, ref.watch(currentDesktopMenuItemProvider.state).state,
onChanged: updateSelectedMenuItem, onChanged: updateSelectedMenuItem,
iconOnly: _width == minimizedWidth, controller: controllers[5],
), ),
const SizedBox( const SizedBox(
height: 2, height: 2,
), ),
DesktopMenuItem( DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset( icon: SvgPicture.asset(
Assets.svg.aboutDesktop, Assets.svg.aboutDesktop,
width: 20, width: 20,
@ -285,10 +335,12 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
group: group:
ref.watch(currentDesktopMenuItemProvider.state).state, ref.watch(currentDesktopMenuItemProvider.state).state,
onChanged: updateSelectedMenuItem, onChanged: updateSelectedMenuItem,
iconOnly: _width == minimizedWidth, controller: controllers[6],
), ),
const Spacer(), const Spacer(),
DesktopMenuItem( DesktopMenuItem(
duration: duration,
labelLength: 123,
icon: SvgPicture.asset( icon: SvgPicture.asset(
Assets.svg.exitDesktop, Assets.svg.exitDesktop,
width: 20, width: 20,
@ -306,7 +358,7 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
// todo: save stuff/ notify before exit? // todo: save stuff/ notify before exit?
exit(0); exit(0);
}, },
iconOnly: _width == minimizedWidth, controller: controllers[7],
), ),
], ],
), ),

View file

@ -2,7 +2,14 @@ import 'package:flutter/material.dart';
import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart'; import 'package:stackwallet/utilities/theme/stack_colors.dart';
class DesktopMenuItem<T> extends StatelessWidget { class DMIController {
VoidCallback? toggle;
void dispose() {
toggle = null;
}
}
class DesktopMenuItem<T> extends StatefulWidget {
const DesktopMenuItem({ const DesktopMenuItem({
Key? key, Key? key,
required this.icon, required this.icon,
@ -10,7 +17,9 @@ class DesktopMenuItem<T> extends StatelessWidget {
required this.value, required this.value,
required this.group, required this.group,
required this.onChanged, required this.onChanged,
required this.iconOnly, required this.duration,
this.labelLength = 125,
this.controller,
}) : super(key: key); }) : super(key: key);
final Widget icon; final Widget icon;
@ -18,7 +27,67 @@ class DesktopMenuItem<T> extends StatelessWidget {
final T value; final T value;
final T group; final T group;
final void Function(T) onChanged; final void Function(T) onChanged;
final bool iconOnly; final Duration duration;
final double labelLength;
final DMIController? controller;
@override
State<DesktopMenuItem<T>> createState() => _DesktopMenuItemState<T>();
}
class _DesktopMenuItemState<T> extends State<DesktopMenuItem<T>>
with SingleTickerProviderStateMixin {
late final Widget icon;
late final String label;
late final T value;
late final T group;
late final void Function(T) onChanged;
late final Duration duration;
late final double labelLength;
late final DMIController? controller;
late final AnimationController animationController;
bool _iconOnly = false;
void toggle() {
setState(() {
_iconOnly = !_iconOnly;
});
if (_iconOnly) {
animationController.reverse();
} else {
animationController.forward();
}
}
@override
void initState() {
icon = widget.icon;
label = widget.label;
value = widget.value;
group = widget.group;
onChanged = widget.onChanged;
duration = widget.duration;
labelLength = widget.labelLength;
controller = widget.controller;
controller?.toggle = toggle;
animationController = AnimationController(
vsync: this,
duration: duration,
);
super.initState();
}
@override
void dispose() {
controller?.dispose();
animationController.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -34,20 +103,31 @@ class DesktopMenuItem<T> extends StatelessWidget {
onChanged(value); onChanged(value);
}, },
child: Padding( child: Padding(
padding: EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(
vertical: 16, vertical: 16,
horizontal: iconOnly ? 0 : 16,
), ),
child: Row( child: Row(
mainAxisAlignment: mainAxisAlignment: MainAxisAlignment.center,
iconOnly ? MainAxisAlignment.center : MainAxisAlignment.start,
children: [ children: [
AnimatedContainer(
duration: duration,
width: _iconOnly ? 0 : 16,
),
icon, icon,
if (!iconOnly) AnimatedOpacity(
duration: duration,
opacity: _iconOnly ? 0 : 1.0,
child: SizeTransition(
sizeFactor: animationController,
axis: Axis.horizontal,
axisAlignment: -1,
child: SizedBox(
width: labelLength,
child: Row(
children: [
const SizedBox( const SizedBox(
width: 12, width: 12,
), ),
if (!iconOnly)
Text( Text(
label, label,
style: value == group style: value == group
@ -57,6 +137,11 @@ class DesktopMenuItem<T> extends StatelessWidget {
], ],
), ),
), ),
),
)
],
),
),
); );
} }
} }