diff --git a/auth/lib/ui/code_widget.dart b/auth/lib/ui/code_widget.dart index 0a74ad1ce..c579def12 100644 --- a/auth/lib/ui/code_widget.dart +++ b/auth/lib/ui/code_widget.dart @@ -17,8 +17,8 @@ import 'package:ente_auth/utils/dialog_util.dart'; import 'package:ente_auth/utils/platform_util.dart'; import 'package:ente_auth/utils/toast_util.dart'; import 'package:ente_auth/utils/totp_util.dart'; -import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_context_menu/flutter_context_menu.dart'; import 'package:flutter_slidable/flutter_slidable.dart'; import 'package:logging/logging.dart'; import 'package:move_to_background/move_to_background.dart'; @@ -86,108 +86,122 @@ class _CodeWidgetState extends State { final l10n = context.l10n; return Container( margin: const EdgeInsets.only(left: 16, right: 16, bottom: 8, top: 8), - child: Slidable( - key: ValueKey(widget.code.hashCode), - endActionPane: ActionPane( - extentRatio: 0.60, - motion: const ScrollMotion(), - children: [ - const SizedBox( - width: 4, - ), - SlidableAction( - onPressed: _onShowQrPressed, - backgroundColor: Colors.grey.withOpacity(0.1), - borderRadius: const BorderRadius.all(Radius.circular(12.0)), - foregroundColor: - Theme.of(context).colorScheme.inverseBackgroundColor, - icon: Icons.qr_code_2_outlined, - label: "QR", - padding: const EdgeInsets.only(left: 4, right: 0), - spacing: 8, - ), - const SizedBox( - width: 4, - ), - SlidableAction( - onPressed: _onEditPressed, - backgroundColor: Colors.grey.withOpacity(0.1), - borderRadius: const BorderRadius.all(Radius.circular(12.0)), - foregroundColor: - Theme.of(context).colorScheme.inverseBackgroundColor, - icon: Icons.edit_outlined, - label: l10n.edit, - padding: const EdgeInsets.only(left: 4, right: 0), - spacing: 8, - ), - const SizedBox( - width: 4, - ), - SlidableAction( - onPressed: _onDeletePressed, - backgroundColor: Colors.grey.withOpacity(0.1), - borderRadius: const BorderRadius.all(Radius.circular(12.0)), - foregroundColor: const Color(0xFFFE4A49), - icon: Icons.delete, - label: l10n.delete, - padding: const EdgeInsets.only(left: 0, right: 0), - spacing: 8, - ), - ], - ), - child: Builder( - builder: (context) { - return RawGestureDetector( - gestures: { - PanGestureRecognizer: - GestureRecognizerFactoryWithHandlers( - () => PanGestureRecognizer( - debugOwner: this, - // This recognizer accepts any button press made with a secondary button. - allowedButtonsFilter: (int buttons) => - buttons & kSecondaryButton != 0, + child: Builder( + builder: (context) { + if (PlatformUtil.isDesktop()) { + return ContextMenuRegion( + contextMenu: ContextMenu( + entries: [ + MenuItem( + label: 'QR', + icon: Icons.qr_code_2_outlined, + onSelected: () => _onShowQrPressed(null), ), - (PanGestureRecognizer instance) { - instance - ..dragStartBehavior = DragStartBehavior.down - ..onEnd = (DragEndDetails details) { - Slidable.of(context)?.openEndActionPane(); - }; - }, - ), - }, - child: ClipRRect( - borderRadius: BorderRadius.circular(8), - child: Container( - color: Theme.of(context).colorScheme.codeCardBackgroundColor, - child: Material( - color: Colors.transparent, - child: InkWell( - customBorder: RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), - ), - onTap: () { - _copyCurrentOTPToClipboard(); - }, - onDoubleTap: isMaskingEnabled - ? () { - setState( - () { - _hideCode = !_hideCode; - }, - ); - } - : null, - onLongPress: () { - _copyCurrentOTPToClipboard(); - }, - child: _getCardContents(l10n), - ), + MenuItem( + label: 'Edit', + icon: Icons.edit, + onSelected: () => _onEditPressed(null), ), - ), + const MenuDivider(), + MenuItem( + label: 'Delete', + value: "Delete", + icon: Icons.delete, + onSelected: () => _onDeletePressed(null), + ), + ], + padding: const EdgeInsets.all(8.0), ), + child: _clippedCard(l10n), ); - }, + } + + return Slidable( + key: ValueKey(widget.code.hashCode), + endActionPane: ActionPane( + extentRatio: 0.60, + motion: const ScrollMotion(), + children: [ + const SizedBox( + width: 4, + ), + SlidableAction( + onPressed: _onShowQrPressed, + backgroundColor: Colors.grey.withOpacity(0.1), + borderRadius: const BorderRadius.all(Radius.circular(12.0)), + foregroundColor: + Theme.of(context).colorScheme.inverseBackgroundColor, + icon: Icons.qr_code_2_outlined, + label: "QR", + padding: const EdgeInsets.only(left: 4, right: 0), + spacing: 8, + ), + const SizedBox( + width: 4, + ), + SlidableAction( + onPressed: _onEditPressed, + backgroundColor: Colors.grey.withOpacity(0.1), + borderRadius: const BorderRadius.all(Radius.circular(12.0)), + foregroundColor: + Theme.of(context).colorScheme.inverseBackgroundColor, + icon: Icons.edit_outlined, + label: l10n.edit, + padding: const EdgeInsets.only(left: 4, right: 0), + spacing: 8, + ), + const SizedBox( + width: 4, + ), + SlidableAction( + onPressed: _onDeletePressed, + backgroundColor: Colors.grey.withOpacity(0.1), + borderRadius: const BorderRadius.all(Radius.circular(12.0)), + foregroundColor: const Color(0xFFFE4A49), + icon: Icons.delete, + label: l10n.delete, + padding: const EdgeInsets.only(left: 0, right: 0), + spacing: 8, + ), + ], + ), + child: Builder( + builder: (context) => _clippedCard(l10n), + ), + ); + }, + ), + ); + } + + Widget _clippedCard(AppLocalizations l10n) { + return ClipRRect( + borderRadius: BorderRadius.circular(8), + child: Container( + color: Theme.of(context).colorScheme.codeCardBackgroundColor, + child: Material( + color: Colors.transparent, + child: InkWell( + customBorder: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + onTap: () { + _copyCurrentOTPToClipboard(); + }, + onDoubleTap: isMaskingEnabled + ? () { + setState( + () { + _hideCode = !_hideCode; + }, + ); + } + : null, + onLongPress: () { + _copyCurrentOTPToClipboard(); + }, + child: _getCardContents(l10n), + ), ), ), ); diff --git a/auth/pubspec.lock b/auth/pubspec.lock index df8506d8e..35dd96356 100644 --- a/auth/pubspec.lock +++ b/auth/pubspec.lock @@ -347,6 +347,14 @@ packages: url: "https://github.com/ente-io/ente_crypto_dart.git" source: git version: "1.0.0" + equatable: + dependency: transitive + description: + name: equatable + sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2 + url: "https://pub.dev" + source: hosted + version: "2.0.5" event_bus: dependency: "direct main" description: @@ -440,6 +448,14 @@ packages: url: "https://pub.dev" source: hosted version: "8.1.5" + flutter_context_menu: + dependency: "direct main" + description: + name: flutter_context_menu + sha256: "9f220a8fa0290c68e38000d6d62a0dc4555d490c15a5bd856a6e6d255d81b8dc" + url: "https://pub.dev" + source: hosted + version: "0.1.3" flutter_displaymode: dependency: "direct main" description: diff --git a/auth/pubspec.yaml b/auth/pubspec.yaml index 5f0cdb1d5..c1f0e4806 100644 --- a/auth/pubspec.yaml +++ b/auth/pubspec.yaml @@ -41,6 +41,7 @@ dependencies: flutter: sdk: flutter flutter_bloc: ^8.0.1 + flutter_context_menu: ^0.1.3 flutter_displaymode: ^0.6.0 flutter_email_sender: ^6.0.2 flutter_inappwebview: ^6.0.0