mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-20 06:08:34 +02:00
CAKE-198 | applied ability to make a note with some details about transaction; added transactionNote property and note getter to transaction_description.dart; added multiline textfield for notes (send_page.dart); added transaction_details_list_item.dart, textfield_list_item.dart, textfield_list_row.dart, transaction_details_view_model.dart to the app
This commit is contained in:
@@ -31,6 +31,7 @@ class SendPage extends BasePage {
|
||||
: _addressController = TextEditingController(),
|
||||
_cryptoAmountController = TextEditingController(),
|
||||
_fiatAmountController = TextEditingController(),
|
||||
_noteController = TextEditingController(),
|
||||
_formKey = GlobalKey<FormState>(),
|
||||
_cryptoAmountFocus = FocusNode(),
|
||||
_fiatAmountFocus = FocusNode(),
|
||||
@@ -46,6 +47,7 @@ class SendPage extends BasePage {
|
||||
final TextEditingController _addressController;
|
||||
final TextEditingController _cryptoAmountController;
|
||||
final TextEditingController _fiatAmountController;
|
||||
final TextEditingController _noteController;
|
||||
final GlobalKey<FormState> _formKey;
|
||||
final FocusNode _cryptoAmountFocus;
|
||||
final FocusNode _fiatAmountFocus;
|
||||
@@ -304,6 +306,30 @@ class SendPage extends BasePage {
|
||||
fontWeight: FontWeight.w500,
|
||||
fontSize: 14),
|
||||
)),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 20),
|
||||
child: BaseTextFormField(
|
||||
controller: _noteController,
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: null,
|
||||
borderColor: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.headline
|
||||
.color,
|
||||
textStyle: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Colors.white),
|
||||
hintText: 'Note (optional)',
|
||||
placeholderTextStyle: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.headline
|
||||
.decorationColor),
|
||||
),
|
||||
),
|
||||
Observer(
|
||||
builder: (_) => GestureDetector(
|
||||
onTap: () =>
|
||||
@@ -534,6 +560,14 @@ class SendPage extends BasePage {
|
||||
}
|
||||
});
|
||||
|
||||
_noteController.addListener(() {
|
||||
final note = _noteController.text ?? '';
|
||||
|
||||
if (note != sendViewModel.note) {
|
||||
sendViewModel.note = note;
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => sendViewModel.sendAll, (bool all) {
|
||||
if (all) {
|
||||
_cryptoAmountController.text = S.current.all;
|
||||
@@ -571,6 +605,12 @@ class SendPage extends BasePage {
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => sendViewModel.note, (String note) {
|
||||
if (note != _noteController.text) {
|
||||
_noteController.text = note;
|
||||
}
|
||||
});
|
||||
|
||||
reaction((_) => sendViewModel.state, (ExecutionState state) {
|
||||
if (state is FailureState) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
class StandartListItem {
|
||||
StandartListItem({this.title, this.value});
|
||||
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_list_item.dart';
|
||||
|
||||
final String title;
|
||||
final String value;
|
||||
class StandartListItem extends TransactionDetailsListItem {
|
||||
StandartListItem({String title, String value})
|
||||
: super(title: title, value: value);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import 'package:cake_wallet/src/screens/transaction_details/transaction_details_list_item.dart';
|
||||
|
||||
class TextFieldListItem extends TransactionDetailsListItem {
|
||||
TextFieldListItem({String title, String value, this.onSubmitted})
|
||||
: super(title: title, value: value);
|
||||
|
||||
final Function(String value) onSubmitted;
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
abstract class TransactionDetailsListItem {
|
||||
TransactionDetailsListItem({this.title, this.value});
|
||||
|
||||
final String title;
|
||||
final String value;
|
||||
}
|
||||
@@ -1,87 +1,21 @@
|
||||
import 'package:cake_wallet/entities/transaction_description.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/textfield_list_item.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/widgets/textfield_list_row.dart';
|
||||
import 'package:cake_wallet/utils/show_bar.dart';
|
||||
import 'package:cake_wallet/view_model/transaction_details_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin_transaction_info.dart';
|
||||
import 'package:cake_wallet/monero/monero_transaction_info.dart';
|
||||
import 'package:cake_wallet/entities/transaction_info.dart';
|
||||
import 'package:cake_wallet/src/widgets/standart_list_row.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/standart_list_item.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/utils/date_formatter.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
|
||||
class TransactionDetailsPage extends BasePage {
|
||||
TransactionDetailsPage(this.transactionInfo, bool showRecipientAddress,
|
||||
Box<TransactionDescription> transactionDescriptionBox)
|
||||
: _items = [] {
|
||||
final dateFormat = DateFormatter.withCurrentLocal();
|
||||
final tx = transactionInfo;
|
||||
|
||||
if (tx is MoneroTransactionInfo) {
|
||||
final items = [
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_transaction_id, value: tx.id),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_date,
|
||||
value: dateFormat.format(tx.date)),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_height, value: '${tx.height}'),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_amount,
|
||||
value: tx.amountFormatted()),
|
||||
StandartListItem(title: S.current.send_fee, value: tx.feeFormatted())
|
||||
];
|
||||
|
||||
if (tx.key?.isNotEmpty ?? null) {
|
||||
// FIXME: add translation
|
||||
items.add(StandartListItem(title: 'Transaction Key', value: tx.key));
|
||||
}
|
||||
|
||||
_items.addAll(items);
|
||||
}
|
||||
|
||||
if (tx is BitcoinTransactionInfo) {
|
||||
final items = [
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_transaction_id, value: tx.id),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_date,
|
||||
value: dateFormat.format(tx.date)),
|
||||
StandartListItem(
|
||||
title: 'Confirmations', value: tx.confirmations?.toString()),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_height, value: '${tx.height}'),
|
||||
StandartListItem(
|
||||
title: S.current.transaction_details_amount,
|
||||
value: tx.amountFormatted()),
|
||||
if (tx.feeFormatted()?.isNotEmpty)
|
||||
StandartListItem(title: S.current.send_fee, value: tx.feeFormatted())
|
||||
];
|
||||
|
||||
_items.addAll(items);
|
||||
}
|
||||
|
||||
if (showRecipientAddress) {
|
||||
final recipientAddress = transactionDescriptionBox.values
|
||||
.firstWhere((val) => val.id == transactionInfo.id, orElse: () => null)
|
||||
?.recipientAddress;
|
||||
|
||||
if (recipientAddress?.isNotEmpty ?? false) {
|
||||
_items.add(StandartListItem(
|
||||
title: S.current.transaction_details_recipient_address,
|
||||
value: recipientAddress));
|
||||
}
|
||||
}
|
||||
}
|
||||
TransactionDetailsPage({this.transactionDetailsViewModel});
|
||||
|
||||
@override
|
||||
String get title => S.current.transaction_details_title;
|
||||
|
||||
final TransactionInfo transactionInfo;
|
||||
|
||||
final List<StandartListItem> _items;
|
||||
final TransactionDetailsViewModel transactionDetailsViewModel;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
@@ -97,22 +31,37 @@ class TransactionDetailsPage extends BasePage {
|
||||
Theme.of(context).primaryTextTheme.title.backgroundColor,
|
||||
),
|
||||
),
|
||||
itemCount: _items.length,
|
||||
itemCount: transactionDetailsViewModel.items.length,
|
||||
itemBuilder: (context, index) {
|
||||
final item = _items[index];
|
||||
final isDrawBottom = index == _items.length - 1 ? true : false;
|
||||
final item = transactionDetailsViewModel.items[index];
|
||||
final isDrawBottom =
|
||||
index == transactionDetailsViewModel.items.length - 1
|
||||
? true : false;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: item.value));
|
||||
showBar<void>(context,
|
||||
S.of(context).transaction_details_copied(item.title));
|
||||
},
|
||||
child: StandartListRow(
|
||||
title: '${item.title}:',
|
||||
value: item.value,
|
||||
isDrawBottom: isDrawBottom),
|
||||
);
|
||||
if (item is StandartListItem) {
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
Clipboard.setData(ClipboardData(text: item.value));
|
||||
showBar<void>(context,
|
||||
S.of(context).transaction_details_copied(item.title));
|
||||
},
|
||||
child: StandartListRow(
|
||||
title: '${item.title}:',
|
||||
value: item.value,
|
||||
isDrawBottom: isDrawBottom),
|
||||
);
|
||||
}
|
||||
|
||||
if (item is TextFieldListItem) {
|
||||
return TextFieldListRow(
|
||||
title: item.title,
|
||||
value: item.value,
|
||||
onSubmitted: item.onSubmitted,
|
||||
isDrawBottom: isDrawBottom,
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class TextFieldListRow extends StatelessWidget {
|
||||
TextFieldListRow(
|
||||
{this.title,
|
||||
this.value,
|
||||
this.titleFontSize = 14,
|
||||
this.valueFontSize = 16,
|
||||
this.onSubmitted,
|
||||
this.isDrawBottom = false}) {
|
||||
|
||||
_textController = TextEditingController();
|
||||
_textController.text = value;
|
||||
}
|
||||
|
||||
final String title;
|
||||
final String value;
|
||||
final double titleFontSize;
|
||||
final double valueFontSize;
|
||||
final Function(String value) onSubmitted;
|
||||
final bool isDrawBottom;
|
||||
|
||||
TextEditingController _textController;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
Container(
|
||||
width: double.infinity,
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.only(left: 24, top: 16, bottom: 16, right: 24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(title,
|
||||
style: TextStyle(
|
||||
fontSize: titleFontSize,
|
||||
fontWeight: FontWeight.w500,
|
||||
color:
|
||||
Theme.of(context).primaryTextTheme.overline.color),
|
||||
textAlign: TextAlign.left),
|
||||
TextField(
|
||||
controller: _textController,
|
||||
keyboardType: TextInputType.multiline,
|
||||
textInputAction: TextInputAction.done,
|
||||
maxLines: null,
|
||||
textAlign: TextAlign.start,
|
||||
style: TextStyle(
|
||||
fontSize: valueFontSize,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.title
|
||||
.color),
|
||||
decoration: InputDecoration(
|
||||
isDense: true,
|
||||
contentPadding: EdgeInsets.only(top: 12, bottom: 0),
|
||||
hintText: 'Note',
|
||||
hintStyle: TextStyle(
|
||||
fontSize: valueFontSize,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.title
|
||||
.color),
|
||||
border: InputBorder.none
|
||||
),
|
||||
onSubmitted: (value) => onSubmitted.call(value),
|
||||
)
|
||||
]),
|
||||
),
|
||||
),
|
||||
isDrawBottom
|
||||
? Container(
|
||||
height: 1,
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).primaryTextTheme.title.backgroundColor,
|
||||
),
|
||||
)
|
||||
: Offstage(),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ class BaseTextFormField extends StatelessWidget {
|
||||
final FocusNode focusNode;
|
||||
final bool readOnly;
|
||||
final bool enableInteractiveSelection;
|
||||
String initialValue;
|
||||
final String initialValue;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
|
||||
Reference in New Issue
Block a user