Skip to content
Merged
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
26 changes: 26 additions & 0 deletions DashWallet.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -630,6 +630,12 @@
5AFDE1012FA1000000000016 /* AddMasternodeScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AFDE1012FA1000000000003 /* AddMasternodeScreen.swift */; };
5AFDE1012FA1000000000017 /* TrackedMasternodeDetailScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AFDE1012FA1000000000004 /* TrackedMasternodeDetailScreen.swift */; };
5AFDE1012FA1000000000018 /* TrackedMasternodeDetailScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AFDE1012FA1000000000004 /* TrackedMasternodeDetailScreen.swift */; };
UB26A0012FA2000000000011 /* PendingMasternodeUnbanStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = UB26A0012FA2000000000001 /* PendingMasternodeUnbanStore.swift */; };
UB26A0012FA2000000000012 /* PendingMasternodeUnbanStore.swift in Sources */ = {isa = PBXBuildFile; fileRef = UB26A0012FA2000000000001 /* PendingMasternodeUnbanStore.swift */; };
UB26A0012FA2000000000013 /* MasternodeUnbanViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = UB26A0012FA2000000000002 /* MasternodeUnbanViewModel.swift */; };
UB26A0012FA2000000000014 /* MasternodeUnbanViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = UB26A0012FA2000000000002 /* MasternodeUnbanViewModel.swift */; };
UB26A0012FA2000000000015 /* UnbanMasternodeSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = UB26A0012FA2000000000003 /* UnbanMasternodeSheet.swift */; };
UB26A0012FA2000000000016 /* UnbanMasternodeSheet.swift in Sources */ = {isa = PBXBuildFile; fileRef = UB26A0012FA2000000000003 /* UnbanMasternodeSheet.swift */; };
5AE5700E2F9C000000000003 /* EvonodeStatusViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AE5700E2F9C000000000001 /* EvonodeStatusViewModel.swift */; };
5AE5700E2F9C000000000004 /* EvonodeStatusViewModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AE5700E2F9C000000000001 /* EvonodeStatusViewModel.swift */; };
5AE5700E2F9C000000000005 /* EvonodeStatusScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AE5700E2F9C000000000002 /* EvonodeStatusScreen.swift */; };
Expand Down Expand Up @@ -2868,6 +2874,9 @@
5AFDE1012FA1000000000002 /* AddMasternodeViewModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AddMasternodeViewModel.swift; sourceTree = "<group>"; };
5AFDE1012FA1000000000003 /* AddMasternodeScreen.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = AddMasternodeScreen.swift; sourceTree = "<group>"; };
5AFDE1012FA1000000000004 /* TrackedMasternodeDetailScreen.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = TrackedMasternodeDetailScreen.swift; sourceTree = "<group>"; };
UB26A0012FA2000000000001 /* PendingMasternodeUnbanStore.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = PendingMasternodeUnbanStore.swift; sourceTree = "<group>"; };
UB26A0012FA2000000000002 /* MasternodeUnbanViewModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = MasternodeUnbanViewModel.swift; sourceTree = "<group>"; };
UB26A0012FA2000000000003 /* UnbanMasternodeSheet.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = UnbanMasternodeSheet.swift; sourceTree = "<group>"; };
5AE5700E2F9C000000000001 /* EvonodeStatusViewModel.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = EvonodeStatusViewModel.swift; sourceTree = "<group>"; };
5AE5700E2F9C000000000002 /* EvonodeStatusScreen.swift */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = sourcecode.swift; path = EvonodeStatusScreen.swift; sourceTree = "<group>"; };
51BA2E9F2F0B2E0100A1B201 /* SwapPendingGate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwapPendingGate.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3849,6 +3858,16 @@
path = "Tracked Masternodes";
sourceTree = "<group>";
};
UB26A0012FA2000000000004 /* Unban */ = {
isa = PBXGroup;
children = (
UB26A0012FA2000000000001 /* PendingMasternodeUnbanStore.swift */,
UB26A0012FA2000000000002 /* MasternodeUnbanViewModel.swift */,
UB26A0012FA2000000000003 /* UnbanMasternodeSheet.swift */,
);
path = Unban;
sourceTree = "<group>";
};
5AE5700E2F9C000000000007 /* Evonode Status */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -4905,6 +4924,7 @@
51AA00202F970020005A0020 /* MasternodesScreen.swift */,
5AEDE0012F9B000000000007 /* Masternode Withdrawal */,
5AFDE1012FA1000000000005 /* Tracked Masternodes */,
UB26A0012FA2000000000004 /* Unban */,
5AE5700E2F9C000000000007 /* Evonode Status */,
7566F4822BB69498005238D2 /* ToolsMenuScreen.swift */,
RC00C0032FA0000000000001 /* CSVExportSheet.swift */,
Expand Down Expand Up @@ -10304,6 +10324,9 @@
5AFDE1012FA1000000000014 /* AddMasternodeViewModel.swift in Sources */,
5AFDE1012FA1000000000016 /* AddMasternodeScreen.swift in Sources */,
5AFDE1012FA1000000000018 /* TrackedMasternodeDetailScreen.swift in Sources */,
UB26A0012FA2000000000012 /* PendingMasternodeUnbanStore.swift in Sources */,
UB26A0012FA2000000000014 /* MasternodeUnbanViewModel.swift in Sources */,
UB26A0012FA2000000000016 /* UnbanMasternodeSheet.swift in Sources */,
5AE5700E2F9C000000000004 /* EvonodeStatusViewModel.swift in Sources */,
5AE5700E2F9C000000000006 /* EvonodeStatusScreen.swift in Sources */,
51AA00022F970002005A0002 /* SyncInfoMenuScreen.swift in Sources */,
Expand Down Expand Up @@ -11336,6 +11359,9 @@
5AFDE1012FA1000000000013 /* AddMasternodeViewModel.swift in Sources */,
5AFDE1012FA1000000000015 /* AddMasternodeScreen.swift in Sources */,
5AFDE1012FA1000000000017 /* TrackedMasternodeDetailScreen.swift in Sources */,
UB26A0012FA2000000000011 /* PendingMasternodeUnbanStore.swift in Sources */,
UB26A0012FA2000000000013 /* MasternodeUnbanViewModel.swift in Sources */,
UB26A0012FA2000000000015 /* UnbanMasternodeSheet.swift in Sources */,
5AE5700E2F9C000000000003 /* EvonodeStatusViewModel.swift in Sources */,
5AE5700E2F9C000000000005 /* EvonodeStatusScreen.swift in Sources */,
51AA00032F970003005A0003 /* SyncInfoMenuScreen.swift in Sources */,
Expand Down
48 changes: 47 additions & 1 deletion DashWallet/Sources/UI/Menu/Tools/MasternodesScreen.swift
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ extension PlatformMasternode {
var statusName: String {
switch masternodeStatus {
case .active: return NSLocalizedString("Active", comment: "Masternode status")
case .inactive: return NSLocalizedString("Inactive", comment: "Masternode status")
case .inactive: return NSLocalizedString("PoSe banned", comment: "Masternode status")
case .retired: return NSLocalizedString("Retired", comment: "Masternode status")
case .unknown: return NSLocalizedString("Unknown", comment: "Masternode status")
}
Expand Down Expand Up @@ -526,6 +526,11 @@ struct MasternodeDetailScreen: View {
let ownerOwnership: String
let votingOwnership: String
@StateObject private var viewModel: MasternodeDetailViewModel
@State private var showUnbanSheet = false
/// Set after a successful ProUpServTx broadcast: the DML entry stays
/// PoSe-banned for a few more blocks, so the row must not invite a
/// duplicate submission in that window.
@State private var unbanSubmitted = false

init(
masternode: PlatformMasternode,
Expand Down Expand Up @@ -559,6 +564,7 @@ struct MasternodeDetailScreen: View {
if masternode.isEvonode {
requestStatusRow
}
unbanRows
}

Section(NSLocalizedString("Registration", comment: "Masternodes")) {
Expand Down Expand Up @@ -677,6 +683,46 @@ struct MasternodeDetailScreen: View {
.task {
await viewModel.load()
}
.sheet(isPresented: $showUnbanSheet) {
UnbanMasternodeSheet(
record: masternode,
keySource: .wallet(operatorKeyIndex: masternode.operatorKeyIndex),
onSubmitted: { unbanSubmitted = true })
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}

/// Unban entry point: shown while the node is PoSe-banned (or an unban
/// funded from the shielded balance is still pending), enabled when this
/// wallet holds the operator key that signs the ProUpServTx.
@ViewBuilder
private var unbanRows: some View {
let pending = PendingMasternodeUnbanStore.shared.pending(forProTxHash: masternode.proTxHash) != nil
if unbanSubmitted {
Text(NSLocalizedString(
"Unban submitted — the masternode list updates within a few blocks.",
comment: "Masternode unban"))
.font(.caption)
.foregroundColor(Color.dash.secondaryText)
} else if masternode.masternodeStatus == .inactive || pending {
if masternode.operatorInWallet {
Button {
showUnbanSheet = true
} label: {
Label(
pending
? NSLocalizedString("Complete unban", comment: "Masternode unban")
: NSLocalizedString("Unban masternode", comment: "Masternode unban"),
systemImage: "arrow.up.heart")
.foregroundColor(Color.dash.blue)
}
} else if masternode.masternodeStatus == .inactive {
Text(NSLocalizedString(
"This wallet doesn't hold this masternode's operator key, so it can't be unbanned from here.",
comment: "Masternode unban"))
.font(.caption)
.foregroundColor(Color.dash.secondaryText)
}
}
}

/// Entry point to the node's DAPI `getStatus` self-report
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,11 @@ struct TrackedMasternodeDetailScreen: View {
@State private var showStopConfirm = false
@State private var showWithdrawSheet = false
@State private var showKeysSheet = false
@State private var showUnbanSheet = false
/// Set after a successful ProUpServTx broadcast: the DML entry stays
/// PoSe-banned for a few more blocks, so the row must not invite a
/// duplicate submission in that window.
@State private var unbanSubmitted = false
let onChanged: () -> Void

init(record: PlatformMasternode, onChanged: @escaping () -> Void) {
Expand All @@ -287,6 +292,18 @@ struct TrackedMasternodeDetailScreen: View {
.sheet(isPresented: $showKeysSheet, onDismiss: { viewModel.reloadAttachedRoles() }) {
TrackedKeyManagementSheet(record: viewModel.record, vault: viewModel.vault)
}
.sheet(isPresented: $showUnbanSheet) {
UnbanMasternodeSheet(
record: viewModel.record,
keySource: .tracked(vault: viewModel.vault),
onSubmitted: {
unbanSubmitted = true
Task {
await viewModel.refresh()
onChanged()
}
})
}
.confirmationDialog(
NSLocalizedString("Stop tracking this masternode?", comment: "Tracked masternodes"),
isPresented: $showStopConfirm,
Expand Down Expand Up @@ -458,6 +475,8 @@ struct TrackedMasternodeDetailScreen: View {

private var manageSection: some View {
Section {
unbanRows

requestStatusRow

Button {
Expand Down Expand Up @@ -486,6 +505,41 @@ struct TrackedMasternodeDetailScreen: View {
}
}

/// Unban entry point: shown while the node is PoSe-banned (or an unban
/// funded from the shielded balance is still pending), enabled when the
/// operator key — the one that signs a ProUpServTx — is on this device.
@ViewBuilder
private var unbanRows: some View {
let pending = PendingMasternodeUnbanStore.shared.pending(
forProTxHash: viewModel.record.proTxHash) != nil
if unbanSubmitted {
Text(NSLocalizedString(
"Unban submitted — the masternode list updates within a few blocks.",
comment: "Masternode unban"))
.font(.caption)
.foregroundColor(Color.dash.secondaryText)
} else if viewModel.record.masternodeStatus == .inactive || pending {
if viewModel.capabilities.canUpdateService {
Button {
showUnbanSheet = true
} label: {
Label(
pending
? NSLocalizedString("Complete unban", comment: "Masternode unban")
: NSLocalizedString("Unban masternode", comment: "Masternode unban"),
systemImage: "arrow.up.heart")
.foregroundColor(Color.dash.blue)
}
} else if viewModel.record.masternodeStatus == .inactive {
Text(NSLocalizedString(
"Add this masternode's operator key to unban it from here.",
comment: "Masternode unban"))
.font(.caption)
.foregroundColor(Color.dash.secondaryText)
}
}
}

/// Ask the node itself for its DAPI status — the same
/// `EvonodeStatusScreen` the wallet-owned detail pushes, keyed off the
/// record's DAPI address (evonodes with a routable service address).
Expand Down
Loading
Loading