diff --git a/assets/svg/monkey.svg b/assets/svg/monkey.svg
new file mode 100644
index 000000000..565ac4fdf
--- /dev/null
+++ b/assets/svg/monkey.svg
@@ -0,0 +1,3 @@
+
diff --git a/crypto_plugins/flutter_libmonero b/crypto_plugins/flutter_libmonero
index e48952185..407425c9f 160000
--- a/crypto_plugins/flutter_libmonero
+++ b/crypto_plugins/flutter_libmonero
@@ -1 +1 @@
-Subproject commit e48952185556a10f182184fd572bcb04365f5831
+Subproject commit 407425c9fcf7a30c81f1345246c7225bc18b5cd5
diff --git a/lib/pages/monkey/monkey_loaded_view.dart b/lib/pages/monkey/monkey_loaded_view.dart
new file mode 100644
index 000000000..93c28b39a
--- /dev/null
+++ b/lib/pages/monkey/monkey_loaded_view.dart
@@ -0,0 +1,275 @@
+// import 'dart:io';
+// import 'dart:typed_data';
+//
+// import 'package:flutter/material.dart';
+// import 'package:flutter_riverpod/flutter_riverpod.dart';
+// import 'package:flutter_svg/svg.dart';
+// import 'package:http/http.dart' as http;
+// import 'package:path_provider/path_provider.dart';
+// import 'package:permission_handler/permission_handler.dart';
+// import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
+// import 'package:stackwallet/providers/global/wallets_provider.dart';
+// import 'package:stackwallet/services/coins/banano/banano_wallet.dart';
+// import 'package:stackwallet/services/coins/manager.dart';
+// import 'package:stackwallet/themes/stack_colors.dart';
+// import 'package:stackwallet/utilities/assets.dart';
+// import 'package:stackwallet/utilities/enums/coin_enum.dart';
+// import 'package:stackwallet/utilities/text_styles.dart';
+// import 'package:stackwallet/widgets/background.dart';
+// import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+// import 'package:stackwallet/widgets/desktop/secondary_button.dart';
+//
+// class MonkeyLoadedView extends ConsumerStatefulWidget {
+// const MonkeyLoadedView({
+// Key? key,
+// required this.walletId,
+// required this.managerProvider,
+// }) : super(key: key);
+//
+// static const String routeName = "/hasMonkey";
+// static const double navBarHeight = 65.0;
+//
+// final String walletId;
+// final ChangeNotifierProvider managerProvider;
+//
+// @override
+// ConsumerState createState() => _MonkeyLoadedViewState();
+// }
+//
+// class _MonkeyLoadedViewState extends ConsumerState {
+// late final String walletId;
+// late final ChangeNotifierProvider managerProvider;
+//
+// String receivingAddress = "";
+//
+// void getMonkeySVG(String address) async {
+// if (address.isEmpty) {
+// //address shouldn't be empty
+// return;
+// }
+//
+// final http.Response response = await http
+// .get(Uri.parse('https://monkey.banano.cc/api/v1/monkey/$address'));
+//
+// if (response.statusCode == 200) {
+// final decodedResponse = response.bodyBytes;
+// Directory directory = await getApplicationDocumentsDirectory();
+// late Directory sampleFolder;
+//
+// if (Platform.isAndroid) {
+// directory = Directory("/storage/emulated/0/");
+// sampleFolder = Directory('${directory!.path}Documents');
+// } else if (Platform.isIOS) {
+// sampleFolder = Directory(directory!.path);
+// } else if (Platform.isLinux) {
+// sampleFolder = Directory('${directory!.path}Documents');
+// } else if (Platform.isWindows) {
+// sampleFolder = Directory('${directory!.path}Documents');
+// } else if (Platform.isMacOS) {
+// sampleFolder = Directory('${directory!.path}Documents');
+// }
+//
+// try {
+// if (!sampleFolder.existsSync()) {
+// sampleFolder.createSync(recursive: true);
+// }
+// } catch (e, s) {
+// // todo: come back to this
+// debugPrint("$e $s");
+// }
+//
+// final docPath = sampleFolder.path;
+// final filePath = "$docPath/monkey.svg";
+//
+// File imgFile = File(filePath);
+// await imgFile.writeAsBytes(decodedResponse);
+// } else {
+// throw Exception("Failed to get MonKey");
+// }
+// }
+//
+// void getMonkeyPNG(String address) async {
+// if (address.isEmpty) {
+// //address shouldn't be empty
+// return;
+// }
+//
+// final http.Response response = await http.get(Uri.parse(
+// 'https://monkey.banano.cc/api/v1/monkey/${address}?format=png&size=512&background=false'));
+//
+// if (response.statusCode == 200) {
+// if (Platform.isAndroid) {
+// await Permission.storage.request();
+// }
+//
+// final decodedResponse = response.bodyBytes;
+// Directory directory = await getApplicationDocumentsDirectory();
+// late Directory sampleFolder;
+//
+// if (Platform.isAndroid) {
+// directory = Directory("/storage/emulated/0/");
+// sampleFolder = Directory('${directory!.path}Documents');
+// } else if (Platform.isIOS) {
+// sampleFolder = Directory(directory!.path);
+// } else if (Platform.isLinux) {
+// sampleFolder = Directory('${directory!.path}Documents');
+// } else if (Platform.isWindows) {
+// sampleFolder = Directory('${directory!.path}Documents');
+// } else if (Platform.isMacOS) {
+// sampleFolder = Directory('${directory!.path}Documents');
+// }
+//
+// try {
+// if (!sampleFolder.existsSync()) {
+// sampleFolder.createSync(recursive: true);
+// }
+// } catch (e, s) {
+// // todo: come back to this
+// debugPrint("$e $s");
+// }
+//
+// final docPath = sampleFolder.path;
+// final filePath = "$docPath/monkey.png";
+//
+// File imgFile = File(filePath);
+// await imgFile.writeAsBytes(decodedResponse);
+// } else {
+// throw Exception("Failed to get MonKey");
+// }
+// }
+//
+// @override
+// void initState() {
+// walletId = widget.walletId;
+// managerProvider = widget.managerProvider;
+//
+// WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
+// final address = await ref
+// .read(walletsChangeNotifierProvider)
+// .getManager(walletId)
+// .currentReceivingAddress;
+// setState(() {
+// receivingAddress = address;
+// });
+// });
+//
+// super.initState();
+// }
+//
+// @override
+// void dispose() {
+// super.dispose();
+// }
+//
+// @override
+// Widget build(BuildContext context) {
+// final Coin coin = ref.watch(managerProvider.select((value) => value.coin));
+// final manager = ref.watch(walletsChangeNotifierProvider
+// .select((value) => value.getManager(widget.walletId)));
+//
+// List? imageBytes;
+// imageBytes = (manager.wallet as BananoWallet).getMonkeyImageBytes();
+//
+// return Background(
+// child: Stack(
+// children: [
+// Scaffold(
+// appBar: AppBar(
+// leading: AppBarBackButton(
+// onPressed: () {
+// Navigator.of(context).popUntil(
+// ModalRoute.withName(WalletView.routeName),
+// );
+// },
+// ),
+// title: Text(
+// "MonKey",
+// style: STextStyles.navBarTitle(context),
+// ),
+// actions: [
+// AspectRatio(
+// aspectRatio: 1,
+// child: AppBarIconButton(
+// icon: SvgPicture.asset(Assets.svg.circleQuestion),
+// onPressed: () {
+// showDialog(
+// context: context,
+// useSafeArea: false,
+// barrierDismissible: true,
+// builder: (context) {
+// return Dialog(
+// child: Material(
+// borderRadius: BorderRadius.circular(
+// 20,
+// ),
+// child: Container(
+// height: 200,
+// decoration: BoxDecoration(
+// color: Theme.of(context)
+// .extension()!
+// .popupBG,
+// borderRadius: BorderRadius.circular(
+// 20,
+// ),
+// ),
+// child: Column(
+// children: [
+// Center(
+// child: Text(
+// "Help",
+// style: STextStyles.pageTitleH2(
+// context),
+// ),
+// )
+// ],
+// ),
+// ),
+// ),
+// );
+// });
+// }),
+// )
+// ],
+// ),
+// body: Column(
+// children: [
+// const Spacer(
+// flex: 1,
+// ),
+// if (imageBytes != null)
+// Container(
+// child: SvgPicture.memory(Uint8List.fromList(imageBytes!)),
+// width: 300,
+// height: 300,
+// ),
+// const Spacer(
+// flex: 1,
+// ),
+// Padding(
+// padding: const EdgeInsets.all(16.0),
+// child: Column(
+// children: [
+// SecondaryButton(
+// label: "Download as SVG",
+// onPressed: () async {
+// getMonkeySVG(receivingAddress);
+// },
+// ),
+// const SizedBox(height: 12),
+// SecondaryButton(
+// label: "Download as PNG",
+// onPressed: () {
+// getMonkeyPNG(receivingAddress);
+// },
+// ),
+// ],
+// ),
+// ),
+// ],
+// ),
+// ),
+// ],
+// ),
+// );
+// }
+// }
diff --git a/lib/pages/monkey/monkey_view.dart b/lib/pages/monkey/monkey_view.dart
new file mode 100644
index 000000000..2ad4b18eb
--- /dev/null
+++ b/lib/pages/monkey/monkey_view.dart
@@ -0,0 +1,497 @@
+import 'dart:io';
+import 'dart:typed_data';
+
+import 'package:flutter/material.dart';
+import 'package:flutter_riverpod/flutter_riverpod.dart';
+import 'package:flutter_svg/svg.dart';
+import 'package:http/http.dart' as http;
+import 'package:path_provider/path_provider.dart';
+import 'package:permission_handler/permission_handler.dart';
+import 'package:stackwallet/providers/global/wallets_provider.dart';
+import 'package:stackwallet/services/coins/banano/banano_wallet.dart';
+import 'package:stackwallet/themes/coin_icon_provider.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/assets.dart';
+import 'package:stackwallet/utilities/enums/coin_enum.dart';
+import 'package:stackwallet/utilities/show_loading.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/widgets/background.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
+import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
+import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
+import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
+import 'package:stackwallet/widgets/desktop/primary_button.dart';
+import 'package:stackwallet/widgets/desktop/secondary_button.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+
+class MonkeyView extends ConsumerStatefulWidget {
+ const MonkeyView({
+ Key? key,
+ required this.walletId,
+ }) : super(key: key);
+
+ static const String routeName = "/monkey";
+ static const double navBarHeight = 65.0;
+
+ final String walletId;
+
+ @override
+ ConsumerState createState() => _MonkeyViewState();
+}
+
+class _MonkeyViewState extends ConsumerState {
+ late final String walletId;
+ List? imageBytes;
+
+ String receivingAddress = "";
+
+ Future getMonkeyImage(String address) async {
+ if (address.isEmpty) {
+ //address shouldn't be empty
+ return;
+ }
+
+ final http.Response response = await http
+ .get(Uri.parse('https://monkey.banano.cc/api/v1/monkey/$address'));
+
+ if (response.statusCode == 200) {
+ final manager =
+ ref.read(walletsChangeNotifierProvider).getManager(walletId);
+ final decodedResponse = response.bodyBytes;
+ await (manager.wallet as BananoWallet)
+ .updateMonkeyImageBytes(decodedResponse);
+ } else {
+ throw Exception("Failed to get MonKey");
+ }
+ }
+
+ // void getMonkeySVG(String address) async {
+ // if (address.isEmpty) {
+ // //address shouldn't be empty
+ // return;
+ // }
+ //
+ // final http.Response response = await http
+ // .get(Uri.parse('https://monkey.banano.cc/api/v1/monkey/$address'));
+ //
+ // if (response.statusCode == 200) {
+ // final decodedResponse = response.bodyBytes;
+ // Directory directory = await getApplicationDocumentsDirectory();
+ // late Directory sampleFolder;
+ //
+ // if (Platform.isAndroid) {
+ // directory = Directory("/storage/emulated/0/");
+ // sampleFolder = Directory('${directory!.path}Documents');
+ // } else if (Platform.isIOS) {
+ // sampleFolder = Directory(directory!.path);
+ // } else if (Platform.isLinux) {
+ // sampleFolder = Directory('${directory!.path}Documents');
+ // } else if (Platform.isWindows) {
+ // sampleFolder = Directory('${directory!.path}Documents');
+ // } else if (Platform.isMacOS) {
+ // sampleFolder = Directory('${directory!.path}Documents');
+ // }
+ //
+ // try {
+ // if (!sampleFolder.existsSync()) {
+ // sampleFolder.createSync(recursive: true);
+ // }
+ // } catch (e, s) {
+ // // todo: come back to this
+ // debugPrint("$e $s");
+ // }
+ //
+ // final docPath = sampleFolder.path;
+ // final filePath = "$docPath/monkey.svg";
+ //
+ // File imgFile = File(filePath);
+ // await imgFile.writeAsBytes(decodedResponse);
+ // } else {
+ // throw Exception("Failed to get MonKey");
+ // }
+ // }
+
+ Future getDocsDir() async {
+ try {
+ if (Platform.isAndroid) {
+ return Directory("/storage/emulated/0/Documents");
+ }
+
+ return await getApplicationDocumentsDirectory();
+ } catch (_) {
+ return null;
+ }
+ }
+
+ Future downloadMonkey(String address, bool isPNG) async {
+ if (address.isEmpty) {
+ //address shouldn't be empty
+ return;
+ }
+
+ String url = "https://monkey.banano.cc/api/v1/monkey/$address";
+
+ if (isPNG) {
+ url += '?format=png&size=512&background=false';
+ }
+
+ final http.Response response = await http.get(Uri.parse(url));
+
+ if (response.statusCode == 200) {
+ if (Platform.isAndroid) {
+ await Permission.storage.request();
+ }
+
+ final decodedResponse = response.bodyBytes;
+ final Directory? sampleFolder = await getDocsDir();
+
+ print("PATH: ${sampleFolder?.path}");
+
+ if (sampleFolder == null) {
+ print("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA");
+ return;
+ }
+
+ // try {
+ // if (!sampleFolder.existsSync()) {
+ // sampleFolder.createSync(recursive: true);
+ // }
+ // } catch (e, s) {
+ // // todo: come back to this
+ // debugPrint("$e $s");
+ // }
+
+ final docPath = sampleFolder.path;
+ String filePath = "$docPath/monkey_$address";
+
+ filePath += isPNG ? ".png" : ".svg";
+
+ // todo check if monkey.png exists
+
+ File imgFile = File(filePath);
+ await imgFile.writeAsBytes(decodedResponse);
+ } else {
+ throw Exception("Failed to get MonKey");
+ }
+ }
+
+ @override
+ void initState() {
+ walletId = widget.walletId;
+
+ WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
+ final address = await ref
+ .read(walletsChangeNotifierProvider)
+ .getManager(walletId)
+ .currentReceivingAddress;
+ setState(() {
+ receivingAddress = address;
+ });
+ });
+
+ super.initState();
+ }
+
+ @override
+ void dispose() {
+ super.dispose();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ final manager = ref.watch(walletsChangeNotifierProvider
+ .select((value) => value.getManager(widget.walletId)));
+ final Coin coin = manager.coin;
+
+ final bool isDesktop = Util.isDesktop;
+
+ imageBytes ??= (manager.wallet as BananoWallet).getMonkeyImageBytes();
+
+ //edit for desktop
+ return Background(
+ child: ConditionalParent(
+ condition: isDesktop,
+ builder: (child) => DesktopScaffold(
+ appBar: DesktopAppBar(
+ background: Theme.of(context).extension()!.popupBG,
+ leading: Expanded(
+ child: Row(
+ children: [
+ const SizedBox(
+ width: 32,
+ ),
+ AppBarIconButton(
+ size: 32,
+ color: Theme.of(context)
+ .extension()!
+ .textFieldDefaultBG,
+ shadows: const [],
+ icon: SvgPicture.asset(
+ Assets.svg.arrowLeft,
+ width: 18,
+ height: 18,
+ color: Theme.of(context)
+ .extension()!
+ .topNavIconPrimary,
+ ),
+ onPressed: () {
+ if (mounted) {
+ Navigator.of(context).pop();
+ }
+ },
+ ),
+ const SizedBox(
+ width: 15,
+ ),
+ SvgPicture.asset(Assets.svg.monkey),
+ const SizedBox(
+ width: 12,
+ ),
+ Text(
+ "MonKey",
+ style: STextStyles.navBarTitle(context),
+ ),
+ ],
+ ),
+ ),
+ trailing: Padding(
+ padding: const EdgeInsets.all(8.0),
+ child: MouseRegion(
+ cursor: SystemMouseCursors.click,
+ child: GestureDetector(
+ onTap: () {
+ showDialog(
+ context: context,
+ useSafeArea: false,
+ barrierDismissible: true,
+ builder: (context) {
+ return const StackDialog(
+ title: "About MonKeys",
+ message:
+ "A MonKey is a visual representation of your Banano address.",
+ );
+ });
+ },
+ child: Row(
+ children: [
+ SvgPicture.asset(
+ Assets.svg.circleQuestion,
+ color: Colors.blue[800],
+ ),
+ const SizedBox(
+ width: 6,
+ ),
+ Padding(
+ padding: const EdgeInsets.only(bottom: 8.0),
+ child: Text(
+ "What is MonKey?",
+ style: STextStyles.desktopTextSmall(context).copyWith(
+ color: Colors.blue[800],
+ ),
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ useSpacers: false,
+ isCompactHeight: true,
+ ),
+ body: child,
+ ),
+ child: ConditionalParent(
+ condition: !isDesktop,
+ builder: (child) => Scaffold(
+ appBar: AppBar(
+ leading: AppBarBackButton(
+ onPressed: () {
+ Navigator.of(context).pop();
+ },
+ ),
+ title: Text(
+ "MonKey",
+ style: STextStyles.navBarTitle(context),
+ ),
+ actions: [
+ AspectRatio(
+ aspectRatio: 1,
+ child: AppBarIconButton(
+ icon: SvgPicture.asset(
+ Assets.svg.circleQuestion,
+ ),
+ onPressed: () {
+ showDialog(
+ context: context,
+ useSafeArea: false,
+ barrierDismissible: true,
+ builder: (context) {
+ return const StackOkDialog(
+ title: "About MonKeys",
+ message:
+ "A MonKey is a visual representation of your Banano address.",
+ );
+ });
+ }),
+ ),
+ ],
+ ),
+ body: child,
+ ),
+ child: ConditionalParent(
+ condition: isDesktop,
+ builder: (child) => SizedBox(
+ width: 318,
+ child: child,
+ ),
+ child: ConditionalParent(
+ condition: imageBytes != null,
+ builder: (_) => Column(
+ children: [
+ isDesktop
+ ? const SizedBox(
+ height: 50,
+ )
+ : const Spacer(
+ flex: 1,
+ ),
+ if (imageBytes != null)
+ SizedBox(
+ width: 300,
+ height: 300,
+ child: SvgPicture.memory(Uint8List.fromList(imageBytes!)),
+ ),
+ isDesktop
+ ? const SizedBox(
+ height: 50,
+ )
+ : const Spacer(
+ flex: 1,
+ ),
+ Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: Column(
+ children: [
+ SecondaryButton(
+ label: "Save as SVG",
+ onPressed: () async {
+ await showLoading(
+ whileFuture:
+ downloadMonkey(receivingAddress, false),
+ context: context,
+ isDesktop: Util.isDesktop,
+ message: "Saving MonKey svg",
+ );
+ },
+ ),
+ const SizedBox(height: 12),
+ SecondaryButton(
+ label: "Download as PNG",
+ onPressed: () async {
+ await showLoading(
+ whileFuture:
+ downloadMonkey(receivingAddress, true),
+ context: context,
+ isDesktop: Util.isDesktop,
+ message: "Downloading MonKey png",
+ );
+ },
+ ),
+ ],
+ ),
+ ),
+ // child,
+ ],
+ ),
+ child: Column(
+ children: [
+ isDesktop
+ ? const SizedBox(
+ height: 100,
+ )
+ : const Spacer(
+ flex: 4,
+ ),
+ Center(
+ child: Column(
+ children: [
+ Opacity(
+ opacity: 0.2,
+ child: SvgPicture.file(
+ File(
+ ref.watch(coinIconProvider(coin)),
+ ),
+ width: 200,
+ height: 200,
+ ),
+ ),
+ const SizedBox(
+ height: 70,
+ ),
+ Text(
+ "You do not have a MonKey yet. \nFetch yours now!",
+ style: STextStyles.smallMed14(context).copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .textDark3,
+ ),
+ textAlign: TextAlign.center,
+ ),
+ ],
+ ),
+ ),
+ isDesktop
+ ? const SizedBox(
+ height: 50,
+ )
+ : const Spacer(
+ flex: 6,
+ ),
+ Padding(
+ padding: const EdgeInsets.all(16.0),
+ child: PrimaryButton(
+ label: "Fetch MonKey",
+ onPressed: () async {
+ final future = Future.wait([
+ getMonkeyImage(receivingAddress),
+ Future.delayed(const Duration(seconds: 2)),
+ ]);
+
+ await showLoading(
+ whileFuture: future,
+ context: context,
+ isDesktop: Util.isDesktop,
+ message: "Fetching MonKey",
+ subMessage: "We are fetching your MonKey",
+ );
+
+ imageBytes = (manager.wallet as BananoWallet)
+ .getMonkeyImageBytes();
+
+ if (imageBytes != null) {
+ setState(() {});
+ }
+
+ // if (isDesktop) {
+ // Navigator.of(context).popUntil(
+ // ModalRoute.withName(
+ // DesktopWalletView.routeName),
+ // );
+ // } else {
+ // Navigator.of(context).popUntil(
+ // ModalRoute.withName(WalletView.routeName),
+ // );
+ // }
+ },
+ ),
+ ),
+ ],
+ ),
+ ),
+ ),
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/pages/monkey/sub_widgets/fetch_monkey_dialog.dart b/lib/pages/monkey/sub_widgets/fetch_monkey_dialog.dart
new file mode 100644
index 000000000..94034fb78
--- /dev/null
+++ b/lib/pages/monkey/sub_widgets/fetch_monkey_dialog.dart
@@ -0,0 +1,135 @@
+/*
+ * This file is part of Stack Wallet.
+ *
+ * Copyright (c) 2023 Cypher Stack
+ * All Rights Reserved.
+ * The code is distributed under GPLv3 license, see LICENSE file for details.
+ * Generated by Cypher Stack on 2023-05-26
+ *
+ */
+
+import 'package:flutter/material.dart';
+import 'package:stackwallet/themes/stack_colors.dart';
+import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/utilities/util.dart';
+import 'package:stackwallet/widgets/animated_widgets/rotating_arrows.dart';
+import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
+import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
+import 'package:stackwallet/widgets/desktop/secondary_button.dart';
+import 'package:stackwallet/widgets/stack_dialog.dart';
+
+class FetchMonkeyDialog extends StatefulWidget {
+ const FetchMonkeyDialog({
+ Key? key,
+ required this.onCancel,
+ }) : super(key: key);
+
+ final Future Function() onCancel;
+
+ @override
+ State createState() => _FetchMonkeyDialogState();
+}
+
+class _FetchMonkeyDialogState extends State {
+ late final Future Function() onCancel;
+ @override
+ void initState() {
+ onCancel = widget.onCancel;
+
+ super.initState();
+ }
+
+ @override
+ Widget build(BuildContext context) {
+ if (Util.isDesktop) {
+ return DesktopDialog(
+ child: Column(
+ children: [
+ DesktopDialogCloseButton(
+ onPressedOverride: () async {
+ await onCancel.call();
+ if (mounted) {
+ Navigator.of(context).pop();
+ }
+ },
+ ),
+ const Spacer(
+ flex: 1,
+ ),
+ const RotatingArrows(
+ width: 40,
+ height: 40,
+ ),
+ const Spacer(
+ flex: 2,
+ ),
+ Text(
+ "Fetching MonKey",
+ style: STextStyles.desktopH2(context),
+ textAlign: TextAlign.center,
+ ),
+ const SizedBox(
+ height: 16,
+ ),
+ Text(
+ "We are fetching your MonKey",
+ style: STextStyles.desktopTextMedium(context).copyWith(
+ color: Theme.of(context).extension()!.textDark3,
+ ),
+ textAlign: TextAlign.center,
+ ),
+ const Spacer(
+ flex: 2,
+ ),
+ Padding(
+ padding: const EdgeInsets.only(
+ left: 32,
+ right: 32,
+ bottom: 32,
+ ),
+ child: SecondaryButton(
+ label: "Cancel",
+ width: 272.5,
+ onPressed: () async {
+ await onCancel.call();
+ if (mounted) {
+ Navigator.of(context).pop();
+ }
+ },
+ ),
+ ),
+ ],
+ ),
+ );
+ } else {
+ return WillPopScope(
+ onWillPop: () async {
+ return false;
+ },
+ child: StackDialog(
+ title: "Fetching MonKey",
+ message: "We are fetching your MonKey",
+ icon: const RotatingArrows(
+ width: 24,
+ height: 24,
+ ),
+ rightButton: TextButton(
+ style: Theme.of(context)
+ .extension()!
+ .getSecondaryEnabledButtonStyle(context),
+ child: Text(
+ "Cancel",
+ style: STextStyles.itemSubtitle12(context),
+ ),
+ onPressed: () async {
+ await onCancel.call();
+ if (mounted) {
+ Navigator.of(context).pop();
+ }
+ },
+ ),
+ ),
+ );
+ }
+ }
+}
diff --git a/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart b/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart
index a4716d190..0c4e6fb08 100644
--- a/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart
+++ b/lib/pages/wallet_view/sub_widgets/wallet_summary_info.dart
@@ -10,6 +10,7 @@
import 'dart:async';
import 'dart:io';
+import 'dart:typed_data';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
@@ -19,6 +20,7 @@ import 'package:stackwallet/pages/wallet_view/sub_widgets/wallet_refresh_button.
import 'package:stackwallet/providers/providers.dart';
import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart';
import 'package:stackwallet/providers/wallet/wallet_balance_toggle_state_provider.dart';
+import 'package:stackwallet/services/coins/banano/banano_wallet.dart';
import 'package:stackwallet/services/coins/firo/firo_wallet.dart';
import 'package:stackwallet/services/event_bus/events/global/balance_refreshed_event.dart';
import 'package:stackwallet/services/event_bus/events/global/wallet_sync_status_changed_event.dart';
@@ -31,6 +33,7 @@ import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/enums/wallet_balance_toggle_state.dart';
import 'package:stackwallet/utilities/text_styles.dart';
+import 'package:stackwallet/widgets/conditional_parent.dart';
class WalletSummaryInfo extends ConsumerStatefulWidget {
const WalletSummaryInfo({
@@ -49,6 +52,8 @@ class WalletSummaryInfo extends ConsumerStatefulWidget {
class _WalletSummaryInfoState extends ConsumerState {
late StreamSubscription _balanceUpdated;
+ String receivingAddress = "";
+
void showSheet() {
showModalBottomSheet(
backgroundColor: Colors.transparent,
@@ -72,6 +77,17 @@ class _WalletSummaryInfoState extends ConsumerState {
}
},
);
+
+ // managerProvider = widget.managerProvider;
+ WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
+ final address = await ref
+ .read(walletsChangeNotifierProvider)
+ .getManager(widget.walletId)
+ .currentReceivingAddress;
+ setState(() {
+ receivingAddress = address;
+ });
+ });
super.initState();
}
@@ -85,10 +101,14 @@ class _WalletSummaryInfoState extends ConsumerState {
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
+ bool isMonkey = true;
+
+ final manager = ref.watch(walletsChangeNotifierProvider
+ .select((value) => value.getManager(widget.walletId)));
+
final externalCalls = ref.watch(
prefsChangeNotifierProvider.select((value) => value.externalCalls));
- final coin = ref.watch(walletsChangeNotifierProvider
- .select((value) => value.getManager(widget.walletId).coin));
+ final coin = manager.coin;
final balance = ref.watch(walletsChangeNotifierProvider
.select((value) => value.getManager(widget.walletId).balance));
@@ -125,84 +145,104 @@ class _WalletSummaryInfoState extends ConsumerState {
title = _showAvailable ? "Available balance" : "Full balance";
}
- return Row(
- children: [
- Expanded(
- child: Column(
- crossAxisAlignment: CrossAxisAlignment.start,
- children: [
- GestureDetector(
- onTap: showSheet,
- child: Row(
- children: [
- Text(
- title,
- style: STextStyles.subtitle500(context).copyWith(
+ List? imageBytes;
+
+ if (coin == Coin.banano) {
+ imageBytes = (manager.wallet as BananoWallet).getMonkeyImageBytes();
+ }
+
+ return ConditionalParent(
+ condition: imageBytes != null,
+ builder: (child) => Stack(
+ children: [
+ Positioned.fill(
+ left: 150.0,
+ child: SvgPicture.memory(
+ Uint8List.fromList(imageBytes!),
+ ),
+ ),
+ child,
+ ],
+ ),
+ child: Row(
+ children: [
+ Expanded(
+ child: Column(
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ GestureDetector(
+ onTap: showSheet,
+ child: Row(
+ children: [
+ Text(
+ title,
+ style: STextStyles.subtitle500(context).copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .textFavoriteCard,
+ ),
+ ),
+ const SizedBox(
+ width: 4,
+ ),
+ SvgPicture.asset(
+ Assets.svg.chevronDown,
color: Theme.of(context)
.extension()!
.textFavoriteCard,
+ width: 8,
+ height: 4,
),
- ),
- const SizedBox(
- width: 4,
- ),
- SvgPicture.asset(
- Assets.svg.chevronDown,
+ ],
+ ),
+ ),
+ const Spacer(),
+ FittedBox(
+ fit: BoxFit.scaleDown,
+ child: SelectableText(
+ ref.watch(pAmountFormatter(coin)).format(balanceToShow),
+ style: STextStyles.pageTitleH1(context).copyWith(
+ fontSize: 24,
color: Theme.of(context)
.extension()!
.textFavoriteCard,
- width: 8,
- height: 4,
),
- ],
+ ),
),
+ if (externalCalls)
+ Text(
+ "${(priceTuple.item1 * balanceToShow.decimal).toAmount(
+ fractionDigits: 2,
+ ).fiatString(
+ locale: locale,
+ )} $baseCurrency",
+ style: STextStyles.subtitle500(context).copyWith(
+ color: Theme.of(context)
+ .extension()!
+ .textFavoriteCard,
+ ),
+ ),
+ ],
+ ),
+ ),
+ Column(
+ children: [
+ SvgPicture.file(
+ File(
+ ref.watch(coinIconProvider(coin)),
+ ),
+ width: 24,
+ height: 24,
),
const Spacer(),
- FittedBox(
- fit: BoxFit.scaleDown,
- child: SelectableText(
- ref.watch(pAmountFormatter(coin)).format(balanceToShow),
- style: STextStyles.pageTitleH1(context).copyWith(
- fontSize: 24,
- color: Theme.of(context)
- .extension()!
- .textFavoriteCard,
- ),
- ),
+ WalletRefreshButton(
+ walletId: widget.walletId,
+ initialSyncStatus: widget.initialSyncStatus,
),
- if (externalCalls)
- Text(
- "${(priceTuple.item1 * balanceToShow.decimal).toAmount(
- fractionDigits: 2,
- ).fiatString(
- locale: locale,
- )} $baseCurrency",
- style: STextStyles.subtitle500(context).copyWith(
- color: Theme.of(context)
- .extension()!
- .textFavoriteCard,
- ),
- ),
],
- ),
- ),
- Column(
- children: [
- SvgPicture.file(
- File(
- ref.watch(coinIconProvider(coin)),
- ),
- width: 24,
- height: 24,
- ),
- const Spacer(),
- WalletRefreshButton(
- walletId: widget.walletId,
- initialSyncStatus: widget.initialSyncStatus,
- ),
- ],
- )
- ],
+ )
+ ],
+ ),
);
}
}
diff --git a/lib/pages/wallet_view/wallet_view.dart b/lib/pages/wallet_view/wallet_view.dart
index 3e51d25a9..5e9fc8eba 100644
--- a/lib/pages/wallet_view/wallet_view.dart
+++ b/lib/pages/wallet_view/wallet_view.dart
@@ -22,6 +22,7 @@ import 'package:stackwallet/pages/buy_view/buy_in_wallet_view.dart';
import 'package:stackwallet/pages/coin_control/coin_control_view.dart';
import 'package:stackwallet/pages/exchange_view/wallet_initiated_exchange_view.dart';
import 'package:stackwallet/pages/home_view/home_view.dart';
+import 'package:stackwallet/pages/monkey/monkey_view.dart';
import 'package:stackwallet/pages/notification_views/notifications_view.dart';
import 'package:stackwallet/pages/ordinals/ordinals_view.dart';
import 'package:stackwallet/pages/paynym/paynym_claim_view.dart';
@@ -926,6 +927,22 @@ class _WalletViewState extends ConsumerState {
);
},
),
+ WalletNavigationBarItemData(
+ icon: SvgPicture.asset(
+ Assets.svg.monkey,
+ height: 20,
+ width: 20,
+ color: Theme.of(context)
+ .extension()!
+ .bottomNavIconIcon,
+ ),
+ label: "MonKey",
+ onTap: () {
+ Navigator.of(context).pushNamed(
+ MonkeyView.routeName,
+ arguments: widget.walletId,
+ );
+ }),
if (ref.watch(
walletsChangeNotifierProvider.select(
(value) => value
diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_features.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_features.dart
index 44b1853db..2a6cadf11 100644
--- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_features.dart
+++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/desktop_wallet_features.dart
@@ -16,6 +16,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:flutter_svg/svg.dart';
import 'package:stackwallet/notifications/show_flush_bar.dart';
+import 'package:stackwallet/pages/monkey/monkey_view.dart';
import 'package:stackwallet/pages/paynym/paynym_claim_view.dart';
import 'package:stackwallet/pages/paynym/paynym_home_view.dart';
import 'package:stackwallet/pages_desktop_specific/coin_control/desktop_coin_control_view.dart';
@@ -82,6 +83,7 @@ class _DesktopWalletFeaturesState extends ConsumerState {
onAnonymizeAllPressed: _onAnonymizeAllPressed,
onWhirlpoolPressed: _onWhirlpoolPressed,
onOrdinalsPressed: _onOrdinalsPressed,
+ onMonkeyPressed: _onMonkeyPressed,
),
);
}
@@ -315,6 +317,15 @@ class _DesktopWalletFeaturesState extends ConsumerState {
}
}
+ Future _onMonkeyPressed() async {
+ Navigator.of(context, rootNavigator: true).pop();
+
+ await (Navigator.of(context).pushNamed(
+ MonkeyView.routeName,
+ arguments: widget.walletId,
+ ));
+ }
+
void _onOrdinalsPressed() {
Navigator.of(context, rootNavigator: true).pop();
@@ -342,8 +353,8 @@ class _DesktopWalletFeaturesState extends ConsumerState {
manager.coin == Coin.firo ||
manager.coin == Coin.firoTestNet ||
manager.hasWhirlpoolSupport ||
- manager.hasOrdinalsSupport;
-
+ manager.coin == Coin.banano ||
+ manager.hasWhirlpoolSupport;
return Row(
children: [
if (Constants.enableExchange)
diff --git a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart
index fc9c03de4..09c400324 100644
--- a/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart
+++ b/lib/pages_desktop_specific/my_stack_view/wallet_view/sub_widgets/more_features/more_features_dialog.dart
@@ -30,6 +30,7 @@ class MoreFeaturesDialog extends ConsumerStatefulWidget {
required this.onAnonymizeAllPressed,
required this.onWhirlpoolPressed,
required this.onOrdinalsPressed,
+ required this.onMonkeyPressed,
}) : super(key: key);
final String walletId;
@@ -38,6 +39,7 @@ class MoreFeaturesDialog extends ConsumerStatefulWidget {
final VoidCallback? onAnonymizeAllPressed;
final VoidCallback? onWhirlpoolPressed;
final VoidCallback? onOrdinalsPressed;
+ final VoidCallback? onMonkeyPressed;
@override
ConsumerState createState() => _MoreFeaturesDialogState();
@@ -102,7 +104,7 @@ class _MoreFeaturesDialogState extends ConsumerState {
_MoreFeaturesItem(
label: "PayNym",
detail: "Increased address privacy using BIP47",
- iconAsset: Assets.svg.ordinal,
+ iconAsset: Assets.svg.robotHead,
onPressed: () => widget.onPaynymPressed?.call(),
),
if (manager.hasOrdinalsSupport)
@@ -112,6 +114,13 @@ class _MoreFeaturesDialogState extends ConsumerState {
iconAsset: Assets.svg.ordinal,
onPressed: () => widget.onOrdinalsPressed?.call(),
),
+ if (manager.coin == Coin.banano)
+ _MoreFeaturesItem(
+ label: "MonKey",
+ detail: "Generate Banano MonKey",
+ iconAsset: Assets.svg.monkey,
+ onPressed: () => widget.onMonkeyPressed?.call(),
+ ),
const SizedBox(
height: 28,
),
diff --git a/lib/route_generator.dart b/lib/route_generator.dart
index 4c77021ea..8916bb008 100644
--- a/lib/route_generator.dart
+++ b/lib/route_generator.dart
@@ -58,6 +58,7 @@ import 'package:stackwallet/pages/generic/single_field_edit_view.dart';
import 'package:stackwallet/pages/home_view/home_view.dart';
import 'package:stackwallet/pages/intro_view.dart';
import 'package:stackwallet/pages/manage_favorites_view/manage_favorites_view.dart';
+import 'package:stackwallet/pages/monkey/monkey_view.dart';
import 'package:stackwallet/pages/notification_views/notifications_view.dart';
import 'package:stackwallet/pages/ordinals/ordinal_details_view.dart';
import 'package:stackwallet/pages/ordinals/ordinals_filter_view.dart';
@@ -381,6 +382,35 @@ class RouteGenerator {
}
return _routeError("${settings.name} invalid args: ${args.toString()}");
+ case MonkeyView.routeName:
+ if (args is String) {
+ return getRoute(
+ shouldUseMaterialRoute: useMaterialPageRoute,
+ builder: (_) => MonkeyView(
+ walletId: args,
+ ),
+ settings: RouteSettings(
+ name: settings.name,
+ ),
+ );
+ }
+ return _routeError("${settings.name} invalid args: ${args.toString()}");
+
+ // case MonkeyLoadedView.routeName:
+ // if (args is Tuple2>) {
+ // return getRoute(
+ // shouldUseMaterialRoute: useMaterialPageRoute,
+ // builder: (_) => MonkeyLoadedView(
+ // walletId: args.item1,
+ // managerProvider: args.item2,
+ // ),
+ // settings: RouteSettings(
+ // name: settings.name,
+ // ),
+ // );
+ // }
+ // return _routeError("${settings.name} invalid args: ${args.toString()}");
+
case CoinControlView.routeName:
if (args is Tuple2) {
return getRoute(
diff --git a/lib/services/coins/banano/banano_wallet.dart b/lib/services/coins/banano/banano_wallet.dart
index a050b4027..e2032aa09 100644
--- a/lib/services/coins/banano/banano_wallet.dart
+++ b/lib/services/coins/banano/banano_wallet.dart
@@ -4,6 +4,7 @@ import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:isar/isar.dart';
import 'package:nanodart/nanodart.dart';
+import 'package:stackwallet/db/hive/db.dart';
import 'package:stackwallet/db/isar/main_db.dart';
import 'package:stackwallet/models/balance.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart';
@@ -925,6 +926,21 @@ class BananoWallet extends CoinServiceAPI with WalletCache, WalletDB {
await updateCachedChainHeight(height ?? 0);
}
+ Future updateMonkeyImageBytes(List bytes) async {
+ await DB.instance.put(
+ boxName: _walletId,
+ key: "monkeyImageBytesKey",
+ value: bytes,
+ );
+ }
+
+ List? getMonkeyImageBytes() {
+ return DB.instance.get(
+ boxName: _walletId,
+ key: "monkeyImageBytesKey",
+ ) as List?;
+ }
+
Future getCurrentRepresentative() async {
final serverURI = Uri.parse(getCurrentNode().host);
final address = await currentReceivingAddress;
diff --git a/lib/utilities/assets.dart b/lib/utilities/assets.dart
index 2686c1463..d1d7a55d8 100644
--- a/lib/utilities/assets.dart
+++ b/lib/utilities/assets.dart
@@ -92,6 +92,7 @@ class _SVG {
final coinControl = const _COIN_CONTROL();
+ String get monkey => "assets/svg/monkey.svg";
String get circleSliders => "assets/svg/configuration.svg";
String get circlePlus => "assets/svg/plus-circle.svg";
String get circlePlusFilled => "assets/svg/circle-plus-filled.svg";
diff --git a/pubspec.yaml b/pubspec.yaml
index 5a08f3018..bff7cae6e 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -337,6 +337,7 @@ flutter:
- assets/svg/trocador_rating_d.svg
- assets/svg/send.svg
- assets/svg/ordinal.svg
+ - assets/svg/monkey.svg
# coin control icons
- assets/svg/coin_control/