feat: Added receive and send pages
This commit is contained in:
parent
eaff0ee299
commit
3bd61ae1ee
@ -72,7 +72,14 @@ class _DomainsPageState extends State<DomainsPage> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('${widget.wallet} Domains'),
|
title: Text('${widget.wallet} - Domains'),
|
||||||
|
// Add refresh button to the app bar
|
||||||
|
actions: <Widget>[
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.refresh),
|
||||||
|
onPressed: fetchDomains,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
// Get wallet list from api and display here
|
// Get wallet list from api and display here
|
||||||
body: Center(
|
body: Center(
|
||||||
@ -89,7 +96,6 @@ class _DomainsPageState extends State<DomainsPage> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
TextButton(onPressed: fetchDomains, child: Text('Refresh')),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -5,6 +5,8 @@ import 'dart:convert';
|
|||||||
import 'package:firewallet/home.dart';
|
import 'package:firewallet/home.dart';
|
||||||
import 'package:firewallet/transactions.dart';
|
import 'package:firewallet/transactions.dart';
|
||||||
import 'package:firewallet/domains.dart';
|
import 'package:firewallet/domains.dart';
|
||||||
|
import 'package:firewallet/receive.dart';
|
||||||
|
import 'package:firewallet/send.dart';
|
||||||
|
|
||||||
Future<void> main() async {
|
Future<void> main() async {
|
||||||
WidgetsFlutterBinding.ensureInitialized();
|
WidgetsFlutterBinding.ensureInitialized();
|
||||||
@ -96,6 +98,12 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
icon: Icon(Icons.home_outlined),
|
icon: Icon(Icons.home_outlined),
|
||||||
label: 'Home',
|
label: 'Home',
|
||||||
),
|
),
|
||||||
|
NavigationDestination(
|
||||||
|
icon: Icon(Icons.call_received), label: 'Receive'),
|
||||||
|
NavigationDestination(
|
||||||
|
icon: Icon(Icons.send),
|
||||||
|
label: 'Send',
|
||||||
|
),
|
||||||
NavigationDestination(
|
NavigationDestination(
|
||||||
icon: Icon(Icons.text_format_rounded),
|
icon: Icon(Icons.text_format_rounded),
|
||||||
label: 'Domains',
|
label: 'Domains',
|
||||||
@ -111,6 +119,8 @@ class _MyHomePageState extends State<MyHomePage> {
|
|||||||
index: currentPageIndex,
|
index: currentPageIndex,
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
IndexPage(uuid: widget.uuid, wallet: wallet, setWallet: setWallet),
|
IndexPage(uuid: widget.uuid, wallet: wallet, setWallet: setWallet),
|
||||||
|
ReceivePage(uuid: widget.uuid, wallet: wallet),
|
||||||
|
SendPage(uuid: widget.uuid, wallet: wallet),
|
||||||
DomainsPage(uuid: widget.uuid, wallet: wallet),
|
DomainsPage(uuid: widget.uuid, wallet: wallet),
|
||||||
TransactionsPage(uuid: widget.uuid, wallet: wallet),
|
TransactionsPage(uuid: widget.uuid, wallet: wallet),
|
||||||
],
|
],
|
||||||
|
104
lib/receive.dart
Normal file
104
lib/receive.dart
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
|
|
||||||
|
class ReceivePage extends StatefulWidget {
|
||||||
|
ReceivePage({Key? key, required this.uuid, required this.wallet})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
final String uuid;
|
||||||
|
String wallet;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_ReceivePageState createState() => _ReceivePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _ReceivePageState extends State<ReceivePage> {
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
fetchReceive();
|
||||||
|
}
|
||||||
|
|
||||||
|
String address = '';
|
||||||
|
|
||||||
|
Future<void> fetchReceive() async {
|
||||||
|
// Fetch domains from api
|
||||||
|
final response = await http.get(Uri.parse(
|
||||||
|
'https://api.firewallet.au/wallet/address?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(() {
|
||||||
|
address = 'No address found';
|
||||||
|
});
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
final addressData = data as Map;
|
||||||
|
setState(() {
|
||||||
|
address = addressData['address'];
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Handle error
|
||||||
|
print('Failed to load wallet names');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text('${widget.wallet} - Receive HNS or Domains'),
|
||||||
|
),
|
||||||
|
// Get wallet list from api and display here
|
||||||
|
body: Center(
|
||||||
|
child: LayoutBuilder(
|
||||||
|
builder: (BuildContext context, BoxConstraints constraints) {
|
||||||
|
return ListView(
|
||||||
|
children: <Widget>[
|
||||||
|
Center(child: Text(address, style: TextStyle(fontSize: 18.0))),
|
||||||
|
// QR Code
|
||||||
|
Center(
|
||||||
|
child: QrImageView(
|
||||||
|
data: address,
|
||||||
|
version: QrVersions.auto,
|
||||||
|
// Width = 90% of the screen width
|
||||||
|
size: constraints.maxWidth * 0.9,
|
||||||
|
eyeStyle: QrEyeStyle(
|
||||||
|
eyeShape: QrEyeShape.square,
|
||||||
|
color: Theme.of(context).brightness == Brightness.light
|
||||||
|
? Colors.black
|
||||||
|
: Colors.white,
|
||||||
|
),
|
||||||
|
dataModuleStyle: QrDataModuleStyle(
|
||||||
|
dataModuleShape: QrDataModuleShape.square,
|
||||||
|
color: Theme.of(context).brightness == Brightness.light
|
||||||
|
? Colors.black
|
||||||
|
: Colors.white,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
|
||||||
|
TextButton(onPressed: copyAddress, child: Text('Copy Address')),
|
||||||
|
TextButton(onPressed: fetchReceive, child: Text('Refresh')),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> copyAddress() async {
|
||||||
|
// Copy the address to the clipboard
|
||||||
|
await Clipboard.setData(ClipboardData(text: address));
|
||||||
|
}
|
||||||
|
}
|
189
lib/send.dart
Normal file
189
lib/send.dart
Normal file
@ -0,0 +1,189 @@
|
|||||||
|
import 'dart:math';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
import 'package:http/http.dart' as http;
|
||||||
|
import 'dart:convert';
|
||||||
|
import 'package:qr_flutter/qr_flutter.dart';
|
||||||
|
|
||||||
|
class SendPage extends StatefulWidget {
|
||||||
|
SendPage({Key? key, required this.uuid, required this.wallet})
|
||||||
|
: super(key: key);
|
||||||
|
|
||||||
|
final String uuid;
|
||||||
|
String wallet;
|
||||||
|
|
||||||
|
@override
|
||||||
|
_SendPageState createState() => _SendPageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SendPageState extends State<SendPage> {
|
||||||
|
late double walletBalance = 0;
|
||||||
|
bool balanceLoaded = false;
|
||||||
|
final TextEditingController addressController = TextEditingController();
|
||||||
|
final TextEditingController amountController = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
// Dispose of the controllers when the widget is disposed
|
||||||
|
addressController.dispose();
|
||||||
|
amountController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
Future<void> fetchWalletBalance() async {
|
||||||
|
if (widget.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=${widget.wallet}'));
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final data = jsonDecode(response.body);
|
||||||
|
print(data);
|
||||||
|
|
||||||
|
setState(() {
|
||||||
|
walletBalance = data['available'];
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Handle error
|
||||||
|
print('Failed to load wallet balance');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Scaffold(
|
||||||
|
appBar: AppBar(
|
||||||
|
title: Text('${widget.wallet} - Send HNS'),
|
||||||
|
),
|
||||||
|
// Get wallet list from api and display here
|
||||||
|
body: Center(
|
||||||
|
child: LayoutBuilder(
|
||||||
|
builder: (BuildContext context, BoxConstraints constraints) {
|
||||||
|
return ListView(
|
||||||
|
padding: const EdgeInsets.all(16),
|
||||||
|
children: <Widget>[
|
||||||
|
// Display the wallet balance
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.center,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
'Max ${(walletBalance - 0.02).toStringAsFixed(2)} HNS'),
|
||||||
|
TextButton(
|
||||||
|
onPressed: fetchWalletBalance,
|
||||||
|
child: const Icon(Icons.refresh)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
// Address input field
|
||||||
|
TextField(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: 'Address',
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.text,
|
||||||
|
inputFormatters: [
|
||||||
|
FilteringTextInputFormatter.allow(RegExp(r'[a-zA-Z0-9]')),
|
||||||
|
],
|
||||||
|
controller: addressController,
|
||||||
|
),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
// Amount input field
|
||||||
|
TextField(
|
||||||
|
decoration: const InputDecoration(
|
||||||
|
border: OutlineInputBorder(),
|
||||||
|
labelText: 'Amount',
|
||||||
|
suffix: Text('HNS'),
|
||||||
|
),
|
||||||
|
keyboardType: TextInputType.number,
|
||||||
|
inputFormatters: [
|
||||||
|
FilteringTextInputFormatter.allow(RegExp(r'[0-9.]')),
|
||||||
|
],
|
||||||
|
controller: amountController,
|
||||||
|
),
|
||||||
|
TextButton(
|
||||||
|
onPressed: () => amountController.text =
|
||||||
|
(walletBalance - 0.02).toStringAsFixed(2),
|
||||||
|
child: const Text('Max')),
|
||||||
|
SizedBox(height: 16),
|
||||||
|
// Send button
|
||||||
|
ElevatedButton(
|
||||||
|
onPressed: sendHNS,
|
||||||
|
child: const Text('Send'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendHNS() {
|
||||||
|
// Send HNS to the address
|
||||||
|
String toAddress = addressController.text;
|
||||||
|
double amount = double.parse(amountController.text);
|
||||||
|
print('Send $amount HNS to $toAddress');
|
||||||
|
if (amount > (walletBalance - 0.01)) {
|
||||||
|
// Not enough balance
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text('Not enough balance'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
bool sendMax = false;
|
||||||
|
if (amount >= (walletBalance - 0.02)) {
|
||||||
|
sendMax = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
print(sendMax);
|
||||||
|
// https://api.firewallet.au/wallet/send?uuid=99879737-0c27-497b-b357-f75720feb32e&name=hot&address=hs1qca9n20ew7ph6l5galfnftmwme6kwmu26mzjgtx&amount=2
|
||||||
|
http
|
||||||
|
.post(
|
||||||
|
Uri.parse(
|
||||||
|
'https://api.firewallet.au/wallet/send?uuid=${widget.uuid}&name=${widget.wallet}&address=$toAddress&amount=$amount'),
|
||||||
|
headers: <String, String>{
|
||||||
|
'Content-Type': 'application/json; charset=UTF-8',
|
||||||
|
},
|
||||||
|
body: '{}',
|
||||||
|
)
|
||||||
|
.then((response) {
|
||||||
|
if (response.statusCode == 200) {
|
||||||
|
final data = jsonDecode(response.body);
|
||||||
|
print(data);
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
SnackBar(
|
||||||
|
content: Text('Sent $amount HNS to $toAddress'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
if (sendMax) {
|
||||||
|
amountController.text = '';
|
||||||
|
} else {
|
||||||
|
amountController.text =
|
||||||
|
min(amount, walletBalance - 0.02).toStringAsFixed(2);
|
||||||
|
}
|
||||||
|
fetchWalletBalance();
|
||||||
|
} else {
|
||||||
|
// Handle error
|
||||||
|
print('Failed to send HNS');
|
||||||
|
ScaffoldMessenger.of(context).showSnackBar(
|
||||||
|
const SnackBar(
|
||||||
|
content: Text('Failed to send HNS'),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
@ -105,7 +105,14 @@ class _TransactionsPageState extends State<TransactionsPage> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
appBar: AppBar(
|
appBar: AppBar(
|
||||||
title: Text('${widget.wallet} Transactions'),
|
title: Text('${widget.wallet} - Transactions'),
|
||||||
|
// Add refresh button to the app bar
|
||||||
|
actions: <Widget>[
|
||||||
|
IconButton(
|
||||||
|
icon: Icon(Icons.refresh),
|
||||||
|
onPressed: fetchTransactions,
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
// Get wallet list from api and display here
|
// Get wallet list from api and display here
|
||||||
body: Center(
|
body: Center(
|
||||||
@ -113,8 +120,6 @@ class _TransactionsPageState extends State<TransactionsPage> {
|
|||||||
builder: (BuildContext context, BoxConstraints constraints) {
|
builder: (BuildContext context, BoxConstraints constraints) {
|
||||||
return ListView(
|
return ListView(
|
||||||
children: <Widget>[
|
children: <Widget>[
|
||||||
TextButton(
|
|
||||||
onPressed: fetchTransactions, child: Text('Refresh')),
|
|
||||||
...transactions.map((tx) {
|
...transactions.map((tx) {
|
||||||
return Card(
|
return Card(
|
||||||
child: ListTile(
|
child: ListTile(
|
||||||
@ -184,6 +189,7 @@ class Transaction {
|
|||||||
int transfers = 0;
|
int transfers = 0;
|
||||||
int finalizes = 0;
|
int finalizes = 0;
|
||||||
int renews = 0;
|
int renews = 0;
|
||||||
|
int revokes = 0;
|
||||||
int other = 0;
|
int other = 0;
|
||||||
|
|
||||||
outputs.forEach((output) {
|
outputs.forEach((output) {
|
||||||
@ -205,6 +211,8 @@ class Transaction {
|
|||||||
finalizes++;
|
finalizes++;
|
||||||
} else if (output.covenant.action == 'RENEW') {
|
} else if (output.covenant.action == 'RENEW') {
|
||||||
renews++;
|
renews++;
|
||||||
|
} else if (output.covenant.action == 'REVOKE') {
|
||||||
|
revokes++;
|
||||||
} else if (output.covenant.action == 'NONE') {
|
} else if (output.covenant.action == 'NONE') {
|
||||||
other++;
|
other++;
|
||||||
} else {
|
} else {
|
||||||
@ -244,6 +252,9 @@ class Transaction {
|
|||||||
if (renews > 0) {
|
if (renews > 0) {
|
||||||
outputString += 'Renews: $renews, ';
|
outputString += 'Renews: $renews, ';
|
||||||
}
|
}
|
||||||
|
if (revokes > 0) {
|
||||||
|
outputString += 'Revokes: $revokes, ';
|
||||||
|
}
|
||||||
|
|
||||||
// Remove trailing comma
|
// Remove trailing comma
|
||||||
if (outputString.isNotEmpty) {
|
if (outputString.isNotEmpty) {
|
||||||
@ -251,7 +262,12 @@ class Transaction {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (outputString.isEmpty) {
|
if (outputString.isEmpty) {
|
||||||
outputString = 'Sent HNS';
|
// Check if sent or received
|
||||||
|
if (value() > 0) {
|
||||||
|
outputString = 'Received HNS';
|
||||||
|
} else {
|
||||||
|
outputString = 'Sent HNS';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return outputString;
|
return outputString;
|
||||||
|
16
pubspec.lock
16
pubspec.lock
@ -288,6 +288,22 @@ packages:
|
|||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "2.1.8"
|
version: "2.1.8"
|
||||||
|
qr:
|
||||||
|
dependency: transitive
|
||||||
|
description:
|
||||||
|
name: qr
|
||||||
|
sha256: "64957a3930367bf97cc211a5af99551d630f2f4625e38af10edd6b19131b64b3"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "3.0.1"
|
||||||
|
qr_flutter:
|
||||||
|
dependency: "direct main"
|
||||||
|
description:
|
||||||
|
name: qr_flutter
|
||||||
|
sha256: "5095f0fc6e3f71d08adef8feccc8cea4f12eec18a2e31c2e8d82cb6019f4b097"
|
||||||
|
url: "https://pub.dev"
|
||||||
|
source: hosted
|
||||||
|
version: "4.1.0"
|
||||||
shared_preferences:
|
shared_preferences:
|
||||||
dependency: "direct main"
|
dependency: "direct main"
|
||||||
description:
|
description:
|
||||||
|
@ -38,6 +38,7 @@ dependencies:
|
|||||||
shared_preferences: ^2.2.3
|
shared_preferences: ^2.2.3
|
||||||
http: ^1.2.1
|
http: ^1.2.1
|
||||||
url_launcher: ^6.2.6
|
url_launcher: ^6.2.6
|
||||||
|
qr_flutter: ^4.1.0
|
||||||
|
|
||||||
dev_dependencies:
|
dev_dependencies:
|
||||||
flutter_test:
|
flutter_test:
|
||||||
|
Loading…
Reference in New Issue
Block a user