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 minimizedWidth = 72.0;
final Duration duration = const Duration(milliseconds: 250);
late final List<DMIController> controllers;
double _width = expandedWidth;
void updateSelectedMenuItem(DesktopMenuItemId idKey) {
@ -49,26 +52,58 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
}
void toggleMinimize() {
final expanded = _width == expandedWidth;
for (var e in controllers) {
e.toggle?.call();
}
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
Widget build(BuildContext context) {
return Material(
color: Theme.of(context).extension<StackColors>()!.popupBG,
child: SizedBox(
child: AnimatedContainer(
width: _width,
duration: duration,
child: Column(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
SizedBox(
height: _width == expandedWidth ? 22 : 25,
const SizedBox(
height: 25,
),
SizedBox(
AnimatedContainer(
duration: duration,
width: _width == expandedWidth ? 70 : 32,
height: _width == expandedWidth ? 70 : 32,
height: 70, //_width == expandedWidth ? 70 : 32,
child: SvgPicture.asset(
Assets.svg.stackIcon(context),
),
@ -76,18 +111,26 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
const SizedBox(
height: 10,
),
Text(
_width == expandedWidth ? "Stack Wallet" : "",
style: STextStyles.desktopH2(context).copyWith(
fontSize: 18,
height: 23.4 / 18,
AnimatedOpacity(
duration: duration,
opacity: _width == expandedWidth ? 1 : 0,
child: SizedBox(
height: 28,
child: Text(
"Stack Wallet",
style: STextStyles.desktopH2(context).copyWith(
fontSize: 18,
height: 23.4 / 18,
),
),
),
),
const SizedBox(
height: 60,
),
Expanded(
child: SizedBox(
child: AnimatedContainer(
duration: duration,
width: _width == expandedWidth
? _width - 32 // 16 padding on either side
: _width - 16, // 8 padding on either side
@ -95,6 +138,7 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset(
Assets.svg.walletDesktop,
width: 20,
@ -116,12 +160,13 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
group:
ref.watch(currentDesktopMenuItemProvider.state).state,
onChanged: updateSelectedMenuItem,
iconOnly: _width == minimizedWidth,
controller: controllers[0],
),
const SizedBox(
height: 2,
),
DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset(
Assets.svg.exchangeDesktop,
width: 20,
@ -143,12 +188,13 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
group:
ref.watch(currentDesktopMenuItemProvider.state).state,
onChanged: updateSelectedMenuItem,
iconOnly: _width == minimizedWidth,
controller: controllers[1],
),
const SizedBox(
height: 2,
),
DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset(
ref.watch(notificationsProvider.select(
(value) => value.hasUnreadNotifications))
@ -177,12 +223,13 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
group:
ref.watch(currentDesktopMenuItemProvider.state).state,
onChanged: updateSelectedMenuItem,
iconOnly: _width == minimizedWidth,
controller: controllers[2],
),
const SizedBox(
height: 2,
),
DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset(
Assets.svg.addressBookDesktop,
width: 20,
@ -204,12 +251,13 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
group:
ref.watch(currentDesktopMenuItemProvider.state).state,
onChanged: updateSelectedMenuItem,
iconOnly: _width == minimizedWidth,
controller: controllers[3],
),
const SizedBox(
height: 2,
),
DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset(
Assets.svg.gear,
width: 20,
@ -231,12 +279,13 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
group:
ref.watch(currentDesktopMenuItemProvider.state).state,
onChanged: updateSelectedMenuItem,
iconOnly: _width == minimizedWidth,
controller: controllers[4],
),
const SizedBox(
height: 2,
),
DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset(
Assets.svg.messageQuestion,
width: 20,
@ -258,12 +307,13 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
group:
ref.watch(currentDesktopMenuItemProvider.state).state,
onChanged: updateSelectedMenuItem,
iconOnly: _width == minimizedWidth,
controller: controllers[5],
),
const SizedBox(
height: 2,
),
DesktopMenuItem(
duration: duration,
icon: SvgPicture.asset(
Assets.svg.aboutDesktop,
width: 20,
@ -285,10 +335,12 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
group:
ref.watch(currentDesktopMenuItemProvider.state).state,
onChanged: updateSelectedMenuItem,
iconOnly: _width == minimizedWidth,
controller: controllers[6],
),
const Spacer(),
DesktopMenuItem(
duration: duration,
labelLength: 123,
icon: SvgPicture.asset(
Assets.svg.exitDesktop,
width: 20,
@ -306,7 +358,7 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
// todo: save stuff/ notify before exit?
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/theme/stack_colors.dart';
class DesktopMenuItem<T> extends StatelessWidget {
class DMIController {
VoidCallback? toggle;
void dispose() {
toggle = null;
}
}
class DesktopMenuItem<T> extends StatefulWidget {
const DesktopMenuItem({
Key? key,
required this.icon,
@ -10,7 +17,9 @@ class DesktopMenuItem<T> extends StatelessWidget {
required this.value,
required this.group,
required this.onChanged,
required this.iconOnly,
required this.duration,
this.labelLength = 125,
this.controller,
}) : super(key: key);
final Widget icon;
@ -18,7 +27,67 @@ class DesktopMenuItem<T> extends StatelessWidget {
final T value;
final T group;
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
Widget build(BuildContext context) {
@ -34,26 +103,42 @@ class DesktopMenuItem<T> extends StatelessWidget {
onChanged(value);
},
child: Padding(
padding: EdgeInsets.symmetric(
padding: const EdgeInsets.symmetric(
vertical: 16,
horizontal: iconOnly ? 0 : 16,
),
child: Row(
mainAxisAlignment:
iconOnly ? MainAxisAlignment.center : MainAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.center,
children: [
AnimatedContainer(
duration: duration,
width: _iconOnly ? 0 : 16,
),
icon,
if (!iconOnly)
const SizedBox(
width: 12,
),
if (!iconOnly)
Text(
label,
style: value == group
? STextStyles.desktopMenuItemSelected(context)
: STextStyles.desktopMenuItem(context),
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(
width: 12,
),
Text(
label,
style: value == group
? STextStyles.desktopMenuItemSelected(context)
: STextStyles.desktopMenuItem(context),
),
],
),
),
),
)
],
),
),