mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-12-23 11:59:30 +00:00
refactor network call into mockable provider and handle errors
This commit is contained in:
parent
2130b76788
commit
8b88890e05
2 changed files with 187 additions and 162 deletions
|
@ -4,11 +4,12 @@ import 'dart:typed_data';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
import 'package:flutter_svg/svg.dart';
|
import 'package:flutter_svg/svg.dart';
|
||||||
import 'package:http/http.dart' as http;
|
|
||||||
import 'package:path_provider/path_provider.dart';
|
import 'package:path_provider/path_provider.dart';
|
||||||
import 'package:permission_handler/permission_handler.dart';
|
import 'package:permission_handler/permission_handler.dart';
|
||||||
|
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||||
import 'package:stackwallet/services/coins/banano/banano_wallet.dart';
|
import 'package:stackwallet/services/coins/banano/banano_wallet.dart';
|
||||||
|
import 'package:stackwallet/services/monkey_service.dart';
|
||||||
import 'package:stackwallet/themes/coin_icon_provider.dart';
|
import 'package:stackwallet/themes/coin_icon_provider.dart';
|
||||||
import 'package:stackwallet/themes/stack_colors.dart';
|
import 'package:stackwallet/themes/stack_colors.dart';
|
||||||
import 'package:stackwallet/utilities/assets.dart';
|
import 'package:stackwallet/utilities/assets.dart';
|
||||||
|
@ -44,75 +45,14 @@ class _MonkeyViewState extends ConsumerState<MonkeyView> {
|
||||||
late final String walletId;
|
late final String walletId;
|
||||||
List<int>? imageBytes;
|
List<int>? imageBytes;
|
||||||
|
|
||||||
String receivingAddress = "";
|
Future<void> _updateWalletMonKey(Uint8List monKeyBytes) async {
|
||||||
|
final manager =
|
||||||
Future<void> getMonkeyImage(String address) async {
|
ref.read(walletsChangeNotifierProvider).getManager(walletId);
|
||||||
if (address.isEmpty) {
|
await (manager.wallet as BananoWallet)
|
||||||
//address shouldn't be empty
|
.updateMonkeyImageBytes(monKeyBytes.toList());
|
||||||
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 {
|
Future<Directory?> _getDocsDir() 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<Directory?> getDocsDir() async {
|
|
||||||
try {
|
try {
|
||||||
if (Platform.isAndroid) {
|
if (Platform.isAndroid) {
|
||||||
return Directory("/storage/emulated/0/Documents");
|
return Directory("/storage/emulated/0/Documents");
|
||||||
|
@ -124,80 +64,45 @@ class _MonkeyViewState extends ConsumerState<MonkeyView> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> downloadMonkey(String address, bool isPNG) async {
|
Future<void> _saveMonKeyToFile({
|
||||||
if (address.isEmpty) {
|
required Uint8List bytes,
|
||||||
//address shouldn't be empty
|
bool isPNG = false,
|
||||||
return;
|
bool overwrite = false,
|
||||||
|
}) async {
|
||||||
|
if (Platform.isAndroid) {
|
||||||
|
await Permission.storage.request();
|
||||||
}
|
}
|
||||||
|
|
||||||
String url = "https://monkey.banano.cc/api/v1/monkey/$address";
|
final dir = await _getDocsDir();
|
||||||
|
if (dir == null) {
|
||||||
if (isPNG) {
|
throw Exception("Failed to get documents directory to save monKey image");
|
||||||
url += '?format=png&size=512&background=false';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
final http.Response response = await http.get(Uri.parse(url));
|
final address = await ref
|
||||||
|
.read(walletsChangeNotifierProvider)
|
||||||
|
.getManager(walletId)
|
||||||
|
.currentReceivingAddress;
|
||||||
|
final docPath = dir.path;
|
||||||
|
String filePath = "$docPath/monkey_$address";
|
||||||
|
|
||||||
if (response.statusCode == 200) {
|
filePath += isPNG ? ".png" : ".svg";
|
||||||
if (Platform.isAndroid) {
|
|
||||||
await Permission.storage.request();
|
|
||||||
}
|
|
||||||
|
|
||||||
final decodedResponse = response.bodyBytes;
|
File imgFile = File(filePath);
|
||||||
final Directory? sampleFolder = await getDocsDir();
|
|
||||||
|
|
||||||
print("PATH: ${sampleFolder?.path}");
|
if (imgFile.existsSync() && !overwrite) {
|
||||||
|
throw Exception("File already exists");
|
||||||
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");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await imgFile.writeAsBytes(bytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
walletId = widget.walletId;
|
walletId = widget.walletId;
|
||||||
|
|
||||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
|
||||||
final address = await ref
|
|
||||||
.read(walletsChangeNotifierProvider)
|
|
||||||
.getManager(walletId)
|
|
||||||
.currentReceivingAddress;
|
|
||||||
setState(() {
|
|
||||||
receivingAddress = address;
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
super.initState();
|
super.initState();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final manager = ref.watch(walletsChangeNotifierProvider
|
final manager = ref.watch(walletsChangeNotifierProvider
|
||||||
|
@ -318,22 +223,24 @@ class _MonkeyViewState extends ConsumerState<MonkeyView> {
|
||||||
AspectRatio(
|
AspectRatio(
|
||||||
aspectRatio: 1,
|
aspectRatio: 1,
|
||||||
child: AppBarIconButton(
|
child: AppBarIconButton(
|
||||||
icon: SvgPicture.asset(
|
icon: SvgPicture.asset(
|
||||||
Assets.svg.circleQuestion,
|
Assets.svg.circleQuestion,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
showDialog<dynamic>(
|
showDialog<dynamic>(
|
||||||
context: context,
|
context: context,
|
||||||
useSafeArea: false,
|
useSafeArea: false,
|
||||||
barrierDismissible: true,
|
barrierDismissible: true,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return const StackOkDialog(
|
return const StackOkDialog(
|
||||||
title: "About MonKeys",
|
title: "About MonKeys",
|
||||||
message:
|
message:
|
||||||
"A MonKey is a visual representation of your Banano address.",
|
"A MonKey is a visual representation of your Banano address.",
|
||||||
);
|
);
|
||||||
});
|
},
|
||||||
}),
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -376,26 +283,95 @@ class _MonkeyViewState extends ConsumerState<MonkeyView> {
|
||||||
SecondaryButton(
|
SecondaryButton(
|
||||||
label: "Save as SVG",
|
label: "Save as SVG",
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
|
bool didError = false;
|
||||||
await showLoading(
|
await showLoading(
|
||||||
whileFuture:
|
whileFuture: Future.wait([
|
||||||
downloadMonkey(receivingAddress, false),
|
_saveMonKeyToFile(
|
||||||
|
bytes: Uint8List.fromList(
|
||||||
|
(manager.wallet as BananoWallet)
|
||||||
|
.getMonkeyImageBytes()!),
|
||||||
|
),
|
||||||
|
Future<void>.delayed(
|
||||||
|
const Duration(seconds: 2),
|
||||||
|
),
|
||||||
|
]),
|
||||||
context: context,
|
context: context,
|
||||||
isDesktop: Util.isDesktop,
|
isDesktop: Util.isDesktop,
|
||||||
message: "Saving MonKey svg",
|
message: "Saving MonKey svg",
|
||||||
|
onException: (e) {
|
||||||
|
didError = true;
|
||||||
|
String msg = e.toString();
|
||||||
|
while (msg.isNotEmpty &&
|
||||||
|
msg.startsWith("Exception:")) {
|
||||||
|
msg = msg.substring(10).trim();
|
||||||
|
}
|
||||||
|
showFloatingFlushBar(
|
||||||
|
type: FlushBarType.warning,
|
||||||
|
message: msg,
|
||||||
|
context: context,
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!didError && mounted) {
|
||||||
|
await showFloatingFlushBar(
|
||||||
|
type: FlushBarType.success,
|
||||||
|
message: "SVG MonKey image saved",
|
||||||
|
context: context,
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(height: 12),
|
const SizedBox(height: 12),
|
||||||
SecondaryButton(
|
SecondaryButton(
|
||||||
label: "Download as PNG",
|
label: "Download as PNG",
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
|
bool didError = false;
|
||||||
await showLoading(
|
await showLoading(
|
||||||
whileFuture:
|
whileFuture: Future.wait([
|
||||||
downloadMonkey(receivingAddress, true),
|
manager.currentReceivingAddress.then(
|
||||||
|
(address) async => await ref
|
||||||
|
.read(pMonKeyService)
|
||||||
|
.fetchMonKey(
|
||||||
|
address: address,
|
||||||
|
png: true,
|
||||||
|
)
|
||||||
|
.then(
|
||||||
|
(monKeyBytes) async =>
|
||||||
|
await _saveMonKeyToFile(
|
||||||
|
bytes: monKeyBytes,
|
||||||
|
isPNG: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Future<void>.delayed(
|
||||||
|
const Duration(seconds: 2)),
|
||||||
|
]),
|
||||||
context: context,
|
context: context,
|
||||||
isDesktop: Util.isDesktop,
|
isDesktop: Util.isDesktop,
|
||||||
message: "Downloading MonKey png",
|
message: "Downloading MonKey png",
|
||||||
|
onException: (e) {
|
||||||
|
didError = true;
|
||||||
|
String msg = e.toString();
|
||||||
|
while (msg.isNotEmpty &&
|
||||||
|
msg.startsWith("Exception:")) {
|
||||||
|
msg = msg.substring(10).trim();
|
||||||
|
}
|
||||||
|
showFloatingFlushBar(
|
||||||
|
type: FlushBarType.warning,
|
||||||
|
message: msg,
|
||||||
|
context: context,
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (!didError && mounted) {
|
||||||
|
await showFloatingFlushBar(
|
||||||
|
type: FlushBarType.success,
|
||||||
|
message: "PNG MonKey image saved",
|
||||||
|
context: context,
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -453,17 +429,37 @@ class _MonkeyViewState extends ConsumerState<MonkeyView> {
|
||||||
child: PrimaryButton(
|
child: PrimaryButton(
|
||||||
label: "Fetch MonKey",
|
label: "Fetch MonKey",
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
final future = Future.wait([
|
|
||||||
getMonkeyImage(receivingAddress),
|
|
||||||
Future<void>.delayed(const Duration(seconds: 2)),
|
|
||||||
]);
|
|
||||||
|
|
||||||
await showLoading(
|
await showLoading(
|
||||||
whileFuture: future,
|
whileFuture: Future.wait([
|
||||||
|
manager.currentReceivingAddress.then(
|
||||||
|
(address) async => await ref
|
||||||
|
.read(pMonKeyService)
|
||||||
|
.fetchMonKey(address: address)
|
||||||
|
.then(
|
||||||
|
(monKeyBytes) async =>
|
||||||
|
await _updateWalletMonKey(
|
||||||
|
monKeyBytes,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Future<void>.delayed(const Duration(seconds: 2)),
|
||||||
|
]),
|
||||||
context: context,
|
context: context,
|
||||||
isDesktop: Util.isDesktop,
|
isDesktop: Util.isDesktop,
|
||||||
message: "Fetching MonKey",
|
message: "Fetching MonKey",
|
||||||
subMessage: "We are fetching your MonKey",
|
subMessage: "We are fetching your MonKey",
|
||||||
|
onException: (e) {
|
||||||
|
String msg = e.toString();
|
||||||
|
while (msg.isNotEmpty &&
|
||||||
|
msg.startsWith("Exception:")) {
|
||||||
|
msg = msg.substring(10).trim();
|
||||||
|
}
|
||||||
|
showFloatingFlushBar(
|
||||||
|
type: FlushBarType.warning,
|
||||||
|
message: msg,
|
||||||
|
context: context,
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
imageBytes = (manager.wallet as BananoWallet)
|
imageBytes = (manager.wallet as BananoWallet)
|
||||||
|
@ -472,17 +468,6 @@ class _MonkeyViewState extends ConsumerState<MonkeyView> {
|
||||||
if (imageBytes != null) {
|
if (imageBytes != null) {
|
||||||
setState(() {});
|
setState(() {});
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (isDesktop) {
|
|
||||||
// Navigator.of(context).popUntil(
|
|
||||||
// ModalRoute.withName(
|
|
||||||
// DesktopWalletView.routeName),
|
|
||||||
// );
|
|
||||||
// } else {
|
|
||||||
// Navigator.of(context).popUntil(
|
|
||||||
// ModalRoute.withName(WalletView.routeName),
|
|
||||||
// );
|
|
||||||
// }
|
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
40
lib/services/monkey_service.dart
Normal file
40
lib/services/monkey_service.dart
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
import 'dart:typed_data';
|
||||||
|
|
||||||
|
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'package:stackwallet/utilities/logger.dart';
|
||||||
|
|
||||||
|
final pMonKeyService = Provider((ref) => MonKeyService());
|
||||||
|
|
||||||
|
class MonKeyService {
|
||||||
|
static const baseURL = "https://monkey.banano.cc/api/v1/monkey/";
|
||||||
|
|
||||||
|
Future<Uint8List> fetchMonKey({
|
||||||
|
required String address,
|
||||||
|
bool png = false,
|
||||||
|
}) async {
|
||||||
|
try {
|
||||||
|
String url = "https://monkey.banano.cc/api/v1/monkey/$address";
|
||||||
|
|
||||||
|
if (png) {
|
||||||
|
url += '?format=png&size=512&background=false';
|
||||||
|
}
|
||||||
|
|
||||||
|
final response = await http.get(Uri.parse(url));
|
||||||
|
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
return response.bodyBytes;
|
||||||
|
} else {
|
||||||
|
throw Exception(
|
||||||
|
"statusCode=${response.statusCode} body=${response.body}",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e, s) {
|
||||||
|
Logging.instance.log(
|
||||||
|
"Failed fetchMonKey($address): $e\n$s",
|
||||||
|
level: LogLevel.Error,
|
||||||
|
);
|
||||||
|
rethrow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue