mirror of
https://github.com/ente-io/ente.git
synced 2025-08-08 23:39:30 +00:00
fix: use context menu on desktop
This commit is contained in:
parent
056e29a5f5
commit
f8fbedfe10
@ -18,8 +18,8 @@ import 'package:ente_auth/utils/dialog_util.dart';
|
|||||||
import 'package:ente_auth/utils/platform_util.dart';
|
import 'package:ente_auth/utils/platform_util.dart';
|
||||||
import 'package:ente_auth/utils/toast_util.dart';
|
import 'package:ente_auth/utils/toast_util.dart';
|
||||||
import 'package:ente_auth/utils/totp_util.dart';
|
import 'package:ente_auth/utils/totp_util.dart';
|
||||||
import 'package:flutter/gestures.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_context_menu/flutter_context_menu.dart';
|
||||||
import 'package:flutter_slidable/flutter_slidable.dart';
|
import 'package:flutter_slidable/flutter_slidable.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
import 'package:move_to_background/move_to_background.dart';
|
import 'package:move_to_background/move_to_background.dart';
|
||||||
@ -87,106 +87,121 @@ class _CodeWidgetState extends State<CodeWidget> {
|
|||||||
final l10n = context.l10n;
|
final l10n = context.l10n;
|
||||||
return Container(
|
return Container(
|
||||||
margin: const EdgeInsets.only(left: 16, right: 16, bottom: 8, top: 8),
|
margin: const EdgeInsets.only(left: 16, right: 16, bottom: 8, top: 8),
|
||||||
child: Slidable(
|
child: Builder(
|
||||||
enabled: PlatformUtil.isMobile(),
|
builder: (context) {
|
||||||
key: ValueKey(widget.code.hashCode),
|
if (PlatformUtil.isDesktop()) {
|
||||||
endActionPane: ActionPane(
|
return ContextMenuRegion(
|
||||||
extentRatio: 0.60,
|
contextMenu: ContextMenu(
|
||||||
motion: const ScrollMotion(),
|
entries: <ContextMenuEntry>[
|
||||||
children: [
|
MenuItem(
|
||||||
const SizedBox(
|
label: 'QR',
|
||||||
width: 4,
|
icon: Icons.qr_code,
|
||||||
),
|
onSelected: () => _onShowQrPressed(null),
|
||||||
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) => RawGestureDetector(
|
|
||||||
gestures: {
|
|
||||||
PanGestureRecognizer:
|
|
||||||
GestureRecognizerFactoryWithHandlers<PanGestureRecognizer>(
|
|
||||||
() => PanGestureRecognizer(
|
|
||||||
debugOwner: this,
|
|
||||||
// This recognizer accepts any button press made with a secondary button.
|
|
||||||
allowedButtonsFilter: (int buttons) =>
|
|
||||||
buttons & kSecondaryButton != 0,
|
|
||||||
),
|
|
||||||
(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),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -223,50 +238,6 @@ class _CodeWidgetState extends State<CodeWidget> {
|
|||||||
const SizedBox(
|
const SizedBox(
|
||||||
height: 20,
|
height: 20,
|
||||||
),
|
),
|
||||||
if (PlatformUtil.isDesktop())
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.end,
|
|
||||||
children: [
|
|
||||||
SlideAction(
|
|
||||||
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,
|
|
||||||
),
|
|
||||||
SlideAction(
|
|
||||||
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,
|
|
||||||
),
|
|
||||||
SlideAction(
|
|
||||||
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,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -529,57 +500,3 @@ class _CodeWidgetState extends State<CodeWidget> {
|
|||||||
return code;
|
return code;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SlideAction extends StatelessWidget {
|
|
||||||
const SlideAction({
|
|
||||||
super.key,
|
|
||||||
required this.onPressed,
|
|
||||||
required this.backgroundColor,
|
|
||||||
required this.borderRadius,
|
|
||||||
required this.foregroundColor,
|
|
||||||
required this.icon,
|
|
||||||
required this.label,
|
|
||||||
required this.padding,
|
|
||||||
required this.spacing,
|
|
||||||
});
|
|
||||||
|
|
||||||
final void Function(dynamic) onPressed;
|
|
||||||
final Color backgroundColor;
|
|
||||||
final BorderRadius borderRadius;
|
|
||||||
final Color foregroundColor;
|
|
||||||
final IconData icon;
|
|
||||||
final String label;
|
|
||||||
final EdgeInsets padding;
|
|
||||||
final double spacing;
|
|
||||||
|
|
||||||
@override
|
|
||||||
Widget build(BuildContext context) {
|
|
||||||
return InkWell(
|
|
||||||
onTap: () => onPressed(0),
|
|
||||||
child: Container(
|
|
||||||
color: backgroundColor,
|
|
||||||
height: 52,
|
|
||||||
width: 52,
|
|
||||||
child: Column(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Icon(
|
|
||||||
icon,
|
|
||||||
size: 16,
|
|
||||||
color: foregroundColor,
|
|
||||||
),
|
|
||||||
const SizedBox(
|
|
||||||
height: 4,
|
|
||||||
),
|
|
||||||
Text(
|
|
||||||
label,
|
|
||||||
style: Theme.of(context).textTheme.bodySmall?.copyWith(
|
|
||||||
color: foregroundColor,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -347,6 +347,14 @@ packages:
|
|||||||
url: "https://github.com/ente-io/ente_crypto_dart.git"
|
url: "https://github.com/ente-io/ente_crypto_dart.git"
|
||||||
source: git
|
source: git
|
||||||
version: "1.0.0"
|
version: "1.0.0"
|
||||||
|
equatable:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: equatable
|
||||||
|
sha256: c2b87cb7756efdf69892005af546c56c0b5037f54d2a88269b4f347a505e3ca2
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "2.0.5"
|
||||||
event_bus:
|
event_bus:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
@ -440,6 +448,14 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "8.1.5"
|
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:
|
flutter_displaymode:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -41,6 +41,7 @@ dependencies:
|
|||||||
flutter:
|
flutter:
|
||||||
sdk: flutter
|
sdk: flutter
|
||||||
flutter_bloc: ^8.0.1
|
flutter_bloc: ^8.0.1
|
||||||
|
flutter_context_menu: ^0.1.3
|
||||||
flutter_displaymode: ^0.6.0
|
flutter_displaymode: ^0.6.0
|
||||||
flutter_email_sender: ^6.0.2
|
flutter_email_sender: ^6.0.2
|
||||||
flutter_inappwebview: ^6.0.0
|
flutter_inappwebview: ^6.0.0
|
||||||
|
Loading…
x
Reference in New Issue
Block a user