montana/macOS/MontanaPresence/ReceiveView.swift

138 lines
5.9 KiB
Swift

import SwiftUI
import CoreImage.CIFilterBuiltins
struct ReceiveView: View {
@EnvironmentObject var engine: PresenceEngine
@State private var copiedNumber = false
@State private var copiedFull = false
@Environment(\.dismiss) private var dismiss
private let cyan = Color(red: 0, green: 0.83, blue: 1)
private let cardBg = Color(red: 0.09, green: 0.09, blue: 0.12)
private let gold = Color(red: 0.85, green: 0.68, blue: 0.25)
var body: some View {
VStack(spacing: 0) {
// Header
HStack {
Image(systemName: "arrow.down.circle.fill")
.foregroundColor(cyan)
Text("\u{0248} \u{041f}\u{043e}\u{043b}\u{0443}\u{0447}\u{0438}\u{0442}\u{044c}")
.font(.system(size: 16, weight: .bold))
Spacer()
Button(action: { dismiss() }) {
Image(systemName: "xmark.circle.fill")
.foregroundColor(.secondary)
}
.buttonStyle(.plain)
}
.padding(.horizontal, 16)
.padding(.top, 14)
.padding(.bottom, 10)
let walletNum = UserDefaults.standard.integer(forKey: "wallet_number")
// Alias + copy number button
if walletNum > 0 {
VStack(spacing: 6) {
Text("\u{0248}-\(walletNum)")
.font(.system(size: 36, weight: .bold, design: .monospaced))
.foregroundColor(gold)
.textSelection(.enabled)
Button(action: {
NSPasteboard.general.clearContents()
NSPasteboard.general.setString("\(walletNum)", forType: .string)
copiedNumber = true
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { copiedNumber = false }
}) {
HStack(spacing: 4) {
Image(systemName: copiedNumber ? "checkmark" : "doc.on.doc")
.font(.system(size: 10))
Text(copiedNumber ? "\u{0421}\u{043a}\u{043e}\u{043f}\u{0438}\u{0440}\u{043e}\u{0432}\u{0430}\u{043d}\u{043e}!" : "\u{041a}\u{043e}\u{043f}\u{0438}\u{0440}\u{043e}\u{0432}\u{0430}\u{0442}\u{044c} \u{043d}\u{043e}\u{043c}\u{0435}\u{0440}")
.font(.system(size: 11, weight: .medium))
}
.foregroundColor(copiedNumber ? .green : cyan)
}
.buttonStyle(.plain)
Text("\u{041d}\u{0430}\u{0437}\u{043e}\u{0432}\u{0438}\u{0442}\u{0435} \u{043d}\u{043e}\u{043c}\u{0435}\u{0440} \u{043e}\u{0442}\u{043f}\u{0440}\u{0430}\u{0432}\u{0438}\u{0442}\u{0435}\u{043b}\u{044e}")
.font(.system(size: 10))
.foregroundColor(.secondary)
}
.padding(.bottom, 12)
}
// QR code
if let addr = engine.address, !addr.isEmpty {
let qrString = walletNum > 0 ? "\(walletNum)" : addr
if let qrImage = generateQR(from: qrString) {
Image(nsImage: qrImage)
.resizable()
.interpolation(.none)
.frame(width: 150, height: 150)
.background(Color.white)
.cornerRadius(8)
.padding(.bottom, 12)
}
}
// Full address card
if let addr = engine.address {
VStack(spacing: 8) {
Text(addr)
.font(.system(size: 10, design: .monospaced))
.foregroundColor(.secondary)
.lineLimit(1)
.truncationMode(.middle)
.textSelection(.enabled)
.frame(maxWidth: .infinity)
Button(action: {
NSPasteboard.general.clearContents()
NSPasteboard.general.setString(addr, forType: .string)
copiedFull = true
DispatchQueue.main.asyncAfter(deadline: .now() + 2) { copiedFull = false }
}) {
HStack(spacing: 4) {
Image(systemName: copiedFull ? "checkmark" : "rectangle.on.rectangle")
.font(.system(size: 10))
Text(copiedFull ? "\u{0421}\u{043a}\u{043e}\u{043f}\u{0438}\u{0440}\u{043e}\u{0432}\u{0430}\u{043d}\u{043e}!" : "\u{041a}\u{043e}\u{043f}\u{0438}\u{0440}\u{043e}\u{0432}\u{0430}\u{0442}\u{044c} \u{0430}\u{0434}\u{0440}\u{0435}\u{0441}")
.font(.system(size: 11, weight: .medium))
}
.frame(maxWidth: .infinity)
}
.buttonStyle(.bordered)
.tint(copiedFull ? .green : .secondary)
.controlSize(.small)
}
.padding(12)
.background(cardBg)
.cornerRadius(8)
.padding(.horizontal, 16)
}
Spacer()
}
.frame(width: 280, height: walletNumValue > 0 ? 430 : 370)
}
private var walletNumValue: Int {
UserDefaults.standard.integer(forKey: "wallet_number")
}
private func generateQR(from string: String) -> NSImage? {
let filter = CIFilter.qrCodeGenerator()
filter.message = Data(string.utf8)
filter.correctionLevel = "M"
guard let ciImage = filter.outputImage else { return nil }
let scaled = ciImage.transformed(by: CGAffineTransform(scaleX: 10, y: 10))
let rep = NSCIImageRep(ciImage: scaled)
let nsImage = NSImage(size: rep.size)
nsImage.addRepresentation(rep)
return nsImage
}
}