From b60e3fbf1bc58554207f0b27c1b81f6feb47f194 Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Tue, 18 Jul 2023 16:36:26 -0500 Subject: [PATCH 01/31] add dtos for ord-litecoin documented endpoint responses --- lib/dto/ordinals/address_response.dart | 48 +++++++++++ lib/dto/ordinals/block_response.dart | 58 +++++++++++++ lib/dto/ordinals/content_response.dart | 19 +++++ lib/dto/ordinals/feed_response.dart | 14 ++++ lib/dto/ordinals/inscription_response.dart | 95 ++++++++++++++++++++++ lib/dto/ordinals/output_response | 42 ++++++++++ lib/dto/ordinals/preview_response.dart | 19 +++++ lib/dto/ordinals/sat_response.dart | 82 +++++++++++++++++++ lib/dto/ordinals/transaction_response.dart | 78 ++++++++++++++++++ 9 files changed, 455 insertions(+) create mode 100644 lib/dto/ordinals/address_response.dart create mode 100644 lib/dto/ordinals/block_response.dart create mode 100644 lib/dto/ordinals/content_response.dart create mode 100644 lib/dto/ordinals/feed_response.dart create mode 100644 lib/dto/ordinals/inscription_response.dart create mode 100644 lib/dto/ordinals/output_response create mode 100644 lib/dto/ordinals/preview_response.dart create mode 100644 lib/dto/ordinals/sat_response.dart create mode 100644 lib/dto/ordinals/transaction_response.dart diff --git a/lib/dto/ordinals/address_response.dart b/lib/dto/ordinals/address_response.dart new file mode 100644 index 000000000..024543b92 --- /dev/null +++ b/lib/dto/ordinals/address_response.dart @@ -0,0 +1,48 @@ +class AddressResponse { + final AddressLinks links; + final String address; + final List<InscriptionLink> inscriptions; + + AddressResponse({ + required this.links, + required this.address, + required this.inscriptions, + }); + + factory AddressResponse.fromJson(Map<String, dynamic> json) { + final inscriptionsJson = json['inscriptions'] as List; + final inscriptions = inscriptionsJson + .map((inscriptionJson) => InscriptionLink.fromJson(inscriptionJson)) + .toList(); + + return AddressResponse( + links: AddressLinks.fromJson(json['_links']), + address: json['address'], + inscriptions: inscriptions, + ); + } +} + +class AddressLinks { + final AddressLink? self; + + AddressLinks({ + this.self, + }); + + factory AddressLinks.fromJson(Map<String, dynamic> json) { + return AddressLinks( + self: AddressLink.fromJson(json['self']), + ); + } +} + +class AddressLink { + final String href; + + AddressLink({required this.href}); + + factory AddressLink.fromJson(Map<String, dynamic> json) { + return AddressLink(href: json['href']); + } +} diff --git a/lib/dto/ordinals/block_response.dart b/lib/dto/ordinals/block_response.dart new file mode 100644 index 000000000..365098594 --- /dev/null +++ b/lib/dto/ordinals/block_response.dart @@ -0,0 +1,58 @@ +class BlockResponse { + final BlockLinks links; + final String hash; + final String previousBlockhash; + final int size; + final String target; + final String timestamp; + final int weight; + + BlockResponse({ + required this.links, + required this.hash, + required this.previousBlockhash, + required this.size, + required this.target, + required this.timestamp, + required this.weight, + }); + + factory BlockResponse.fromJson(Map<String, dynamic> json) { + return BlockResponse( + links: BlockLinks.fromJson(json['_links']), + hash: json['hash'], + previousBlockhash: json['previous_blockhash'], + size: json['size'], + target: json['target'], + timestamp: json['timestamp'], + weight: json['weight'], + ); + } +} + +class BlockLinks { + final BlockLink? prev; + final BlockLink? self; + + BlockLinks({ + this.prev, + this.self, + }); + + factory BlockLinks.fromJson(Map<String, dynamic> json) { + return BlockLinks( + prev: BlockLink.fromJson(json['prev']), + self: BlockLink.fromJson(json['self']), + ); + } +} + +class BlockLink { + final String href; + + BlockLink({required this.href}); + + factory BlockLink.fromJson(Map<String, dynamic> json) { + return BlockLink(href: json['href']); + } +} diff --git a/lib/dto/ordinals/content_response.dart b/lib/dto/ordinals/content_response.dart new file mode 100644 index 000000000..35a2c8ef8 --- /dev/null +++ b/lib/dto/ordinals/content_response.dart @@ -0,0 +1,19 @@ +class ContentResponse { + final FileLink fileLink; + + ContentResponse({required this.fileLink}); + + factory ContentResponse.fromJson(Map<String, dynamic> json) { + return ContentResponse(fileLink: FileLink.fromJson(json['_links']['file'])); + } +} + +class FileLink { + final String href; + + FileLink({required this.href}); + + factory FileLink.fromJson(Map<String, dynamic> json) { + return FileLink(href: json['href']); + } +} diff --git a/lib/dto/ordinals/feed_response.dart b/lib/dto/ordinals/feed_response.dart new file mode 100644 index 000000000..b6af1c1ca --- /dev/null +++ b/lib/dto/ordinals/feed_response.dart @@ -0,0 +1,14 @@ +class FeedResponse { + final List<InscriptionLink> inscriptions; + + FeedResponse(this.inscriptions); + + factory FeedResponse.fromJson(Map<String, dynamic> json) { + final inscriptionsJson = json['_links']['inscriptions'] as List; + final inscriptions = inscriptionsJson + .map((inscriptionJson) => InscriptionLink.fromJson(inscriptionJson)) + .toList(); + + return FeedResponse(inscriptions); + } +} diff --git a/lib/dto/ordinals/inscription_response.dart b/lib/dto/ordinals/inscription_response.dart new file mode 100644 index 000000000..e06ddca6d --- /dev/null +++ b/lib/dto/ordinals/inscription_response.dart @@ -0,0 +1,95 @@ +class InscriptionResponse { + final InscriptionLinks links; + final String address; + final int contentLength; + final String contentType; + final int genesisFee; + final int genesisHeight; + final String genesisTransaction; + final String location; + final int number; + final int offset; + final String output; + final dynamic sat; // Change to appropriate type if available + final String timestamp; + + InscriptionResponse({ + required this.links, + required this.address, + required this.contentLength, + required this.contentType, + required this.genesisFee, + required this.genesisHeight, + required this.genesisTransaction, + required this.location, + required this.number, + required this.offset, + required this.output, + required this.sat, + required this.timestamp, + }); + + factory InscriptionResponse.fromJson(Map<String, dynamic> json) { + return InscriptionResponse( + links: InscriptionLinks.fromJson(json['_links']), + address: json['address'], + contentLength: json['content_length'], + contentType: json['content_type'], + genesisFee: json['genesis_fee'], + genesisHeight: json['genesis_height'], + genesisTransaction: json['genesis_transaction'], + location: json['location'], + number: json['number'], + offset: json['offset'], + output: json['output'], + sat: json['sat'], + timestamp: json['timestamp'], + ); + } +} + +class InscriptionLinks { + final InscriptionLink? content; + final InscriptionLink? genesisTransaction; + final InscriptionLink? next; + final InscriptionLink? output; + final InscriptionLink? prev; + final InscriptionLink? preview; + final InscriptionLink? sat; + final InscriptionLink? self; + + InscriptionLinks({ + this.content, + this.genesisTransaction, + this.next, + this.output, + this.prev, + this.preview, + this.sat, + this.self, + }); + + factory InscriptionLinks.fromJson(Map<String, dynamic> json) { + return InscriptionLinks( + content: InscriptionLink.fromJson(json['content']), + genesisTransaction: InscriptionLink.fromJson(json['genesis_transaction']), + next: InscriptionLink.fromJson(json['next']), + output: InscriptionLink.fromJson(json['output']), + prev: InscriptionLink.fromJson(json['prev']), + preview: InscriptionLink.fromJson(json['preview']), + sat: InscriptionLink.fromJson(json['sat']), + self: InscriptionLink.fromJson(json['self']), + ); + } +} + +class InscriptionLink { + final String href; + final String title; + + InscriptionLink({required this.href, required this.title}); + + factory InscriptionLink.fromJson(Map<String, dynamic> json) { + return InscriptionLink(href: json['href'], title: json['title']); + } +} diff --git a/lib/dto/ordinals/output_response b/lib/dto/ordinals/output_response new file mode 100644 index 000000000..cd25fe961 --- /dev/null +++ b/lib/dto/ordinals/output_response @@ -0,0 +1,42 @@ +class OutputResponse { + final OutputLinks links; + final String address; + final String scriptPubkey; + final String transaction; + final int value; + + OutputResponse({ + required this.links, + required this.address, + required this.scriptPubkey, + required this.transaction, + required this.value, + }); + + factory OutputResponse.fromJson(Map<String, dynamic> json) { + return OutputResponse( + links: OutputLinks.fromJson(json['_links']), + address: json['address'], + scriptPubkey: json['script_pubkey'], + transaction: json['transaction'], + value: json['value'], + ); + } +} + +class OutputLinks { + final OutputLink? self; + final TransactionLink? transaction; + + OutputLinks({ + this.self, + this.transaction, + }); + + factory OutputLinks.fromJson(Map<String, dynamic> json) { + return OutputLinks( + self: OutputLink.fromJson(json['self']), + transaction: TransactionLink.fromJson(json['transaction']), + ); + } +} \ No newline at end of file diff --git a/lib/dto/ordinals/preview_response.dart b/lib/dto/ordinals/preview_response.dart new file mode 100644 index 000000000..d7171702d --- /dev/null +++ b/lib/dto/ordinals/preview_response.dart @@ -0,0 +1,19 @@ +class PreviewResponse { + final ImageLink imageLink; + + PreviewResponse({required this.imageLink}); + + factory PreviewResponse.fromJson(Map<String, dynamic> json) { + return PreviewResponse(imageLink: ImageLink.fromJson(json['_links']['image'])); + } +} + +class ImageLink { + final String href; + + ImageLink({required this.href}); + + factory ImageLink.fromJson(Map<String, dynamic> json) { + return ImageLink(href: json['href']); + } +} \ No newline at end of file diff --git a/lib/dto/ordinals/sat_response.dart b/lib/dto/ordinals/sat_response.dart new file mode 100644 index 000000000..0f88918f3 --- /dev/null +++ b/lib/dto/ordinals/sat_response.dart @@ -0,0 +1,82 @@ +class SatResponse { + final SatLinks links; + final int block; + final int cycle; + final String decimal; + final String degree; + final int epoch; + final String name; + final int offset; + final String percentile; + final int period; + final String rarity; + final String timestamp; + + SatResponse({ + required this.links, + required this.block, + required this.cycle, + required this.decimal, + required this.degree, + required this.epoch, + required this.name, + required this.offset, + required this.percentile, + required this.period, + required this.rarity, + required this.timestamp, + }); + + factory SatResponse.fromJson(Map<String, dynamic> json) { + return SatResponse( + links: SatLinks.fromJson(json['_links']), + block: json['block'], + cycle: json['cycle'], + decimal: json['decimal'], + degree: json['degree'], + epoch: json['epoch'], + name: json['name'], + offset: json['offset'], + percentile: json['percentile'], + period: json['period'], + rarity: json['rarity'], + timestamp: json['timestamp'], + ); + } +} + +class SatLinks { + final SatLink? block; + final SatLink? inscription; + final SatLink? next; + final SatLink? prev; + final SatLink? self; + + SatLinks({ + this.block, + this.inscription, + this.next, + this.prev, + this.self, + }); + + factory SatLinks.fromJson(Map<String, dynamic> json) { + return SatLinks( + block: SatLink.fromJson(json['block']), + inscription: SatLink.fromJson(json['inscription']), + next: SatLink.fromJson(json['next']), + prev: SatLink.fromJson(json['prev']), + self: SatLink.fromJson(json['self']), + ); + } +} + +class SatLink { + final String href; + + SatLink({required this.href}); + + factory SatLink.fromJson(Map<String, dynamic> json) { + return SatLink(href: json['href']); + } +} diff --git a/lib/dto/ordinals/transaction_response.dart b/lib/dto/ordinals/transaction_response.dart new file mode 100644 index 000000000..b030a1daa --- /dev/null +++ b/lib/dto/ordinals/transaction_response.dart @@ -0,0 +1,78 @@ +class TransactionResponse { + final TransactionLinks links; + final List<OutputLink> inputs; + final InscriptionLink inscription; + final List<OutputLink> outputs; + final TransactionLink self; + final String transaction; + + TransactionResponse({ + required this.links, + required this.inputs, + required this.inscription, + required this.outputs, + required this.self, + required this.transaction, + }); + + factory TransactionResponse.fromJson(Map<String, dynamic> json) { + final inputsJson = json['_links']['inputs'] as List; + final inputs = inputsJson + .map((inputJson) => OutputLink.fromJson(inputJson)) + .toList(); + + final outputsJson = json['_links']['outputs'] as List; + final outputs = outputsJson + .map((outputJson) => OutputLink.fromJson(outputJson)) + .toList(); + + return TransactionResponse( + links: TransactionLinks.fromJson(json['_links']), + inputs: inputs, + inscription: InscriptionLink.fromJson(json['_links']['inscription']), + outputs: outputs, + self: TransactionLink.fromJson(json['_links']['self']), + transaction: json['transaction'], + ); + } +} + +class TransactionLinks { + final TransactionLink? block; + final InscriptionLink? inscription; + final TransactionLink? self; + + TransactionLinks({ + this.block, + this.inscription, + this.self, + }); + + factory TransactionLinks.fromJson(Map<String, dynamic> json) { + return TransactionLinks( + block: TransactionLink.fromJson(json['block']), + inscription: InscriptionLink.fromJson(json['inscription']), + self: TransactionLink.fromJson(json['self']), + ); + } +} + +class TransactionLink { + final String href; + + TransactionLink({required this.href}); + + factory TransactionLink.fromJson(Map<String, dynamic> json) { + return TransactionLink(href: json['href']); + } +} + +class OutputLink { + final String href; + + OutputLink({required this.href}); + + factory OutputLink.fromJson(Map<String, dynamic> json) { + return OutputLink(href: json['href']); + } +} From 51155372d30ca33ccccd1b66c9370da9bb6e012c Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Wed, 19 Jul 2023 10:37:42 -0500 Subject: [PATCH 02/31] add inscription endpoint --- lib/dto/ordinals/feed_response.dart | 24 +++- lib/dto/ordinals/inscription_response.dart | 123 ++++++++++----------- lib/services/ordinals_api.dart | 38 ++++++- 3 files changed, 112 insertions(+), 73 deletions(-) diff --git a/lib/dto/ordinals/feed_response.dart b/lib/dto/ordinals/feed_response.dart index b6af1c1ca..d958fbe4c 100644 --- a/lib/dto/ordinals/feed_response.dart +++ b/lib/dto/ordinals/feed_response.dart @@ -1,14 +1,28 @@ class FeedResponse { final List<InscriptionLink> inscriptions; - FeedResponse(this.inscriptions); + FeedResponse({required this.inscriptions}); factory FeedResponse.fromJson(Map<String, dynamic> json) { - final inscriptionsJson = json['_links']['inscriptions'] as List; - final inscriptions = inscriptionsJson - .map((inscriptionJson) => InscriptionLink.fromJson(inscriptionJson)) + final List<dynamic> inscriptionsJson = json['_links']['inscriptions'] as List<dynamic>; + final List<InscriptionLink> inscriptions = inscriptionsJson + .map((json) => InscriptionLink.fromJson(json as Map<String, dynamic>)) .toList(); - return FeedResponse(inscriptions); + return FeedResponse(inscriptions: inscriptions); + } +} + +class InscriptionLink { + final String href; + final String title; + + InscriptionLink({required this.href, required this.title}); + + factory InscriptionLink.fromJson(Map<String, dynamic> json) { + return InscriptionLink( + href: json['href'] as String ?? '', + title: json['title'] as String ?? '', + ); } } diff --git a/lib/dto/ordinals/inscription_response.dart b/lib/dto/ordinals/inscription_response.dart index e06ddca6d..ab093b750 100644 --- a/lib/dto/ordinals/inscription_response.dart +++ b/lib/dto/ordinals/inscription_response.dart @@ -1,17 +1,17 @@ class InscriptionResponse { - final InscriptionLinks links; - final String address; - final int contentLength; - final String contentType; - final int genesisFee; - final int genesisHeight; - final String genesisTransaction; - final String location; - final int number; - final int offset; - final String output; - final dynamic sat; // Change to appropriate type if available - final String timestamp; + late final Links links; + late final String address; + late final int contentLength; + late final String contentType; + late final int genesisFee; + late final int genesisHeight; + late final String genesisTransaction; + late final String location; + late final int number; + late final int offset; + late final String output; + late final String? sat; // Make sure to update the type to allow null + late final String timestamp; InscriptionResponse({ required this.links, @@ -29,67 +29,62 @@ class InscriptionResponse { required this.timestamp, }); - factory InscriptionResponse.fromJson(Map<String, dynamic> json) { - return InscriptionResponse( - links: InscriptionLinks.fromJson(json['_links']), - address: json['address'], - contentLength: json['content_length'], - contentType: json['content_type'], - genesisFee: json['genesis_fee'], - genesisHeight: json['genesis_height'], - genesisTransaction: json['genesis_transaction'], - location: json['location'], - number: json['number'], - offset: json['offset'], - output: json['output'], - sat: json['sat'], - timestamp: json['timestamp'], - ); + InscriptionResponse.fromJson(Map<String, dynamic> json) { + links = Links.fromJson(json['_links'] as Map<String, dynamic>); + address = json['address'] as String; + contentLength = json['content_length'] as int; + contentType = json['content_type'] as String; + genesisFee = json['genesis_fee'] as int; + genesisHeight = json['genesis_height'] as int; + genesisTransaction = json['genesis_transaction'] as String; + location = json['location'] as String; + number = json['number'] as int; + offset = json['offset'] as int; + output = json['output'] as String; + sat = json['sat'] as String?; + timestamp = json['timestamp'] as String; } } -class InscriptionLinks { - final InscriptionLink? content; - final InscriptionLink? genesisTransaction; - final InscriptionLink? next; - final InscriptionLink? output; - final InscriptionLink? prev; - final InscriptionLink? preview; - final InscriptionLink? sat; - final InscriptionLink? self; +class Links { + late final Link content; + late final Link genesisTransaction; + late final Link next; + late final Link output; + late final Link prev; + late final Link preview; + late final Link? sat; // Make sure to update the type to allow null + late final Link self; - InscriptionLinks({ - this.content, - this.genesisTransaction, - this.next, - this.output, - this.prev, - this.preview, + Links({ + required this.content, + required this.genesisTransaction, + required this.next, + required this.output, + required this.prev, + required this.preview, this.sat, - this.self, + required this.self, }); - factory InscriptionLinks.fromJson(Map<String, dynamic> json) { - return InscriptionLinks( - content: InscriptionLink.fromJson(json['content']), - genesisTransaction: InscriptionLink.fromJson(json['genesis_transaction']), - next: InscriptionLink.fromJson(json['next']), - output: InscriptionLink.fromJson(json['output']), - prev: InscriptionLink.fromJson(json['prev']), - preview: InscriptionLink.fromJson(json['preview']), - sat: InscriptionLink.fromJson(json['sat']), - self: InscriptionLink.fromJson(json['self']), - ); + Links.fromJson(Map<String, dynamic> json) { + content = Link.fromJson(json['content'] as Map<String, dynamic>); + genesisTransaction = Link.fromJson(json['genesis_transaction'] as Map<String, dynamic>); + next = Link.fromJson(json['next'] as Map<String, dynamic>); + output = Link.fromJson(json['output'] as Map<String, dynamic>); + prev = Link.fromJson(json['prev'] as Map<String, dynamic>); + preview = Link.fromJson(json['preview'] 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>); } } -class InscriptionLink { - final String href; - final String title; +class Link { + late final String href; - InscriptionLink({required this.href, required this.title}); + Link({required this.href}); - factory InscriptionLink.fromJson(Map<String, dynamic> json) { - return InscriptionLink(href: json['href'], title: json['title']); + Link.fromJson(Map<String, dynamic> json) { + href = json['href'] as String; } -} +} \ No newline at end of file diff --git a/lib/services/ordinals_api.dart b/lib/services/ordinals_api.dart index 97cc45834..a966988d7 100644 --- a/lib/services/ordinals_api.dart +++ b/lib/services/ordinals_api.dart @@ -1,9 +1,39 @@ -import 'package:stackwallet/models/ordinal.dart'; +import 'dart:convert'; +import 'package:http/http.dart' as http; + +import 'package:stackwallet/dto/ordinals/feed_response.dart'; +import 'package:stackwallet/dto/ordinals/inscription_response.dart'; class OrdinalsAPI { - // dummy class with sample functions to be changed / filled out + final String baseUrl; - static Future<List<Ordinal>> fetch() async { - return []; + OrdinalsAPI({required this.baseUrl}); + + Future<Map<String, dynamic>> _getResponse(String endpoint) async { + final response = await http.get(Uri.parse('$baseUrl$endpoint')); + if (response.statusCode == 200) { + return _validateJson(response.body); + } else { + throw Exception('Failed to load data'); + } + } + + Map<String, dynamic> _validateJson(String responseBody) { + final parsed = jsonDecode(responseBody); + if (parsed is Map<String, dynamic>) { + return parsed; + } else { + throw const FormatException('Invalid JSON format'); + } + } + + Future<FeedResponse> getLatestInscriptions() async { + final response = await _getResponse('/feed'); + return FeedResponse.fromJson(response); + } + + Future<InscriptionResponse> getInscriptionDetails(String inscriptionId) async { + final response = await _getResponse('/inscription/$inscriptionId'); + return InscriptionResponse.fromJson(response); } } From 828782f00cd120125a9996cb9666aa8ed0c075f2 Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Wed, 19 Jul 2023 10:41:23 -0500 Subject: [PATCH 03/31] add sat endpoint --- lib/dto/ordinals/sat_response.dart | 36 +++++++++++++++--------------- lib/services/ordinals_api.dart | 6 +++++ 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/lib/dto/ordinals/sat_response.dart b/lib/dto/ordinals/sat_response.dart index 0f88918f3..b57ccb3cf 100644 --- a/lib/dto/ordinals/sat_response.dart +++ b/lib/dto/ordinals/sat_response.dart @@ -29,18 +29,18 @@ class SatResponse { factory SatResponse.fromJson(Map<String, dynamic> json) { return SatResponse( - links: SatLinks.fromJson(json['_links']), - block: json['block'], - cycle: json['cycle'], - decimal: json['decimal'], - degree: json['degree'], - epoch: json['epoch'], - name: json['name'], - offset: json['offset'], - percentile: json['percentile'], - period: json['period'], - rarity: json['rarity'], - timestamp: json['timestamp'], + links: SatLinks.fromJson(json['_links'] as Map<String, dynamic>), + block: json['block'] as int, + cycle: json['cycle'] as int, + decimal: json['decimal'] as String, + degree: json['degree'] as String, + epoch: json['epoch'] as int, + name: json['name'] as String, + offset: json['offset'] as int, + percentile: json['percentile'] as String, + period: json['period'] as int, + rarity: json['rarity'] as String, + timestamp: json['timestamp'] as String, ); } } @@ -62,11 +62,11 @@ class SatLinks { factory SatLinks.fromJson(Map<String, dynamic> json) { return SatLinks( - block: SatLink.fromJson(json['block']), - inscription: SatLink.fromJson(json['inscription']), - next: SatLink.fromJson(json['next']), - prev: SatLink.fromJson(json['prev']), - self: SatLink.fromJson(json['self']), + block: SatLink.fromJson(json['block'] as Map<String, dynamic>), + inscription: SatLink.fromJson(json['inscription'] as Map<String, dynamic>), + next: SatLink.fromJson(json['next'] as Map<String, dynamic>), + prev: SatLink.fromJson(json['prev'] as Map<String, dynamic>), + self: SatLink.fromJson(json['self'] as Map<String, dynamic>), ); } } @@ -77,6 +77,6 @@ class SatLink { SatLink({required this.href}); factory SatLink.fromJson(Map<String, dynamic> json) { - return SatLink(href: json['href']); + return SatLink(href: json['href'] as String); } } diff --git a/lib/services/ordinals_api.dart b/lib/services/ordinals_api.dart index a966988d7..264223f8a 100644 --- a/lib/services/ordinals_api.dart +++ b/lib/services/ordinals_api.dart @@ -3,6 +3,7 @@ import 'package:http/http.dart' as http; import 'package:stackwallet/dto/ordinals/feed_response.dart'; import 'package:stackwallet/dto/ordinals/inscription_response.dart'; +import 'package:stackwallet/dto/ordinals/sat_response.dart'; class OrdinalsAPI { final String baseUrl; @@ -36,4 +37,9 @@ class OrdinalsAPI { final response = await _getResponse('/inscription/$inscriptionId'); return InscriptionResponse.fromJson(response); } + + Future<SatResponse> getSatDetails(int satNumber) async { + final response = await _getResponse('/sat/$satNumber'); + return SatResponse.fromJson(response); + } } From 48e4f8c57790bd790fd194069f55f9e94d59e169 Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Wed, 19 Jul 2023 10:45:18 -0500 Subject: [PATCH 04/31] add output endpoint --- .../{output_response => output_response.dart} | 16 +++++++++------- lib/services/ordinals_api.dart | 12 ++++++++++++ 2 files changed, 21 insertions(+), 7 deletions(-) rename lib/dto/ordinals/{output_response => output_response.dart} (57%) diff --git a/lib/dto/ordinals/output_response b/lib/dto/ordinals/output_response.dart similarity index 57% rename from lib/dto/ordinals/output_response rename to lib/dto/ordinals/output_response.dart index cd25fe961..6faf40845 100644 --- a/lib/dto/ordinals/output_response +++ b/lib/dto/ordinals/output_response.dart @@ -1,3 +1,5 @@ +import 'package:stackwallet/dto/ordinals/transaction_response.dart'; + class OutputResponse { final OutputLinks links; final String address; @@ -15,11 +17,11 @@ class OutputResponse { factory OutputResponse.fromJson(Map<String, dynamic> json) { return OutputResponse( - links: OutputLinks.fromJson(json['_links']), - address: json['address'], - scriptPubkey: json['script_pubkey'], - transaction: json['transaction'], - value: json['value'], + links: OutputLinks.fromJson(json['_links'] as Map<String, dynamic>), + address: json['address'] as String, + scriptPubkey: json['script_pubkey'] as String, + transaction: json['transaction'] as String, + value: json['value'] as int, ); } } @@ -35,8 +37,8 @@ class OutputLinks { factory OutputLinks.fromJson(Map<String, dynamic> json) { return OutputLinks( - self: OutputLink.fromJson(json['self']), - transaction: TransactionLink.fromJson(json['transaction']), + self: OutputLink.fromJson(json['self'] as Map<String, dynamic>), + transaction: TransactionLink.fromJson(json['transaction'] as Map<String, dynamic>), ); } } \ No newline at end of file diff --git a/lib/services/ordinals_api.dart b/lib/services/ordinals_api.dart index 264223f8a..e83e9eb9e 100644 --- a/lib/services/ordinals_api.dart +++ b/lib/services/ordinals_api.dart @@ -4,6 +4,8 @@ import 'package:http/http.dart' as http; import 'package:stackwallet/dto/ordinals/feed_response.dart'; import 'package:stackwallet/dto/ordinals/inscription_response.dart'; import 'package:stackwallet/dto/ordinals/sat_response.dart'; +import 'package:stackwallet/dto/ordinals/transaction_response.dart'; +import 'package:stackwallet/dto/ordinals/output_response.dart'; class OrdinalsAPI { final String baseUrl; @@ -42,4 +44,14 @@ class OrdinalsAPI { final response = await _getResponse('/sat/$satNumber'); return SatResponse.fromJson(response); } + + Future<TransactionResponse> getTransaction(String transactionId) async { + final response = await _getResponse('/tx/$transactionId'); + return TransactionResponse.fromJson(response); + } + + Future<OutputResponse> getTransactionOutputs(String transactionId) async { + final response = await _getResponse('/output/$transactionId'); + return OutputResponse.fromJson(response); + } } From f972c34dc4eb0a7f19627da3b4ecd0e375bce8a9 Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Wed, 19 Jul 2023 10:48:54 -0500 Subject: [PATCH 05/31] add address endpoint --- lib/dto/ordinals/address_response.dart | 23 ++++++++++++++++++----- lib/dto/ordinals/output_response.dart | 2 +- lib/services/ordinals_api.dart | 6 ++++++ 3 files changed, 25 insertions(+), 6 deletions(-) diff --git a/lib/dto/ordinals/address_response.dart b/lib/dto/ordinals/address_response.dart index 024543b92..7932d8ec7 100644 --- a/lib/dto/ordinals/address_response.dart +++ b/lib/dto/ordinals/address_response.dart @@ -1,3 +1,5 @@ +import 'package:stackwallet/dto/ordinals/inscription_response.dart'; + class AddressResponse { final AddressLinks links; final String address; @@ -12,12 +14,12 @@ class AddressResponse { factory AddressResponse.fromJson(Map<String, dynamic> json) { final inscriptionsJson = json['inscriptions'] as List; final inscriptions = inscriptionsJson - .map((inscriptionJson) => InscriptionLink.fromJson(inscriptionJson)) + .map((inscriptionJson) => InscriptionLink.fromJson(inscriptionJson as Map<String, dynamic>)) .toList(); return AddressResponse( - links: AddressLinks.fromJson(json['_links']), - address: json['address'], + links: AddressLinks.fromJson(json['_links'] as Map<String, dynamic>), + address: json['address'] as String, inscriptions: inscriptions, ); } @@ -32,7 +34,7 @@ class AddressLinks { factory AddressLinks.fromJson(Map<String, dynamic> json) { return AddressLinks( - self: AddressLink.fromJson(json['self']), + self: AddressLink.fromJson(json['self'] as Map<String, dynamic>), ); } } @@ -43,6 +45,17 @@ class AddressLink { AddressLink({required this.href}); factory AddressLink.fromJson(Map<String, dynamic> json) { - return AddressLink(href: json['href']); + return AddressLink(href: json['href'] as String); + } +} + +class InscriptionLink { + final String href; + final String title; + + InscriptionLink(this.href, this.title); + + factory InscriptionLink.fromJson(Map<String, dynamic> json) { + return InscriptionLink(json['href'] as String, json['title'] as String); } } diff --git a/lib/dto/ordinals/output_response.dart b/lib/dto/ordinals/output_response.dart index 6faf40845..cd4bde563 100644 --- a/lib/dto/ordinals/output_response.dart +++ b/lib/dto/ordinals/output_response.dart @@ -41,4 +41,4 @@ class OutputLinks { transaction: TransactionLink.fromJson(json['transaction'] as Map<String, dynamic>), ); } -} \ No newline at end of file +} diff --git a/lib/services/ordinals_api.dart b/lib/services/ordinals_api.dart index e83e9eb9e..a0586d1ec 100644 --- a/lib/services/ordinals_api.dart +++ b/lib/services/ordinals_api.dart @@ -6,6 +6,7 @@ import 'package:stackwallet/dto/ordinals/inscription_response.dart'; import 'package:stackwallet/dto/ordinals/sat_response.dart'; import 'package:stackwallet/dto/ordinals/transaction_response.dart'; import 'package:stackwallet/dto/ordinals/output_response.dart'; +import 'package:stackwallet/dto/ordinals/address_response.dart'; class OrdinalsAPI { final String baseUrl; @@ -54,4 +55,9 @@ class OrdinalsAPI { final response = await _getResponse('/output/$transactionId'); return OutputResponse.fromJson(response); } + + Future<AddressResponse> getInscriptionsByAddress(String address) async { + final response = await _getResponse('/address/$address'); + return AddressResponse.fromJson(response); + } } From 6d772b0acdabdd19f0ed66663528a9a2912eb165 Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Wed, 19 Jul 2023 10:50:56 -0500 Subject: [PATCH 06/31] add block endpoint --- lib/dto/ordinals/block_response.dart | 20 ++++++++++---------- lib/services/ordinals_api.dart | 6 ++++++ 2 files changed, 16 insertions(+), 10 deletions(-) diff --git a/lib/dto/ordinals/block_response.dart b/lib/dto/ordinals/block_response.dart index 365098594..a3de1ee1c 100644 --- a/lib/dto/ordinals/block_response.dart +++ b/lib/dto/ordinals/block_response.dart @@ -19,13 +19,13 @@ class BlockResponse { factory BlockResponse.fromJson(Map<String, dynamic> json) { return BlockResponse( - links: BlockLinks.fromJson(json['_links']), - hash: json['hash'], - previousBlockhash: json['previous_blockhash'], - size: json['size'], - target: json['target'], - timestamp: json['timestamp'], - weight: json['weight'], + links: BlockLinks.fromJson(json['_links'] as Map<String, dynamic>), + hash: json['hash'] as String, + previousBlockhash: json['previous_blockhash'] as String, + size: json['size'] as int, + target: json['target'] as String, + timestamp: json['timestamp'] as String, + weight: json['weight'] as int, ); } } @@ -41,8 +41,8 @@ class BlockLinks { factory BlockLinks.fromJson(Map<String, dynamic> json) { return BlockLinks( - prev: BlockLink.fromJson(json['prev']), - self: BlockLink.fromJson(json['self']), + prev: BlockLink.fromJson(json['prev'] as Map<String, dynamic>), + self: BlockLink.fromJson(json['self'] as Map<String, dynamic>), ); } } @@ -53,6 +53,6 @@ class BlockLink { BlockLink({required this.href}); factory BlockLink.fromJson(Map<String, dynamic> json) { - return BlockLink(href: json['href']); + return BlockLink(href: json['href'] as String); } } diff --git a/lib/services/ordinals_api.dart b/lib/services/ordinals_api.dart index a0586d1ec..de9740554 100644 --- a/lib/services/ordinals_api.dart +++ b/lib/services/ordinals_api.dart @@ -7,6 +7,7 @@ import 'package:stackwallet/dto/ordinals/sat_response.dart'; import 'package:stackwallet/dto/ordinals/transaction_response.dart'; import 'package:stackwallet/dto/ordinals/output_response.dart'; import 'package:stackwallet/dto/ordinals/address_response.dart'; +import 'package:stackwallet/dto/ordinals/block_response.dart'; class OrdinalsAPI { final String baseUrl; @@ -60,4 +61,9 @@ class OrdinalsAPI { final response = await _getResponse('/address/$address'); return AddressResponse.fromJson(response); } + + Future<BlockResponse> getBlock(int blockNumber) async { + final response = await _getResponse('/block/$blockNumber'); + return BlockResponse.fromJson(response); + } } From d623480a758ee0a1acdfdc707ea503be03f314d2 Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Wed, 19 Jul 2023 10:51:46 -0500 Subject: [PATCH 07/31] add content endpoint --- lib/dto/ordinals/content_response.dart | 4 ++-- lib/services/ordinals_api.dart | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/dto/ordinals/content_response.dart b/lib/dto/ordinals/content_response.dart index 35a2c8ef8..d1131950b 100644 --- a/lib/dto/ordinals/content_response.dart +++ b/lib/dto/ordinals/content_response.dart @@ -4,7 +4,7 @@ class ContentResponse { ContentResponse({required this.fileLink}); factory ContentResponse.fromJson(Map<String, dynamic> json) { - return ContentResponse(fileLink: FileLink.fromJson(json['_links']['file'])); + return ContentResponse(fileLink: FileLink.fromJson(json['_links']['file'] as Map<String, dynamic>)); } } @@ -14,6 +14,6 @@ class FileLink { FileLink({required this.href}); factory FileLink.fromJson(Map<String, dynamic> json) { - return FileLink(href: json['href']); + return FileLink(href: json['href'] as String); } } diff --git a/lib/services/ordinals_api.dart b/lib/services/ordinals_api.dart index de9740554..4228ddd72 100644 --- a/lib/services/ordinals_api.dart +++ b/lib/services/ordinals_api.dart @@ -8,6 +8,7 @@ import 'package:stackwallet/dto/ordinals/transaction_response.dart'; import 'package:stackwallet/dto/ordinals/output_response.dart'; import 'package:stackwallet/dto/ordinals/address_response.dart'; import 'package:stackwallet/dto/ordinals/block_response.dart'; +import 'package:stackwallet/dto/ordinals/content_response.dart'; class OrdinalsAPI { final String baseUrl; @@ -66,4 +67,9 @@ class OrdinalsAPI { final response = await _getResponse('/block/$blockNumber'); return BlockResponse.fromJson(response); } + + Future<ContentResponse> getInscriptionContent(String inscriptionId) async { + final response = await _getResponse('/content/$inscriptionId'); + return ContentResponse.fromJson(response); + } } From 697f40fce1835e1e6cd494fb6a99a02bf319b11d Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Wed, 19 Jul 2023 10:55:46 -0500 Subject: [PATCH 08/31] add preview endpoint --- lib/dto/ordinals/preview_response.dart | 4 ++-- lib/services/ordinals_api.dart | 6 ++++++ 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/lib/dto/ordinals/preview_response.dart b/lib/dto/ordinals/preview_response.dart index d7171702d..9eabd590a 100644 --- a/lib/dto/ordinals/preview_response.dart +++ b/lib/dto/ordinals/preview_response.dart @@ -4,7 +4,7 @@ class PreviewResponse { PreviewResponse({required this.imageLink}); factory PreviewResponse.fromJson(Map<String, dynamic> json) { - return PreviewResponse(imageLink: ImageLink.fromJson(json['_links']['image'])); + return PreviewResponse(imageLink: ImageLink.fromJson(json['_links']['image'] as Map<String, dynamic>)); } } @@ -14,6 +14,6 @@ class ImageLink { ImageLink({required this.href}); factory ImageLink.fromJson(Map<String, dynamic> json) { - return ImageLink(href: json['href']); + return ImageLink(href: json['href'] as String); } } \ No newline at end of file diff --git a/lib/services/ordinals_api.dart b/lib/services/ordinals_api.dart index 4228ddd72..4d8360e06 100644 --- a/lib/services/ordinals_api.dart +++ b/lib/services/ordinals_api.dart @@ -9,6 +9,7 @@ import 'package:stackwallet/dto/ordinals/output_response.dart'; import 'package:stackwallet/dto/ordinals/address_response.dart'; import 'package:stackwallet/dto/ordinals/block_response.dart'; import 'package:stackwallet/dto/ordinals/content_response.dart'; +import 'package:stackwallet/dto/ordinals/preview_response.dart'; class OrdinalsAPI { final String baseUrl; @@ -72,4 +73,9 @@ class OrdinalsAPI { final response = await _getResponse('/content/$inscriptionId'); return ContentResponse.fromJson(response); } + + Future<PreviewResponse> getInscriptionPreview(String inscriptionId) async { + final response = await _getResponse('/preview/$inscriptionId'); + return PreviewResponse.fromJson(response); + } } From afbf818ab5815b07481bab41e1c1c27ffa704751 Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Wed, 19 Jul 2023 11:04:19 -0500 Subject: [PATCH 09/31] refactor InscriptionLink factory, casting TODO replace casting throughout ordinals DTOs with refactored validation --- lib/dto/ordinals/address_response.dart | 13 +----------- lib/dto/ordinals/feed_response.dart | 16 ++------------- lib/dto/ordinals/inscription_link.dart | 13 ++++++++++++ lib/dto/ordinals/transaction_response.dart | 24 ++++++++++++---------- 4 files changed, 29 insertions(+), 37 deletions(-) create mode 100644 lib/dto/ordinals/inscription_link.dart diff --git a/lib/dto/ordinals/address_response.dart b/lib/dto/ordinals/address_response.dart index 7932d8ec7..5c1f66323 100644 --- a/lib/dto/ordinals/address_response.dart +++ b/lib/dto/ordinals/address_response.dart @@ -1,4 +1,4 @@ -import 'package:stackwallet/dto/ordinals/inscription_response.dart'; +import 'package:stackwallet/dto/ordinals/inscription_link.dart'; class AddressResponse { final AddressLinks links; @@ -48,14 +48,3 @@ class AddressLink { return AddressLink(href: json['href'] as String); } } - -class InscriptionLink { - final String href; - final String title; - - InscriptionLink(this.href, this.title); - - factory InscriptionLink.fromJson(Map<String, dynamic> json) { - return InscriptionLink(json['href'] as String, json['title'] as String); - } -} diff --git a/lib/dto/ordinals/feed_response.dart b/lib/dto/ordinals/feed_response.dart index d958fbe4c..e29d2d334 100644 --- a/lib/dto/ordinals/feed_response.dart +++ b/lib/dto/ordinals/feed_response.dart @@ -1,3 +1,5 @@ +import 'package:stackwallet/dto/ordinals/inscription_link.dart'; + class FeedResponse { final List<InscriptionLink> inscriptions; @@ -12,17 +14,3 @@ class FeedResponse { return FeedResponse(inscriptions: inscriptions); } } - -class InscriptionLink { - final String href; - final String title; - - InscriptionLink({required this.href, required this.title}); - - factory InscriptionLink.fromJson(Map<String, dynamic> json) { - return InscriptionLink( - href: json['href'] as String ?? '', - title: json['title'] as String ?? '', - ); - } -} diff --git a/lib/dto/ordinals/inscription_link.dart b/lib/dto/ordinals/inscription_link.dart new file mode 100644 index 000000000..f23b63248 --- /dev/null +++ b/lib/dto/ordinals/inscription_link.dart @@ -0,0 +1,13 @@ +class InscriptionLink { + final String href; + final String title; + + InscriptionLink({required this.href, required this.title}); + + factory InscriptionLink.fromJson(Map<String, dynamic> json) { + return InscriptionLink( + href: json['href'] as String ?? '', + title: json['title'] as String ?? '', + ); + } +} diff --git a/lib/dto/ordinals/transaction_response.dart b/lib/dto/ordinals/transaction_response.dart index b030a1daa..11912a3ad 100644 --- a/lib/dto/ordinals/transaction_response.dart +++ b/lib/dto/ordinals/transaction_response.dart @@ -1,3 +1,5 @@ +import 'package:stackwallet/dto/ordinals/inscription_link.dart'; + class TransactionResponse { final TransactionLinks links; final List<OutputLink> inputs; @@ -18,21 +20,21 @@ class TransactionResponse { factory TransactionResponse.fromJson(Map<String, dynamic> json) { final inputsJson = json['_links']['inputs'] as List; final inputs = inputsJson - .map((inputJson) => OutputLink.fromJson(inputJson)) + .map((inputJson) => OutputLink.fromJson(inputJson as Map<String, dynamic>)) .toList(); final outputsJson = json['_links']['outputs'] as List; final outputs = outputsJson - .map((outputJson) => OutputLink.fromJson(outputJson)) + .map((outputJson) => OutputLink.fromJson(outputJson as Map<String, dynamic>)) .toList(); return TransactionResponse( - links: TransactionLinks.fromJson(json['_links']), + links: TransactionLinks.fromJson(json['_links'] as Map<String, dynamic>), inputs: inputs, - inscription: InscriptionLink.fromJson(json['_links']['inscription']), + inscription: InscriptionLink.fromJson(json['_links']['inscription'] as Map<String, dynamic>), outputs: outputs, - self: TransactionLink.fromJson(json['_links']['self']), - transaction: json['transaction'], + self: TransactionLink.fromJson(json['_links']['self'] as Map<String, dynamic>), + transaction: json['transaction'] as String, ); } } @@ -50,9 +52,9 @@ class TransactionLinks { factory TransactionLinks.fromJson(Map<String, dynamic> json) { return TransactionLinks( - block: TransactionLink.fromJson(json['block']), - inscription: InscriptionLink.fromJson(json['inscription']), - self: TransactionLink.fromJson(json['self']), + block: TransactionLink.fromJson(json['block'] as Map<String, dynamic>), + inscription: InscriptionLink.fromJson(json['inscription'] as Map<String, dynamic>), + self: TransactionLink.fromJson(json['self'] as Map<String, dynamic>), ); } } @@ -63,7 +65,7 @@ class TransactionLink { TransactionLink({required this.href}); factory TransactionLink.fromJson(Map<String, dynamic> json) { - return TransactionLink(href: json['href']); + return TransactionLink(href: json['href'] as String); } } @@ -73,6 +75,6 @@ class OutputLink { OutputLink({required this.href}); factory OutputLink.fromJson(Map<String, dynamic> json) { - return OutputLink(href: json['href']); + return OutputLink(href: json['href'] as String); } } From 8e17556e4128f00f915460f19eb7464c5ae54e16 Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Wed, 19 Jul 2023 13:03:17 -0500 Subject: [PATCH 10/31] use an OrdinalsResponse response type which can return an error --- lib/dto/ordinals/address_response.dart | 14 +++-- lib/dto/ordinals/block_response.dart | 25 +++++---- lib/dto/ordinals/content_response.dart | 9 ++- lib/dto/ordinals/feed_response.dart | 11 ++-- lib/dto/ordinals/inscription_response.dart | 61 ++++++++++++--------- lib/dto/ordinals/ordinals_response.dart | 6 ++ lib/dto/ordinals/output_response.dart | 21 ++++--- lib/dto/ordinals/preview_response.dart | 11 ++-- lib/dto/ordinals/sat_response.dart | 41 +++++++------- lib/dto/ordinals/transaction_response.dart | 24 ++++---- lib/services/mixins/ordinals_interface.dart | 18 +++++- lib/services/ordinals_api.dart | 5 +- 12 files changed, 148 insertions(+), 98 deletions(-) create mode 100644 lib/dto/ordinals/ordinals_response.dart diff --git a/lib/dto/ordinals/address_response.dart b/lib/dto/ordinals/address_response.dart index 5c1f66323..9136aa523 100644 --- a/lib/dto/ordinals/address_response.dart +++ b/lib/dto/ordinals/address_response.dart @@ -1,6 +1,7 @@ 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 String address; final List<InscriptionLink> inscriptions; @@ -11,15 +12,16 @@ class AddressResponse { required this.inscriptions, }); - factory AddressResponse.fromJson(Map<String, dynamic> json) { - final inscriptionsJson = json['inscriptions'] as List; + factory AddressResponse.fromJson(OrdinalsResponse json) { + final data = json.data as Map<String, dynamic>; + final inscriptionsJson = data['inscriptions'] as List; final inscriptions = inscriptionsJson .map((inscriptionJson) => InscriptionLink.fromJson(inscriptionJson as Map<String, dynamic>)) .toList(); return AddressResponse( - links: AddressLinks.fromJson(json['_links'] as Map<String, dynamic>), - address: json['address'] as String, + links: AddressLinks.fromJson(data['_links'] as Map<String, dynamic>), + address: data['address'] as String, inscriptions: inscriptions, ); } @@ -34,7 +36,7 @@ class AddressLinks { factory AddressLinks.fromJson(Map<String, dynamic> json) { return AddressLinks( - self: AddressLink.fromJson(json['self'] as Map<String, dynamic>), + self: json['self'] != null ? AddressLink.fromJson(json['self'] as Map<String, dynamic>) : null, ); } } diff --git a/lib/dto/ordinals/block_response.dart b/lib/dto/ordinals/block_response.dart index a3de1ee1c..0eef8d569 100644 --- a/lib/dto/ordinals/block_response.dart +++ b/lib/dto/ordinals/block_response.dart @@ -1,4 +1,6 @@ -class BlockResponse { +import 'package:stackwallet/dto/ordinals/ordinals_response.dart'; + +class BlockResponse extends OrdinalsResponse<BlockResponse> { final BlockLinks links; final String hash; final String previousBlockhash; @@ -17,15 +19,16 @@ class BlockResponse { 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( - links: BlockLinks.fromJson(json['_links'] as Map<String, dynamic>), - hash: json['hash'] as String, - previousBlockhash: json['previous_blockhash'] as String, - size: json['size'] as int, - target: json['target'] as String, - timestamp: json['timestamp'] as String, - weight: json['weight'] as int, + links: BlockLinks.fromJson(data['_links'] as Map<String, dynamic>), + hash: data['hash'] as String, + previousBlockhash: data['previous_blockhash'] as String, + size: data['size'] as int, + target: data['target'] as String, + timestamp: data['timestamp'] as String, + weight: data['weight'] as int, ); } } @@ -41,8 +44,8 @@ class BlockLinks { factory BlockLinks.fromJson(Map<String, dynamic> json) { return BlockLinks( - prev: BlockLink.fromJson(json['prev'] as Map<String, dynamic>), - self: BlockLink.fromJson(json['self'] as Map<String, dynamic>), + prev: json['prev'] != null ? BlockLink.fromJson(json['prev'] as Map<String, dynamic>) : null, + self: json['self'] != null ? BlockLink.fromJson(json['self'] as Map<String, dynamic>) : null, ); } } diff --git a/lib/dto/ordinals/content_response.dart b/lib/dto/ordinals/content_response.dart index d1131950b..7cfbaf9fd 100644 --- a/lib/dto/ordinals/content_response.dart +++ b/lib/dto/ordinals/content_response.dart @@ -1,10 +1,13 @@ -class ContentResponse { +import 'package:stackwallet/dto/ordinals/ordinals_response.dart'; + +class ContentResponse extends OrdinalsResponse<ContentResponse> { final FileLink fileLink; ContentResponse({required this.fileLink}); - factory ContentResponse.fromJson(Map<String, dynamic> json) { - return ContentResponse(fileLink: FileLink.fromJson(json['_links']['file'] as Map<String, dynamic>)); + factory ContentResponse.fromJson(OrdinalsResponse json) { + 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> } } diff --git a/lib/dto/ordinals/feed_response.dart b/lib/dto/ordinals/feed_response.dart index e29d2d334..525a7f727 100644 --- a/lib/dto/ordinals/feed_response.dart +++ b/lib/dto/ordinals/feed_response.dart @@ -1,16 +1,17 @@ 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; FeedResponse({required this.inscriptions}); - - factory FeedResponse.fromJson(Map<String, dynamic> json) { - final List<dynamic> inscriptionsJson = json['_links']['inscriptions'] as List<dynamic>; + + factory FeedResponse.fromJson(OrdinalsResponse json) { + final List<dynamic> inscriptionsJson = json.data['_links']['inscriptions'] as List<dynamic>; final List<InscriptionLink> inscriptions = inscriptionsJson .map((json) => InscriptionLink.fromJson(json as Map<String, dynamic>)) .toList(); return FeedResponse(inscriptions: inscriptions); } -} +} \ No newline at end of file diff --git a/lib/dto/ordinals/inscription_response.dart b/lib/dto/ordinals/inscription_response.dart index ab093b750..d45300aee 100644 --- a/lib/dto/ordinals/inscription_response.dart +++ b/lib/dto/ordinals/inscription_response.dart @@ -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 String address; late final int contentLength; @@ -29,20 +31,23 @@ class InscriptionResponse { required this.timestamp, }); - InscriptionResponse.fromJson(Map<String, dynamic> json) { - links = Links.fromJson(json['_links'] as Map<String, dynamic>); - address = json['address'] as String; - contentLength = json['content_length'] as int; - contentType = json['content_type'] as String; - genesisFee = json['genesis_fee'] as int; - genesisHeight = json['genesis_height'] as int; - genesisTransaction = json['genesis_transaction'] as String; - location = json['location'] as String; - number = json['number'] as int; - offset = json['offset'] as int; - output = json['output'] as String; - sat = json['sat'] as String?; - timestamp = json['timestamp'] as String; + factory InscriptionResponse.fromJson(OrdinalsResponse json) { + final data = json.data as Map<String, dynamic>; + return InscriptionResponse( + links: Links.fromJson(data['_links'] as Map<String, dynamic>), + address: data['address'] as String, + contentLength: data['content_length'] as int, + contentType: data['content_type'] as String, + genesisFee: data['genesis_fee'] as int, + genesisHeight: data['genesis_height'] as int, + genesisTransaction: data['genesis_transaction'] as String, + location: data['location'] as String, + number: data['number'] as int, + offset: data['offset'] as int, + output: data['output'] as String, + sat: data['sat'] as String?, + timestamp: data['timestamp'] as String, + ); } } @@ -67,15 +72,17 @@ class Links { required this.self, }); - Links.fromJson(Map<String, dynamic> json) { - content = Link.fromJson(json['content'] as Map<String, dynamic>); - genesisTransaction = Link.fromJson(json['genesis_transaction'] as Map<String, dynamic>); - next = Link.fromJson(json['next'] as Map<String, dynamic>); - output = Link.fromJson(json['output'] as Map<String, dynamic>); - prev = Link.fromJson(json['prev'] as Map<String, dynamic>); - preview = Link.fromJson(json['preview'] 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>); + factory Links.fromJson(Map<String, dynamic> json) { + return Links( + content: Link.fromJson(json['content'] as Map<String, dynamic>), + genesisTransaction: Link.fromJson(json['genesis_transaction'] as Map<String, dynamic>), + next: Link.fromJson(json['next'] as Map<String, dynamic>), + output: Link.fromJson(json['output'] as Map<String, dynamic>), + prev: Link.fromJson(json['prev'] as Map<String, dynamic>), + preview: Link.fromJson(json['preview'] 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.fromJson(Map<String, dynamic> json) { - href = json['href'] as String; + factory Link.fromJson(Map<String, dynamic> json) { + return Link(href: json['href'] as String); } -} \ No newline at end of file +} diff --git a/lib/dto/ordinals/ordinals_response.dart b/lib/dto/ordinals/ordinals_response.dart new file mode 100644 index 000000000..bf57db46b --- /dev/null +++ b/lib/dto/ordinals/ordinals_response.dart @@ -0,0 +1,6 @@ +class OrdinalsResponse<T> { + final T? data; + final String? error; + + OrdinalsResponse({this.data, this.error}); +} diff --git a/lib/dto/ordinals/output_response.dart b/lib/dto/ordinals/output_response.dart index cd4bde563..cc7b2107f 100644 --- a/lib/dto/ordinals/output_response.dart +++ b/lib/dto/ordinals/output_response.dart @@ -1,6 +1,7 @@ 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 String address; final String scriptPubkey; @@ -15,13 +16,15 @@ class OutputResponse { 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( - links: OutputLinks.fromJson(json['_links'] as Map<String, dynamic>), - address: json['address'] as String, - scriptPubkey: json['script_pubkey'] as String, - transaction: json['transaction'] as String, - value: json['value'] as int, + links: OutputLinks.fromJson(data['_links'] as Map<String, dynamic>), + address: data['address'] as String, + scriptPubkey: data['script_pubkey'] as String, + transaction: data['transaction'] as String, + value: data['value'] as int, ); } } @@ -37,8 +40,8 @@ class OutputLinks { factory OutputLinks.fromJson(Map<String, dynamic> json) { return OutputLinks( - self: OutputLink.fromJson(json['self'] as Map<String, dynamic>), - transaction: TransactionLink.fromJson(json['transaction'] as Map<String, dynamic>), + self: json['self'] != null ? OutputLink.fromJson(json['self'] as Map<String, dynamic>) : null, + transaction: json['transaction'] != null ? TransactionLink.fromJson(json['transaction'] as Map<String, dynamic>) : null, ); } } diff --git a/lib/dto/ordinals/preview_response.dart b/lib/dto/ordinals/preview_response.dart index 9eabd590a..b3e184acd 100644 --- a/lib/dto/ordinals/preview_response.dart +++ b/lib/dto/ordinals/preview_response.dart @@ -1,10 +1,13 @@ -class PreviewResponse { +import 'package:stackwallet/dto/ordinals/ordinals_response.dart'; + +class PreviewResponse extends OrdinalsResponse<PreviewResponse> { final ImageLink imageLink; PreviewResponse({required this.imageLink}); - factory PreviewResponse.fromJson(Map<String, dynamic> json) { - return PreviewResponse(imageLink: ImageLink.fromJson(json['_links']['image'] as Map<String, dynamic>)); + factory PreviewResponse.fromJson(OrdinalsResponse json) { + 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) { return ImageLink(href: json['href'] as String); } -} \ No newline at end of file +} diff --git a/lib/dto/ordinals/sat_response.dart b/lib/dto/ordinals/sat_response.dart index b57ccb3cf..40efb1440 100644 --- a/lib/dto/ordinals/sat_response.dart +++ b/lib/dto/ordinals/sat_response.dart @@ -1,4 +1,6 @@ -class SatResponse { +import 'package:stackwallet/dto/ordinals/ordinals_response.dart'; + +class SatResponse extends OrdinalsResponse<SatResponse> { final SatLinks links; final int block; final int cycle; @@ -27,20 +29,21 @@ class SatResponse { 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( - links: SatLinks.fromJson(json['_links'] as Map<String, dynamic>), - block: json['block'] as int, - cycle: json['cycle'] as int, - decimal: json['decimal'] as String, - degree: json['degree'] as String, - epoch: json['epoch'] as int, - name: json['name'] as String, - offset: json['offset'] as int, - percentile: json['percentile'] as String, - period: json['period'] as int, - rarity: json['rarity'] as String, - timestamp: json['timestamp'] as String, + links: SatLinks.fromJson(data['_links'] as Map<String, dynamic>), + block: data['block'] as int, + cycle: data['cycle'] as int, + decimal: data['decimal'] as String, + degree: data['degree'] as String, + epoch: data['epoch'] as int, + name: data['name'] as String, + offset: data['offset'] as int, + percentile: data['percentile'] as String, + period: data['period'] as int, + rarity: data['rarity'] as String, + timestamp: data['timestamp'] as String, ); } } @@ -62,11 +65,11 @@ class SatLinks { factory SatLinks.fromJson(Map<String, dynamic> json) { return SatLinks( - block: SatLink.fromJson(json['block'] as Map<String, dynamic>), - inscription: SatLink.fromJson(json['inscription'] as Map<String, dynamic>), - next: SatLink.fromJson(json['next'] as Map<String, dynamic>), - prev: SatLink.fromJson(json['prev'] as Map<String, dynamic>), - self: SatLink.fromJson(json['self'] as Map<String, dynamic>), + block: json['block'] != null ? SatLink.fromJson(json['block'] as Map<String, dynamic>) : null, + inscription: json['inscription'] != null ? SatLink.fromJson(json['inscription'] as Map<String, dynamic>) : null, + next: json['next'] != null ? SatLink.fromJson(json['next'] as Map<String, dynamic>) : null, + prev: json['prev'] != null ? SatLink.fromJson(json['prev'] as Map<String, dynamic>) : null, + self: json['self'] != null ? SatLink.fromJson(json['self'] as Map<String, dynamic>) : null, ); } } diff --git a/lib/dto/ordinals/transaction_response.dart b/lib/dto/ordinals/transaction_response.dart index 11912a3ad..c77e07914 100644 --- a/lib/dto/ordinals/transaction_response.dart +++ b/lib/dto/ordinals/transaction_response.dart @@ -1,6 +1,7 @@ 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 List<OutputLink> inputs; final InscriptionLink inscription; @@ -17,24 +18,25 @@ class TransactionResponse { required this.transaction, }); - factory TransactionResponse.fromJson(Map<String, dynamic> json) { - final inputsJson = json['_links']['inputs'] as List; + factory TransactionResponse.fromJson(OrdinalsResponse json) { + final data = json.data as Map<String, dynamic>; + final inputsJson = data['_links']['inputs'] as List; final inputs = inputsJson .map((inputJson) => OutputLink.fromJson(inputJson as Map<String, dynamic>)) .toList(); - final outputsJson = json['_links']['outputs'] as List; + final outputsJson = data['_links']['outputs'] as List; final outputs = outputsJson .map((outputJson) => OutputLink.fromJson(outputJson as Map<String, dynamic>)) .toList(); return TransactionResponse( - links: TransactionLinks.fromJson(json['_links'] as Map<String, dynamic>), + links: TransactionLinks.fromJson(data['_links'] as Map<String, dynamic>), inputs: inputs, - inscription: InscriptionLink.fromJson(json['_links']['inscription'] as Map<String, dynamic>), + inscription: InscriptionLink.fromJson(data['_links']['inscription'] as Map<String, dynamic>), outputs: outputs, - self: TransactionLink.fromJson(json['_links']['self'] as Map<String, dynamic>), - transaction: json['transaction'] as String, + self: TransactionLink.fromJson(data['_links']['self'] as Map<String, dynamic>), + transaction: data['transaction'] as String, ); } } @@ -52,9 +54,9 @@ class TransactionLinks { factory TransactionLinks.fromJson(Map<String, dynamic> json) { return TransactionLinks( - block: TransactionLink.fromJson(json['block'] as Map<String, dynamic>), - inscription: InscriptionLink.fromJson(json['inscription'] as Map<String, dynamic>), - self: TransactionLink.fromJson(json['self'] as Map<String, dynamic>), + block: json['block'] != null ? TransactionLink.fromJson(json['block'] as Map<String, dynamic>) : null, + inscription: json['inscription'] != null ? InscriptionLink.fromJson(json['inscription'] as Map<String, dynamic>) : null, + self: json['self'] != null ? TransactionLink.fromJson(json['self'] as Map<String, dynamic>) : null, ); } } diff --git a/lib/services/mixins/ordinals_interface.dart b/lib/services/mixins/ordinals_interface.dart index 06f2377e9..57a76fbd6 100644 --- a/lib/services/mixins/ordinals_interface.dart +++ b/lib/services/mixins/ordinals_interface.dart @@ -1,3 +1,19 @@ +import 'package:stackwallet/services/ordinals_api.dart'; +import 'package:stackwallet/dto/ordinals/feed_response.dart'; + 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'); + } + } } diff --git a/lib/services/ordinals_api.dart b/lib/services/ordinals_api.dart index 4d8360e06..e9d734203 100644 --- a/lib/services/ordinals_api.dart +++ b/lib/services/ordinals_api.dart @@ -1,6 +1,7 @@ import 'dart:convert'; 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/inscription_response.dart'; import 'package:stackwallet/dto/ordinals/sat_response.dart'; @@ -16,10 +17,10 @@ class OrdinalsAPI { 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')); if (response.statusCode == 200) { - return _validateJson(response.body); + return OrdinalsResponse(data: _validateJson(response.body)); } else { throw Exception('Failed to load data'); } From bc8f5ce8f93ba2d7163a7d47878c92522314ca69 Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Wed, 19 Jul 2023 15:58:26 -0500 Subject: [PATCH 11/31] update OrdinalsInterface to not need baseUrl declared by withee classes --- lib/services/mixins/ordinals_interface.dart | 10 ++++++---- lib/services/ordinals_api.dart | 15 ++++++++++++--- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/services/mixins/ordinals_interface.dart b/lib/services/mixins/ordinals_interface.dart index 57a76fbd6..1ab157b2c 100644 --- a/lib/services/mixins/ordinals_interface.dart +++ b/lib/services/mixins/ordinals_interface.dart @@ -1,8 +1,10 @@ -import 'package:stackwallet/services/ordinals_api.dart'; -import 'package:stackwallet/dto/ordinals/feed_response.dart'; +import 'package:stackwallet/dto/ordinals/feed_response.dart'; // Assuming this import is necessary +import 'package:stackwallet/services/ordinals_api.dart'; // Assuming this import is necessary mixin OrdinalsInterface { - Future<FeedResponse> fetchLatestInscriptions(OrdinalsAPI ordinalsAPI) async { + final OrdinalsAPI ordinalsAPI = OrdinalsAPI(baseUrl: 'http://ord-litecoin.stackwallet.com'); + + Future<FeedResponse> fetchLatestInscriptions() async { try { final feedResponse = await ordinalsAPI.getLatestInscriptions(); // Process the feedResponse data as needed @@ -16,4 +18,4 @@ mixin OrdinalsInterface { throw Exception('Error in OrdinalsInterface: $e'); } } -} +} \ No newline at end of file diff --git a/lib/services/ordinals_api.dart b/lib/services/ordinals_api.dart index e9d734203..c1d3aad94 100644 --- a/lib/services/ordinals_api.dart +++ b/lib/services/ordinals_api.dart @@ -12,10 +12,19 @@ import 'package:stackwallet/dto/ordinals/block_response.dart'; import 'package:stackwallet/dto/ordinals/content_response.dart'; import 'package:stackwallet/dto/ordinals/preview_response.dart'; -class OrdinalsAPI { - final String baseUrl; +import 'package:stackwallet/dto/ordinals/feed_response.dart'; // Assuming this import is necessary - OrdinalsAPI({required this.baseUrl}); +class OrdinalsAPI { + static final OrdinalsAPI _instance = OrdinalsAPI._internal(); + + factory OrdinalsAPI({required String baseUrl}) { + _instance.baseUrl = baseUrl; + return _instance; + } + + OrdinalsAPI._internal(); + + late String baseUrl; Future<OrdinalsResponse> _getResponse(String endpoint) async { final response = await http.get(Uri.parse('$baseUrl$endpoint')); From 2de8ffe5934d9534d79705a16e7d991c2c2369fe Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Wed, 19 Jul 2023 15:58:34 -0500 Subject: [PATCH 12/31] add test button --- lib/pages/ordinals/ordinals_view.dart | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/lib/pages/ordinals/ordinals_view.dart b/lib/pages/ordinals/ordinals_view.dart index fe60b5e28..2d051b07a 100644 --- a/lib/pages/ordinals/ordinals_view.dart +++ b/lib/pages/ordinals/ordinals_view.dart @@ -14,6 +14,8 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/models/ordinal.dart'; import 'package:stackwallet/pages/ordinals/ordinals_filter_view.dart'; import 'package:stackwallet/pages/ordinals/widgets/ordinals_list.dart'; +import 'package:stackwallet/services/ordinals_api.dart'; +import 'package:stackwallet/services/mixins/ordinals_interface.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; import 'package:stackwallet/utilities/constants.dart'; @@ -39,7 +41,7 @@ class OrdinalsView extends ConsumerStatefulWidget { ConsumerState<OrdinalsView> createState() => _OrdinalsViewState(); } -class _OrdinalsViewState extends ConsumerState<OrdinalsView> { +class _OrdinalsViewState extends ConsumerState<OrdinalsView> with OrdinalsInterface { late final TextEditingController searchController; late final FocusNode searchFocus; @@ -49,6 +51,7 @@ class _OrdinalsViewState extends ConsumerState<OrdinalsView> { void initState() { searchController = TextEditingController(); searchFocus = FocusNode(); + super.initState(); } @@ -178,6 +181,13 @@ class _OrdinalsViewState extends ConsumerState<OrdinalsView> { const SizedBox( height: 16, ), + TextButton(onPressed: () async { + await fetchLatestInscriptions(); + }, child: Text( + "Test", + style: STextStyles.navBarTitle(context), + ) + ), Expanded( child: OrdinalsList( walletId: widget.walletId, From 0284bb2951e362cc7c76309c0bd7683731e345bd Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Wed, 19 Jul 2023 17:13:54 -0500 Subject: [PATCH 13/31] use https api, implement other methods --- lib/pages/ordinals/ordinals_view.dart | 2 +- lib/services/mixins/ordinals_interface.dart | 87 +++++++++++++++++++-- 2 files changed, 81 insertions(+), 8 deletions(-) diff --git a/lib/pages/ordinals/ordinals_view.dart b/lib/pages/ordinals/ordinals_view.dart index 2d051b07a..3dd8b7ae7 100644 --- a/lib/pages/ordinals/ordinals_view.dart +++ b/lib/pages/ordinals/ordinals_view.dart @@ -182,7 +182,7 @@ class _OrdinalsViewState extends ConsumerState<OrdinalsView> with OrdinalsInterf height: 16, ), TextButton(onPressed: () async { - await fetchLatestInscriptions(); + await getTransaction('ed5a5c4e555e204768ec54c049ae0b01c86fdcc8b126a9d100c4dff745e7d3ca'); }, child: Text( "Test", style: STextStyles.navBarTitle(context), diff --git a/lib/services/mixins/ordinals_interface.dart b/lib/services/mixins/ordinals_interface.dart index 1ab157b2c..92974c67d 100644 --- a/lib/services/mixins/ordinals_interface.dart +++ b/lib/services/mixins/ordinals_interface.dart @@ -1,21 +1,94 @@ -import 'package:stackwallet/dto/ordinals/feed_response.dart'; // Assuming this import is necessary +import 'package:stackwallet/dto/ordinals/feed_response.dart'; +import 'package:stackwallet/dto/ordinals/inscription_response.dart'; +import 'package:stackwallet/dto/ordinals/sat_response.dart'; +import 'package:stackwallet/dto/ordinals/transaction_response.dart'; +import 'package:stackwallet/dto/ordinals/output_response.dart'; +import 'package:stackwallet/dto/ordinals/address_response.dart'; +import 'package:stackwallet/dto/ordinals/block_response.dart'; +import 'package:stackwallet/dto/ordinals/content_response.dart'; +import 'package:stackwallet/dto/ordinals/preview_response.dart'; import 'package:stackwallet/services/ordinals_api.dart'; // Assuming this import is necessary mixin OrdinalsInterface { - final OrdinalsAPI ordinalsAPI = OrdinalsAPI(baseUrl: 'http://ord-litecoin.stackwallet.com'); + final OrdinalsAPI ordinalsAPI = OrdinalsAPI(baseUrl: 'https://ord-litecoin.stackwallet.com'); Future<FeedResponse> fetchLatestInscriptions() 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}'); - } + // 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'); + throw Exception('Error in OrdinalsInterface fetchLatestInscriptions: $e'); + } + } + + Future<InscriptionResponse> getInscriptionDetails(String inscriptionId) async { + try { + return await ordinalsAPI.getInscriptionDetails(inscriptionId); + } catch (e) { + throw Exception('Error in OrdinalsInterface getInscriptionDetails: $e'); + } + } + + Future<SatResponse> getSatDetails(int satNumber) async { + try { + return await ordinalsAPI.getSatDetails(satNumber); + } catch (e) { + throw Exception('Error in OrdinalsInterface getSatDetails: $e'); + } + } + + Future<TransactionResponse> getTransaction(String transactionId) async { + try { + print(1); + return await ordinalsAPI.getTransaction(transactionId); + } catch (e) { + throw Exception('Error in OrdinalsInterface getTransaction: $e'); + } + } + + Future<OutputResponse> getTransactionOutputs(String transactionId) async { + try { + return await ordinalsAPI.getTransactionOutputs(transactionId); + } catch (e) { + throw Exception('Error in OrdinalsInterface getTransactionOutputs: $e'); + } + } + + Future<AddressResponse> getInscriptionsByAddress(String address) async { + try { + return await ordinalsAPI.getInscriptionsByAddress(address); + } catch (e) { + throw Exception('Error in OrdinalsInterface getInscriptionsByAddress: $e'); + } + } + + Future<BlockResponse> getBlock(int blockNumber) async { + try { + return await ordinalsAPI.getBlock(blockNumber); + } catch (e) { + throw Exception('Error in OrdinalsInterface getBlock: $e'); + } + } + + Future<ContentResponse> getInscriptionContent(String inscriptionId) async { + try { + return await ordinalsAPI.getInscriptionContent(inscriptionId); + } catch (e) { + throw Exception('Error in OrdinalsInterface getInscriptionContent: $e'); + } + } + + Future<PreviewResponse> getInscriptionPreview(String inscriptionId) async { + try { + return await ordinalsAPI.getInscriptionPreview(inscriptionId); + } catch (e) { + throw Exception('Error in OrdinalsInterface getInscriptionPreview: $e'); } } } \ No newline at end of file From d02b7f7ad4bbc4c5335fac7c0cce3f588760c580 Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Thu, 20 Jul 2023 14:05:51 -0500 Subject: [PATCH 14/31] formatting and model updates --- lib/pages/ordinals/ordinals_view.dart | 3 +++ lib/services/ordinals_api.dart | 2 -- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/pages/ordinals/ordinals_view.dart b/lib/pages/ordinals/ordinals_view.dart index 3dd8b7ae7..a60bf4226 100644 --- a/lib/pages/ordinals/ordinals_view.dart +++ b/lib/pages/ordinals/ordinals_view.dart @@ -197,6 +197,9 @@ class _OrdinalsViewState extends ConsumerState<OrdinalsView> with OrdinalsInterf name: "dummy name $i", inscription: "insc$i", rank: "r$i", + collection: OrdCollection.moonbirds, + utxoTXID: 'txid', + utxoVOUT: 1 ), ], ), diff --git a/lib/services/ordinals_api.dart b/lib/services/ordinals_api.dart index c1d3aad94..290b1c869 100644 --- a/lib/services/ordinals_api.dart +++ b/lib/services/ordinals_api.dart @@ -12,8 +12,6 @@ import 'package:stackwallet/dto/ordinals/block_response.dart'; import 'package:stackwallet/dto/ordinals/content_response.dart'; import 'package:stackwallet/dto/ordinals/preview_response.dart'; -import 'package:stackwallet/dto/ordinals/feed_response.dart'; // Assuming this import is necessary - class OrdinalsAPI { static final OrdinalsAPI _instance = OrdinalsAPI._internal(); From f046912c89a2e64d28687f5d1631f0279659506d Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Thu, 20 Jul 2023 14:38:56 -0500 Subject: [PATCH 15/31] litescribe api and demo --- .../address_inscription_response.dart | 91 +++++++++++++++++++ lib/dto/ordinals/litescribe_response.dart | 6 ++ lib/pages/ordinals/ordinals_view.dart | 5 +- lib/services/litescribe_api.dart | 45 +++++++++ lib/services/mixins/ordinals_interface.dart | 38 ++++++-- lib/services/ordinals_api.dart | 4 +- 6 files changed, 176 insertions(+), 13 deletions(-) create mode 100644 lib/dto/ordinals/address_inscription_response.dart create mode 100644 lib/dto/ordinals/litescribe_response.dart create mode 100644 lib/services/litescribe_api.dart diff --git a/lib/dto/ordinals/address_inscription_response.dart b/lib/dto/ordinals/address_inscription_response.dart new file mode 100644 index 000000000..c424d73e0 --- /dev/null +++ b/lib/dto/ordinals/address_inscription_response.dart @@ -0,0 +1,91 @@ +import 'package:stackwallet/dto/ordinals/litescribe_response.dart'; + +class AddressInscriptionResponse extends LitescribeResponse<AddressInscriptionResponse> { + final int status; + final String message; + final AddressInscriptionResult result; + + AddressInscriptionResponse({ + required this.status, + required this.message, + required this.result, + }); + + factory AddressInscriptionResponse.fromJson(Map<String, dynamic> json) { + return AddressInscriptionResponse( + status: json['status'] as int, + message: json['message'] as String, + result: AddressInscriptionResult.fromJson(json['result'] as Map<String, dynamic>), + ); + } +} + +class AddressInscriptionResult { + final List<AddressInscription> list; + final int total; + + AddressInscriptionResult({ + required this.list, + required this.total, + }); + + factory AddressInscriptionResult.fromJson(Map<String, dynamic> json) { + return AddressInscriptionResult( + list: (json['list'] as List).map((item) => AddressInscription.fromJson(item as Map<String, dynamic>)).toList(), + total: json['total'] as int, + ); + } +} + +class AddressInscription { + final String inscriptionId; + final int inscriptionNumber; + final String address; + final String preview; + final String content; + final int contentLength; + final String contentType; + final String contentBody; + final int timestamp; + final String genesisTransaction; + final String location; + final String output; + final int outputValue; + final int offset; + + AddressInscription({ + required this.inscriptionId, + required this.inscriptionNumber, + required this.address, + required this.preview, + required this.content, + required this.contentLength, + required this.contentType, + required this.contentBody, + required this.timestamp, + required this.genesisTransaction, + required this.location, + required this.output, + required this.outputValue, + required this.offset, + }); + + factory AddressInscription.fromJson(Map<String, dynamic> json) { + return AddressInscription( + inscriptionId: json['inscriptionId'] as String, + inscriptionNumber: json['inscriptionNumber'] as int, + address: json['address'] as String, + preview: json['preview'] as String, + content: json['content'] as String, + contentLength: json['contentLength'] as int, + contentType: json['contentType'] as String, + contentBody: json['contentBody'] as String, + timestamp: json['timestamp'] as int, + genesisTransaction: json['genesisTransaction'] as String, + location: json['location'] as String, + output: json['output'] as String, + outputValue: json['outputValue'] as int, + offset: json['offset'] as int, + ); + } +} diff --git a/lib/dto/ordinals/litescribe_response.dart b/lib/dto/ordinals/litescribe_response.dart new file mode 100644 index 000000000..bebd5ce10 --- /dev/null +++ b/lib/dto/ordinals/litescribe_response.dart @@ -0,0 +1,6 @@ +class LitescribeResponse<T> { + final T? data; + final String? error; + + LitescribeResponse({this.data, this.error}); +} diff --git a/lib/pages/ordinals/ordinals_view.dart b/lib/pages/ordinals/ordinals_view.dart index a60bf4226..4bd7385d3 100644 --- a/lib/pages/ordinals/ordinals_view.dart +++ b/lib/pages/ordinals/ordinals_view.dart @@ -182,7 +182,10 @@ class _OrdinalsViewState extends ConsumerState<OrdinalsView> with OrdinalsInterf height: 16, ), TextButton(onPressed: () async { - await getTransaction('ed5a5c4e555e204768ec54c049ae0b01c86fdcc8b126a9d100c4dff745e7d3ca'); + // await fetchLatestInscriptions(); + // await getTransaction('ed5a5c4e555e204768ec54c049ae0b01c86fdcc8b126a9d100c4dff745e7d3ca'); + // await getBlock('31278055ba414fe6dbed75e4a77e841da4481972ac09bd2a214c445da1a44aad'); + await getInscriptionsByAddress('ltc1qk4e8hdq5w6rvk5xvkxajjak78v45pkul8a2cg9'); }, child: Text( "Test", style: STextStyles.navBarTitle(context), diff --git a/lib/services/litescribe_api.dart b/lib/services/litescribe_api.dart new file mode 100644 index 000000000..507492ee6 --- /dev/null +++ b/lib/services/litescribe_api.dart @@ -0,0 +1,45 @@ +import 'dart:convert'; +import 'package:http/http.dart' as http; + +import 'package:stackwallet/dto/ordinals/address_inscription_response.dart'; +import 'package:stackwallet/dto/ordinals/litescribe_response.dart'; + +class LitescribeAPI { + static final LitescribeAPI _instance = LitescribeAPI._internal(); + + factory LitescribeAPI({required String baseUrl}) { + _instance.baseUrl = baseUrl; + return _instance; + } + + LitescribeAPI._internal(); + + late String baseUrl; + + Future<LitescribeResponse> _getResponse(String endpoint) async { + final response = await http.get(Uri.parse('$baseUrl$endpoint')); + if (response.statusCode == 200) { + return LitescribeResponse(data: _validateJson(response.body)); + } else { + throw Exception('LitescribeAPI _getResponse exception: Failed to load data'); + } + } + + Map<String, dynamic> _validateJson(String responseBody) { + final parsed = jsonDecode(responseBody); + if (parsed is Map<String, dynamic>) { + return parsed; + } else { + throw const FormatException('LitescribeAPI _validateJson exception: Invalid JSON format'); + } + } + + Future<AddressInscriptionResponse> getInscriptionsByAddress(String address, {int cursor = 0, int size = 1000}) async { // size = 1000 = hardcoded limit as default limit to inscriptions returned from API call, TODO increase limit if returned inscriptions = limit + final response = await _getResponse('/address/inscriptions?address=$address&cursor=$cursor&size=$size'); + try { + return AddressInscriptionResponse.fromJson(response.data as Map<String, dynamic>); + } catch(e) { + throw const FormatException('LitescribeAPI getInscriptionsByAddress exception: AddressInscriptionResponse.fromJson failure'); + } + } +} \ No newline at end of file diff --git a/lib/services/mixins/ordinals_interface.dart b/lib/services/mixins/ordinals_interface.dart index 92974c67d..a9fbcbca6 100644 --- a/lib/services/mixins/ordinals_interface.dart +++ b/lib/services/mixins/ordinals_interface.dart @@ -1,15 +1,32 @@ -import 'package:stackwallet/dto/ordinals/feed_response.dart'; -import 'package:stackwallet/dto/ordinals/inscription_response.dart'; -import 'package:stackwallet/dto/ordinals/sat_response.dart'; -import 'package:stackwallet/dto/ordinals/transaction_response.dart'; -import 'package:stackwallet/dto/ordinals/output_response.dart'; -import 'package:stackwallet/dto/ordinals/address_response.dart'; -import 'package:stackwallet/dto/ordinals/block_response.dart'; -import 'package:stackwallet/dto/ordinals/content_response.dart'; -import 'package:stackwallet/dto/ordinals/preview_response.dart'; -import 'package:stackwallet/services/ordinals_api.dart'; // Assuming this import is necessary +// ord-litecoin-specific imports +// import 'package:stackwallet/dto/ordinals/feed_response.dart'; +// import 'package:stackwallet/dto/ordinals/inscription_response.dart'; +// import 'package:stackwallet/dto/ordinals/sat_response.dart'; +// import 'package:stackwallet/dto/ordinals/transaction_response.dart'; +// import 'package:stackwallet/dto/ordinals/output_response.dart'; +// import 'package:stackwallet/dto/ordinals/address_response.dart'; +// import 'package:stackwallet/dto/ordinals/block_response.dart'; +// import 'package:stackwallet/dto/ordinals/content_response.dart'; +// import 'package:stackwallet/dto/ordinals/preview_response.dart'; +// import 'package:stackwallet/services/ordinals_api.dart'; + +import 'package:stackwallet/dto/ordinals/address_inscription_response.dart'; // verbose due to Litescribe being the 2nd API +import 'package:stackwallet/services/litescribe_api.dart'; mixin OrdinalsInterface { + final LitescribeAPI litescribeAPI = LitescribeAPI(baseUrl: 'https://litescribe.io/api'); + + Future<List<AddressInscription>> getInscriptionsByAddress(String address) async { + try { + var response = await litescribeAPI.getInscriptionsByAddress(address); + print("Found ${response.result.total} inscriptions at address $address"); // TODO disable (POC) + return response.result.list; + } catch (e) { + throw Exception('Error in OrdinalsInterface getInscriptionsByAddress: $e'); + } + } + + /* // ord-litecoin interface final OrdinalsAPI ordinalsAPI = OrdinalsAPI(baseUrl: 'https://ord-litecoin.stackwallet.com'); Future<FeedResponse> fetchLatestInscriptions() async { @@ -91,4 +108,5 @@ mixin OrdinalsInterface { throw Exception('Error in OrdinalsInterface getInscriptionPreview: $e'); } } + */ // /ord-litecoin interface } \ No newline at end of file diff --git a/lib/services/ordinals_api.dart b/lib/services/ordinals_api.dart index 290b1c869..e6df3c05e 100644 --- a/lib/services/ordinals_api.dart +++ b/lib/services/ordinals_api.dart @@ -72,8 +72,8 @@ class OrdinalsAPI { return AddressResponse.fromJson(response); } - Future<BlockResponse> getBlock(int blockNumber) async { - final response = await _getResponse('/block/$blockNumber'); + Future<BlockResponse> getBlock(String blockHash) async { + final response = await _getResponse('/block/$blockHash'); return BlockResponse.fromJson(response); } From a322c1395432a18f1fc1f53eff53037ec7e3499b Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Thu, 20 Jul 2023 14:46:15 -0500 Subject: [PATCH 16/31] return inscriptions in batches of 1000 --- lib/services/litescribe_api.dart | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/lib/services/litescribe_api.dart b/lib/services/litescribe_api.dart index 507492ee6..edb46f1d2 100644 --- a/lib/services/litescribe_api.dart +++ b/lib/services/litescribe_api.dart @@ -34,12 +34,29 @@ class LitescribeAPI { } } - Future<AddressInscriptionResponse> getInscriptionsByAddress(String address, {int cursor = 0, int size = 1000}) async { // size = 1000 = hardcoded limit as default limit to inscriptions returned from API call, TODO increase limit if returned inscriptions = limit + Future<AddressInscriptionResponse> getInscriptionsByAddress(String address, {int cursor = 0, int size = 1000}) async { + // size param determines how many inscriptions are returned per response + // default of 1000 is used to cover most addresses (I assume) + // if the total number of inscriptions at the address exceeds the length of the list of inscriptions returned, another call with a higher size is made + final int defaultLimit = 1000; final response = await _getResponse('/address/inscriptions?address=$address&cursor=$cursor&size=$size'); - try { - return AddressInscriptionResponse.fromJson(response.data as Map<String, dynamic>); - } catch(e) { - throw const FormatException('LitescribeAPI getInscriptionsByAddress exception: AddressInscriptionResponse.fromJson failure'); + + // Check if the number of returned inscriptions equals the limit + final list = response.data['result']['list'] as List<dynamic>; + final int total = response.data['result']['total'] as int; + final int currentSize = list.length; + + if (currentSize == size && currentSize < total) { + // If the number of returned inscriptions equals the limit and there are more inscriptions available, + // increase the size to fetch all inscriptions. + return getInscriptionsByAddress(address, cursor: cursor, size: total+1); // potential off-by-one error, but should be safe + // TODO don't re-request the same inscriptions previously returned; increment cursor (probably) by size and only request the rest. ex: cursor=0 size=1000 probably returns inscriptions 0-999, so set cursor=size (or size-1?) to get 1000-1999 + } else { + try { + return AddressInscriptionResponse.fromJson(response.data as Map<String, dynamic>); + } catch (e) { + throw const FormatException('LitescribeAPI getInscriptionsByAddress exception: AddressInscriptionResponse.fromJson failure'); + } } } } \ No newline at end of file From 22e222ffd6c0ea7bd1851a36ce2e64e9fc8f32cb Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Thu, 20 Jul 2023 14:48:12 -0500 Subject: [PATCH 17/31] paginate inscription responses --- lib/services/litescribe_api.dart | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/services/litescribe_api.dart b/lib/services/litescribe_api.dart index edb46f1d2..abc28123e 100644 --- a/lib/services/litescribe_api.dart +++ b/lib/services/litescribe_api.dart @@ -48,9 +48,10 @@ class LitescribeAPI { if (currentSize == size && currentSize < total) { // If the number of returned inscriptions equals the limit and there are more inscriptions available, - // increase the size to fetch all inscriptions. - return getInscriptionsByAddress(address, cursor: cursor, size: total+1); // potential off-by-one error, but should be safe - // TODO don't re-request the same inscriptions previously returned; increment cursor (probably) by size and only request the rest. ex: cursor=0 size=1000 probably returns inscriptions 0-999, so set cursor=size (or size-1?) to get 1000-1999 + // increment the cursor and make the next API call to fetch the remaining inscriptions. + final int newCursor = cursor + size; + return getInscriptionsByAddress(address, cursor: newCursor, size: size); + // TODO test logic with smaller size "pagination" } else { try { return AddressInscriptionResponse.fromJson(response.data as Map<String, dynamic>); From 4be7919e46c288668d28b18b1d2d19e5cd6a8eaf Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Thu, 20 Jul 2023 14:52:05 -0500 Subject: [PATCH 18/31] expand upon demo TODO remove WIP, hook directly into StreamBuilder --- lib/pages/ordinals/ordinals_view.dart | 9 ++++++++- lib/services/mixins/ordinals_interface.dart | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/pages/ordinals/ordinals_view.dart b/lib/pages/ordinals/ordinals_view.dart index 4bd7385d3..d2b6a34d6 100644 --- a/lib/pages/ordinals/ordinals_view.dart +++ b/lib/pages/ordinals/ordinals_view.dart @@ -185,7 +185,14 @@ class _OrdinalsViewState extends ConsumerState<OrdinalsView> with OrdinalsInterf // await fetchLatestInscriptions(); // await getTransaction('ed5a5c4e555e204768ec54c049ae0b01c86fdcc8b126a9d100c4dff745e7d3ca'); // await getBlock('31278055ba414fe6dbed75e4a77e841da4481972ac09bd2a214c445da1a44aad'); - await getInscriptionsByAddress('ltc1qk4e8hdq5w6rvk5xvkxajjak78v45pkul8a2cg9'); + var inscriptions = await getInscriptionsByAddress('ltc1qk4e8hdq5w6rvk5xvkxajjak78v45pkul8a2cg9'); + for (var inscription in inscriptions) { + print(inscription); + print(inscription.address); + print(inscription.content); + print(inscription.inscriptionId); + print(inscription.inscriptionNumber); + } }, child: Text( "Test", style: STextStyles.navBarTitle(context), diff --git a/lib/services/mixins/ordinals_interface.dart b/lib/services/mixins/ordinals_interface.dart index a9fbcbca6..f39b2259f 100644 --- a/lib/services/mixins/ordinals_interface.dart +++ b/lib/services/mixins/ordinals_interface.dart @@ -19,7 +19,7 @@ mixin OrdinalsInterface { Future<List<AddressInscription>> getInscriptionsByAddress(String address) async { try { var response = await litescribeAPI.getInscriptionsByAddress(address); - print("Found ${response.result.total} inscriptions at address $address"); // TODO disable (POC) + print("Found ${response.result.total} inscription${response.result.total > 1 ? 's' : ''} at address $address"); // TODO disable (POC) return response.result.list; } catch (e) { throw Exception('Error in OrdinalsInterface getInscriptionsByAddress: $e'); From ca8e930904cd9497f38fd13cc15d2f78b07d6b3a Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Thu, 20 Jul 2023 15:32:39 -0500 Subject: [PATCH 19/31] move demo into refresh button, add refreshInscriptions() stub w prev poc --- lib/pages/ordinals/ordinals_view.dart | 22 +++------------------ lib/services/mixins/ordinals_interface.dart | 12 +++++++++++ 2 files changed, 15 insertions(+), 19 deletions(-) diff --git a/lib/pages/ordinals/ordinals_view.dart b/lib/pages/ordinals/ordinals_view.dart index d2b6a34d6..7a0572c78 100644 --- a/lib/pages/ordinals/ordinals_view.dart +++ b/lib/pages/ordinals/ordinals_view.dart @@ -14,6 +14,7 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/models/ordinal.dart'; import 'package:stackwallet/pages/ordinals/ordinals_filter_view.dart'; import 'package:stackwallet/pages/ordinals/widgets/ordinals_list.dart'; +import 'package:stackwallet/services/litescribe_api.dart'; import 'package:stackwallet/services/ordinals_api.dart'; import 'package:stackwallet/services/mixins/ordinals_interface.dart'; import 'package:stackwallet/themes/stack_colors.dart'; @@ -90,8 +91,8 @@ class _OrdinalsViewState extends ConsumerState<OrdinalsView> with OrdinalsInterf .extension<StackColors>()! .topNavIconPrimary, ), - onPressed: () { - // todo refresh + onPressed: () async { + refreshInscriptions(); }, ), ), @@ -181,23 +182,6 @@ class _OrdinalsViewState extends ConsumerState<OrdinalsView> with OrdinalsInterf const SizedBox( height: 16, ), - TextButton(onPressed: () async { - // await fetchLatestInscriptions(); - // await getTransaction('ed5a5c4e555e204768ec54c049ae0b01c86fdcc8b126a9d100c4dff745e7d3ca'); - // await getBlock('31278055ba414fe6dbed75e4a77e841da4481972ac09bd2a214c445da1a44aad'); - var inscriptions = await getInscriptionsByAddress('ltc1qk4e8hdq5w6rvk5xvkxajjak78v45pkul8a2cg9'); - for (var inscription in inscriptions) { - print(inscription); - print(inscription.address); - print(inscription.content); - print(inscription.inscriptionId); - print(inscription.inscriptionNumber); - } - }, child: Text( - "Test", - style: STextStyles.navBarTitle(context), - ) - ), Expanded( child: OrdinalsList( walletId: widget.walletId, diff --git a/lib/services/mixins/ordinals_interface.dart b/lib/services/mixins/ordinals_interface.dart index f39b2259f..d60786b4d 100644 --- a/lib/services/mixins/ordinals_interface.dart +++ b/lib/services/mixins/ordinals_interface.dart @@ -26,6 +26,18 @@ mixin OrdinalsInterface { } } + void refreshInscriptions() async { + // TODO get all inscriptions at all addresses in wallet + var inscriptions = await getInscriptionsByAddress('ltc1qk4e8hdq5w6rvk5xvkxajjak78v45pkul8a2cg9'); + for (var inscription in inscriptions) { + print(inscription); + print(inscription.address); + print(inscription.content); + print(inscription.inscriptionId); + print(inscription.inscriptionNumber); + } + } + /* // ord-litecoin interface final OrdinalsAPI ordinalsAPI = OrdinalsAPI(baseUrl: 'https://ord-litecoin.stackwallet.com'); From 06c433ff8565479860cbb3ddd2f7f18e389a83c6 Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Thu, 20 Jul 2023 15:56:11 -0500 Subject: [PATCH 20/31] add init method, build on poc --- lib/services/mixins/ordinals_interface.dart | 36 +++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/lib/services/mixins/ordinals_interface.dart b/lib/services/mixins/ordinals_interface.dart index d60786b4d..caac7a854 100644 --- a/lib/services/mixins/ordinals_interface.dart +++ b/lib/services/mixins/ordinals_interface.dart @@ -1,3 +1,8 @@ +import 'package:isar/isar.dart'; +import 'package:stackwallet/db/isar/main_db.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; + // ord-litecoin-specific imports // import 'package:stackwallet/dto/ordinals/feed_response.dart'; // import 'package:stackwallet/dto/ordinals/inscription_response.dart'; @@ -13,7 +18,21 @@ import 'package:stackwallet/dto/ordinals/address_inscription_response.dart'; // verbose due to Litescribe being the 2nd API import 'package:stackwallet/services/litescribe_api.dart'; + mixin OrdinalsInterface { + late final String _walletId; + late final Coin _coin; + late final MainDB _db; + + void initOrdinalsInterface({ + required String walletId, + required Coin coin, + required MainDB db, + }) { + _walletId = walletId; + _coin = coin; + _db = db; + } final LitescribeAPI litescribeAPI = LitescribeAPI(baseUrl: 'https://litescribe.io/api'); Future<List<AddressInscription>> getInscriptionsByAddress(String address) async { @@ -27,6 +46,13 @@ mixin OrdinalsInterface { } void refreshInscriptions() async { + List<dynamic> _inscriptions; + final utxos = await _db.getUTXOs(_walletId).findAll(); + final uniqueAddresses = getUniqueAddressesFromUTXOs(utxos); + for (String address in uniqueAddresses) { + // TODO fetch all inscriptions from all addresses + // TODO save those inscriptions to isar, which a StreamBuilder will be "subscribed"-to + } // TODO get all inscriptions at all addresses in wallet var inscriptions = await getInscriptionsByAddress('ltc1qk4e8hdq5w6rvk5xvkxajjak78v45pkul8a2cg9'); for (var inscription in inscriptions) { @@ -38,6 +64,16 @@ mixin OrdinalsInterface { } } + List<String> getUniqueAddressesFromUTXOs(List<UTXO> utxos) { + final Set<String> uniqueAddresses = <String>{}; + for (var utxo in utxos) { + if (utxo.address != null) { + uniqueAddresses.add(utxo.address!); + } + } + return uniqueAddresses.toList(); + } + /* // ord-litecoin interface final OrdinalsAPI ordinalsAPI = OrdinalsAPI(baseUrl: 'https://ord-litecoin.stackwallet.com'); From 4db0328c73a859f4550fedafd3486e508a599921 Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Thu, 20 Jul 2023 16:30:39 -0500 Subject: [PATCH 21/31] WIP _db not initialized, refresh on ordinals view for poc --- .../address_inscription_response.dart | 58 +------------------ lib/dto/ordinals/inscription_data.dart | 53 +++++++++++++++++ lib/pages/ordinals/ordinals_view.dart | 6 +- .../coins/litecoin/litecoin_wallet.dart | 1 + lib/services/litescribe_api.dart | 8 +-- lib/services/mixins/ordinals_interface.dart | 52 +++++++++-------- 6 files changed, 93 insertions(+), 85 deletions(-) create mode 100644 lib/dto/ordinals/inscription_data.dart diff --git a/lib/dto/ordinals/address_inscription_response.dart b/lib/dto/ordinals/address_inscription_response.dart index c424d73e0..240374284 100644 --- a/lib/dto/ordinals/address_inscription_response.dart +++ b/lib/dto/ordinals/address_inscription_response.dart @@ -1,4 +1,5 @@ import 'package:stackwallet/dto/ordinals/litescribe_response.dart'; +import 'package:stackwallet/dto/ordinals/inscription_data.dart'; class AddressInscriptionResponse extends LitescribeResponse<AddressInscriptionResponse> { final int status; @@ -21,7 +22,7 @@ class AddressInscriptionResponse extends LitescribeResponse<AddressInscriptionRe } class AddressInscriptionResult { - final List<AddressInscription> list; + final List<InscriptionData> list; final int total; AddressInscriptionResult({ @@ -31,61 +32,8 @@ class AddressInscriptionResult { factory AddressInscriptionResult.fromJson(Map<String, dynamic> json) { return AddressInscriptionResult( - list: (json['list'] as List).map((item) => AddressInscription.fromJson(item as Map<String, dynamic>)).toList(), + list: (json['list'] as List).map((item) => InscriptionData.fromJson(item as Map<String, dynamic>)).toList(), total: json['total'] as int, ); } } - -class AddressInscription { - final String inscriptionId; - final int inscriptionNumber; - final String address; - final String preview; - final String content; - final int contentLength; - final String contentType; - final String contentBody; - final int timestamp; - final String genesisTransaction; - final String location; - final String output; - final int outputValue; - final int offset; - - AddressInscription({ - required this.inscriptionId, - required this.inscriptionNumber, - required this.address, - required this.preview, - required this.content, - required this.contentLength, - required this.contentType, - required this.contentBody, - required this.timestamp, - required this.genesisTransaction, - required this.location, - required this.output, - required this.outputValue, - required this.offset, - }); - - factory AddressInscription.fromJson(Map<String, dynamic> json) { - return AddressInscription( - inscriptionId: json['inscriptionId'] as String, - inscriptionNumber: json['inscriptionNumber'] as int, - address: json['address'] as String, - preview: json['preview'] as String, - content: json['content'] as String, - contentLength: json['contentLength'] as int, - contentType: json['contentType'] as String, - contentBody: json['contentBody'] as String, - timestamp: json['timestamp'] as int, - genesisTransaction: json['genesisTransaction'] as String, - location: json['location'] as String, - output: json['output'] as String, - outputValue: json['outputValue'] as int, - offset: json['offset'] as int, - ); - } -} diff --git a/lib/dto/ordinals/inscription_data.dart b/lib/dto/ordinals/inscription_data.dart new file mode 100644 index 000000000..b7bba8697 --- /dev/null +++ b/lib/dto/ordinals/inscription_data.dart @@ -0,0 +1,53 @@ +// inscription data from litescribe /address/inscriptions endpoint +class InscriptionData { + final String inscriptionId; + final int inscriptionNumber; + final String address; + final String preview; + final String content; + final int contentLength; + final String contentType; + final String contentBody; + final int timestamp; + final String genesisTransaction; + final String location; + final String output; + final int outputValue; + final int offset; + + InscriptionData({ + required this.inscriptionId, + required this.inscriptionNumber, + required this.address, + required this.preview, + required this.content, + required this.contentLength, + required this.contentType, + required this.contentBody, + required this.timestamp, + required this.genesisTransaction, + required this.location, + required this.output, + required this.outputValue, + required this.offset, + }); + + factory InscriptionData.fromJson(Map<String, dynamic> json) { + return InscriptionData( + inscriptionId: json['inscriptionId'] as String, + inscriptionNumber: json['inscriptionNumber'] as int, + address: json['address'] as String, + preview: json['preview'] as String, + content: json['content'] as String, + contentLength: json['contentLength'] as int, + contentType: json['contentType'] as String, + contentBody: json['contentBody'] as String, + timestamp: json['timestamp'] as int, + genesisTransaction: json['genesisTransaction'] as String, + location: json['location'] as String, + output: json['output'] as String, + outputValue: json['outputValue'] as int, + offset: json['offset'] as int, + ); + } +} diff --git a/lib/pages/ordinals/ordinals_view.dart b/lib/pages/ordinals/ordinals_view.dart index 7a0572c78..f5f3ca23a 100644 --- a/lib/pages/ordinals/ordinals_view.dart +++ b/lib/pages/ordinals/ordinals_view.dart @@ -14,8 +14,9 @@ import 'package:flutter_svg/svg.dart'; import 'package:stackwallet/models/ordinal.dart'; import 'package:stackwallet/pages/ordinals/ordinals_filter_view.dart'; import 'package:stackwallet/pages/ordinals/widgets/ordinals_list.dart'; -import 'package:stackwallet/services/litescribe_api.dart'; -import 'package:stackwallet/services/ordinals_api.dart'; +import 'package:stackwallet/providers/global/wallets_provider.dart'; +// import 'package:stackwallet/services/litescribe_api.dart'; +// import 'package:stackwallet/services/ordinals_api.dart'; import 'package:stackwallet/services/mixins/ordinals_interface.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; @@ -28,6 +29,7 @@ import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:stackwallet/widgets/textfield_icon_button.dart'; + class OrdinalsView extends ConsumerStatefulWidget { const OrdinalsView({ super.key, diff --git a/lib/services/coins/litecoin/litecoin_wallet.dart b/lib/services/coins/litecoin/litecoin_wallet.dart index 2edc32fc6..944182abd 100644 --- a/lib/services/coins/litecoin/litecoin_wallet.dart +++ b/lib/services/coins/litecoin/litecoin_wallet.dart @@ -136,6 +136,7 @@ class LitecoinWallet extends CoinServiceAPI _secureStore = secureStore; initCache(walletId, coin); initWalletDB(mockableOverride: mockableOverride); + initOrdinalsInterface(walletId:walletId, coin: coin, db: db); initCoinControlInterface( walletId: walletId, walletName: walletName, diff --git a/lib/services/litescribe_api.dart b/lib/services/litescribe_api.dart index abc28123e..f7634b387 100644 --- a/lib/services/litescribe_api.dart +++ b/lib/services/litescribe_api.dart @@ -1,7 +1,7 @@ import 'dart:convert'; import 'package:http/http.dart' as http; -import 'package:stackwallet/dto/ordinals/address_inscription_response.dart'; +import 'package:stackwallet/dto/ordinals/inscription_data.dart'; import 'package:stackwallet/dto/ordinals/litescribe_response.dart'; class LitescribeAPI { @@ -34,7 +34,7 @@ class LitescribeAPI { } } - Future<AddressInscriptionResponse> getInscriptionsByAddress(String address, {int cursor = 0, int size = 1000}) async { + Future<List<InscriptionData>> getInscriptionsByAddress(String address, {int cursor = 0, int size = 1000}) async { // size param determines how many inscriptions are returned per response // default of 1000 is used to cover most addresses (I assume) // if the total number of inscriptions at the address exceeds the length of the list of inscriptions returned, another call with a higher size is made @@ -42,7 +42,7 @@ class LitescribeAPI { final response = await _getResponse('/address/inscriptions?address=$address&cursor=$cursor&size=$size'); // Check if the number of returned inscriptions equals the limit - final list = response.data['result']['list'] as List<dynamic>; + final list = response.data['result']['list'] as List<InscriptionData>; final int total = response.data['result']['total'] as int; final int currentSize = list.length; @@ -54,7 +54,7 @@ class LitescribeAPI { // TODO test logic with smaller size "pagination" } else { try { - return AddressInscriptionResponse.fromJson(response.data as Map<String, dynamic>); + return list; } catch (e) { throw const FormatException('LitescribeAPI getInscriptionsByAddress exception: AddressInscriptionResponse.fromJson failure'); } diff --git a/lib/services/mixins/ordinals_interface.dart b/lib/services/mixins/ordinals_interface.dart index caac7a854..fbd41d80b 100644 --- a/lib/services/mixins/ordinals_interface.dart +++ b/lib/services/mixins/ordinals_interface.dart @@ -15,8 +15,8 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart'; // import 'package:stackwallet/dto/ordinals/preview_response.dart'; // import 'package:stackwallet/services/ordinals_api.dart'; -import 'package:stackwallet/dto/ordinals/address_inscription_response.dart'; // verbose due to Litescribe being the 2nd API import 'package:stackwallet/services/litescribe_api.dart'; +import 'package:stackwallet/dto/ordinals/inscription_data.dart'; mixin OrdinalsInterface { @@ -29,39 +29,29 @@ mixin OrdinalsInterface { required Coin coin, required MainDB db, }) { + print('init'); _walletId = walletId; _coin = coin; _db = db; } final LitescribeAPI litescribeAPI = LitescribeAPI(baseUrl: 'https://litescribe.io/api'); - Future<List<AddressInscription>> getInscriptionsByAddress(String address) async { - try { - var response = await litescribeAPI.getInscriptionsByAddress(address); - print("Found ${response.result.total} inscription${response.result.total > 1 ? 's' : ''} at address $address"); // TODO disable (POC) - return response.result.list; - } catch (e) { - throw Exception('Error in OrdinalsInterface getInscriptionsByAddress: $e'); - } - } + // Future<List<InscriptionData>> getInscriptionsByAddress(String address) async { + // try { + // var response = await litescribeAPI.getInscriptionsByAddress(address); + // // print("Found ${response.result.total} inscription${response.result.total > 1 ? 's' : ''} at address $address"); // TODO disable (POC) + // return response.result.list; + // } catch (e) { + // throw Exception('Error in OrdinalsInterface getInscriptionsByAddress: $e'); + // } + // } void refreshInscriptions() async { List<dynamic> _inscriptions; final utxos = await _db.getUTXOs(_walletId).findAll(); final uniqueAddresses = getUniqueAddressesFromUTXOs(utxos); - for (String address in uniqueAddresses) { - // TODO fetch all inscriptions from all addresses - // TODO save those inscriptions to isar, which a StreamBuilder will be "subscribed"-to - } - // TODO get all inscriptions at all addresses in wallet - var inscriptions = await getInscriptionsByAddress('ltc1qk4e8hdq5w6rvk5xvkxajjak78v45pkul8a2cg9'); - for (var inscription in inscriptions) { - print(inscription); - print(inscription.address); - print(inscription.content); - print(inscription.inscriptionId); - print(inscription.inscriptionNumber); - } + _inscriptions = await getAllInscriptionsFromAddresses(uniqueAddresses); + // TODO save inscriptions to isar which gets watched by a StreamBuilder } List<String> getUniqueAddressesFromUTXOs(List<UTXO> utxos) { @@ -74,7 +64,21 @@ mixin OrdinalsInterface { return uniqueAddresses.toList(); } - /* // ord-litecoin interface + Future<List<InscriptionData>> getAllInscriptionsFromAddresses(List<String> addresses) async { + List<InscriptionData> allInscriptions = []; + for (String address in addresses) { + try { + var inscriptions = await litescribeAPI.getInscriptionsByAddress(address); + print("Found ${inscriptions.length} inscription${inscriptions.length > 1 ? 's' : ''} at address $address"); + allInscriptions.addAll(inscriptions); + } catch (e) { + print("Error fetching inscriptions for address $address: $e"); + } + } + return allInscriptions; + } + +/* // ord-litecoin interface final OrdinalsAPI ordinalsAPI = OrdinalsAPI(baseUrl: 'https://ord-litecoin.stackwallet.com'); Future<FeedResponse> fetchLatestInscriptions() async { From b773811eac6007dd878b4337711e7b2df963cdaa Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Thu, 20 Jul 2023 16:49:26 -0500 Subject: [PATCH 22/31] working proof of concept --- lib/pages/ordinals/ordinals_view.dart | 10 +++++----- lib/services/litescribe_api.dart | 11 ++++++++--- lib/services/mixins/ordinals_interface.dart | 7 ++++--- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/lib/pages/ordinals/ordinals_view.dart b/lib/pages/ordinals/ordinals_view.dart index f5f3ca23a..8993ed4e7 100644 --- a/lib/pages/ordinals/ordinals_view.dart +++ b/lib/pages/ordinals/ordinals_view.dart @@ -15,8 +15,6 @@ import 'package:stackwallet/models/ordinal.dart'; import 'package:stackwallet/pages/ordinals/ordinals_filter_view.dart'; import 'package:stackwallet/pages/ordinals/widgets/ordinals_list.dart'; import 'package:stackwallet/providers/global/wallets_provider.dart'; -// import 'package:stackwallet/services/litescribe_api.dart'; -// import 'package:stackwallet/services/ordinals_api.dart'; import 'package:stackwallet/services/mixins/ordinals_interface.dart'; import 'package:stackwallet/themes/stack_colors.dart'; import 'package:stackwallet/utilities/assets.dart'; @@ -29,7 +27,6 @@ import 'package:stackwallet/widgets/icon_widgets/x_icon.dart'; import 'package:stackwallet/widgets/stack_text_field.dart'; import 'package:stackwallet/widgets/textfield_icon_button.dart'; - class OrdinalsView extends ConsumerStatefulWidget { const OrdinalsView({ super.key, @@ -44,7 +41,7 @@ class OrdinalsView extends ConsumerStatefulWidget { ConsumerState<OrdinalsView> createState() => _OrdinalsViewState(); } -class _OrdinalsViewState extends ConsumerState<OrdinalsView> with OrdinalsInterface { +class _OrdinalsViewState extends ConsumerState<OrdinalsView> { late final TextEditingController searchController; late final FocusNode searchFocus; @@ -94,7 +91,10 @@ class _OrdinalsViewState extends ConsumerState<OrdinalsView> with OrdinalsInterf .topNavIconPrimary, ), onPressed: () async { - refreshInscriptions(); + final manager = ref.watch(walletsChangeNotifierProvider + .select((value) => value.getManager(widget.walletId))); + + (manager.wallet as OrdinalsInterface).refreshInscriptions(); }, ), ), diff --git a/lib/services/litescribe_api.dart b/lib/services/litescribe_api.dart index f7634b387..7fc92910d 100644 --- a/lib/services/litescribe_api.dart +++ b/lib/services/litescribe_api.dart @@ -42,7 +42,7 @@ class LitescribeAPI { final response = await _getResponse('/address/inscriptions?address=$address&cursor=$cursor&size=$size'); // Check if the number of returned inscriptions equals the limit - final list = response.data['result']['list'] as List<InscriptionData>; + final list = response.data['result']['list']; final int total = response.data['result']['total'] as int; final int currentSize = list.length; @@ -51,10 +51,15 @@ class LitescribeAPI { // increment the cursor and make the next API call to fetch the remaining inscriptions. final int newCursor = cursor + size; return getInscriptionsByAddress(address, cursor: newCursor, size: size); - // TODO test logic with smaller size "pagination" + } else { try { - return list; + // Iterate through the list and create InscriptionData objects from each element + final List<InscriptionData> inscriptions = (list as List<dynamic>) + .map((json) => InscriptionData.fromJson(json as Map<String, dynamic>)) + .toList(); + + return inscriptions; } catch (e) { throw const FormatException('LitescribeAPI getInscriptionsByAddress exception: AddressInscriptionResponse.fromJson failure'); } diff --git a/lib/services/mixins/ordinals_interface.dart b/lib/services/mixins/ordinals_interface.dart index fbd41d80b..a04b6522c 100644 --- a/lib/services/mixins/ordinals_interface.dart +++ b/lib/services/mixins/ordinals_interface.dart @@ -1,3 +1,5 @@ +import 'dart:async'; + import 'package:isar/isar.dart'; import 'package:stackwallet/db/isar/main_db.dart'; import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart'; @@ -18,7 +20,6 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/services/litescribe_api.dart'; import 'package:stackwallet/dto/ordinals/inscription_data.dart'; - mixin OrdinalsInterface { late final String _walletId; late final Coin _coin; @@ -50,7 +51,7 @@ mixin OrdinalsInterface { List<dynamic> _inscriptions; final utxos = await _db.getUTXOs(_walletId).findAll(); final uniqueAddresses = getUniqueAddressesFromUTXOs(utxos); - _inscriptions = await getAllInscriptionsFromAddresses(uniqueAddresses); + _inscriptions = await getInscriptionsFromAddresses(uniqueAddresses); // TODO save inscriptions to isar which gets watched by a StreamBuilder } @@ -64,7 +65,7 @@ mixin OrdinalsInterface { return uniqueAddresses.toList(); } - Future<List<InscriptionData>> getAllInscriptionsFromAddresses(List<String> addresses) async { + Future<List<InscriptionData>> getInscriptionsFromAddresses(List<String> addresses) async { List<InscriptionData> allInscriptions = []; for (String address in addresses) { try { From 20fdcf48174c8cb102e950fd3f8ed146be96998a Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Thu, 20 Jul 2023 17:15:25 -0500 Subject: [PATCH 23/31] refactor manager var out to _manager, comment update --- lib/pages/ordinals/ordinals_view.dart | 9 +++++---- lib/services/mixins/ordinals_interface.dart | 2 +- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/pages/ordinals/ordinals_view.dart b/lib/pages/ordinals/ordinals_view.dart index 8993ed4e7..bf0545d4c 100644 --- a/lib/pages/ordinals/ordinals_view.dart +++ b/lib/pages/ordinals/ordinals_view.dart @@ -46,12 +46,16 @@ class _OrdinalsViewState extends ConsumerState<OrdinalsView> { late final FocusNode searchFocus; String _searchTerm = ""; + dynamic _manager; @override void initState() { searchController = TextEditingController(); searchFocus = FocusNode(); + _manager = ref.watch(walletsChangeNotifierProvider + .select((value) => value.getManager(widget.walletId))); + super.initState(); } @@ -91,10 +95,7 @@ class _OrdinalsViewState extends ConsumerState<OrdinalsView> { .topNavIconPrimary, ), onPressed: () async { - final manager = ref.watch(walletsChangeNotifierProvider - .select((value) => value.getManager(widget.walletId))); - - (manager.wallet as OrdinalsInterface).refreshInscriptions(); + (_manager.wallet as OrdinalsInterface).refreshInscriptions(); }, ), ), diff --git a/lib/services/mixins/ordinals_interface.dart b/lib/services/mixins/ordinals_interface.dart index a04b6522c..2d887bfcd 100644 --- a/lib/services/mixins/ordinals_interface.dart +++ b/lib/services/mixins/ordinals_interface.dart @@ -52,7 +52,7 @@ mixin OrdinalsInterface { final utxos = await _db.getUTXOs(_walletId).findAll(); final uniqueAddresses = getUniqueAddressesFromUTXOs(utxos); _inscriptions = await getInscriptionsFromAddresses(uniqueAddresses); - // TODO save inscriptions to isar which gets watched by a StreamBuilder + // TODO save inscriptions to isar which gets watched by a FutureBuilder/StreamBuilder } List<String> getUniqueAddressesFromUTXOs(List<UTXO> utxos) { From af30826e9e9fa33502a5ac583eba14d0d4ff8dcd Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Fri, 21 Jul 2023 10:03:05 -0500 Subject: [PATCH 24/31] remove ord-litecoin imports --- lib/dto/ordinals/address_response.dart | 52 ----------- lib/dto/ordinals/block_response.dart | 61 ------------- lib/dto/ordinals/content_response.dart | 22 ----- lib/dto/ordinals/feed_response.dart | 17 ---- lib/dto/ordinals/inscription_link.dart | 13 --- lib/dto/ordinals/inscription_response.dart | 97 --------------------- lib/dto/ordinals/ordinals_response.dart | 6 -- lib/dto/ordinals/output_response.dart | 47 ---------- lib/dto/ordinals/preview_response.dart | 22 ----- lib/dto/ordinals/sat_response.dart | 85 ------------------ lib/dto/ordinals/transaction_response.dart | 82 ----------------- lib/services/mixins/ordinals_interface.dart | 12 --- 12 files changed, 516 deletions(-) delete mode 100644 lib/dto/ordinals/address_response.dart delete mode 100644 lib/dto/ordinals/block_response.dart delete mode 100644 lib/dto/ordinals/content_response.dart delete mode 100644 lib/dto/ordinals/feed_response.dart delete mode 100644 lib/dto/ordinals/inscription_link.dart delete mode 100644 lib/dto/ordinals/inscription_response.dart delete mode 100644 lib/dto/ordinals/ordinals_response.dart delete mode 100644 lib/dto/ordinals/output_response.dart delete mode 100644 lib/dto/ordinals/preview_response.dart delete mode 100644 lib/dto/ordinals/sat_response.dart delete mode 100644 lib/dto/ordinals/transaction_response.dart diff --git a/lib/dto/ordinals/address_response.dart b/lib/dto/ordinals/address_response.dart deleted file mode 100644 index 9136aa523..000000000 --- a/lib/dto/ordinals/address_response.dart +++ /dev/null @@ -1,52 +0,0 @@ -import 'package:stackwallet/dto/ordinals/inscription_link.dart'; -import 'package:stackwallet/dto/ordinals/ordinals_response.dart'; - -class AddressResponse extends OrdinalsResponse<AddressResponse> { - final AddressLinks links; - final String address; - final List<InscriptionLink> inscriptions; - - AddressResponse({ - required this.links, - required this.address, - required this.inscriptions, - }); - - factory AddressResponse.fromJson(OrdinalsResponse json) { - final data = json.data as Map<String, dynamic>; - final inscriptionsJson = data['inscriptions'] as List; - final inscriptions = inscriptionsJson - .map((inscriptionJson) => InscriptionLink.fromJson(inscriptionJson as Map<String, dynamic>)) - .toList(); - - return AddressResponse( - links: AddressLinks.fromJson(data['_links'] as Map<String, dynamic>), - address: data['address'] as String, - inscriptions: inscriptions, - ); - } -} - -class AddressLinks { - final AddressLink? self; - - AddressLinks({ - this.self, - }); - - factory AddressLinks.fromJson(Map<String, dynamic> json) { - return AddressLinks( - self: json['self'] != null ? AddressLink.fromJson(json['self'] as Map<String, dynamic>) : null, - ); - } -} - -class AddressLink { - final String href; - - AddressLink({required this.href}); - - factory AddressLink.fromJson(Map<String, dynamic> json) { - return AddressLink(href: json['href'] as String); - } -} diff --git a/lib/dto/ordinals/block_response.dart b/lib/dto/ordinals/block_response.dart deleted file mode 100644 index 0eef8d569..000000000 --- a/lib/dto/ordinals/block_response.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'package:stackwallet/dto/ordinals/ordinals_response.dart'; - -class BlockResponse extends OrdinalsResponse<BlockResponse> { - final BlockLinks links; - final String hash; - final String previousBlockhash; - final int size; - final String target; - final String timestamp; - final int weight; - - BlockResponse({ - required this.links, - required this.hash, - required this.previousBlockhash, - required this.size, - required this.target, - required this.timestamp, - required this.weight, - }); - - factory BlockResponse.fromJson(OrdinalsResponse json) { - final data = json.data as Map<String, dynamic>; - return BlockResponse( - links: BlockLinks.fromJson(data['_links'] as Map<String, dynamic>), - hash: data['hash'] as String, - previousBlockhash: data['previous_blockhash'] as String, - size: data['size'] as int, - target: data['target'] as String, - timestamp: data['timestamp'] as String, - weight: data['weight'] as int, - ); - } -} - -class BlockLinks { - final BlockLink? prev; - final BlockLink? self; - - BlockLinks({ - this.prev, - this.self, - }); - - factory BlockLinks.fromJson(Map<String, dynamic> json) { - return BlockLinks( - prev: json['prev'] != null ? BlockLink.fromJson(json['prev'] as Map<String, dynamic>) : null, - self: json['self'] != null ? BlockLink.fromJson(json['self'] as Map<String, dynamic>) : null, - ); - } -} - -class BlockLink { - final String href; - - BlockLink({required this.href}); - - factory BlockLink.fromJson(Map<String, dynamic> json) { - return BlockLink(href: json['href'] as String); - } -} diff --git a/lib/dto/ordinals/content_response.dart b/lib/dto/ordinals/content_response.dart deleted file mode 100644 index 7cfbaf9fd..000000000 --- a/lib/dto/ordinals/content_response.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:stackwallet/dto/ordinals/ordinals_response.dart'; - -class ContentResponse extends OrdinalsResponse<ContentResponse> { - final FileLink fileLink; - - ContentResponse({required this.fileLink}); - - factory ContentResponse.fromJson(OrdinalsResponse json) { - 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> - } -} - -class FileLink { - final String href; - - FileLink({required this.href}); - - factory FileLink.fromJson(Map<String, dynamic> json) { - return FileLink(href: json['href'] as String); - } -} diff --git a/lib/dto/ordinals/feed_response.dart b/lib/dto/ordinals/feed_response.dart deleted file mode 100644 index 525a7f727..000000000 --- a/lib/dto/ordinals/feed_response.dart +++ /dev/null @@ -1,17 +0,0 @@ -import 'package:stackwallet/dto/ordinals/inscription_link.dart'; -import 'package:stackwallet/dto/ordinals/ordinals_response.dart'; - -class FeedResponse extends OrdinalsResponse<FeedResponse> { - final List<InscriptionLink> inscriptions; - - FeedResponse({required this.inscriptions}); - - factory FeedResponse.fromJson(OrdinalsResponse json) { - final List<dynamic> inscriptionsJson = json.data['_links']['inscriptions'] as List<dynamic>; - final List<InscriptionLink> inscriptions = inscriptionsJson - .map((json) => InscriptionLink.fromJson(json as Map<String, dynamic>)) - .toList(); - - return FeedResponse(inscriptions: inscriptions); - } -} \ No newline at end of file diff --git a/lib/dto/ordinals/inscription_link.dart b/lib/dto/ordinals/inscription_link.dart deleted file mode 100644 index f23b63248..000000000 --- a/lib/dto/ordinals/inscription_link.dart +++ /dev/null @@ -1,13 +0,0 @@ -class InscriptionLink { - final String href; - final String title; - - InscriptionLink({required this.href, required this.title}); - - factory InscriptionLink.fromJson(Map<String, dynamic> json) { - return InscriptionLink( - href: json['href'] as String ?? '', - title: json['title'] as String ?? '', - ); - } -} diff --git a/lib/dto/ordinals/inscription_response.dart b/lib/dto/ordinals/inscription_response.dart deleted file mode 100644 index d45300aee..000000000 --- a/lib/dto/ordinals/inscription_response.dart +++ /dev/null @@ -1,97 +0,0 @@ -import 'package:stackwallet/dto/ordinals/ordinals_response.dart'; - -class InscriptionResponse extends OrdinalsResponse<InscriptionResponse> { - late final Links links; - late final String address; - late final int contentLength; - late final String contentType; - late final int genesisFee; - late final int genesisHeight; - late final String genesisTransaction; - late final String location; - late final int number; - late final int offset; - late final String output; - late final String? sat; // Make sure to update the type to allow null - late final String timestamp; - - InscriptionResponse({ - required this.links, - required this.address, - required this.contentLength, - required this.contentType, - required this.genesisFee, - required this.genesisHeight, - required this.genesisTransaction, - required this.location, - required this.number, - required this.offset, - required this.output, - required this.sat, - required this.timestamp, - }); - - factory InscriptionResponse.fromJson(OrdinalsResponse json) { - final data = json.data as Map<String, dynamic>; - return InscriptionResponse( - links: Links.fromJson(data['_links'] as Map<String, dynamic>), - address: data['address'] as String, - contentLength: data['content_length'] as int, - contentType: data['content_type'] as String, - genesisFee: data['genesis_fee'] as int, - genesisHeight: data['genesis_height'] as int, - genesisTransaction: data['genesis_transaction'] as String, - location: data['location'] as String, - number: data['number'] as int, - offset: data['offset'] as int, - output: data['output'] as String, - sat: data['sat'] as String?, - timestamp: data['timestamp'] as String, - ); - } -} - -class Links { - late final Link content; - late final Link genesisTransaction; - late final Link next; - late final Link output; - late final Link prev; - late final Link preview; - late final Link? sat; // Make sure to update the type to allow null - late final Link self; - - Links({ - required this.content, - required this.genesisTransaction, - required this.next, - required this.output, - required this.prev, - required this.preview, - this.sat, - required this.self, - }); - - factory Links.fromJson(Map<String, dynamic> json) { - return Links( - content: Link.fromJson(json['content'] as Map<String, dynamic>), - genesisTransaction: Link.fromJson(json['genesis_transaction'] as Map<String, dynamic>), - next: Link.fromJson(json['next'] as Map<String, dynamic>), - output: Link.fromJson(json['output'] as Map<String, dynamic>), - prev: Link.fromJson(json['prev'] as Map<String, dynamic>), - preview: Link.fromJson(json['preview'] 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>), - ); - } -} - -class Link { - late final String href; - - Link({required this.href}); - - factory Link.fromJson(Map<String, dynamic> json) { - return Link(href: json['href'] as String); - } -} diff --git a/lib/dto/ordinals/ordinals_response.dart b/lib/dto/ordinals/ordinals_response.dart deleted file mode 100644 index bf57db46b..000000000 --- a/lib/dto/ordinals/ordinals_response.dart +++ /dev/null @@ -1,6 +0,0 @@ -class OrdinalsResponse<T> { - final T? data; - final String? error; - - OrdinalsResponse({this.data, this.error}); -} diff --git a/lib/dto/ordinals/output_response.dart b/lib/dto/ordinals/output_response.dart deleted file mode 100644 index cc7b2107f..000000000 --- a/lib/dto/ordinals/output_response.dart +++ /dev/null @@ -1,47 +0,0 @@ -import 'package:stackwallet/dto/ordinals/transaction_response.dart'; -import 'package:stackwallet/dto/ordinals/ordinals_response.dart'; - -class OutputResponse extends OrdinalsResponse<OutputResponse> { - final OutputLinks links; - final String address; - final String scriptPubkey; - final String transaction; - final int value; - - OutputResponse({ - required this.links, - required this.address, - required this.scriptPubkey, - required this.transaction, - required this.value, - }); - - factory OutputResponse.fromJson(OrdinalsResponse json) { - final data = json.data as Map<String, dynamic>; - - return OutputResponse( - links: OutputLinks.fromJson(data['_links'] as Map<String, dynamic>), - address: data['address'] as String, - scriptPubkey: data['script_pubkey'] as String, - transaction: data['transaction'] as String, - value: data['value'] as int, - ); - } -} - -class OutputLinks { - final OutputLink? self; - final TransactionLink? transaction; - - OutputLinks({ - this.self, - this.transaction, - }); - - factory OutputLinks.fromJson(Map<String, dynamic> json) { - return OutputLinks( - self: json['self'] != null ? OutputLink.fromJson(json['self'] as Map<String, dynamic>) : null, - transaction: json['transaction'] != null ? TransactionLink.fromJson(json['transaction'] as Map<String, dynamic>) : null, - ); - } -} diff --git a/lib/dto/ordinals/preview_response.dart b/lib/dto/ordinals/preview_response.dart deleted file mode 100644 index b3e184acd..000000000 --- a/lib/dto/ordinals/preview_response.dart +++ /dev/null @@ -1,22 +0,0 @@ -import 'package:stackwallet/dto/ordinals/ordinals_response.dart'; - -class PreviewResponse extends OrdinalsResponse<PreviewResponse> { - final ImageLink imageLink; - - PreviewResponse({required this.imageLink}); - - factory PreviewResponse.fromJson(OrdinalsResponse json) { - final data = json.data as Map<String, dynamic>; - return PreviewResponse(imageLink: ImageLink.fromJson(data['_links']['image'] as Map<String, dynamic>)); - } -} - -class ImageLink { - final String href; - - ImageLink({required this.href}); - - factory ImageLink.fromJson(Map<String, dynamic> json) { - return ImageLink(href: json['href'] as String); - } -} diff --git a/lib/dto/ordinals/sat_response.dart b/lib/dto/ordinals/sat_response.dart deleted file mode 100644 index 40efb1440..000000000 --- a/lib/dto/ordinals/sat_response.dart +++ /dev/null @@ -1,85 +0,0 @@ -import 'package:stackwallet/dto/ordinals/ordinals_response.dart'; - -class SatResponse extends OrdinalsResponse<SatResponse> { - final SatLinks links; - final int block; - final int cycle; - final String decimal; - final String degree; - final int epoch; - final String name; - final int offset; - final String percentile; - final int period; - final String rarity; - final String timestamp; - - SatResponse({ - required this.links, - required this.block, - required this.cycle, - required this.decimal, - required this.degree, - required this.epoch, - required this.name, - required this.offset, - required this.percentile, - required this.period, - required this.rarity, - required this.timestamp, - }); - - factory SatResponse.fromJson(OrdinalsResponse json) { - final data = json.data as Map<String, dynamic>; - return SatResponse( - links: SatLinks.fromJson(data['_links'] as Map<String, dynamic>), - block: data['block'] as int, - cycle: data['cycle'] as int, - decimal: data['decimal'] as String, - degree: data['degree'] as String, - epoch: data['epoch'] as int, - name: data['name'] as String, - offset: data['offset'] as int, - percentile: data['percentile'] as String, - period: data['period'] as int, - rarity: data['rarity'] as String, - timestamp: data['timestamp'] as String, - ); - } -} - -class SatLinks { - final SatLink? block; - final SatLink? inscription; - final SatLink? next; - final SatLink? prev; - final SatLink? self; - - SatLinks({ - this.block, - this.inscription, - this.next, - this.prev, - this.self, - }); - - factory SatLinks.fromJson(Map<String, dynamic> json) { - return SatLinks( - block: json['block'] != null ? SatLink.fromJson(json['block'] as Map<String, dynamic>) : null, - inscription: json['inscription'] != null ? SatLink.fromJson(json['inscription'] as Map<String, dynamic>) : null, - next: json['next'] != null ? SatLink.fromJson(json['next'] as Map<String, dynamic>) : null, - prev: json['prev'] != null ? SatLink.fromJson(json['prev'] as Map<String, dynamic>) : null, - self: json['self'] != null ? SatLink.fromJson(json['self'] as Map<String, dynamic>) : null, - ); - } -} - -class SatLink { - final String href; - - SatLink({required this.href}); - - factory SatLink.fromJson(Map<String, dynamic> json) { - return SatLink(href: json['href'] as String); - } -} diff --git a/lib/dto/ordinals/transaction_response.dart b/lib/dto/ordinals/transaction_response.dart deleted file mode 100644 index c77e07914..000000000 --- a/lib/dto/ordinals/transaction_response.dart +++ /dev/null @@ -1,82 +0,0 @@ -import 'package:stackwallet/dto/ordinals/inscription_link.dart'; -import 'package:stackwallet/dto/ordinals/ordinals_response.dart'; - -class TransactionResponse extends OrdinalsResponse<TransactionResponse> { - final TransactionLinks links; - final List<OutputLink> inputs; - final InscriptionLink inscription; - final List<OutputLink> outputs; - final TransactionLink self; - final String transaction; - - TransactionResponse({ - required this.links, - required this.inputs, - required this.inscription, - required this.outputs, - required this.self, - required this.transaction, - }); - - factory TransactionResponse.fromJson(OrdinalsResponse json) { - final data = json.data as Map<String, dynamic>; - final inputsJson = data['_links']['inputs'] as List; - final inputs = inputsJson - .map((inputJson) => OutputLink.fromJson(inputJson as Map<String, dynamic>)) - .toList(); - - final outputsJson = data['_links']['outputs'] as List; - final outputs = outputsJson - .map((outputJson) => OutputLink.fromJson(outputJson as Map<String, dynamic>)) - .toList(); - - return TransactionResponse( - links: TransactionLinks.fromJson(data['_links'] as Map<String, dynamic>), - inputs: inputs, - inscription: InscriptionLink.fromJson(data['_links']['inscription'] as Map<String, dynamic>), - outputs: outputs, - self: TransactionLink.fromJson(data['_links']['self'] as Map<String, dynamic>), - transaction: data['transaction'] as String, - ); - } -} - -class TransactionLinks { - final TransactionLink? block; - final InscriptionLink? inscription; - final TransactionLink? self; - - TransactionLinks({ - this.block, - this.inscription, - this.self, - }); - - factory TransactionLinks.fromJson(Map<String, dynamic> json) { - return TransactionLinks( - block: json['block'] != null ? TransactionLink.fromJson(json['block'] as Map<String, dynamic>) : null, - inscription: json['inscription'] != null ? InscriptionLink.fromJson(json['inscription'] as Map<String, dynamic>) : null, - self: json['self'] != null ? TransactionLink.fromJson(json['self'] as Map<String, dynamic>) : null, - ); - } -} - -class TransactionLink { - final String href; - - TransactionLink({required this.href}); - - factory TransactionLink.fromJson(Map<String, dynamic> json) { - return TransactionLink(href: json['href'] as String); - } -} - -class OutputLink { - final String href; - - OutputLink({required this.href}); - - factory OutputLink.fromJson(Map<String, dynamic> json) { - return OutputLink(href: json['href'] as String); - } -} diff --git a/lib/services/mixins/ordinals_interface.dart b/lib/services/mixins/ordinals_interface.dart index 2d887bfcd..c7bc5ff28 100644 --- a/lib/services/mixins/ordinals_interface.dart +++ b/lib/services/mixins/ordinals_interface.dart @@ -5,18 +5,6 @@ import 'package:stackwallet/db/isar/main_db.dart'; import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart'; import 'package:stackwallet/utilities/enums/coin_enum.dart'; -// ord-litecoin-specific imports -// import 'package:stackwallet/dto/ordinals/feed_response.dart'; -// import 'package:stackwallet/dto/ordinals/inscription_response.dart'; -// import 'package:stackwallet/dto/ordinals/sat_response.dart'; -// import 'package:stackwallet/dto/ordinals/transaction_response.dart'; -// import 'package:stackwallet/dto/ordinals/output_response.dart'; -// import 'package:stackwallet/dto/ordinals/address_response.dart'; -// import 'package:stackwallet/dto/ordinals/block_response.dart'; -// import 'package:stackwallet/dto/ordinals/content_response.dart'; -// import 'package:stackwallet/dto/ordinals/preview_response.dart'; -// import 'package:stackwallet/services/ordinals_api.dart'; - import 'package:stackwallet/services/litescribe_api.dart'; import 'package:stackwallet/dto/ordinals/inscription_data.dart'; From 39eaa937fc83fb3aec9882ad1b6744ff1367abef Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Fri, 21 Jul 2023 10:06:34 -0500 Subject: [PATCH 25/31] add convenience method, remove ord-litecoin API file, cast dynamic->int --- lib/services/litescribe_api.dart | 2 +- lib/services/mixins/ordinals_interface.dart | 6 ++ lib/services/ordinals_api.dart | 89 --------------------- 3 files changed, 7 insertions(+), 90 deletions(-) delete mode 100644 lib/services/ordinals_api.dart diff --git a/lib/services/litescribe_api.dart b/lib/services/litescribe_api.dart index 7fc92910d..d5cd3d733 100644 --- a/lib/services/litescribe_api.dart +++ b/lib/services/litescribe_api.dart @@ -44,7 +44,7 @@ class LitescribeAPI { // Check if the number of returned inscriptions equals the limit final list = response.data['result']['list']; final int total = response.data['result']['total'] as int; - final int currentSize = list.length; + final int currentSize = list.length as int; if (currentSize == size && currentSize < total) { // If the number of returned inscriptions equals the limit and there are more inscriptions available, diff --git a/lib/services/mixins/ordinals_interface.dart b/lib/services/mixins/ordinals_interface.dart index c7bc5ff28..51323fa0c 100644 --- a/lib/services/mixins/ordinals_interface.dart +++ b/lib/services/mixins/ordinals_interface.dart @@ -43,6 +43,12 @@ mixin OrdinalsInterface { // TODO save inscriptions to isar which gets watched by a FutureBuilder/StreamBuilder } + Future<List<InscriptionData>> getInscriptions() async { + final utxos = await _db.getUTXOs(_walletId).findAll(); + final uniqueAddresses = getUniqueAddressesFromUTXOs(utxos); + return await getInscriptionsFromAddresses(uniqueAddresses); + } + List<String> getUniqueAddressesFromUTXOs(List<UTXO> utxos) { final Set<String> uniqueAddresses = <String>{}; for (var utxo in utxos) { diff --git a/lib/services/ordinals_api.dart b/lib/services/ordinals_api.dart deleted file mode 100644 index e6df3c05e..000000000 --- a/lib/services/ordinals_api.dart +++ /dev/null @@ -1,89 +0,0 @@ -import 'dart:convert'; -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/inscription_response.dart'; -import 'package:stackwallet/dto/ordinals/sat_response.dart'; -import 'package:stackwallet/dto/ordinals/transaction_response.dart'; -import 'package:stackwallet/dto/ordinals/output_response.dart'; -import 'package:stackwallet/dto/ordinals/address_response.dart'; -import 'package:stackwallet/dto/ordinals/block_response.dart'; -import 'package:stackwallet/dto/ordinals/content_response.dart'; -import 'package:stackwallet/dto/ordinals/preview_response.dart'; - -class OrdinalsAPI { - static final OrdinalsAPI _instance = OrdinalsAPI._internal(); - - factory OrdinalsAPI({required String baseUrl}) { - _instance.baseUrl = baseUrl; - return _instance; - } - - OrdinalsAPI._internal(); - - late String baseUrl; - - Future<OrdinalsResponse> _getResponse(String endpoint) async { - final response = await http.get(Uri.parse('$baseUrl$endpoint')); - if (response.statusCode == 200) { - return OrdinalsResponse(data: _validateJson(response.body)); - } else { - throw Exception('Failed to load data'); - } - } - - Map<String, dynamic> _validateJson(String responseBody) { - final parsed = jsonDecode(responseBody); - if (parsed is Map<String, dynamic>) { - return parsed; - } else { - throw const FormatException('Invalid JSON format'); - } - } - - Future<FeedResponse> getLatestInscriptions() async { - final response = await _getResponse('/feed'); - return FeedResponse.fromJson(response); - } - - Future<InscriptionResponse> getInscriptionDetails(String inscriptionId) async { - final response = await _getResponse('/inscription/$inscriptionId'); - return InscriptionResponse.fromJson(response); - } - - Future<SatResponse> getSatDetails(int satNumber) async { - final response = await _getResponse('/sat/$satNumber'); - return SatResponse.fromJson(response); - } - - Future<TransactionResponse> getTransaction(String transactionId) async { - final response = await _getResponse('/tx/$transactionId'); - return TransactionResponse.fromJson(response); - } - - Future<OutputResponse> getTransactionOutputs(String transactionId) async { - final response = await _getResponse('/output/$transactionId'); - return OutputResponse.fromJson(response); - } - - Future<AddressResponse> getInscriptionsByAddress(String address) async { - final response = await _getResponse('/address/$address'); - return AddressResponse.fromJson(response); - } - - Future<BlockResponse> getBlock(String blockHash) async { - final response = await _getResponse('/block/$blockHash'); - return BlockResponse.fromJson(response); - } - - Future<ContentResponse> getInscriptionContent(String inscriptionId) async { - final response = await _getResponse('/content/$inscriptionId'); - return ContentResponse.fromJson(response); - } - - Future<PreviewResponse> getInscriptionPreview(String inscriptionId) async { - final response = await _getResponse('/preview/$inscriptionId'); - return PreviewResponse.fromJson(response); - } -} From c295ca9a6f1c7146960b455c3bb428a82fe7de72 Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Fri, 21 Jul 2023 10:12:31 -0500 Subject: [PATCH 26/31] fix ordinal view crash --- lib/pages/ordinals/ordinals_view.dart | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/pages/ordinals/ordinals_view.dart b/lib/pages/ordinals/ordinals_view.dart index bf0545d4c..c340fa6c6 100644 --- a/lib/pages/ordinals/ordinals_view.dart +++ b/lib/pages/ordinals/ordinals_view.dart @@ -53,9 +53,6 @@ class _OrdinalsViewState extends ConsumerState<OrdinalsView> { searchController = TextEditingController(); searchFocus = FocusNode(); - _manager = ref.watch(walletsChangeNotifierProvider - .select((value) => value.getManager(widget.walletId))); - super.initState(); } @@ -95,6 +92,8 @@ class _OrdinalsViewState extends ConsumerState<OrdinalsView> { .topNavIconPrimary, ), onPressed: () async { + _manager = ref.watch(walletsChangeNotifierProvider + .select((value) => value.getManager(widget.walletId))); (_manager.wallet as OrdinalsInterface).refreshInscriptions(); }, ), From f750bbfe102239ec7d0f7ac195896ca23218693b Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Fri, 21 Jul 2023 10:30:47 -0500 Subject: [PATCH 27/31] hook OrdinalsList up to OrdinalsInterface --- lib/pages/ordinals/ordinals_view.dart | 22 +++---- lib/pages/ordinals/widgets/ordinal_card.dart | 24 +++---- lib/pages/ordinals/widgets/ordinals_list.dart | 62 +++++++++++-------- 3 files changed, 57 insertions(+), 51 deletions(-) diff --git a/lib/pages/ordinals/ordinals_view.dart b/lib/pages/ordinals/ordinals_view.dart index c340fa6c6..b12fb78c4 100644 --- a/lib/pages/ordinals/ordinals_view.dart +++ b/lib/pages/ordinals/ordinals_view.dart @@ -56,6 +56,14 @@ class _OrdinalsViewState extends ConsumerState<OrdinalsView> { super.initState(); } + @override + void didChangeDependencies() { + super.didChangeDependencies(); + // Set _manager here when the widget's dependencies change + _manager = ref.watch(walletsChangeNotifierProvider + .select((value) => value.getManager(widget.walletId))); + } + @override void dispose() { searchController.dispose(); @@ -92,8 +100,6 @@ class _OrdinalsViewState extends ConsumerState<OrdinalsView> { .topNavIconPrimary, ), onPressed: () async { - _manager = ref.watch(walletsChangeNotifierProvider - .select((value) => value.getManager(widget.walletId))); (_manager.wallet as OrdinalsInterface).refreshInscriptions(); }, ), @@ -187,17 +193,7 @@ class _OrdinalsViewState extends ConsumerState<OrdinalsView> { Expanded( child: OrdinalsList( walletId: widget.walletId, - ordinals: [ - for (int i = 0; i < 13; i++) - Ordinal( - name: "dummy name $i", - inscription: "insc$i", - rank: "r$i", - collection: OrdCollection.moonbirds, - utxoTXID: 'txid', - utxoVOUT: 1 - ), - ], + ordinalsFuture: (_manager.wallet as OrdinalsInterface).getInscriptions(), ), ), ], diff --git a/lib/pages/ordinals/widgets/ordinal_card.dart b/lib/pages/ordinals/widgets/ordinal_card.dart index a3419ae87..a4d58711e 100644 --- a/lib/pages/ordinals/widgets/ordinal_card.dart +++ b/lib/pages/ordinals/widgets/ordinal_card.dart @@ -1,18 +1,19 @@ import 'package:flutter/material.dart'; -import 'package:stackwallet/models/ordinal.dart'; +import 'package:stackwallet/dto/ordinals/inscription_data.dart'; +import 'package:stackwallet/models/ordinal.dart'; // TODO generalize InscriptionData models -> Ordinal import 'package:stackwallet/pages/ordinals/ordinal_details_view.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; class OrdinalCard extends StatelessWidget { const OrdinalCard({ - super.key, + Key? key, required this.walletId, - required this.ordinal, - }); + required this.inscriptionData, + }) : super(key: key); final String walletId; - final Ordinal ordinal; + final InscriptionData inscriptionData; @override Widget build(BuildContext context) { @@ -21,7 +22,7 @@ class OrdinalCard extends StatelessWidget { onPressed: () { Navigator.of(context).pushNamed( OrdinalDetailsView.routeName, - arguments: (walletId: walletId, ordinal: ordinal), + arguments: (walletId: walletId, inscriptionData: inscriptionData), ); }, child: Column( @@ -31,21 +32,20 @@ class OrdinalCard extends StatelessWidget { aspectRatio: 1, child: Container( color: Colors.red, - child: const Center( - child: Text( - "replace red container with image", - ), + child: Image.network( + inscriptionData.preview, // Use the preview URL as the image source + fit: BoxFit.cover, ), ), ), const Spacer(), Text( - ordinal.name, + inscriptionData.address, style: STextStyles.w500_12(context), ), const Spacer(), Text( - "INSC. ${ordinal.inscription} RANK ${ordinal.rank}", + "INSC. ${inscriptionData.inscriptionNumber} ID ${inscriptionData.inscriptionId}", style: STextStyles.w500_8(context), ), ], diff --git a/lib/pages/ordinals/widgets/ordinals_list.dart b/lib/pages/ordinals/widgets/ordinals_list.dart index ca7c71446..d161cafeb 100644 --- a/lib/pages/ordinals/widgets/ordinals_list.dart +++ b/lib/pages/ordinals/widgets/ordinals_list.dart @@ -1,39 +1,49 @@ import 'package:flutter/material.dart'; -import 'package:stackwallet/models/ordinal.dart'; +import 'package:stackwallet/dto/ordinals/inscription_data.dart'; + import 'package:stackwallet/pages/ordinals/widgets/ordinal_card.dart'; -class OrdinalsList extends StatefulWidget { +class OrdinalsList extends StatelessWidget { const OrdinalsList({ - super.key, + Key? key, required this.walletId, - required this.ordinals, - }); + required this.ordinalsFuture, + }) : super(key: key); final String walletId; - final List<Ordinal> ordinals; + final Future<List<InscriptionData>> ordinalsFuture; - @override - State<OrdinalsList> createState() => _OrdinalsListState(); -} - -class _OrdinalsListState extends State<OrdinalsList> { - static const spacing = 10.0; + get spacing => 2.0; @override Widget build(BuildContext context) { - return GridView.builder( - shrinkWrap: true, - itemCount: widget.ordinals.length, - gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( - crossAxisSpacing: spacing, - mainAxisSpacing: spacing, - crossAxisCount: 2, - childAspectRatio: 3 / 4, - ), - itemBuilder: (_, i) => OrdinalCard( - walletId: widget.walletId, - ordinal: widget.ordinals[i], - ), + return FutureBuilder<List<InscriptionData>>( + future: ordinalsFuture, + builder: (context, snapshot) { + if (snapshot.connectionState == ConnectionState.waiting) { + return const CircularProgressIndicator(); + } else if (snapshot.hasError) { + return Text('Error: ${snapshot.error}'); + } else if (snapshot.hasData) { + final List<InscriptionData> inscriptions = snapshot.data!; + return GridView.builder( + shrinkWrap: true, + itemCount: inscriptions.length, + gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( + crossAxisSpacing: spacing as double, + mainAxisSpacing: spacing as double, + crossAxisCount: 2, + childAspectRatio: 3 / 4, + ), + itemBuilder: (_, i) => OrdinalCard( + walletId: walletId, + inscriptionData: inscriptions[i], + ), + ); + } else { + return Text('No data found.'); + } + }, ); } -} +} \ No newline at end of file From 65e8c34e34fd33dabff5909d3ee0666a06e1f50b Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Fri, 21 Jul 2023 10:43:02 -0500 Subject: [PATCH 28/31] hook up details view to OrdinalsInterface --- lib/pages/ordinals/ordinal_details_view.dart | 47 ++++++++++---------- lib/route_generator.dart | 10 ++--- 2 files changed, 29 insertions(+), 28 deletions(-) diff --git a/lib/pages/ordinals/ordinal_details_view.dart b/lib/pages/ordinals/ordinal_details_view.dart index 2057e8792..c1ca67500 100644 --- a/lib/pages/ordinals/ordinal_details_view.dart +++ b/lib/pages/ordinals/ordinal_details_view.dart @@ -3,7 +3,7 @@ import 'dart:async'; import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_svg/flutter_svg.dart'; -import 'package:stackwallet/models/ordinal.dart'; +import 'package:stackwallet/dto/ordinals/inscription_data.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/ordinals/widgets/dialogs.dart'; import 'package:stackwallet/themes/stack_colors.dart'; @@ -15,20 +15,21 @@ import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/desktop/secondary_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; + class OrdinalDetailsView extends StatefulWidget { const OrdinalDetailsView({ - super.key, + Key? key, required this.walletId, - required this.ordinal, - }); + required this.inscriptionData, + }) : super(key: key); final String walletId; - final Ordinal ordinal; + final InscriptionData inscriptionData; static const routeName = "/ordinalDetailsView"; @override - State<OrdinalDetailsView> createState() => _OrdinalDetailsViewState(); + _OrdinalDetailsViewState createState() => _OrdinalDetailsViewState(); } class _OrdinalDetailsViewState extends State<OrdinalDetailsView> { @@ -40,10 +41,10 @@ class _OrdinalDetailsViewState extends State<OrdinalDetailsView> { child: SafeArea( child: Scaffold( backgroundColor: - Theme.of(context).extension<StackColors>()!.background, + Theme.of(context).extension<StackColors>()!.background, appBar: AppBar( backgroundColor: - Theme.of(context).extension<StackColors>()!.background, + Theme.of(context).extension<StackColors>()!.background, leading: const AppBarBackButton(), title: Text( "Ordinal details", @@ -61,20 +62,20 @@ class _OrdinalDetailsViewState extends State<OrdinalDetailsView> { horizontal: 39, ), child: _OrdinalImageGroup( - ordinal: widget.ordinal, + inscriptionData: widget.inscriptionData, walletId: widget.walletId, ), ), _DetailsItemWCopy( title: "Inscription number", - data: widget.ordinal.inscription, + data: widget.inscriptionData.inscriptionNumber.toString(), ), const SizedBox( height: _spacing, ), _DetailsItemWCopy( - title: "Rank", - data: widget.ordinal.rank, + title: "ID", + data: widget.inscriptionData.inscriptionId, ), const SizedBox( height: _spacing, @@ -85,21 +86,21 @@ class _OrdinalDetailsViewState extends State<OrdinalDetailsView> { ), _DetailsItemWCopy( title: "Amount", - data: "FIXME", + data: "${widget.inscriptionData.outputValue}", ), const SizedBox( height: _spacing, ), _DetailsItemWCopy( title: "Owner address", - data: "FIXME", + data: widget.inscriptionData.address, ), const SizedBox( height: _spacing, ), _DetailsItemWCopy( title: "Transaction ID", - data: "FIXME", + data: widget.inscriptionData.genesisTransaction, ), const SizedBox( height: _spacing, @@ -116,10 +117,10 @@ class _OrdinalDetailsViewState extends State<OrdinalDetailsView> { class _DetailsItemWCopy extends StatelessWidget { const _DetailsItemWCopy({ - super.key, + Key? key, required this.title, required this.data, - }); + }) : super(key: key); final String title; final String data; @@ -153,7 +154,7 @@ class _DetailsItemWCopy extends StatelessWidget { child: SvgPicture.asset( Assets.svg.copy, color: - Theme.of(context).extension<StackColors>()!.infoItemIcons, + Theme.of(context).extension<StackColors>()!.infoItemIcons, width: 12, ), ), @@ -174,13 +175,13 @@ class _DetailsItemWCopy extends StatelessWidget { class _OrdinalImageGroup extends StatelessWidget { const _OrdinalImageGroup({ - super.key, + Key? key, required this.walletId, - required this.ordinal, - }); + required this.inscriptionData, + }) : super(key: key); final String walletId; - final Ordinal ordinal; + final InscriptionData inscriptionData; static const _spacing = 12.0; @@ -191,7 +192,7 @@ class _OrdinalImageGroup extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( - ordinal.name, + "${inscriptionData.inscriptionId}", // Use any other property you want style: STextStyles.w600_16(context), ), const SizedBox( diff --git a/lib/route_generator.dart b/lib/route_generator.dart index 6217cf201..e67254135 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -12,13 +12,15 @@ import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:isar/isar.dart'; +import 'package:stackwallet/dto/ordinals/inscription_data.dart'; import 'package:stackwallet/models/add_wallet_list_entity/add_wallet_list_entity.dart'; import 'package:stackwallet/models/add_wallet_list_entity/sub_classes/eth_token_entity.dart'; import 'package:stackwallet/models/buy/response_objects/quote.dart'; import 'package:stackwallet/models/exchange/incomplete_exchange.dart'; import 'package:stackwallet/models/exchange/response_objects/trade.dart'; +import 'package:stackwallet/models/isar/models/contact_entry.dart'; import 'package:stackwallet/models/isar/models/isar_models.dart'; -import 'package:stackwallet/models/ordinal.dart'; +import 'package:stackwallet/models/ordinal.dart'; // TODO generalize InscriptionData -> Ordinal import 'package:stackwallet/models/paynym/paynym_account_lite.dart'; import 'package:stackwallet/models/send_view_auto_fill_data.dart'; import 'package:stackwallet/pages/add_wallet_views/add_token_view/add_custom_token_view.dart'; @@ -168,8 +170,6 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart'; import 'package:stackwallet/widgets/choose_coin_view.dart'; import 'package:tuple/tuple.dart'; -import 'models/isar/models/contact_entry.dart'; - /* * This file contains all the routes for the app. * To add a new route, add it to the switch statement in the generateRoute method. @@ -423,12 +423,12 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case OrdinalDetailsView.routeName: - if (args is ({Ordinal ordinal, String walletId})) { + if (args is ({InscriptionData inscriptionData, String walletId})) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => OrdinalDetailsView( walletId: args.walletId, - ordinal: args.ordinal, + inscriptionData: args.inscriptionData, ), settings: RouteSettings( name: settings.name, From ddba1c54f76fcb82ede425cc6676813640b12295 Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Fri, 21 Jul 2023 10:49:30 -0500 Subject: [PATCH 29/31] show ordinal image --- lib/pages/ordinals/ordinal_details_view.dart | 12 ++++++++++-- lib/pages/ordinals/widgets/ordinal_card.dart | 9 +++++---- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/pages/ordinals/ordinal_details_view.dart b/lib/pages/ordinals/ordinal_details_view.dart index c1ca67500..bd5b9a17e 100644 --- a/lib/pages/ordinals/ordinal_details_view.dart +++ b/lib/pages/ordinals/ordinal_details_view.dart @@ -200,8 +200,16 @@ class _OrdinalImageGroup extends StatelessWidget { ), AspectRatio( aspectRatio: 1, - child: Container( - color: Colors.red, + child: AspectRatio( + aspectRatio: 1, + child: Container( + color: Colors.red, + child: Image.network( + inscriptionData.content, // Use the preview URL as the image source + fit: BoxFit.cover, + filterQuality: FilterQuality.none, // Set the filter mode to nearest + ), + ), ), ), const SizedBox( diff --git a/lib/pages/ordinals/widgets/ordinal_card.dart b/lib/pages/ordinals/widgets/ordinal_card.dart index a4d58711e..0c05f686a 100644 --- a/lib/pages/ordinals/widgets/ordinal_card.dart +++ b/lib/pages/ordinals/widgets/ordinal_card.dart @@ -28,13 +28,14 @@ class OrdinalCard extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.center, children: [ - AspectRatio( - aspectRatio: 1, - child: Container( + AspectRatio( + aspectRatio: 1, + child: Container( color: Colors.red, child: Image.network( - inscriptionData.preview, // Use the preview URL as the image source + inscriptionData.content, // Use the preview URL as the image source fit: BoxFit.cover, + filterQuality: FilterQuality.none, // Set the filter mode to nearest ), ), ), From f46a37d4d4775cb9f8bc3feb825350e577d202f2 Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Fri, 21 Jul 2023 11:48:31 -0500 Subject: [PATCH 30/31] convert/map/cast InscriptionData->Ordinal --- lib/models/ordinal.dart | 33 ++-- lib/pages/ordinals/ordinal_details_view.dart | 30 ++-- lib/pages/ordinals/ordinals_view.dart | 2 +- lib/pages/ordinals/widgets/ordinal_card.dart | 16 +- lib/pages/ordinals/widgets/ordinals_list.dart | 12 +- lib/route_generator.dart | 4 +- lib/services/mixins/ordinals_interface.dart | 146 ++++++------------ 7 files changed, 99 insertions(+), 144 deletions(-) diff --git a/lib/models/ordinal.dart b/lib/models/ordinal.dart index 1feb98b9d..66a69de94 100644 --- a/lib/models/ordinal.dart +++ b/lib/models/ordinal.dart @@ -1,26 +1,29 @@ -enum OrdCollection { - punks, - moonbirds, -} +import 'package:stackwallet/dto/ordinals/inscription_data.dart'; class Ordinal { - final String name; - final String inscription; - final String rank; - final OrdCollection collection; + final String inscriptionId; + final int inscriptionNumber; + final String content; // following two are used to look up the UTXO object in isar combined w/ walletId final String utxoTXID; final int utxoVOUT; - // TODO: make a proper Isar class instead of this placeholder - Ordinal({ - required this.name, - required this.inscription, - required this.rank, - required this.collection, + required this.inscriptionId, + required this.inscriptionNumber, + required this.content, required this.utxoTXID, required this.utxoVOUT, }); -} + + factory Ordinal.fromInscriptionData(InscriptionData data) { + return Ordinal( + inscriptionId: data.inscriptionId, + inscriptionNumber: data.inscriptionNumber, + content: data.content, + utxoTXID: data.output.split(':')[0], // "output": "062f32e21aa04246b8873b5d9a929576addd0339881e1ea478b406795d6b6c47:0" + utxoVOUT: int.parse(data.output.split(':')[1]), + ); + } +} \ No newline at end of file diff --git a/lib/pages/ordinals/ordinal_details_view.dart b/lib/pages/ordinals/ordinal_details_view.dart index bd5b9a17e..6aab95586 100644 --- a/lib/pages/ordinals/ordinal_details_view.dart +++ b/lib/pages/ordinals/ordinal_details_view.dart @@ -4,6 +4,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:flutter_svg/flutter_svg.dart'; import 'package:stackwallet/dto/ordinals/inscription_data.dart'; +import 'package:stackwallet/models/ordinal.dart'; import 'package:stackwallet/notifications/show_flush_bar.dart'; import 'package:stackwallet/pages/ordinals/widgets/dialogs.dart'; import 'package:stackwallet/themes/stack_colors.dart'; @@ -15,16 +16,15 @@ import 'package:stackwallet/widgets/desktop/primary_button.dart'; import 'package:stackwallet/widgets/desktop/secondary_button.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; - class OrdinalDetailsView extends StatefulWidget { const OrdinalDetailsView({ Key? key, required this.walletId, - required this.inscriptionData, + required this.ordinal, }) : super(key: key); final String walletId; - final InscriptionData inscriptionData; + final Ordinal ordinal; static const routeName = "/ordinalDetailsView"; @@ -62,20 +62,20 @@ class _OrdinalDetailsViewState extends State<OrdinalDetailsView> { horizontal: 39, ), child: _OrdinalImageGroup( - inscriptionData: widget.inscriptionData, + ordinal: widget.ordinal, walletId: widget.walletId, ), ), _DetailsItemWCopy( title: "Inscription number", - data: widget.inscriptionData.inscriptionNumber.toString(), + data: widget.ordinal.inscriptionNumber.toString(), ), const SizedBox( height: _spacing, ), _DetailsItemWCopy( title: "ID", - data: widget.inscriptionData.inscriptionId, + data: widget.ordinal.inscriptionId, ), const SizedBox( height: _spacing, @@ -84,23 +84,23 @@ class _OrdinalDetailsViewState extends State<OrdinalDetailsView> { const SizedBox( height: _spacing, ), - _DetailsItemWCopy( + const _DetailsItemWCopy( title: "Amount", - data: "${widget.inscriptionData.outputValue}", + data: "TODO", // TODO infer from utxo utxoTXID:utxoVOUT ), const SizedBox( height: _spacing, ), - _DetailsItemWCopy( + const _DetailsItemWCopy( title: "Owner address", - data: widget.inscriptionData.address, + data: "TODO", // infer from address associated w utxoTXID ), const SizedBox( height: _spacing, ), _DetailsItemWCopy( title: "Transaction ID", - data: widget.inscriptionData.genesisTransaction, + data: widget.ordinal.utxoTXID, ), const SizedBox( height: _spacing, @@ -177,11 +177,11 @@ class _OrdinalImageGroup extends StatelessWidget { const _OrdinalImageGroup({ Key? key, required this.walletId, - required this.inscriptionData, + required this.ordinal, }) : super(key: key); final String walletId; - final InscriptionData inscriptionData; + final Ordinal ordinal; static const _spacing = 12.0; @@ -192,7 +192,7 @@ class _OrdinalImageGroup extends StatelessWidget { crossAxisAlignment: CrossAxisAlignment.center, children: [ Text( - "${inscriptionData.inscriptionId}", // Use any other property you want + "${ordinal.inscriptionId}", // Use any other property you want style: STextStyles.w600_16(context), ), const SizedBox( @@ -205,7 +205,7 @@ class _OrdinalImageGroup extends StatelessWidget { child: Container( color: Colors.red, child: Image.network( - inscriptionData.content, // Use the preview URL as the image source + ordinal.content, // Use the preview URL as the image source fit: BoxFit.cover, filterQuality: FilterQuality.none, // Set the filter mode to nearest ), diff --git a/lib/pages/ordinals/ordinals_view.dart b/lib/pages/ordinals/ordinals_view.dart index b12fb78c4..a4adfa019 100644 --- a/lib/pages/ordinals/ordinals_view.dart +++ b/lib/pages/ordinals/ordinals_view.dart @@ -193,7 +193,7 @@ class _OrdinalsViewState extends ConsumerState<OrdinalsView> { Expanded( child: OrdinalsList( walletId: widget.walletId, - ordinalsFuture: (_manager.wallet as OrdinalsInterface).getInscriptions(), + ordinalsFuture: (_manager.wallet as OrdinalsInterface).getOrdinals(), ), ), ], diff --git a/lib/pages/ordinals/widgets/ordinal_card.dart b/lib/pages/ordinals/widgets/ordinal_card.dart index 0c05f686a..c9060b32e 100644 --- a/lib/pages/ordinals/widgets/ordinal_card.dart +++ b/lib/pages/ordinals/widgets/ordinal_card.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:stackwallet/dto/ordinals/inscription_data.dart'; -import 'package:stackwallet/models/ordinal.dart'; // TODO generalize InscriptionData models -> Ordinal + +import 'package:stackwallet/models/ordinal.dart'; import 'package:stackwallet/pages/ordinals/ordinal_details_view.dart'; import 'package:stackwallet/utilities/text_styles.dart'; import 'package:stackwallet/widgets/rounded_white_container.dart'; @@ -9,11 +9,11 @@ class OrdinalCard extends StatelessWidget { const OrdinalCard({ Key? key, required this.walletId, - required this.inscriptionData, + required this.ordinal, }) : super(key: key); final String walletId; - final InscriptionData inscriptionData; + final Ordinal ordinal; @override Widget build(BuildContext context) { @@ -22,7 +22,7 @@ class OrdinalCard extends StatelessWidget { onPressed: () { Navigator.of(context).pushNamed( OrdinalDetailsView.routeName, - arguments: (walletId: walletId, inscriptionData: inscriptionData), + arguments: (walletId: walletId, ordinal: ordinal), ); }, child: Column( @@ -33,7 +33,7 @@ class OrdinalCard extends StatelessWidget { child: Container( color: Colors.red, child: Image.network( - inscriptionData.content, // Use the preview URL as the image source + ordinal.content, // Use the preview URL as the image source fit: BoxFit.cover, filterQuality: FilterQuality.none, // Set the filter mode to nearest ), @@ -41,12 +41,12 @@ class OrdinalCard extends StatelessWidget { ), const Spacer(), Text( - inscriptionData.address, + 'TODO', // infer from address associated with utxoTXID style: STextStyles.w500_12(context), ), const Spacer(), Text( - "INSC. ${inscriptionData.inscriptionNumber} ID ${inscriptionData.inscriptionId}", + "INSC. ${ordinal.inscriptionNumber} ID ${ordinal.inscriptionId}", style: STextStyles.w500_8(context), ), ], diff --git a/lib/pages/ordinals/widgets/ordinals_list.dart b/lib/pages/ordinals/widgets/ordinals_list.dart index d161cafeb..fe7618cd0 100644 --- a/lib/pages/ordinals/widgets/ordinals_list.dart +++ b/lib/pages/ordinals/widgets/ordinals_list.dart @@ -1,5 +1,5 @@ import 'package:flutter/material.dart'; -import 'package:stackwallet/dto/ordinals/inscription_data.dart'; +import 'package:stackwallet/models/ordinal.dart'; import 'package:stackwallet/pages/ordinals/widgets/ordinal_card.dart'; @@ -11,13 +11,13 @@ class OrdinalsList extends StatelessWidget { }) : super(key: key); final String walletId; - final Future<List<InscriptionData>> ordinalsFuture; + final Future<List<Ordinal>> ordinalsFuture; get spacing => 2.0; @override Widget build(BuildContext context) { - return FutureBuilder<List<InscriptionData>>( + return FutureBuilder<List<Ordinal>>( future: ordinalsFuture, builder: (context, snapshot) { if (snapshot.connectionState == ConnectionState.waiting) { @@ -25,10 +25,10 @@ class OrdinalsList extends StatelessWidget { } else if (snapshot.hasError) { return Text('Error: ${snapshot.error}'); } else if (snapshot.hasData) { - final List<InscriptionData> inscriptions = snapshot.data!; + final List<Ordinal> ordinals = snapshot.data!; return GridView.builder( shrinkWrap: true, - itemCount: inscriptions.length, + itemCount: ordinals.length, gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( crossAxisSpacing: spacing as double, mainAxisSpacing: spacing as double, @@ -37,7 +37,7 @@ class OrdinalsList extends StatelessWidget { ), itemBuilder: (_, i) => OrdinalCard( walletId: walletId, - inscriptionData: inscriptions[i], + ordinal: ordinals[i], ), ); } else { diff --git a/lib/route_generator.dart b/lib/route_generator.dart index e67254135..7c0807caf 100644 --- a/lib/route_generator.dart +++ b/lib/route_generator.dart @@ -423,12 +423,12 @@ class RouteGenerator { return _routeError("${settings.name} invalid args: ${args.toString()}"); case OrdinalDetailsView.routeName: - if (args is ({InscriptionData inscriptionData, String walletId})) { + if (args is ({Ordinal ordinal, String walletId})) { return getRoute( shouldUseMaterialRoute: useMaterialPageRoute, builder: (_) => OrdinalDetailsView( walletId: args.walletId, - inscriptionData: args.inscriptionData, + ordinal: args.ordinal, ), settings: RouteSettings( name: settings.name, diff --git a/lib/services/mixins/ordinals_interface.dart b/lib/services/mixins/ordinals_interface.dart index 51323fa0c..a779f5b2e 100644 --- a/lib/services/mixins/ordinals_interface.dart +++ b/lib/services/mixins/ordinals_interface.dart @@ -2,11 +2,11 @@ import 'dart:async'; import 'package:isar/isar.dart'; import 'package:stackwallet/db/isar/main_db.dart'; -import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart'; -import 'package:stackwallet/utilities/enums/coin_enum.dart'; - -import 'package:stackwallet/services/litescribe_api.dart'; import 'package:stackwallet/dto/ordinals/inscription_data.dart'; +import 'package:stackwallet/models/isar/models/blockchain_data/utxo.dart'; +import 'package:stackwallet/models/ordinal.dart'; +import 'package:stackwallet/services/litescribe_api.dart'; +import 'package:stackwallet/utilities/enums/coin_enum.dart'; mixin OrdinalsInterface { late final String _walletId; @@ -25,28 +25,32 @@ mixin OrdinalsInterface { } final LitescribeAPI litescribeAPI = LitescribeAPI(baseUrl: 'https://litescribe.io/api'); - // Future<List<InscriptionData>> getInscriptionsByAddress(String address) async { - // try { - // var response = await litescribeAPI.getInscriptionsByAddress(address); - // // print("Found ${response.result.total} inscription${response.result.total > 1 ? 's' : ''} at address $address"); // TODO disable (POC) - // return response.result.list; - // } catch (e) { - // throw Exception('Error in OrdinalsInterface getInscriptionsByAddress: $e'); - // } - // } - void refreshInscriptions() async { List<dynamic> _inscriptions; final utxos = await _db.getUTXOs(_walletId).findAll(); final uniqueAddresses = getUniqueAddressesFromUTXOs(utxos); - _inscriptions = await getInscriptionsFromAddresses(uniqueAddresses); + _inscriptions = await getInscriptionDataFromAddresses(uniqueAddresses); // TODO save inscriptions to isar which gets watched by a FutureBuilder/StreamBuilder } - Future<List<InscriptionData>> getInscriptions() async { - final utxos = await _db.getUTXOs(_walletId).findAll(); - final uniqueAddresses = getUniqueAddressesFromUTXOs(utxos); - return await getInscriptionsFromAddresses(uniqueAddresses); + Future<List<InscriptionData>> getInscriptionData() async { + try { + final utxos = await _db.getUTXOs(_walletId).findAll(); + final uniqueAddresses = getUniqueAddressesFromUTXOs(utxos); + return await getInscriptionDataFromAddresses(uniqueAddresses); + } catch (e) { + throw Exception('Error in OrdinalsInterface getInscriptions: $e'); + } + } + + Future<List<Ordinal>> getOrdinals() async { + try { + final utxos = await _db.getUTXOs(_walletId).findAll(); + final uniqueAddresses = getUniqueAddressesFromUTXOs(utxos); + return await getOrdinalsFromAddresses(uniqueAddresses); + } catch (e) { + throw Exception('Error in OrdinalsInterface getOrdinals: $e'); + } } List<String> getUniqueAddressesFromUTXOs(List<UTXO> utxos) { @@ -59,12 +63,22 @@ mixin OrdinalsInterface { return uniqueAddresses.toList(); } - Future<List<InscriptionData>> getInscriptionsFromAddresses(List<String> addresses) async { + Future<List<InscriptionData>> getInscriptionDataFromAddress(String address) async { + List<InscriptionData> allInscriptions = []; + try { + var inscriptions = await litescribeAPI.getInscriptionsByAddress(address); + allInscriptions.addAll(inscriptions); + } catch (e) { + throw Exception('Error in OrdinalsInterface getInscriptionsByAddress: $e'); + } + return allInscriptions; + } + + Future<List<InscriptionData>> getInscriptionDataFromAddresses(List<String> addresses) async { List<InscriptionData> allInscriptions = []; for (String address in addresses) { try { var inscriptions = await litescribeAPI.getInscriptionsByAddress(address); - print("Found ${inscriptions.length} inscription${inscriptions.length > 1 ? 's' : ''} at address $address"); allInscriptions.addAll(inscriptions); } catch (e) { print("Error fetching inscriptions for address $address: $e"); @@ -73,87 +87,25 @@ mixin OrdinalsInterface { return allInscriptions; } -/* // ord-litecoin interface - final OrdinalsAPI ordinalsAPI = OrdinalsAPI(baseUrl: 'https://ord-litecoin.stackwallet.com'); - - Future<FeedResponse> fetchLatestInscriptions() async { + Future<List<Ordinal>> getOrdinalsFromAddress(String address) 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; + var inscriptions = await litescribeAPI.getInscriptionsByAddress(address); + return inscriptions.map((data) => Ordinal.fromInscriptionData(data)).toList(); } catch (e) { - // Handle errors - throw Exception('Error in OrdinalsInterface fetchLatestInscriptions: $e'); + throw Exception('Error in OrdinalsInterface getOrdinalsFromAddress: $e'); } } - Future<InscriptionResponse> getInscriptionDetails(String inscriptionId) async { - try { - return await ordinalsAPI.getInscriptionDetails(inscriptionId); - } catch (e) { - throw Exception('Error in OrdinalsInterface getInscriptionDetails: $e'); + Future<List<Ordinal>> getOrdinalsFromAddresses(List<String> addresses) async { + List<Ordinal> allOrdinals = []; + for (String address in addresses) { + try { + var inscriptions = await litescribeAPI.getInscriptionsByAddress(address); + allOrdinals.addAll(inscriptions.map((data) => Ordinal.fromInscriptionData(data))); + } catch (e) { + print("Error fetching inscriptions for address $address: $e"); + } } + return allOrdinals; } - - Future<SatResponse> getSatDetails(int satNumber) async { - try { - return await ordinalsAPI.getSatDetails(satNumber); - } catch (e) { - throw Exception('Error in OrdinalsInterface getSatDetails: $e'); - } - } - - Future<TransactionResponse> getTransaction(String transactionId) async { - try { - print(1); - return await ordinalsAPI.getTransaction(transactionId); - } catch (e) { - throw Exception('Error in OrdinalsInterface getTransaction: $e'); - } - } - - Future<OutputResponse> getTransactionOutputs(String transactionId) async { - try { - return await ordinalsAPI.getTransactionOutputs(transactionId); - } catch (e) { - throw Exception('Error in OrdinalsInterface getTransactionOutputs: $e'); - } - } - - Future<AddressResponse> getInscriptionsByAddress(String address) async { - try { - return await ordinalsAPI.getInscriptionsByAddress(address); - } catch (e) { - throw Exception('Error in OrdinalsInterface getInscriptionsByAddress: $e'); - } - } - - Future<BlockResponse> getBlock(int blockNumber) async { - try { - return await ordinalsAPI.getBlock(blockNumber); - } catch (e) { - throw Exception('Error in OrdinalsInterface getBlock: $e'); - } - } - - Future<ContentResponse> getInscriptionContent(String inscriptionId) async { - try { - return await ordinalsAPI.getInscriptionContent(inscriptionId); - } catch (e) { - throw Exception('Error in OrdinalsInterface getInscriptionContent: $e'); - } - } - - Future<PreviewResponse> getInscriptionPreview(String inscriptionId) async { - try { - return await ordinalsAPI.getInscriptionPreview(inscriptionId); - } catch (e) { - throw Exception('Error in OrdinalsInterface getInscriptionPreview: $e'); - } - } - */ // /ord-litecoin interface } \ No newline at end of file From 5a845f866936bdc6e2f5b66e540cfb29878ed05c Mon Sep 17 00:00:00 2001 From: sneurlax <sneurlax@gmail.com> Date: Fri, 21 Jul 2023 16:35:00 -0500 Subject: [PATCH 31/31] hide certain fields on ordinals views, change ordinal card aspect ratio --- lib/pages/ordinals/ordinal_details_view.dart | 14 +++++++------- lib/pages/ordinals/widgets/ordinal_card.dart | 12 ++++++------ lib/pages/ordinals/widgets/ordinals_list.dart | 4 ++-- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lib/pages/ordinals/ordinal_details_view.dart b/lib/pages/ordinals/ordinal_details_view.dart index 6aab95586..95cff734e 100644 --- a/lib/pages/ordinals/ordinal_details_view.dart +++ b/lib/pages/ordinals/ordinal_details_view.dart @@ -191,13 +191,13 @@ class _OrdinalImageGroup extends StatelessWidget { mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.center, children: [ - Text( - "${ordinal.inscriptionId}", // Use any other property you want - style: STextStyles.w600_16(context), - ), - const SizedBox( - height: _spacing, - ), + // Text( + // "${ordinal.inscriptionId}", // Use any other property you want + // style: STextStyles.w600_16(context), + // ), + // const SizedBox( + // height: _spacing, + // ), AspectRatio( aspectRatio: 1, child: AspectRatio( diff --git a/lib/pages/ordinals/widgets/ordinal_card.dart b/lib/pages/ordinals/widgets/ordinal_card.dart index c9060b32e..4ac4fd877 100644 --- a/lib/pages/ordinals/widgets/ordinal_card.dart +++ b/lib/pages/ordinals/widgets/ordinal_card.dart @@ -41,14 +41,14 @@ class OrdinalCard extends StatelessWidget { ), const Spacer(), Text( - 'TODO', // infer from address associated with utxoTXID + 'INSC. ${ordinal.inscriptionNumber}', // infer from address associated with utxoTXID style: STextStyles.w500_12(context), ), - const Spacer(), - Text( - "INSC. ${ordinal.inscriptionNumber} ID ${ordinal.inscriptionId}", - style: STextStyles.w500_8(context), - ), + // const Spacer(), + // Text( + // "ID ${ordinal.inscriptionId}", + // style: STextStyles.w500_8(context), + // ), ], ), ); diff --git a/lib/pages/ordinals/widgets/ordinals_list.dart b/lib/pages/ordinals/widgets/ordinals_list.dart index fe7618cd0..62d620130 100644 --- a/lib/pages/ordinals/widgets/ordinals_list.dart +++ b/lib/pages/ordinals/widgets/ordinals_list.dart @@ -33,7 +33,7 @@ class OrdinalsList extends StatelessWidget { crossAxisSpacing: spacing as double, mainAxisSpacing: spacing as double, crossAxisCount: 2, - childAspectRatio: 3 / 4, + childAspectRatio: 6 / 7, // was 3/4, less data displayed now ), itemBuilder: (_, i) => OrdinalCard( walletId: walletId, @@ -41,7 +41,7 @@ class OrdinalsList extends StatelessWidget { ), ); } else { - return Text('No data found.'); + return const Text('No data found.'); } }, );