diff --git a/lib/consts.dart b/lib/consts.dart index e4775069..6a840fe2 100644 --- a/lib/consts.dart +++ b/lib/consts.dart @@ -172,6 +172,7 @@ const kPb15 = EdgeInsets.only( const kPb70 = EdgeInsets.only( bottom: 70, ); +const kSizedBoxEmpty = SizedBox(); const kHSpacer2 = SizedBox(width: 2); const kHSpacer4 = SizedBox(width: 4); const kHSpacer5 = SizedBox(width: 5); diff --git a/lib/screens/envvar/environments_pane.dart b/lib/screens/envvar/environments_pane.dart index 34d58e4b..48f2eed4 100644 --- a/lib/screens/envvar/environments_pane.dart +++ b/lib/screens/envvar/environments_pane.dart @@ -193,6 +193,9 @@ class EnvironmentItem extends ConsumerWidget { ref.read(selectedEnvironmentIdStateProvider.notifier).state = id; kEnvScaffoldKey.currentState?.closeDrawer(); }, + onSecondaryTap: () { + ref.read(selectedEnvironmentIdStateProvider.notifier).state = id; + }, focusNode: ref.watch(nameTextFieldFocusNodeProvider), onChangedNameEditor: (value) { value = value.trim(); diff --git a/lib/screens/home_page/collection_pane.dart b/lib/screens/home_page/collection_pane.dart index b30eded2..7d31ce63 100644 --- a/lib/screens/home_page/collection_pane.dart +++ b/lib/screens/home_page/collection_pane.dart @@ -223,6 +223,9 @@ class RequestItem extends ConsumerWidget { ref.read(selectedIdStateProvider.notifier).state = id; kHomeScaffoldKey.currentState?.closeDrawer(); }, + onSecondaryTap: () { + ref.read(selectedIdStateProvider.notifier).state = id; + }, // onDoubleTap: () { // ref.read(selectedIdStateProvider.notifier).state = id; // ref.read(selectedIdEditStateProvider.notifier).state = id; diff --git a/lib/widgets/card_sidebar_environment.dart b/lib/widgets/card_sidebar_environment.dart index 48f153ed..69426df0 100644 --- a/lib/widgets/card_sidebar_environment.dart +++ b/lib/widgets/card_sidebar_environment.dart @@ -69,7 +69,13 @@ class SidebarEnvironmentCard extends StatelessWidget { hoverColor: colorVariant, focusColor: colorVariant.withOpacity(0.5), onTap: inEditMode ? null : onTap, - onSecondaryTap: onSecondaryTap, + // onSecondaryTap: onSecondaryTap, + onSecondaryTapUp: (isGlobal) + ? null + : (details) { + onSecondaryTap?.call(); + showItemCardMenu(context, details, onMenuSelected); + }, child: Padding( padding: EdgeInsets.only( left: 6, @@ -90,6 +96,7 @@ class SidebarEnvironmentCard extends StatelessWidget { focusNode: focusNode, style: Theme.of(context).textTheme.bodyMedium, onTapOutside: (_) { + FocusScope.of(context).unfocus(); onTapOutsideNameEditor?.call(); }, onFieldSubmitted: (value) { diff --git a/lib/widgets/card_sidebar_request.dart b/lib/widgets/card_sidebar_request.dart index ab8a4706..27cbabf6 100644 --- a/lib/widgets/card_sidebar_request.dart +++ b/lib/widgets/card_sidebar_request.dart @@ -71,7 +71,10 @@ class SidebarRequestCard extends StatelessWidget { focusColor: colorVariant.withOpacity(0.5), onTap: inEditMode ? null : onTap, // onDoubleTap: inEditMode ? null : onDoubleTap, - onSecondaryTap: onSecondaryTap, + onSecondaryTapUp: (details) { + onSecondaryTap?.call(); + showItemCardMenu(context, details, onMenuSelected); + }, child: Padding( padding: EdgeInsets.only( left: 6, @@ -95,8 +98,8 @@ class SidebarRequestCard extends StatelessWidget { //autofocus: true, style: Theme.of(context).textTheme.bodyMedium, onTapOutside: (_) { + FocusScope.of(context).unfocus(); onTapOutsideNameEditor?.call(); - //FocusScope.of(context).unfocus(); }, onFieldSubmitted: (value) { onTapOutsideNameEditor?.call(); diff --git a/lib/widgets/menu_item_card.dart b/lib/widgets/menu_item_card.dart index 5aa9fadb..e31a68b4 100644 --- a/lib/widgets/menu_item_card.dart +++ b/lib/widgets/menu_item_card.dart @@ -41,3 +41,29 @@ class ItemCardMenu extends StatelessWidget { ); } } + +/// Open the item card menu where the right click has been released +Future showItemCardMenu( + BuildContext context, + TapUpDetails details, + Function(ItemMenuOption)? onSelected, +) async { + showMenu( + context: context, + position: RelativeRect.fromLTRB( + details.globalPosition.dx, + details.globalPosition.dy, + details.globalPosition.dx, + details.globalPosition.dy, + ), + items: ItemMenuOption.values + .map>( + (e) => PopupMenuItem( + onTap: () => onSelected?.call(e), + value: e, + child: Text(e.label), + ), + ) + .toList(), + ); +} diff --git a/test/providers/ui_providers_test.dart b/test/providers/ui_providers_test.dart index e8fd0582..ff2102a6 100644 --- a/test/providers/ui_providers_test.dart +++ b/test/providers/ui_providers_test.dart @@ -13,6 +13,7 @@ import 'package:apidash/screens/settings_page.dart'; import 'package:apidash/screens/history/history_page.dart'; import 'package:apidash/widgets/widgets.dart'; import 'package:extended_text_field/extended_text_field.dart'; +import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_portal/flutter_portal.dart'; @@ -279,7 +280,7 @@ void main() { }); testWidgets( - 'selectedIdEditStateProvider should not be null after rename button has been tapped', + 'selectedIdEditStateProvider should not be null after Duplicate button has been tapped', (tester) async { await tester.pumpWidget( ProviderScope( @@ -304,7 +305,11 @@ void main() { await tester.pump(); await tester.tap(find.byType(RequestItem)); await tester.pump(); - await tester.tap(find.byIcon(Icons.more_vert).at(1)); + //await tester.tap(find.byIcon(Icons.more_vert).at(1)); + await tester.tap( + find.byType(RequestItem), + buttons: kSecondaryButton, + ); await tester.pumpAndSettle(); // Tap on the "Duplicate" option in the menu diff --git a/test/widgets/menu_item_card_test.dart b/test/widgets/menu_item_card_test.dart index 52cbcabf..d223eeb6 100644 --- a/test/widgets/menu_item_card_test.dart +++ b/test/widgets/menu_item_card_test.dart @@ -49,4 +49,32 @@ void main() { expect(changedValue, ItemMenuOption.duplicate); }); + + testWidgets('showItemCardMenu shows the menu at the right position', + (WidgetTester tester) async { + await tester.pumpWidget( + MaterialApp( + home: Scaffold( + body: Builder( + builder: (BuildContext context) { + return GestureDetector( + onTapUp: (details) { + showItemCardMenu( + context, details, (ItemMenuOption option) {}); + }, + child: const Text('Show Menu'), + ); + }, + ), + ), + ), + ); + + await tester.tap(find.text('Show Menu')); + await tester.pumpAndSettle(); + + for (var option in ItemMenuOption.values) { + expect(find.text(option.label), findsOneWidget); + } + }); }