use an OrdinalsResponse response type which can return an error

This commit is contained in:
sneurlax 2023-07-19 13:03:17 -05:00
parent d3b4be5d66
commit 8e17556e41
12 changed files with 148 additions and 98 deletions

View file

@ -1,6 +1,7 @@
import 'package:stackwallet/dto/ordinals/inscription_link.dart'; import 'package:stackwallet/dto/ordinals/inscription_link.dart';
import 'package:stackwallet/dto/ordinals/ordinals_response.dart';
class AddressResponse { class AddressResponse extends OrdinalsResponse<AddressResponse> {
final AddressLinks links; final AddressLinks links;
final String address; final String address;
final List<InscriptionLink> inscriptions; final List<InscriptionLink> inscriptions;
@ -11,15 +12,16 @@ class AddressResponse {
required this.inscriptions, required this.inscriptions,
}); });
factory AddressResponse.fromJson(Map<String, dynamic> json) { factory AddressResponse.fromJson(OrdinalsResponse json) {
final inscriptionsJson = json['inscriptions'] as List; final data = json.data as Map<String, dynamic>;
final inscriptionsJson = data['inscriptions'] as List;
final inscriptions = inscriptionsJson final inscriptions = inscriptionsJson
.map((inscriptionJson) => InscriptionLink.fromJson(inscriptionJson as Map<String, dynamic>)) .map((inscriptionJson) => InscriptionLink.fromJson(inscriptionJson as Map<String, dynamic>))
.toList(); .toList();
return AddressResponse( return AddressResponse(
links: AddressLinks.fromJson(json['_links'] as Map<String, dynamic>), links: AddressLinks.fromJson(data['_links'] as Map<String, dynamic>),
address: json['address'] as String, address: data['address'] as String,
inscriptions: inscriptions, inscriptions: inscriptions,
); );
} }
@ -34,7 +36,7 @@ class AddressLinks {
factory AddressLinks.fromJson(Map<String, dynamic> json) { factory AddressLinks.fromJson(Map<String, dynamic> json) {
return AddressLinks( return AddressLinks(
self: AddressLink.fromJson(json['self'] as Map<String, dynamic>), self: json['self'] != null ? AddressLink.fromJson(json['self'] as Map<String, dynamic>) : null,
); );
} }
} }

View file

@ -1,4 +1,6 @@
class BlockResponse { import 'package:stackwallet/dto/ordinals/ordinals_response.dart';
class BlockResponse extends OrdinalsResponse<BlockResponse> {
final BlockLinks links; final BlockLinks links;
final String hash; final String hash;
final String previousBlockhash; final String previousBlockhash;
@ -17,15 +19,16 @@ class BlockResponse {
required this.weight, required this.weight,
}); });
factory BlockResponse.fromJson(Map<String, dynamic> json) { factory BlockResponse.fromJson(OrdinalsResponse json) {
final data = json.data as Map<String, dynamic>;
return BlockResponse( return BlockResponse(
links: BlockLinks.fromJson(json['_links'] as Map<String, dynamic>), links: BlockLinks.fromJson(data['_links'] as Map<String, dynamic>),
hash: json['hash'] as String, hash: data['hash'] as String,
previousBlockhash: json['previous_blockhash'] as String, previousBlockhash: data['previous_blockhash'] as String,
size: json['size'] as int, size: data['size'] as int,
target: json['target'] as String, target: data['target'] as String,
timestamp: json['timestamp'] as String, timestamp: data['timestamp'] as String,
weight: json['weight'] as int, weight: data['weight'] as int,
); );
} }
} }
@ -41,8 +44,8 @@ class BlockLinks {
factory BlockLinks.fromJson(Map<String, dynamic> json) { factory BlockLinks.fromJson(Map<String, dynamic> json) {
return BlockLinks( return BlockLinks(
prev: BlockLink.fromJson(json['prev'] as Map<String, dynamic>), prev: json['prev'] != null ? BlockLink.fromJson(json['prev'] as Map<String, dynamic>) : null,
self: BlockLink.fromJson(json['self'] as Map<String, dynamic>), self: json['self'] != null ? BlockLink.fromJson(json['self'] as Map<String, dynamic>) : null,
); );
} }
} }

View file

@ -1,10 +1,13 @@
class ContentResponse { import 'package:stackwallet/dto/ordinals/ordinals_response.dart';
class ContentResponse extends OrdinalsResponse<ContentResponse> {
final FileLink fileLink; final FileLink fileLink;
ContentResponse({required this.fileLink}); ContentResponse({required this.fileLink});
factory ContentResponse.fromJson(Map<String, dynamic> json) { factory ContentResponse.fromJson(OrdinalsResponse json) {
return ContentResponse(fileLink: FileLink.fromJson(json['_links']['file'] as Map<String, dynamic>)); final data = json.data as Map<String, dynamic>;
return ContentResponse(fileLink: FileLink.fromJson(data['_links']['file'] as Map<String, dynamic>)); // TODO don't cast as Map<String, dynamic>
} }
} }

View file

@ -1,16 +1,17 @@
import 'package:stackwallet/dto/ordinals/inscription_link.dart'; import 'package:stackwallet/dto/ordinals/inscription_link.dart';
import 'package:stackwallet/dto/ordinals/ordinals_response.dart';
class FeedResponse { class FeedResponse extends OrdinalsResponse<FeedResponse> {
final List<InscriptionLink> inscriptions; final List<InscriptionLink> inscriptions;
FeedResponse({required this.inscriptions}); FeedResponse({required this.inscriptions});
factory FeedResponse.fromJson(Map<String, dynamic> json) { factory FeedResponse.fromJson(OrdinalsResponse json) {
final List<dynamic> inscriptionsJson = json['_links']['inscriptions'] as List<dynamic>; final List<dynamic> inscriptionsJson = json.data['_links']['inscriptions'] as List<dynamic>;
final List<InscriptionLink> inscriptions = inscriptionsJson final List<InscriptionLink> inscriptions = inscriptionsJson
.map((json) => InscriptionLink.fromJson(json as Map<String, dynamic>)) .map((json) => InscriptionLink.fromJson(json as Map<String, dynamic>))
.toList(); .toList();
return FeedResponse(inscriptions: inscriptions); return FeedResponse(inscriptions: inscriptions);
} }
} }

View file

@ -1,4 +1,6 @@
class InscriptionResponse { import 'package:stackwallet/dto/ordinals/ordinals_response.dart';
class InscriptionResponse extends OrdinalsResponse<InscriptionResponse> {
late final Links links; late final Links links;
late final String address; late final String address;
late final int contentLength; late final int contentLength;
@ -29,20 +31,23 @@ class InscriptionResponse {
required this.timestamp, required this.timestamp,
}); });
InscriptionResponse.fromJson(Map<String, dynamic> json) { factory InscriptionResponse.fromJson(OrdinalsResponse json) {
links = Links.fromJson(json['_links'] as Map<String, dynamic>); final data = json.data as Map<String, dynamic>;
address = json['address'] as String; return InscriptionResponse(
contentLength = json['content_length'] as int; links: Links.fromJson(data['_links'] as Map<String, dynamic>),
contentType = json['content_type'] as String; address: data['address'] as String,
genesisFee = json['genesis_fee'] as int; contentLength: data['content_length'] as int,
genesisHeight = json['genesis_height'] as int; contentType: data['content_type'] as String,
genesisTransaction = json['genesis_transaction'] as String; genesisFee: data['genesis_fee'] as int,
location = json['location'] as String; genesisHeight: data['genesis_height'] as int,
number = json['number'] as int; genesisTransaction: data['genesis_transaction'] as String,
offset = json['offset'] as int; location: data['location'] as String,
output = json['output'] as String; number: data['number'] as int,
sat = json['sat'] as String?; offset: data['offset'] as int,
timestamp = json['timestamp'] as String; output: data['output'] as String,
sat: data['sat'] as String?,
timestamp: data['timestamp'] as String,
);
} }
} }
@ -67,15 +72,17 @@ class Links {
required this.self, required this.self,
}); });
Links.fromJson(Map<String, dynamic> json) { factory Links.fromJson(Map<String, dynamic> json) {
content = Link.fromJson(json['content'] as Map<String, dynamic>); return Links(
genesisTransaction = Link.fromJson(json['genesis_transaction'] as Map<String, dynamic>); content: Link.fromJson(json['content'] as Map<String, dynamic>),
next = Link.fromJson(json['next'] as Map<String, dynamic>); genesisTransaction: Link.fromJson(json['genesis_transaction'] as Map<String, dynamic>),
output = Link.fromJson(json['output'] as Map<String, dynamic>); next: Link.fromJson(json['next'] as Map<String, dynamic>),
prev = Link.fromJson(json['prev'] as Map<String, dynamic>); output: Link.fromJson(json['output'] as Map<String, dynamic>),
preview = Link.fromJson(json['preview'] as Map<String, dynamic>); prev: Link.fromJson(json['prev'] as Map<String, dynamic>),
sat = json['sat'] != null ? Link.fromJson(json['sat'] as Map<String, dynamic>) : null; preview: Link.fromJson(json['preview'] as Map<String, dynamic>),
self = Link.fromJson(json['self'] as Map<String, dynamic>); sat: json['sat'] != null ? Link.fromJson(json['sat'] as Map<String, dynamic>) : null,
self: Link.fromJson(json['self'] as Map<String, dynamic>),
);
} }
} }
@ -84,7 +91,7 @@ class Link {
Link({required this.href}); Link({required this.href});
Link.fromJson(Map<String, dynamic> json) { factory Link.fromJson(Map<String, dynamic> json) {
href = json['href'] as String; return Link(href: json['href'] as String);
} }
} }

View file

@ -0,0 +1,6 @@
class OrdinalsResponse<T> {
final T? data;
final String? error;
OrdinalsResponse({this.data, this.error});
}

View file

@ -1,6 +1,7 @@
import 'package:stackwallet/dto/ordinals/transaction_response.dart'; import 'package:stackwallet/dto/ordinals/transaction_response.dart';
import 'package:stackwallet/dto/ordinals/ordinals_response.dart';
class OutputResponse { class OutputResponse extends OrdinalsResponse<OutputResponse> {
final OutputLinks links; final OutputLinks links;
final String address; final String address;
final String scriptPubkey; final String scriptPubkey;
@ -15,13 +16,15 @@ class OutputResponse {
required this.value, required this.value,
}); });
factory OutputResponse.fromJson(Map<String, dynamic> json) { factory OutputResponse.fromJson(OrdinalsResponse json) {
final data = json.data as Map<String, dynamic>;
return OutputResponse( return OutputResponse(
links: OutputLinks.fromJson(json['_links'] as Map<String, dynamic>), links: OutputLinks.fromJson(data['_links'] as Map<String, dynamic>),
address: json['address'] as String, address: data['address'] as String,
scriptPubkey: json['script_pubkey'] as String, scriptPubkey: data['script_pubkey'] as String,
transaction: json['transaction'] as String, transaction: data['transaction'] as String,
value: json['value'] as int, value: data['value'] as int,
); );
} }
} }
@ -37,8 +40,8 @@ class OutputLinks {
factory OutputLinks.fromJson(Map<String, dynamic> json) { factory OutputLinks.fromJson(Map<String, dynamic> json) {
return OutputLinks( return OutputLinks(
self: OutputLink.fromJson(json['self'] as Map<String, dynamic>), self: json['self'] != null ? OutputLink.fromJson(json['self'] as Map<String, dynamic>) : null,
transaction: TransactionLink.fromJson(json['transaction'] as Map<String, dynamic>), transaction: json['transaction'] != null ? TransactionLink.fromJson(json['transaction'] as Map<String, dynamic>) : null,
); );
} }
} }

View file

@ -1,10 +1,13 @@
class PreviewResponse { import 'package:stackwallet/dto/ordinals/ordinals_response.dart';
class PreviewResponse extends OrdinalsResponse<PreviewResponse> {
final ImageLink imageLink; final ImageLink imageLink;
PreviewResponse({required this.imageLink}); PreviewResponse({required this.imageLink});
factory PreviewResponse.fromJson(Map<String, dynamic> json) { factory PreviewResponse.fromJson(OrdinalsResponse json) {
return PreviewResponse(imageLink: ImageLink.fromJson(json['_links']['image'] as Map<String, dynamic>)); final data = json.data as Map<String, dynamic>;
return PreviewResponse(imageLink: ImageLink.fromJson(data['_links']['image'] as Map<String, dynamic>));
} }
} }
@ -16,4 +19,4 @@ class ImageLink {
factory ImageLink.fromJson(Map<String, dynamic> json) { factory ImageLink.fromJson(Map<String, dynamic> json) {
return ImageLink(href: json['href'] as String); return ImageLink(href: json['href'] as String);
} }
} }

View file

@ -1,4 +1,6 @@
class SatResponse { import 'package:stackwallet/dto/ordinals/ordinals_response.dart';
class SatResponse extends OrdinalsResponse<SatResponse> {
final SatLinks links; final SatLinks links;
final int block; final int block;
final int cycle; final int cycle;
@ -27,20 +29,21 @@ class SatResponse {
required this.timestamp, required this.timestamp,
}); });
factory SatResponse.fromJson(Map<String, dynamic> json) { factory SatResponse.fromJson(OrdinalsResponse json) {
final data = json.data as Map<String, dynamic>;
return SatResponse( return SatResponse(
links: SatLinks.fromJson(json['_links'] as Map<String, dynamic>), links: SatLinks.fromJson(data['_links'] as Map<String, dynamic>),
block: json['block'] as int, block: data['block'] as int,
cycle: json['cycle'] as int, cycle: data['cycle'] as int,
decimal: json['decimal'] as String, decimal: data['decimal'] as String,
degree: json['degree'] as String, degree: data['degree'] as String,
epoch: json['epoch'] as int, epoch: data['epoch'] as int,
name: json['name'] as String, name: data['name'] as String,
offset: json['offset'] as int, offset: data['offset'] as int,
percentile: json['percentile'] as String, percentile: data['percentile'] as String,
period: json['period'] as int, period: data['period'] as int,
rarity: json['rarity'] as String, rarity: data['rarity'] as String,
timestamp: json['timestamp'] as String, timestamp: data['timestamp'] as String,
); );
} }
} }
@ -62,11 +65,11 @@ class SatLinks {
factory SatLinks.fromJson(Map<String, dynamic> json) { factory SatLinks.fromJson(Map<String, dynamic> json) {
return SatLinks( return SatLinks(
block: SatLink.fromJson(json['block'] as Map<String, dynamic>), block: json['block'] != null ? SatLink.fromJson(json['block'] as Map<String, dynamic>) : null,
inscription: SatLink.fromJson(json['inscription'] as Map<String, dynamic>), inscription: json['inscription'] != null ? SatLink.fromJson(json['inscription'] as Map<String, dynamic>) : null,
next: SatLink.fromJson(json['next'] as Map<String, dynamic>), next: json['next'] != null ? SatLink.fromJson(json['next'] as Map<String, dynamic>) : null,
prev: SatLink.fromJson(json['prev'] as Map<String, dynamic>), prev: json['prev'] != null ? SatLink.fromJson(json['prev'] as Map<String, dynamic>) : null,
self: SatLink.fromJson(json['self'] as Map<String, dynamic>), self: json['self'] != null ? SatLink.fromJson(json['self'] as Map<String, dynamic>) : null,
); );
} }
} }

View file

@ -1,6 +1,7 @@
import 'package:stackwallet/dto/ordinals/inscription_link.dart'; import 'package:stackwallet/dto/ordinals/inscription_link.dart';
import 'package:stackwallet/dto/ordinals/ordinals_response.dart';
class TransactionResponse { class TransactionResponse extends OrdinalsResponse<TransactionResponse> {
final TransactionLinks links; final TransactionLinks links;
final List<OutputLink> inputs; final List<OutputLink> inputs;
final InscriptionLink inscription; final InscriptionLink inscription;
@ -17,24 +18,25 @@ class TransactionResponse {
required this.transaction, required this.transaction,
}); });
factory TransactionResponse.fromJson(Map<String, dynamic> json) { factory TransactionResponse.fromJson(OrdinalsResponse json) {
final inputsJson = json['_links']['inputs'] as List; final data = json.data as Map<String, dynamic>;
final inputsJson = data['_links']['inputs'] as List;
final inputs = inputsJson final inputs = inputsJson
.map((inputJson) => OutputLink.fromJson(inputJson as Map<String, dynamic>)) .map((inputJson) => OutputLink.fromJson(inputJson as Map<String, dynamic>))
.toList(); .toList();
final outputsJson = json['_links']['outputs'] as List; final outputsJson = data['_links']['outputs'] as List;
final outputs = outputsJson final outputs = outputsJson
.map((outputJson) => OutputLink.fromJson(outputJson as Map<String, dynamic>)) .map((outputJson) => OutputLink.fromJson(outputJson as Map<String, dynamic>))
.toList(); .toList();
return TransactionResponse( return TransactionResponse(
links: TransactionLinks.fromJson(json['_links'] as Map<String, dynamic>), links: TransactionLinks.fromJson(data['_links'] as Map<String, dynamic>),
inputs: inputs, inputs: inputs,
inscription: InscriptionLink.fromJson(json['_links']['inscription'] as Map<String, dynamic>), inscription: InscriptionLink.fromJson(data['_links']['inscription'] as Map<String, dynamic>),
outputs: outputs, outputs: outputs,
self: TransactionLink.fromJson(json['_links']['self'] as Map<String, dynamic>), self: TransactionLink.fromJson(data['_links']['self'] as Map<String, dynamic>),
transaction: json['transaction'] as String, transaction: data['transaction'] as String,
); );
} }
} }
@ -52,9 +54,9 @@ class TransactionLinks {
factory TransactionLinks.fromJson(Map<String, dynamic> json) { factory TransactionLinks.fromJson(Map<String, dynamic> json) {
return TransactionLinks( return TransactionLinks(
block: TransactionLink.fromJson(json['block'] as Map<String, dynamic>), block: json['block'] != null ? TransactionLink.fromJson(json['block'] as Map<String, dynamic>) : null,
inscription: InscriptionLink.fromJson(json['inscription'] as Map<String, dynamic>), inscription: json['inscription'] != null ? InscriptionLink.fromJson(json['inscription'] as Map<String, dynamic>) : null,
self: TransactionLink.fromJson(json['self'] as Map<String, dynamic>), self: json['self'] != null ? TransactionLink.fromJson(json['self'] as Map<String, dynamic>) : null,
); );
} }
} }

View file

@ -1,3 +1,19 @@
import 'package:stackwallet/services/ordinals_api.dart';
import 'package:stackwallet/dto/ordinals/feed_response.dart';
mixin OrdinalsInterface { mixin OrdinalsInterface {
// TODO wallet ordinals functionality Future<FeedResponse> fetchLatestInscriptions(OrdinalsAPI ordinalsAPI) async {
try {
final feedResponse = await ordinalsAPI.getLatestInscriptions();
// Process the feedResponse data as needed
print('Latest Inscriptions:');
for (var inscription in feedResponse.inscriptions) {
print('Title: ${inscription.title}, Href: ${inscription.href}');
}
return feedResponse;
} catch (e) {
// Handle errors
throw Exception('Error in OrdinalsInterface: $e');
}
}
} }

View file

@ -1,6 +1,7 @@
import 'dart:convert'; import 'dart:convert';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:stackwallet/dto/ordinals/ordinals_response.dart';
import 'package:stackwallet/dto/ordinals/feed_response.dart'; import 'package:stackwallet/dto/ordinals/feed_response.dart';
import 'package:stackwallet/dto/ordinals/inscription_response.dart'; import 'package:stackwallet/dto/ordinals/inscription_response.dart';
import 'package:stackwallet/dto/ordinals/sat_response.dart'; import 'package:stackwallet/dto/ordinals/sat_response.dart';
@ -16,10 +17,10 @@ class OrdinalsAPI {
OrdinalsAPI({required this.baseUrl}); OrdinalsAPI({required this.baseUrl});
Future<Map<String, dynamic>> _getResponse(String endpoint) async { Future<OrdinalsResponse> _getResponse(String endpoint) async {
final response = await http.get(Uri.parse('$baseUrl$endpoint')); final response = await http.get(Uri.parse('$baseUrl$endpoint'));
if (response.statusCode == 200) { if (response.statusCode == 200) {
return _validateJson(response.body); return OrdinalsResponse(data: _validateJson(response.body));
} else { } else {
throw Exception('Failed to load data'); throw Exception('Failed to load data');
} }