WIP desktop utxo details

This commit is contained in:
julian 2023-03-13 17:09:14 -06:00
parent 397112e0c9
commit b2ce88e33d
4 changed files with 434 additions and 323 deletions

View file

@ -5,6 +5,7 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:isar/isar.dart';
import 'package:stackwallet/db/main_db.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart';
import 'package:stackwallet/pages/wallet_view/transaction_views/transaction_details_view.dart';
import 'package:stackwallet/providers/global/wallets_provider.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/utilities/format.dart';
@ -16,6 +17,8 @@ import 'package:stackwallet/widgets/conditional_parent.dart';
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
import 'package:stackwallet/widgets/custom_buttons/simple_copy_button.dart';
import 'package:stackwallet/widgets/custom_buttons/simple_edit_button.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/rounded_white_container.dart';
@ -36,6 +39,7 @@ class UtxoDetailsView extends ConsumerStatefulWidget {
}
class _UtxoDetailsViewState extends ConsumerState<UtxoDetailsView> {
final isDesktop = Util.isDesktop;
static const double _spacing = 12;
late Stream<UTXO?> streamUTXO;
@ -94,7 +98,7 @@ class _UtxoDetailsViewState extends ConsumerState<UtxoDetailsView> {
);
return ConditionalParent(
condition: !Util.isDesktop,
condition: !isDesktop,
builder: (child) => Background(
child: Scaffold(
backgroundColor:
@ -129,134 +133,86 @@ class _UtxoDetailsViewState extends ConsumerState<UtxoDetailsView> {
),
),
),
child: StreamBuilder<UTXO?>(
stream: streamUTXO,
builder: (context, snapshot) {
if (snapshot.hasData) {
utxo = snapshot.data!;
}
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(
height: 10,
),
RoundedWhiteContainer(
child: Row(
child: ConditionalParent(
condition: isDesktop,
builder: (child) {
return DesktopDialog(
maxHeight: double.infinity,
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${Format.satoshisToAmount(
utxo!.value,
coin: coin,
).toStringAsFixed(
coin.decimals,
)} ${coin.ticker}",
style: STextStyles.pageTitleH2(context),
),
Text(
utxo!.isBlocked
? "Frozen"
: confirmed
? "Available"
: "Unconfirmed",
style: STextStyles.w500_14(context).copyWith(
color: utxo!.isBlocked
? const Color(0xFF7FA2D4) // todo theme
: confirmed
? Theme.of(context)
.extension<StackColors>()!
.accentColorGreen
: Theme.of(context)
.extension<StackColors>()!
.accentColorYellow,
Padding(
padding: const EdgeInsets.only(left: 32),
child: Text(
"Output details",
style: STextStyles.desktopH3(context),
),
),
],
),
),
const SizedBox(
height: _spacing,
),
RoundedWhiteContainer(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Label",
style: STextStyles.w500_14(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
SimpleEditButton(
editValue: utxo!.name,
editLabel: "label",
onValueChanged: (newName) {
MainDB.instance.putUTXO(
utxo!.copyWith(
name: newName,
),
);
},
),
],
),
const SizedBox(
height: 4,
),
Text(
utxo!.name,
style: STextStyles.w500_14(context),
DesktopDialogCloseButton(
onPressedOverride: () {
Navigator.of(context)
.pop(_popWithRefresh ? "refresh" : null);
},
),
],
),
),
const SizedBox(
height: _spacing,
),
RoundedWhiteContainer(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Address",
style: STextStyles.w500_14(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
SimpleCopyButton(
data: utxo!.address!,
),
],
),
const SizedBox(
height: 4,
),
Text(
utxo!.address!,
style: STextStyles.w500_14(context),
),
],
child,
],
),
);
},
child: StreamBuilder<UTXO?>(
stream: streamUTXO,
builder: (context, snapshot) {
if (snapshot.hasData) {
utxo = snapshot.data!;
}
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(
height: 10,
),
RoundedWhiteContainer(
child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${Format.satoshisToAmount(
utxo!.value,
coin: coin,
).toStringAsFixed(
coin.decimals,
)} ${coin.ticker}",
style: STextStyles.pageTitleH2(context),
),
Text(
utxo!.isBlocked
? "Frozen"
: confirmed
? "Available"
: "Unconfirmed",
style: STextStyles.w500_14(context).copyWith(
color: utxo!.isBlocked
? const Color(0xFF7FA2D4) // todo theme
: confirmed
? Theme.of(context)
.extension<StackColors>()!
.accentColorGreen
: Theme.of(context)
.extension<StackColors>()!
.accentColorYellow,
),
),
],
),
),
),
if (label != null && label!.value.isNotEmpty)
const SizedBox(
height: _spacing,
),
if (label != null && label!.value.isNotEmpty)
RoundedWhiteContainer(
child: Column(
mainAxisSize: MainAxisSize.min,
@ -266,15 +222,23 @@ class _UtxoDetailsViewState extends ConsumerState<UtxoDetailsView> {
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Address label",
"Label",
style: STextStyles.w500_14(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
SimpleCopyButton(
data: label!.value,
SimpleEditButton(
editValue: utxo!.name,
editLabel: "label",
onValueChanged: (newName) {
MainDB.instance.putUTXO(
utxo!.copyWith(
name: newName,
),
);
},
),
],
),
@ -282,135 +246,218 @@ class _UtxoDetailsViewState extends ConsumerState<UtxoDetailsView> {
height: 4,
),
Text(
label!.value,
utxo!.name,
style: STextStyles.w500_14(context),
),
],
),
),
const SizedBox(
height: _spacing,
),
RoundedWhiteContainer(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Transaction ID",
style: STextStyles.w500_14(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
const SizedBox(
height: _spacing,
),
RoundedWhiteContainer(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Address",
style: STextStyles.w500_14(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
isDesktop
? IconCopyButton(
data: utxo!.address!,
)
: SimpleCopyButton(
data: utxo!.address!,
),
],
),
const SizedBox(
height: 4,
),
Text(
utxo!.address!,
style: STextStyles.w500_14(context),
),
],
),
),
if (label != null && label!.value.isNotEmpty)
const SizedBox(
height: _spacing,
),
if (label != null && label!.value.isNotEmpty)
RoundedWhiteContainer(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Address label",
style: STextStyles.w500_14(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
isDesktop
? IconCopyButton(
data: utxo!.address!,
)
: SimpleCopyButton(
data: label!.value,
),
],
),
SimpleCopyButton(
data: utxo!.txid,
const SizedBox(
height: 4,
),
Text(
label!.value,
style: STextStyles.w500_14(context),
),
],
),
const SizedBox(
height: 4,
),
Text(
utxo!.txid,
style: STextStyles.w500_14(context),
),
],
),
const SizedBox(
height: _spacing,
),
),
const SizedBox(
height: _spacing,
),
RoundedWhiteContainer(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Confirmations",
style: STextStyles.w500_14(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
const SizedBox(
height: 4,
),
Text(
"${utxo!.getConfirmations(currentHeight)}",
style: STextStyles.w500_14(context),
),
],
),
),
const SizedBox(
height: _spacing,
),
if (utxo!.isBlocked)
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
RoundedWhiteContainer(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
RoundedWhiteContainer(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Freeze reason",
style: STextStyles.w500_14(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
SimpleEditButton(
editValue: utxo!.blockedReason ?? "",
editLabel: "freeze reason",
onValueChanged: (newReason) {
MainDB.instance.putUTXO(
utxo!.copyWith(
blockedReason: newReason,
),
);
},
),
],
),
const SizedBox(
height: 4,
),
Text(
utxo!.blockedReason ?? "",
style: STextStyles.w500_14(context),
"Transaction ID",
style: STextStyles.w500_14(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
isDesktop
? IconCopyButton(
data: utxo!.address!,
)
: SimpleCopyButton(
data: utxo!.txid,
),
],
),
),
const SizedBox(
height: _spacing,
),
],
const SizedBox(
height: 4,
),
Text(
utxo!.txid,
style: STextStyles.w500_14(context),
),
],
),
),
const Spacer(),
SecondaryButton(
label: utxo!.isBlocked ? "Unfreeze" : "Freeze",
onPressed: _toggleFreeze,
),
const SizedBox(
height: 16,
),
],
);
},
const SizedBox(
height: _spacing,
),
RoundedWhiteContainer(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
"Confirmations",
style: STextStyles.w500_14(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
const SizedBox(
height: 4,
),
Text(
"${utxo!.getConfirmations(currentHeight)}",
style: STextStyles.w500_14(context),
),
],
),
),
const SizedBox(
height: _spacing,
),
if (utxo!.isBlocked)
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
RoundedWhiteContainer(
child: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"Freeze reason",
style: STextStyles.w500_14(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
SimpleEditButton(
editValue: utxo!.blockedReason ?? "",
editLabel: "freeze reason",
onValueChanged: (newReason) {
MainDB.instance.putUTXO(
utxo!.copyWith(
blockedReason: newReason,
),
);
},
),
],
),
const SizedBox(
height: 4,
),
Text(
utxo!.blockedReason ?? "",
style: STextStyles.w500_14(context),
),
],
),
),
const SizedBox(
height: _spacing,
),
],
),
if (!isDesktop) const Spacer(),
SecondaryButton(
label: utxo!.isBlocked ? "Unfreeze" : "Freeze",
onPressed: _toggleFreeze,
),
const SizedBox(
height: 16,
),
],
);
},
),
),
);
}

View file

@ -275,6 +275,7 @@ class _DesktopCoinControlViewState
// : _selectedAvailable.contains(utxo);
return UtxoRow(
key: Key("${utxo.walletId}_${utxo.id}_${utxo.isBlocked}"),
utxo: utxo,
walletId: widget.walletId,
onSelectedChanged: (value) {

View file

@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:stackwallet/models/isar/models/isar_models.dart';
import 'package:stackwallet/pages/coin_control/utxo_details_view.dart';
import 'package:stackwallet/utilities/enums/coin_enum.dart';
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
import 'package:stackwallet/widgets/icon_widgets/utxo_status_icon.dart';
@ -57,69 +58,85 @@ class _UtxoRowState extends ConsumerState<UtxoRow> {
final currentChainHeight = ref.watch(walletsChangeNotifierProvider
.select((value) => value.getManager(widget.walletId).currentHeight));
return RoundedWhiteContainer(
child: Row(
children: [
Checkbox(
value: _selected,
onChanged: (value) => setState(() {
_selected = value!;
}),
),
const SizedBox(
width: 10,
),
UTXOStatusIcon(
blocked: utxo.isBlocked,
status: utxo.isConfirmed(
currentChainHeight,
coin.requiredConfirmations,
)
? UTXOStatusIconStatus.confirmed
: UTXOStatusIconStatus.unconfirmed,
background: Theme.of(context).extension<StackColors>()!.popupBG,
selected: false,
width: 32,
height: 32,
),
const SizedBox(
width: 10,
),
Text(
"${Format.satoshisToAmount(
utxo.value,
coin: coin,
).toStringAsFixed(coin.decimals)} ${coin.ticker}",
textAlign: TextAlign.right,
style: STextStyles.w600_14(context),
),
const SizedBox(
width: 10,
),
Expanded(
flex: 13,
child: Text(
utxo.name.isNotEmpty ? utxo.name : utxo.address ?? utxo.txid,
textAlign: TextAlign.center,
style: STextStyles.w500_12(context).copyWith(
color:
Theme.of(context).extension<StackColors>()!.textSubtitle1,
return StreamBuilder<UTXO?>(
stream: stream,
builder: (context, snapshot) {
if (snapshot.hasData) {
utxo = snapshot.data!;
}
return RoundedWhiteContainer(
child: Row(
children: [
Checkbox(
value: _selected,
onChanged: (value) => setState(() {
_selected = value!;
}),
),
),
const SizedBox(
width: 10,
),
UTXOStatusIcon(
blocked: utxo.isBlocked,
status: utxo.isConfirmed(
currentChainHeight,
coin.requiredConfirmations,
)
? UTXOStatusIconStatus.confirmed
: UTXOStatusIconStatus.unconfirmed,
background: Theme.of(context).extension<StackColors>()!.popupBG,
selected: false,
width: 32,
height: 32,
),
const SizedBox(
width: 10,
),
Text(
"${Format.satoshisToAmount(
utxo.value,
coin: coin,
).toStringAsFixed(coin.decimals)} ${coin.ticker}",
textAlign: TextAlign.right,
style: STextStyles.w600_14(context),
),
const SizedBox(
width: 10,
),
Expanded(
flex: 13,
child: Text(
utxo.name.isNotEmpty ? utxo.name : utxo.address ?? utxo.txid,
textAlign: TextAlign.center,
style: STextStyles.w500_12(context).copyWith(
color: Theme.of(context)
.extension<StackColors>()!
.textSubtitle1,
),
),
),
const SizedBox(
width: 10,
),
SecondaryButton(
width: 120,
buttonHeight: ButtonHeight.xs,
label: "Details",
onPressed: () async {
await showDialog<String?>(
context: context,
builder: (context) => UtxoDetailsView(
utxoId: utxo.id,
walletId: widget.walletId,
),
);
},
)
],
),
const SizedBox(
width: 10,
),
SecondaryButton(
width: 120,
buttonHeight: ButtonHeight.xs,
label: "Details",
onPressed: () {
//todo
},
)
],
),
);
},
);
}
}

View file

@ -4,8 +4,12 @@ import 'package:stackwallet/pages/generic/single_field_edit_view.dart';
import 'package:stackwallet/utilities/assets.dart';
import 'package:stackwallet/utilities/text_styles.dart';
import 'package:stackwallet/utilities/theme/stack_colors.dart';
import 'package:stackwallet/utilities/util.dart';
import 'package:tuple/tuple.dart';
import '../desktop/desktop_dialog.dart';
import '../icon_widgets/pencil_icon.dart';
class SimpleEditButton extends StatelessWidget {
const SimpleEditButton({
Key? key,
@ -20,36 +24,78 @@ class SimpleEditButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () async {
final result = await Navigator.of(context).pushNamed(
SingleFieldEditView.routeName,
arguments: Tuple2(
editValue,
editLabel,
if (Util.isDesktop) {
return SizedBox(
height: 26,
width: 26,
child: RawMaterialButton(
fillColor:
Theme.of(context).extension<StackColors>()!.buttonBackSecondary,
elevation: 0,
hoverElevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
),
);
if (result is String && result != editValue) {
onValueChanged(result);
}
},
child: Row(
children: [
SvgPicture.asset(
Assets.svg.pencil,
width: 10,
height: 10,
color: Theme.of(context).extension<StackColors>()!.infoItemIcons,
onPressed: () async {
final result = await showDialog<String?>(
context: context,
builder: (context) {
return DesktopDialog(
maxWidth: 580,
maxHeight: 360,
child: SingleFieldEditView(
initialValue: editValue,
label: editLabel,
),
);
},
);
if (result is String && result != editValue) {
onValueChanged(result);
}
},
child: Padding(
padding: const EdgeInsets.all(5),
child: PencilIcon(
width: 16,
height: 16,
color: Theme.of(context).extension<StackColors>()!.textDark,
),
),
const SizedBox(
width: 4,
),
Text(
"Edit",
style: STextStyles.link2(context),
),
],
),
);
),
);
} else {
return GestureDetector(
onTap: () async {
final result = await Navigator.of(context).pushNamed(
SingleFieldEditView.routeName,
arguments: Tuple2(
editValue,
editLabel,
),
);
if (result is String && result != editValue) {
onValueChanged(result);
}
},
child: Row(
children: [
SvgPicture.asset(
Assets.svg.pencil,
width: 10,
height: 10,
color: Theme.of(context).extension<StackColors>()!.infoItemIcons,
),
const SizedBox(
width: 4,
),
Text(
"Edit",
style: STextStyles.link2(context),
),
],
),
);
}
}
}