144 lines
4.6 KiB
Swift
144 lines
4.6 KiB
Swift
import SwiftUI
|
|
|
|
struct DescriptorImportView: View {
|
|
@Bindable var viewModel: SetupWizardViewModel
|
|
@State private var showScanner = false
|
|
|
|
var body: some View {
|
|
ScrollView {
|
|
VStack(spacing: 24) {
|
|
Text("Import Descriptor")
|
|
.font(.hbDisplay(28))
|
|
.foregroundStyle(Color.hbTextPrimary)
|
|
.padding(.top, 16)
|
|
|
|
Text("Paste or scan a multisig output descriptor")
|
|
.font(.hbBody(15))
|
|
.foregroundStyle(Color.hbTextSecondary)
|
|
.multilineTextAlignment(.center)
|
|
|
|
VStack(alignment: .leading, spacing: 8) {
|
|
HStack {
|
|
Text("Output Descriptor")
|
|
.font(.hbLabel())
|
|
.foregroundStyle(Color.hbTextSecondary)
|
|
|
|
Spacer()
|
|
|
|
Button(action: {
|
|
if let text = UIPasteboard.general.string {
|
|
viewModel.importedDescriptorText = text.trimmingCharacters(in: .whitespacesAndNewlines)
|
|
}
|
|
}) {
|
|
Label("Paste", systemImage: "doc.on.clipboard")
|
|
.font(.hbLabel())
|
|
.foregroundStyle(Color.hbSteelBlue)
|
|
}
|
|
}
|
|
|
|
TextEditor(text: $viewModel.importedDescriptorText)
|
|
.font(.hbMono(11))
|
|
.frame(minHeight: 120)
|
|
.scrollContentBackground(.hidden)
|
|
.padding(12)
|
|
.background(Color.hbSurfaceElevated)
|
|
.clipShape(RoundedRectangle(cornerRadius: 8))
|
|
.foregroundStyle(Color.hbTextPrimary)
|
|
.onChange(of: viewModel.importedDescriptorText) {
|
|
viewModel.importDescriptorError = nil
|
|
}
|
|
|
|
Text("Expected format: wsh(sortedmulti(M,[fp/path]xpub/0/*,...))")
|
|
.font(.hbMono(10))
|
|
.foregroundStyle(Color.hbTextSecondary)
|
|
}
|
|
.hbCard()
|
|
.padding(.horizontal, 24)
|
|
|
|
Button(action: { showScanner = true }) {
|
|
Label("Scan Descriptor QR", systemImage: "qrcode.viewfinder")
|
|
.hbSecondaryButton()
|
|
}
|
|
.padding(.horizontal, 24)
|
|
|
|
// Network picker
|
|
VStack(spacing: 8) {
|
|
Text("Bitcoin Network")
|
|
.font(.hbLabel())
|
|
.foregroundStyle(Color.hbTextSecondary)
|
|
|
|
Picker("Bitcoin Network", selection: $viewModel.network) {
|
|
ForEach(BitcoinNetwork.allCases) { network in
|
|
Text(network.displayName).tag(network)
|
|
}
|
|
}
|
|
.pickerStyle(.segmented)
|
|
}
|
|
.hbCard()
|
|
.padding(.horizontal, 24)
|
|
|
|
if let mismatchError = viewModel.descriptorNetworkMismatchError {
|
|
Text(mismatchError)
|
|
.font(.hbLabel(13))
|
|
.foregroundStyle(Color.hbError)
|
|
.multilineTextAlignment(.center)
|
|
.padding(.horizontal, 24)
|
|
}
|
|
|
|
if let importError = viewModel.importDescriptorError {
|
|
Text(importError)
|
|
.font(.hbBody(13))
|
|
.foregroundStyle(Color.hbError)
|
|
.multilineTextAlignment(.leading)
|
|
.frame(maxWidth: .infinity, alignment: .leading)
|
|
.padding(12)
|
|
.background(Color.hbError.opacity(0.1))
|
|
.clipShape(RoundedRectangle(cornerRadius: 8))
|
|
.padding(.horizontal, 24)
|
|
}
|
|
|
|
// Electrum server
|
|
ElectrumServerSetupSection(viewModel: viewModel, initiallyExpanded: viewModel.network == .mainnet)
|
|
.padding(.horizontal, 24)
|
|
|
|
// Advanced
|
|
WalletAdvancedSetupSection(viewModel: viewModel)
|
|
.padding(.horizontal, 24)
|
|
|
|
HStack(spacing: 16) {
|
|
Button(action: { viewModel.goBack() }) {
|
|
Text("Back")
|
|
.font(.hbBody(16))
|
|
.foregroundStyle(Color.hbTextSecondary)
|
|
}
|
|
|
|
Spacer()
|
|
|
|
Button(action: { viewModel.goToNext() }) {
|
|
let canImport = !viewModel.importedDescriptorText.isEmpty && viewModel.descriptorNetworkMismatchError == nil
|
|
Text("Import")
|
|
.font(.hbHeadline)
|
|
.foregroundStyle(.white)
|
|
.padding(.horizontal, 32)
|
|
.padding(.vertical, 14)
|
|
.background(canImport ? Color.hbBitcoinOrange : Color.hbBorder)
|
|
.clipShape(RoundedRectangle(cornerRadius: 12))
|
|
}
|
|
.disabled(viewModel.importedDescriptorText.isEmpty || viewModel.descriptorNetworkMismatchError != nil)
|
|
}
|
|
.padding(.horizontal, 24)
|
|
.padding(.bottom, 32)
|
|
}
|
|
}
|
|
.scrollDismissesKeyboard(.interactively)
|
|
.sheet(isPresented: $showScanner) {
|
|
URScannerSheet { result in
|
|
if case let .descriptor(text) = result {
|
|
viewModel.importedDescriptorText = text
|
|
}
|
|
showScanner = false
|
|
}
|
|
}
|
|
}
|
|
}
|