|
@@ -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/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';
|
|
@@ -86,108 +86,122 @@ 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(
|
|
|
|
- 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>(
|
|
|
|
- () => 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: <ContextMenuEntry>[
|
|
|
|
+ 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),
|
|
|
|
+ ),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
);
|