viewer: expand one submenu at once

This commit is contained in:
Thibault Deckers 2022-06-18 15:42:23 +09:00
parent 9bced31927
commit 1f3a81e243
3 changed files with 52 additions and 35 deletions

View file

@ -284,6 +284,7 @@ class _CollectionAppBarState extends State<CollectionAppBar> with SingleTickerPr
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
child: PopupMenuItemExpansionPanel<EntrySetAction>( child: PopupMenuItemExpansionPanel<EntrySetAction>(
enabled: canApplyEditActions, enabled: canApplyEditActions,
value: 'edit',
icon: AIcons.edit, icon: AIcons.edit,
title: context.l10n.collectionActionEdit, title: context.l10n.collectionActionEdit,
items: [ items: [

View file

@ -55,25 +55,27 @@ class MenuIconTheme extends StatelessWidget {
class PopupMenuItemExpansionPanel<T> extends StatefulWidget { class PopupMenuItemExpansionPanel<T> extends StatefulWidget {
final bool enabled; final bool enabled;
final String value;
final ValueNotifier<String?> expandedNotifier;
final IconData icon; final IconData icon;
final String title; final String title;
final List<PopupMenuEntry<T>> items; final List<PopupMenuEntry<T>> items;
const PopupMenuItemExpansionPanel({ PopupMenuItemExpansionPanel({
super.key, super.key,
this.enabled = true, this.enabled = true,
required this.value,
ValueNotifier<String?>? expandedNotifier,
required this.icon, required this.icon,
required this.title, required this.title,
required this.items, required this.items,
}); }) : expandedNotifier = expandedNotifier ?? ValueNotifier(null);
@override @override
State<PopupMenuItemExpansionPanel<T>> createState() => _PopupMenuItemExpansionPanelState<T>(); State<PopupMenuItemExpansionPanel<T>> createState() => _PopupMenuItemExpansionPanelState<T>();
} }
class _PopupMenuItemExpansionPanelState<T> extends State<PopupMenuItemExpansionPanel<T>> { class _PopupMenuItemExpansionPanelState<T> extends State<PopupMenuItemExpansionPanel<T>> {
bool _isExpanded = false;
// ref `_kMenuHorizontalPadding` used in `PopupMenuItem` // ref `_kMenuHorizontalPadding` used in `PopupMenuItem`
static const double _horizontalPadding = 16; static const double _horizontalPadding = 16;
@ -86,9 +88,12 @@ class _PopupMenuItemExpansionPanelState<T> extends State<PopupMenuItemExpansionP
} }
final animationDuration = context.select<DurationsData, Duration>((v) => v.expansionTileAnimation); final animationDuration = context.select<DurationsData, Duration>((v) => v.expansionTileAnimation);
Widget child = ExpansionPanelList( Widget child = ValueListenableBuilder<String?>(
valueListenable: widget.expandedNotifier,
builder: (context, expandedValue, child) {
return ExpansionPanelList(
expansionCallback: (index, isExpanded) { expansionCallback: (index, isExpanded) {
setState(() => _isExpanded = !isExpanded); widget.expandedNotifier.value = isExpanded ? null : widget.value;
}, },
animationDuration: animationDuration, animationDuration: animationDuration,
expandedHeaderPadding: EdgeInsets.zero, expandedHeaderPadding: EdgeInsets.zero,
@ -113,12 +118,14 @@ class _PopupMenuItemExpansionPanelState<T> extends State<PopupMenuItemExpansionP
const PopupMenuDivider(height: 0), const PopupMenuDivider(height: 0),
], ],
), ),
isExpanded: _isExpanded, isExpanded: expandedValue == widget.value,
canTapOnHeader: true, canTapOnHeader: true,
backgroundColor: Colors.transparent, backgroundColor: Colors.transparent,
), ),
], ],
); );
},
);
if (!widget.enabled) { if (!widget.enabled) {
child = IgnorePointer(child: child); child = IgnorePointer(child: child);
} }

View file

@ -142,12 +142,13 @@ class ViewerButtonRowContent extends StatelessWidget {
final List<EntryAction> quickActions, topLevelActions, exportActions, videoActions; final List<EntryAction> quickActions, topLevelActions, exportActions, videoActions;
final Animation<double> scale; final Animation<double> scale;
final AvesEntry mainEntry, pageEntry; final AvesEntry mainEntry, pageEntry;
final ValueNotifier<String?> _popupExpandedNotifier = ValueNotifier(null);
AvesEntry get favouriteTargetEntry => mainEntry.isBurst ? pageEntry : mainEntry; AvesEntry get favouriteTargetEntry => mainEntry.isBurst ? pageEntry : mainEntry;
static const double padding = 8; static const double padding = 8;
const ViewerButtonRowContent({ ViewerButtonRowContent({
super.key, super.key,
required this.quickActions, required this.quickActions,
required this.topLevelActions, required this.topLevelActions,
@ -188,6 +189,8 @@ class ViewerButtonRowContent extends StatelessWidget {
PopupMenuItem<EntryAction>( PopupMenuItem<EntryAction>(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
child: PopupMenuItemExpansionPanel<EntryAction>( child: PopupMenuItemExpansionPanel<EntryAction>(
value: 'export',
expandedNotifier: _popupExpandedNotifier,
icon: AIcons.export, icon: AIcons.export,
title: context.l10n.entryActionExport, title: context.l10n.entryActionExport,
items: [ items: [
@ -201,6 +204,8 @@ class ViewerButtonRowContent extends StatelessWidget {
PopupMenuItem<EntryAction>( PopupMenuItem<EntryAction>(
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
child: PopupMenuItemExpansionPanel<EntryAction>( child: PopupMenuItemExpansionPanel<EntryAction>(
value: 'video',
expandedNotifier: _popupExpandedNotifier,
icon: AIcons.video, icon: AIcons.video,
title: context.l10n.settingsSectionVideo, title: context.l10n.settingsSectionVideo,
items: [ items: [
@ -215,9 +220,13 @@ class ViewerButtonRowContent extends StatelessWidget {
]; ];
}, },
onSelected: (action) { onSelected: (action) {
_popupExpandedNotifier.value = null;
// wait for the popup menu to hide before proceeding with the action // wait for the popup menu to hide before proceeding with the action
Future.delayed(Durations.popupMenuAnimation * timeDilation, () => _onActionSelected(context, action)); Future.delayed(Durations.popupMenuAnimation * timeDilation, () => _onActionSelected(context, action));
}, },
onCanceled: () {
_popupExpandedNotifier.value = null;
},
onMenuOpened: () { onMenuOpened: () {
// if the menu is opened while overlay is hiding, // if the menu is opened while overlay is hiding,
// the popup menu button is disposed and menu items are ineffective, // the popup menu button is disposed and menu items are ineffective,