feat: Added tx page
This commit is contained in:
@@ -1,4 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:convert';
|
||||
|
||||
class DomainsPage extends StatefulWidget {
|
||||
DomainsPage({Key? key, required this.uuid, required this.wallet})
|
||||
@@ -15,6 +17,55 @@ class _DomainsPageState extends State<DomainsPage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
fetchDomains();
|
||||
}
|
||||
|
||||
List<Domain> domains = [];
|
||||
|
||||
Future<void> fetchDomains() async {
|
||||
// Fetch domains from api
|
||||
final response = await http.get(Uri.parse(
|
||||
'https://api.firewallet.au/wallet/domains?uuid=${widget.uuid}&name=${widget.wallet}'));
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body);
|
||||
if (data is Map && data.containsKey('error')) {
|
||||
print('Error: ${data['error']}');
|
||||
return;
|
||||
}
|
||||
// Return if empty
|
||||
if (data.isEmpty) {
|
||||
setState(() {
|
||||
domains = [
|
||||
Domain(
|
||||
height: 0,
|
||||
highest: 0,
|
||||
name: 'No domains found',
|
||||
state: 'CLOSED',
|
||||
stats: DomainStats(unParsed: 'No domains found'),
|
||||
value: 0)
|
||||
];
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
final domainsData = data as List;
|
||||
setState(() {
|
||||
domains = domainsData
|
||||
.map((domain) => Domain(
|
||||
name: domain['name'],
|
||||
state: domain['state'],
|
||||
height: domain['height'],
|
||||
highest: domain['highest'],
|
||||
stats: DomainStats(unParsed: domain['stats'].toString()),
|
||||
value: domain['value'],
|
||||
))
|
||||
.toList();
|
||||
});
|
||||
} else {
|
||||
// Handle error
|
||||
print('Failed to load wallet names');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -27,12 +78,18 @@ class _DomainsPageState extends State<DomainsPage> {
|
||||
body: Center(
|
||||
child: LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
return ListView(
|
||||
children: <Widget>[
|
||||
Text("Domain 1"),
|
||||
Text("Domain 2"),
|
||||
Text("Domain 3"),
|
||||
...domains.map((name) {
|
||||
return Card(
|
||||
child: ListTile(
|
||||
title: Text(name.name),
|
||||
subtitle: Text(name.state),
|
||||
trailing: Text(name.value.toString()),
|
||||
),
|
||||
);
|
||||
}),
|
||||
TextButton(onPressed: fetchDomains, child: Text('Refresh')),
|
||||
],
|
||||
);
|
||||
},
|
||||
@@ -41,3 +98,27 @@ class _DomainsPageState extends State<DomainsPage> {
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class Domain {
|
||||
final String name;
|
||||
final String state;
|
||||
final int height;
|
||||
final double highest;
|
||||
final DomainStats stats;
|
||||
final double value;
|
||||
|
||||
Domain({
|
||||
required this.name,
|
||||
required this.state,
|
||||
required this.height,
|
||||
required this.highest,
|
||||
required this.stats,
|
||||
required this.value,
|
||||
});
|
||||
}
|
||||
|
||||
class DomainStats {
|
||||
final String unParsed;
|
||||
|
||||
DomainStats({required this.unParsed});
|
||||
}
|
||||
|
||||
@@ -21,12 +21,15 @@ class IndexPage extends StatefulWidget {
|
||||
class _IndexPageState extends State<IndexPage> {
|
||||
late String wallet;
|
||||
List<String> walletNames = [];
|
||||
late double walletBalance;
|
||||
bool balanceLoaded = false;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
wallet = widget.wallet;
|
||||
fetchWalletNames();
|
||||
fetchWalletBalance();
|
||||
}
|
||||
|
||||
Future<void> fetchWalletNames() async {
|
||||
@@ -108,19 +111,53 @@ class _IndexPageState extends State<IndexPage> {
|
||||
void setWallet(String s) {
|
||||
setState(() {
|
||||
wallet = s;
|
||||
balanceLoaded = false;
|
||||
});
|
||||
widget.setWallet(s);
|
||||
}
|
||||
|
||||
int getWalletBalance() {
|
||||
return 100;
|
||||
Future<void> fetchWalletBalance() async {
|
||||
if (wallet.isEmpty) {
|
||||
walletBalance = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (balanceLoaded) {
|
||||
return;
|
||||
}
|
||||
|
||||
final response = await http.get(Uri.parse(
|
||||
'https://api.firewallet.au/wallet/balance?uuid=${widget.uuid}&name=$wallet'));
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body);
|
||||
print(data);
|
||||
|
||||
setState(() {
|
||||
balanceLoaded = true;
|
||||
walletBalance = data['available'];
|
||||
});
|
||||
} else {
|
||||
// Handle error
|
||||
print('Failed to load wallet balance');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text('$wallet - ${getWalletBalance()} HNS'),
|
||||
title: FutureBuilder<void>(
|
||||
future: fetchWalletBalance(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.waiting) {
|
||||
return Text('$wallet - Loading...');
|
||||
} else if (snapshot.hasError) {
|
||||
return Text('$wallet - Error');
|
||||
} else {
|
||||
return Text('$wallet - ${walletBalance.toStringAsFixed(2)} HNS');
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
body: Center(
|
||||
child: LayoutBuilder(
|
||||
|
||||
@@ -31,6 +31,7 @@ Future<void> main() async {
|
||||
|
||||
// Get the uuid from the shared preferences
|
||||
final String? uuid = prefs.getString('uuid');
|
||||
print('UUID: $uuid');
|
||||
runApp(MyApp(uuid: uuid ?? 'null'));
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:convert';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class TransactionsPage extends StatefulWidget {
|
||||
TransactionsPage({Key? key, required this.uuid, required this.wallet})
|
||||
@@ -15,6 +18,87 @@ class _TransactionsPageState extends State<TransactionsPage> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
fetchTransactions();
|
||||
}
|
||||
|
||||
List<Transaction> transactions = [];
|
||||
|
||||
Future<void> fetchTransactions() async {
|
||||
// Fetch domains from api
|
||||
final response = await http.get(Uri.parse(
|
||||
'https://api.firewallet.au/wallet/transactions?uuid=${widget.uuid}&name=${widget.wallet}'));
|
||||
if (response.statusCode == 200) {
|
||||
final data = jsonDecode(response.body);
|
||||
if (data is Map && data.containsKey('error')) {
|
||||
print('Error: ${data['error']}');
|
||||
return;
|
||||
}
|
||||
// Return if empty
|
||||
if (data.isEmpty) {
|
||||
setState(() {
|
||||
transactions = [
|
||||
Transaction(
|
||||
confirmations: 0,
|
||||
date: 'No transactions found',
|
||||
hash: 'No transactions found',
|
||||
inputs: [],
|
||||
outputs: [])
|
||||
];
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
final txData = data as List;
|
||||
setState(() {
|
||||
transactions = txData
|
||||
.map(
|
||||
(tx) => Transaction(
|
||||
confirmations: tx['confirmations'],
|
||||
date: tx['date'],
|
||||
hash: tx['hash'],
|
||||
inputs: (tx['inputs'] as List<dynamic>).map<TXInput>((input) {
|
||||
return TXInput(
|
||||
address: input['address'],
|
||||
value: input['value'],
|
||||
path: input['path'] == null
|
||||
? Path()
|
||||
: Path(
|
||||
account: input['path']['account'],
|
||||
change: input['path']['change'],
|
||||
derivation: input['path']['derivation'],
|
||||
name: input['path']['name'],
|
||||
));
|
||||
}).toList(),
|
||||
outputs:
|
||||
(tx['outputs'] as List<dynamic>).map<TXOutput>((output) {
|
||||
return TXOutput(
|
||||
address: output['address'],
|
||||
value: output['value'],
|
||||
covenant: Covenant(
|
||||
action: output['covenant']['action'],
|
||||
type: output['covenant']['type'],
|
||||
items: List<String>.from(output['covenant']['items'])),
|
||||
path: output['path'] == null
|
||||
? Path()
|
||||
: Path(
|
||||
account: output['path']['account'],
|
||||
change: output['path']['change'],
|
||||
derivation: output['path']['derivation'],
|
||||
name: output['path']['name'],
|
||||
),
|
||||
);
|
||||
}).toList(),
|
||||
),
|
||||
)
|
||||
.toList();
|
||||
});
|
||||
print(transactions[0].hash);
|
||||
print(transactions[0].value().toStringAsFixed(2));
|
||||
} else {
|
||||
// Handle error
|
||||
print('Failed to load wallet names');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -27,12 +111,20 @@ class _TransactionsPageState extends State<TransactionsPage> {
|
||||
body: Center(
|
||||
child: LayoutBuilder(
|
||||
builder: (BuildContext context, BoxConstraints constraints) {
|
||||
return Column(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
return ListView(
|
||||
children: <Widget>[
|
||||
Text("Domain 1"),
|
||||
Text("Domain 2"),
|
||||
Text("Domain 3"),
|
||||
TextButton(
|
||||
onPressed: fetchTransactions, child: Text('Refresh')),
|
||||
...transactions.map((tx) {
|
||||
return Card(
|
||||
child: ListTile(
|
||||
title: Text(tx.toString()),
|
||||
subtitle: Text(tx.hash),
|
||||
trailing: Text('${tx.value().toStringAsFixed(2)} HNS'),
|
||||
onTap: // Open tx in browser
|
||||
() => openTX(tx.hash)),
|
||||
);
|
||||
}),
|
||||
],
|
||||
);
|
||||
},
|
||||
@@ -40,4 +132,200 @@ class _TransactionsPageState extends State<TransactionsPage> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> openTX(String hash) async {
|
||||
// Open the transaction in the browser
|
||||
final Uri url = Uri.parse('https://flutter.dev');
|
||||
if (!await launchUrl(url)) {
|
||||
throw Exception('Could not launch $url');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Transaction {
|
||||
final int confirmations;
|
||||
final String date;
|
||||
final String hash;
|
||||
final List<TXInput> inputs;
|
||||
final List<TXOutput> outputs;
|
||||
double totalValue = 0;
|
||||
bool valueCalculated = false;
|
||||
|
||||
Transaction(
|
||||
{required this.confirmations,
|
||||
required this.date,
|
||||
required this.hash,
|
||||
required this.inputs,
|
||||
required this.outputs});
|
||||
|
||||
// Calculate the total value of the transaction
|
||||
double value() {
|
||||
if (valueCalculated) {
|
||||
return totalValue / 1000000;
|
||||
}
|
||||
totalValue = inputs.fold(0, (prev, input) => prev + input.getValue());
|
||||
totalValue += outputs.fold(0, (prev, output) => prev + output.getValue());
|
||||
valueCalculated = true;
|
||||
return totalValue / 1000000;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
if (inputs.isEmpty) {
|
||||
return 'No Transactions Found';
|
||||
}
|
||||
|
||||
int opens = 0;
|
||||
int bids = 0;
|
||||
int reveals = 0;
|
||||
int redeems = 0;
|
||||
int registers = 0;
|
||||
int updates = 0;
|
||||
int transfers = 0;
|
||||
int finalizes = 0;
|
||||
int renews = 0;
|
||||
int other = 0;
|
||||
|
||||
outputs.forEach((output) {
|
||||
if (output.covenant.action == 'OPEN') {
|
||||
opens++;
|
||||
} else if (output.covenant.action == 'BID') {
|
||||
bids++;
|
||||
} else if (output.covenant.action == 'REVEAL') {
|
||||
reveals++;
|
||||
} else if (output.covenant.action == 'REDEEM') {
|
||||
redeems++;
|
||||
} else if (output.covenant.action == 'REGISTER') {
|
||||
registers++;
|
||||
} else if (output.covenant.action == 'UPDATE') {
|
||||
updates++;
|
||||
} else if (output.covenant.action == 'TRANSFER') {
|
||||
transfers++;
|
||||
} else if (output.covenant.action == 'FINALIZE') {
|
||||
finalizes++;
|
||||
} else if (output.covenant.action == 'RENEW') {
|
||||
renews++;
|
||||
} else if (output.covenant.action == 'NONE') {
|
||||
other++;
|
||||
} else {
|
||||
other++;
|
||||
print('Unknown action: ${output.covenant.action}');
|
||||
}
|
||||
});
|
||||
|
||||
String outputString = '';
|
||||
if (opens > 0) {
|
||||
outputString += 'Opens: $opens, ';
|
||||
}
|
||||
if (bids > 0) {
|
||||
outputString += 'Bids: $bids, ';
|
||||
}
|
||||
if (reveals > 0) {
|
||||
outputString += 'Reveals: $reveals, ';
|
||||
}
|
||||
if (redeems > 0) {
|
||||
outputString += 'Redeems: $redeems, ';
|
||||
}
|
||||
if (registers > 0) {
|
||||
outputString += 'Registers: $registers, ';
|
||||
}
|
||||
if (updates > 0) {
|
||||
outputString += 'Updates: $updates, ';
|
||||
}
|
||||
|
||||
if (transfers > 0) {
|
||||
outputString += 'Transfers: $transfers, ';
|
||||
}
|
||||
|
||||
if (finalizes > 0) {
|
||||
outputString += 'Finalizes: $finalizes, ';
|
||||
}
|
||||
|
||||
if (renews > 0) {
|
||||
outputString += 'Renews: $renews, ';
|
||||
}
|
||||
|
||||
// Remove trailing comma
|
||||
if (outputString.isNotEmpty) {
|
||||
outputString = outputString.substring(0, outputString.length - 2);
|
||||
}
|
||||
|
||||
if (outputString.isEmpty) {
|
||||
outputString = 'Sent HNS';
|
||||
}
|
||||
|
||||
return outputString;
|
||||
}
|
||||
}
|
||||
|
||||
class TXInput {
|
||||
final String address;
|
||||
final int value;
|
||||
final Path path;
|
||||
|
||||
TXInput({required this.address, required this.value, required this.path});
|
||||
|
||||
int getValue() {
|
||||
if (path.userPath()) {
|
||||
return value * -1;
|
||||
}
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
class TXOutput {
|
||||
final String address;
|
||||
final int value;
|
||||
final Covenant covenant;
|
||||
final Path path;
|
||||
|
||||
TXOutput(
|
||||
{required this.address,
|
||||
required this.value,
|
||||
required this.covenant,
|
||||
required this.path});
|
||||
|
||||
int getValue() {
|
||||
if (path.userPath()) {
|
||||
if (covenant.action == 'BID') {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
class Covenant {
|
||||
final String action;
|
||||
final int type;
|
||||
final List<String> items;
|
||||
|
||||
Covenant({required this.action, required this.type, required this.items});
|
||||
}
|
||||
|
||||
class Path {
|
||||
int? account;
|
||||
bool? change;
|
||||
String? derivation;
|
||||
String? name;
|
||||
|
||||
Path({this.account, this.change, this.derivation, this.name});
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
if (name == null) {
|
||||
return 'No Path Found';
|
||||
}
|
||||
if (derivation == null) {
|
||||
return 'Path(name: $name)';
|
||||
}
|
||||
|
||||
return 'Path(account: $account, change: $change, derivation: $derivation, name: $name)';
|
||||
}
|
||||
|
||||
bool userPath() {
|
||||
return derivation != null;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user