Skip to content

Commit

Permalink
Feat: added save, share QR for receiving address
Browse files Browse the repository at this point in the history
  • Loading branch information
alienc0der committed Feb 1, 2023
1 parent 0bfb475 commit 7612fa0
Show file tree
Hide file tree
Showing 6 changed files with 242 additions and 24 deletions.
97 changes: 97 additions & 0 deletions lib/widgets/reusable_widgets/context_menu_region.dart
@@ -0,0 +1,97 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';

typedef ContextMenuBuilder = Widget Function(
BuildContext context, Offset offset);

/// Shows and hides the context menu based on user gestures.
///
/// By default, shows the menu on right clicks and long presses.
class ContextMenuRegion extends StatefulWidget {
/// Creates an instance of [ContextMenuRegion].
const ContextMenuRegion({
Key? key,
required this.child,
required this.contextMenuBuilder,
}) : super(key: key);

/// Builds the context menu.
final ContextMenuBuilder contextMenuBuilder;

/// The child widget that will be listened to for gestures.
final Widget child;

@override
State<ContextMenuRegion> createState() => _ContextMenuRegionState();
}

class _ContextMenuRegionState extends State<ContextMenuRegion> {
Offset? _longPressOffset;

final ContextMenuController _contextMenuController = ContextMenuController();

static bool get _longPressEnabled {
switch (defaultTargetPlatform) {
case TargetPlatform.android:
case TargetPlatform.iOS:
return true;
case TargetPlatform.macOS:
case TargetPlatform.fuchsia:
case TargetPlatform.linux:
case TargetPlatform.windows:
return false;
}
}

void _onSecondaryTapUp(TapUpDetails details) {
_show(details.globalPosition);
}

void _onTap() {
if (!_contextMenuController.isShown) {
return;
}
_hide();
}

void _onLongPressStart(LongPressStartDetails details) {
_longPressOffset = details.globalPosition;
}

void _onLongPress() {
assert(_longPressOffset != null);
_show(_longPressOffset!);
_longPressOffset = null;
}

void _show(Offset position) {
_contextMenuController.show(
context: context,
contextMenuBuilder: (context) {
return widget.contextMenuBuilder(context, position);
},
);
}

void _hide() {
_contextMenuController.remove();
}

@override
void dispose() {
_hide();
super.dispose();
}

@override
Widget build(BuildContext context) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onSecondaryTapUp: _onSecondaryTapUp,
onTap: _onTap,
onLongPress: _longPressEnabled ? _onLongPress : null,
onLongPressStart: _longPressEnabled ? _onLongPressStart : null,
child: widget.child,
);
}
}
2 changes: 1 addition & 1 deletion lib/widgets/reusable_widgets/input_fields/input_field.dart
Expand Up @@ -79,7 +79,7 @@ class _InputFieldState extends State<InputField> {
child: Text(
AdaptiveTextSelectionToolbar.getButtonLabel(
context, buttonItem),
style: const TextStyle(color: Colors.white)),
style: Theme.of(context).textTheme.bodyMedium),
))
]);
}).toList());
Expand Down
158 changes: 137 additions & 21 deletions lib/widgets/reusable_widgets/receive_qr_image.dart
@@ -1,6 +1,16 @@
import 'dart:io';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:flutter_vector_icons/flutter_vector_icons.dart';
import 'package:open_filex/open_filex.dart';
import 'package:path/path.dart' as path;
import 'package:pretty_qr_code/pretty_qr_code.dart';
import 'package:screenshot/screenshot.dart';
import 'package:share_plus/share_plus.dart';
import 'package:zenon_syrius_wallet_flutter/utils/color_utils.dart';
import 'package:zenon_syrius_wallet_flutter/utils/utils.dart';
import 'package:zenon_syrius_wallet_flutter/widgets/reusable_widgets/context_menu_region.dart';
import 'package:znn_sdk_dart/znn_sdk_dart.dart';

class ReceiveQrImage extends StatelessWidget {
Expand All @@ -9,7 +19,9 @@ class ReceiveQrImage extends StatelessWidget {
final TokenStandard tokenStandard;
final BuildContext context;

const ReceiveQrImage({
final ScreenshotController screenshotController = ScreenshotController();

ReceiveQrImage({
required this.data,
required this.size,
required this.tokenStandard,
Expand All @@ -19,25 +31,129 @@ class ReceiveQrImage extends StatelessWidget {

@override
Widget build(BuildContext context) {
return ClipRRect(
borderRadius: BorderRadius.circular(
15.0,
),
child: Container(
padding: const EdgeInsets.all(
10.0,
),
color: Theme.of(context).colorScheme.background,
child: PrettyQr(
data: data,
size: size,
elementColor: ColorUtils.getTokenColor(tokenStandard),
image: const AssetImage('assets/images/qr_code_child_image_znn.png'),
typeNumber: 7,
errorCorrectLevel: QrErrorCorrectLevel.M,
roundEdges: true,
),
),
);
return Screenshot(
controller: screenshotController,
child: ClipRRect(
borderRadius: BorderRadius.circular(
15.0,
),
child: Container(
padding: const EdgeInsets.all(
10.0,
),
color: Theme.of(context).colorScheme.background,
child: ContextMenuRegion(
contextMenuBuilder: (context, offset) {
return AdaptiveTextSelectionToolbar(
anchors: TextSelectionToolbarAnchors(
primaryAnchor: offset,
),
children: [
Row(
children: [
Expanded(
child: Directionality(
textDirection: TextDirection.rtl,
child: TextButton.icon(
icon: Icon(
MaterialCommunityIcons.share,
color:
Theme.of(context).colorScheme.onBackground,
size: 14,
),
onPressed: () {
ContextMenuController.removeAny();
_shareQR();
},
style: TextButton.styleFrom(
shape: const RoundedRectangleBorder(),
),
label: Text(
AdaptiveTextSelectionToolbar.getButtonLabel(
context,
ContextMenuButtonItem(
label: 'Share QR', onPressed: () {})),
style:
Theme.of(context).textTheme.bodyMedium),
),
),
),
],
),
Row(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
Expanded(
flex: 1,
child: Directionality(
textDirection: TextDirection.rtl,
child: TextButton.icon(
icon: Icon(
Icons.save_alt,
color:
Theme.of(context).colorScheme.onBackground,
size: 14,
),
onPressed: () {
ContextMenuController.removeAny();
_saveQR();
},
style: TextButton.styleFrom(
shape: const RoundedRectangleBorder(),
),
label: Text(
AdaptiveTextSelectionToolbar.getButtonLabel(
context,
ContextMenuButtonItem(
label: 'Save QR', onPressed: () {})),
style:
Theme.of(context).textTheme.bodyMedium),
),
),
),
],
),
],
);
},
child: PrettyQr(
data: data,
size: size,
elementColor: ColorUtils.getTokenColor(tokenStandard),
image: const AssetImage(
'assets/images/qr_code_child_image_znn.png'),
typeNumber: 7,
errorCorrectLevel: QrErrorCorrectLevel.M,
roundEdges: true,
),
),
),
));
}

void _saveQR() async {
Uint8List? capture = await screenshotController.capture(
delay: const Duration(milliseconds: 20));
if (capture != null) {
String fileName = DateTime.now().millisecondsSinceEpoch.toString();
final imagePath = await File(
'${znnDefaultPaths.cache.path}${path.separator}$fileName.png')
.create();
await imagePath.writeAsBytes(capture);
await OpenFilex.open(imagePath.path);
}
}

void _shareQR() async {
Uint8List? capture = await screenshotController.capture(
delay: const Duration(milliseconds: 20));
if (capture != null) {
String fileName = DateTime.now().millisecondsSinceEpoch.toString();
final imagePath = await File(
'${znnDefaultPaths.cache.path}${path.separator}$fileName.png')
.create();
await imagePath.writeAsBytes(capture);
await Share.shareXFiles([XFile(imagePath.path)]);
}
}
}
5 changes: 3 additions & 2 deletions pubspec.yaml
Expand Up @@ -33,10 +33,11 @@ dependencies:
package_info_plus: ^1.3.0
device_info_plus: ^4.0.0
infinite_scroll_pagination: ^3.1.0
share_plus: ^4.0.4
share_plus: ^6.3.0
page_transition: ^2.0.4
file_selector_platform_interface: ^2.0.4
pretty_qr_code: ^2.0.2
pretty_qr_code: ^2.0.3
screenshot: ^1.3.0
desktop_drop: ^0.4.0
network_info_plus: ^3.0.1
validators: ^3.0.0
Expand Down
3 changes: 3 additions & 0 deletions windows/flutter/generated_plugin_registrant.cc
Expand Up @@ -11,6 +11,7 @@
#include <local_notifier/local_notifier_plugin.h>
#include <network_info_plus/network_info_plus_windows_plugin.h>
#include <screen_retriever/screen_retriever_plugin.h>
#include <share_plus/share_plus_windows_plugin_c_api.h>
#include <tray_manager/tray_manager_plugin.h>
#include <url_launcher_windows/url_launcher_windows.h>
#include <window_manager/window_manager_plugin.h>
Expand All @@ -26,6 +27,8 @@ void RegisterPlugins(flutter::PluginRegistry* registry) {
registry->GetRegistrarForPlugin("NetworkInfoPlusWindowsPlugin"));
ScreenRetrieverPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("ScreenRetrieverPlugin"));
SharePlusWindowsPluginCApiRegisterWithRegistrar(
registry->GetRegistrarForPlugin("SharePlusWindowsPluginCApi"));
TrayManagerPluginRegisterWithRegistrar(
registry->GetRegistrarForPlugin("TrayManagerPlugin"));
UrlLauncherWindowsRegisterWithRegistrar(
Expand Down
1 change: 1 addition & 0 deletions windows/flutter/generated_plugins.cmake
Expand Up @@ -8,6 +8,7 @@ list(APPEND FLUTTER_PLUGIN_LIST
local_notifier
network_info_plus
screen_retriever
share_plus
tray_manager
url_launcher_windows
window_manager
Expand Down

0 comments on commit 7612fa0

Please sign in to comment.