Skip to content
Snippets Groups Projects
Commit 519a8c25 authored by vjrj's avatar vjrj
Browse files

More payments (WIP)

parent f9954357
No related branches found
No related tags found
No related merge requests found
......@@ -15,8 +15,8 @@
"search_user_title": "User to pay",
"search_user": "Search (user or public key)",
"search_user_btn": "Search user",
"g1_form_pay_desc": "Description",
"g1_form_pay_hint": "Enter a description (optional)",
"g1_form_pay_desc": "Comment",
"g1_form_pay_hint": "Enter a comment (optional)",
"code_card_title": "Code repository",
"intro_1_title": "Welcome to our Ğ1 wallet!",
"intro_1_description": "With this wallet, you can easily and securely store, send, and receive Ğ1 currency (also known as 'June').",
......
......@@ -15,8 +15,8 @@
"search_user_title": "Usuario a pagar",
"search_user": "Buscar (usuari@ o clave pública)",
"search_user_btn": "Buscar usuari@",
"g1_form_pay_desc": "Descripción",
"g1_form_pay_hint": "Introduzca una descripción (opcional)",
"g1_form_pay_desc": "Comment",
"g1_form_pay_hint": "Introduzca un comentario (opcional)",
"code_card_title": "Repositorio de código",
"intro_1_title": "¡Bienvenido a nuestro monedero Ğ1!",
"intro_1_description": "Con este monedero, puede almacenar, enviar y recibir fácil y seguramente la moneda Ğ1 (también conocida como 'Juna').",
......
......@@ -35,9 +35,7 @@ class PaymentCubit extends HydratedCubit<PaymentState> {
void selectKey(String publicKey) {
final PaymentState newState = PaymentState(
publicKey: publicKey,
amount: state.amount,
description: state.description);
publicKey: publicKey, amount: state.amount, comment: state.comment);
emit(newState);
}
......@@ -51,4 +49,8 @@ class PaymentCubit extends HydratedCubit<PaymentState> {
void clearRecipient() {
emit(PaymentState.emptyPayment);
}
void selectAmount(double amount) {
emit(state.copyWith(amount: amount));
}
}
......@@ -3,6 +3,7 @@ import 'dart:typed_data';
import 'package:equatable/equatable.dart';
import 'package:json_annotation/json_annotation.dart';
import '../../g1/g1_helper.dart';
import 'model_utils.dart';
part 'payment_state.g.dart';
......@@ -13,7 +14,7 @@ class PaymentState extends Equatable {
required this.publicKey,
this.nick,
this.avatar,
this.description = '',
this.comment = '',
this.amount,
this.isSent = false,
});
......@@ -21,11 +22,14 @@ class PaymentState extends Equatable {
factory PaymentState.fromJson(Map<String, dynamic> json) =>
_$PaymentStateFromJson(json);
bool canBeSent() =>
!isSent && validateKey(publicKey) && amount != null && amount! > 0;
final String publicKey;
final String? nick;
@JsonKey(fromJson: uIntFromList, toJson: uIntToList)
final Uint8List? avatar;
final String description;
final String comment;
final double? amount;
final bool isSent;
......@@ -43,7 +47,7 @@ class PaymentState extends Equatable {
publicKey: publicKey ?? this.publicKey,
nick: nick ?? this.nick,
avatar: avatar ?? this.avatar,
description: description ?? this.description,
comment: description ?? this.comment,
amount: amount ?? this.amount,
isSent: isSent ?? this.isSent,
);
......@@ -61,5 +65,5 @@ class PaymentState extends Equatable {
@override
List<Object?> get props =>
<dynamic>[publicKey, nick, avatar, description, amount, isSent];
<dynamic>[publicKey, nick, avatar, comment, amount, isSent];
}
......@@ -10,7 +10,7 @@ PaymentState _$PaymentStateFromJson(Map<String, dynamic> json) => PaymentState(
publicKey: json['publicKey'] as String,
nick: json['nick'] as String?,
avatar: uIntFromList(json['avatar'] as List<int>),
description: json['description'] as String? ?? '',
comment: json['comment'] as String? ?? '',
amount: (json['amount'] as num?)?.toDouble(),
isSent: json['isSent'] as bool? ?? false,
);
......@@ -20,7 +20,7 @@ Map<String, dynamic> _$PaymentStateToJson(PaymentState instance) =>
'publicKey': instance.publicKey,
'nick': instance.nick,
'avatar': uIntToList(instance.avatar),
'description': instance.description,
'comment': instance.comment,
'amount': instance.amount,
'isSent': instance.isSent,
};
import 'dart:convert';
// import 'dart:developer' as developer;
import 'dart:io';
import 'package:durt/durt.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
import 'package:http/http.dart';
......@@ -12,6 +12,7 @@ import '../data/models/node.dart';
import '../data/models/node_manager.dart';
import '../data/models/node_type.dart';
import '../main.dart';
import '../shared_prefs.dart';
import 'g1_helper.dart';
// Tx history
......@@ -192,6 +193,11 @@ int nodesWorking(NodeType type) => NodeManager()
.toList()
.length;
List<Node> nodesWorkingList(NodeType type) => NodeManager()
.nodeList(type)
.where((Node n) => n.errors < NodeManager.maxNodeErrors)
.toList();
Future<List<Node>> _fetchDuniterNodesFromPeers() async {
final List<Node> lNodes = <Node>[];
// To compare with something...
......@@ -415,3 +421,21 @@ Future<http.Response> _requestWithRetry(
throw Exception(
'Cannot make the request to any of the ${nodes.length} nodes');
}
Future<String> pay(
{required String to, required double amount, String? comment}) async {
final List<Node> nodes = nodesWorkingList(NodeType.gva);
// reorder list to use others
if (nodes.isNotEmpty) {
nodes.shuffle();
final Gva gva = Gva(node: nodes.first.url);
final CesiumWallet wallet = await SharedPreferencesHelper().getWallet();
final String response = await gva.pay(
recipient: to,
amount: amount,
comment: comment ?? '',
cesiumSeed: wallet.seed);
return response;
}
return 'Sorry: I cannot find a working node to send the transaction';
}
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_svg/flutter_svg.dart';
import '../../data/models/payment_cubit.dart';
import '../../data/models/payment_state.dart';
class G1PayAmountField extends StatelessWidget {
const G1PayAmountField({super.key, required this.controller});
final TextEditingController controller;
@override
Widget build(BuildContext context) {
return TextField(
controller: controller,
keyboardType: const TextInputType.numberWithOptions(decimal: true),
decoration: InputDecoration(
labelText: tr('g1_amount'),
hintText: tr('g1_amount_hint'),
prefixIcon: Padding(
padding: const EdgeInsets.all(10.0),
child: SvgPicture.asset(
colorFilter:
ColorFilter.mode(Colors.purple.shade600, BlendMode.srcIn),
'assets/img/gbrevedot.svg',
width: 20.0,
height: 20.0,
),
),
border: const OutlineInputBorder(),
),
);
}
Widget build(BuildContext context) => BlocBuilder<PaymentCubit, PaymentState>(
builder: (BuildContext context, PaymentState state) => TextField(
controller: controller,
keyboardType: const TextInputType.numberWithOptions(decimal: true),
onChanged: (String? value) {
if (value != null) {
context.read<PaymentCubit>().selectAmount(double.parse(value));
}
},
decoration: InputDecoration(
labelText: tr('g1_amount'),
hintText: tr('g1_amount_hint'),
prefixIcon: Padding(
padding: const EdgeInsets.all(10.0),
child: SvgPicture.asset(
colorFilter:
ColorFilter.mode(Colors.purple.shade600, BlendMode.srcIn),
'assets/img/gbrevedot.svg',
width: 20.0,
height: 20.0,
),
),
border: const OutlineInputBorder(),
),
));
}
......@@ -4,6 +4,9 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import '../../data/models/payment_cubit.dart';
import '../../data/models/payment_state.dart';
import '../../data/models/transaction_cubit.dart';
import '../../g1/api.dart';
import '../ui_helpers.dart';
import 'g1_textfield.dart';
class PayForm extends StatefulWidget {
......@@ -16,7 +19,7 @@ class PayForm extends StatefulWidget {
class _PayFormState extends State<PayForm> {
final GlobalKey<FormState> _formKey = GlobalKey<FormState>();
final TextEditingController _amountController = TextEditingController();
final TextEditingController _descController = TextEditingController();
final TextEditingController _commentController = TextEditingController();
@override
Widget build(BuildContext context) {
......@@ -31,7 +34,7 @@ class _PayFormState extends State<PayForm> {
G1PayAmountField(controller: _amountController),
const SizedBox(height: 10.0),
TextField(
controller: _descController,
controller: _commentController,
decoration: InputDecoration(
labelText: tr('g1_form_pay_desc'),
hintText: tr('g1_form_pay_hint'),
......@@ -41,14 +44,21 @@ class _PayFormState extends State<PayForm> {
),
const SizedBox(height: 10.0),
ElevatedButton(
onPressed:
null /* () {
if (_formKey.currentState != null &&
_formKey.currentState!.validate()) {
// Enviar formulario
}
}, */
,
onPressed: !state.canBeSent() &&
state.amount != null &&
_weHaveBalance(context, state.amount!)
? () {}
: () async {
final String response = await pay(
to: state.publicKey,
comment: state.comment,
amount: state.amount!);
if (!mounted) {
// Cannot show a tooltip if the widget is not now visible
return;
}
showTooltip(context, '', response);
},
child: Text(tr('g1_form_pay_send')),
),
],
......@@ -56,4 +66,7 @@ class _PayFormState extends State<PayForm> {
);
});
}
bool _weHaveBalance(BuildContext context, double amount) =>
context.read<TransactionsCubit>().balance > amount;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment