Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ secp256k1.dll
## other generated project files

pubspec.yaml
!crypto_plugins/firo_bls_dart/**/pubspec.yaml
crypto_plugins/firo_bls_dart/**/target/

/android/app/build.gradle
/android/app/src/debug/AndroidManifest.xml
Expand Down
128 changes: 96 additions & 32 deletions lib/pages/masternodes/masternodes_home_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import '../../widgets/stack_dialog.dart';
import '../send_view/send_view.dart';
import 'create_masternode_view.dart';
import 'sub_widgets/masternodes_list.dart';
import 'sub_widgets/unban_masternode_form.dart';

class MasternodesHomeView extends ConsumerStatefulWidget {
const MasternodesHomeView({super.key, required this.walletId});
Expand Down Expand Up @@ -530,9 +531,9 @@ class _MasternodesHomeViewState extends ConsumerState<MasternodesHomeView> {
width: Util.isDesktop ? 580 : null,
padding: .all(Util.isDesktop ? 32 : 24),
leftButton: TextButton(
style: Theme.of(
ctx,
).extension<StackColors>()!.getSecondaryEnabledButtonStyle(ctx),
style: Theme.of(ctx)
.extension<StackColors>()!
.getSecondaryEnabledButtonStyle(ctx),
child: Text(
"Later",
style: STextStyles.button(ctx).copyWith(
Expand All @@ -542,9 +543,9 @@ class _MasternodesHomeViewState extends ConsumerState<MasternodesHomeView> {
onPressed: () => Navigator.of(ctx).pop(false),
),
rightButton: TextButton(
style: Theme.of(
ctx,
).extension<StackColors>()!.getPrimaryEnabledButtonStyle(ctx),
style: Theme.of(ctx)
.extension<StackColors>()!
.getPrimaryEnabledButtonStyle(ctx),
child: Text("Register", style: STextStyles.button(ctx)),
onPressed: () => Navigator.of(ctx).pop(true),
),
Expand Down Expand Up @@ -600,6 +601,53 @@ class _MasternodesHomeViewState extends ConsumerState<MasternodesHomeView> {
}
}

Future<void> _showUnbanForm([MasternodeInfo? node]) async {
await showDialog<void>(
context: context,
barrierDismissible: false,
builder: (dialogContext) => AnimatedPadding(
padding: EdgeInsets.only(
bottom: Util.isDesktop
? 0
: MediaQuery.viewInsetsOf(dialogContext).bottom,
),
duration: const Duration(milliseconds: 180),
curve: Curves.easeOut,
child: SDialog(
contentCanScroll: true,
padding: EdgeInsets.all(Util.isDesktop ? 24 : 20),
child: SizedBox(
width: Util.isDesktop ? 560 : null,
child: UnbanMasternodeForm(
walletId: widget.walletId,
node: node,
onSuccess: (txid) {
Navigator.of(dialogContext).pop();
if (!mounted) return;
setState(() => _masternodesFuture = _fetchMasternodes());
unawaited(
showDialog<void>(
context: context,
builder: (_) => StackOkDialog(
title: "Masternode Unban Submitted",
message:
"Masternode service update submitted. The masternode "
"will become active after the transaction is "
"confirmed.\n\n"
"Transaction ID: $txid",
desktopPopRootNavigator: Util.isDesktop,
maxWidth: Util.isDesktop ? 440 : null,
),
),
);
},
),
),
),
),
);
}

@override
void initState() {
super.initState();
Expand Down Expand Up @@ -627,18 +675,18 @@ class _MasternodesHomeViewState extends ConsumerState<MasternodesHomeView> {
padding: const EdgeInsets.only(left: 24, right: 20),
child: AppBarIconButton(
size: 32,
color: Theme.of(
context,
).extension<StackColors>()!.textFieldDefaultBG,
color: Theme.of(context)
.extension<StackColors>()!
.textFieldDefaultBG,
shadows: const [],
icon: SvgPicture.asset(
Assets.svg.arrowLeft,
width: 18,
height: 18,
colorFilter: ColorFilter.mode(
Theme.of(
context,
).extension<StackColors>()!.topNavIconPrimary,
Theme.of(context)
.extension<StackColors>()!
.topNavIconPrimary,
BlendMode.srcIn,
),
),
Expand All @@ -660,20 +708,31 @@ class _MasternodesHomeViewState extends ConsumerState<MasternodesHomeView> {
),
trailing: Padding(
padding: const EdgeInsets.only(right: 24),
child: PrimaryButton(
label: "Create Masternode",
buttonHeight: .l,
horizontalContentPadding: 10,
icon: SvgPicture.asset(
Assets.svg.circlePlus,
colorFilter: ColorFilter.mode(
Theme.of(
context,
).extension<StackColors>()!.buttonTextPrimary,
.srcIn,
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
SecondaryButton(
label: "Unban by ProTx hash",
buttonHeight: .l,
onPressed: () => _showUnbanForm(),
),
),
onPressed: _createMasternode,
const SizedBox(width: 12),
PrimaryButton(
label: "Create Masternode",
buttonHeight: .l,
horizontalContentPadding: 10,
icon: SvgPicture.asset(
Assets.svg.circlePlus,
colorFilter: ColorFilter.mode(
Theme.of(context)
.extension<StackColors>()!
.buttonTextPrimary,
.srcIn,
),
),
onPressed: _createMasternode,
),
],
),
),
)
Expand All @@ -688,6 +747,11 @@ class _MasternodesHomeViewState extends ConsumerState<MasternodesHomeView> {
overflow: TextOverflow.ellipsis,
),
actions: [
IconButton(
tooltip: "Unban masternode by ProTx hash",
onPressed: () => _showUnbanForm(),
icon: const Icon(Icons.restore),
),
Padding(
padding: const EdgeInsets.only(
top: 10,
Expand All @@ -700,15 +764,15 @@ class _MasternodesHomeViewState extends ConsumerState<MasternodesHomeView> {
key: const Key("createNewMasterNodeButton"),
size: 36,
shadows: const [],
color: Theme.of(
context,
).extension<StackColors>()!.background,
color: Theme.of(context)
.extension<StackColors>()!
.background,
icon: SvgPicture.asset(
Assets.svg.plus,
colorFilter: ColorFilter.mode(
Theme.of(
context,
).extension<StackColors>()!.accentColorDark,
Theme.of(context)
.extension<StackColors>()!
.accentColorDark,
.srcIn,
),
width: 20,
Expand Down Expand Up @@ -743,7 +807,7 @@ class _MasternodesHomeViewState extends ConsumerState<MasternodesHomeView> {
);
}

return MasternodesList(nodes: nodes);
return MasternodesList(nodes: nodes, onUnban: _showUnbanForm);
},
),
);
Expand Down
103 changes: 67 additions & 36 deletions lib/pages/masternodes/sub_widgets/masternodes_list.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,31 +5,35 @@ import '../../../utilities/text_styles.dart';
import '../../../utilities/util.dart';
import '../../../wallets/wallet/impl/firo_wallet.dart';
import '../../../widgets/desktop/desktop_dialog_close_button.dart';
import '../../../widgets/desktop/secondary_button.dart';
import '../../../widgets/dialogs/s_dialog.dart';
import '../../../widgets/rounded_white_container.dart';
import '../masternode_details_view.dart';
import 'masternode_info_widget.dart';

class MasternodesList extends StatelessWidget {
const MasternodesList({super.key, required this.nodes});
const MasternodesList({super.key, required this.nodes, this.onUnban});

final List<MasternodeInfo> nodes;
final Future<void> Function(MasternodeInfo node)? onUnban;

@override
Widget build(BuildContext context) {
return ListView.separated(
padding: EdgeInsets.all(Util.isDesktop ? 24 : 16),
itemCount: nodes.length,
separatorBuilder: (_, __) => const SizedBox(height: 8),
itemBuilder: (_, index) => _MasternodeCard(node: nodes[index]),
itemBuilder: (_, index) =>
_MasternodeCard(node: nodes[index], onUnban: onUnban),
);
}
}

class _MasternodeCard extends StatelessWidget {
const _MasternodeCard({required this.node});
const _MasternodeCard({required this.node, required this.onUnban});

final MasternodeInfo node;
final Future<void> Function(MasternodeInfo node)? onUnban;

Future<void> _showDetails(BuildContext context) async {
if (Util.isDesktop) {
Expand Down Expand Up @@ -81,42 +85,69 @@ class _MasternodeCard extends StatelessWidget {
return RoundedWhiteContainer(
padding: const EdgeInsets.all(16),
onPressed: () => _showDetails(context),
child: Row(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Expanded(
child: Column(
crossAxisAlignment: .start,
mainAxisSize: .min,
children: [
Text(
"${node.serviceAddr}:${node.servicePort}",
style: STextStyles.titleBold12(context),
overflow: TextOverflow.ellipsis,
Row(
children: [
Expanded(
child: Column(
crossAxisAlignment: .start,
mainAxisSize: .min,
children: [
Text(
"${node.serviceAddr}:${node.servicePort}",
style: STextStyles.titleBold12(context),
overflow: TextOverflow.ellipsis,
),
const SizedBox(height: 2),
Text(
"Last paid height: ${node.lastPaidHeight}",
style: STextStyles.baseXS(context)
.copyWith(color: stack.textSubtitle1),
),
],
),
const SizedBox(height: 2),
Text(
"Last paid height: ${node.lastPaidHeight}",
style: STextStyles.baseXS(context)
.copyWith(color: stack.textSubtitle1),
),
const SizedBox(width: 12),
IntrinsicWidth(
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Container(
padding: const EdgeInsets.symmetric(
horizontal: 8,
vertical: 4,
),
decoration: BoxDecoration(
color: switch (status) {
MasternodeStatus.active => stack.accentColorGreen,
MasternodeStatus.banned => stack.accentColorRed,
},
borderRadius: BorderRadius.circular(8),
),
child: Text(
status.label,
textAlign: TextAlign.center,
style: STextStyles.w600_12(context)
.copyWith(color: stack.textWhite),
),
),
if (status == MasternodeStatus.banned &&
node.poseBanHeight != -1 &&
node.revocationReason == 0 &&
onUnban != null) ...[
const SizedBox(height: 8),
SecondaryButton(
label: "Unban",
onPressed: () => onUnban!(node),
buttonHeight: Util.isDesktop ? .xs : .xl,
),
],
],
),
],
),
),
const SizedBox(width: 12),
Container(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
decoration: BoxDecoration(
color: switch (status) {
MasternodeStatus.active => stack.accentColorGreen,
MasternodeStatus.banned => stack.accentColorRed,
},
borderRadius: BorderRadius.circular(8),
),
child: Text(
status.label,
style: STextStyles.w600_12(context)
.copyWith(color: stack.textWhite),
),
),
],
),
],
),
Expand Down
Loading
Loading