// // ExpandedView.swift // MioIsland AirDrop Plugin // // Main panel rendered when the user opens the AirDrop plugin in // Mio Island. Card-in-container layout: top transparent strip for // the notch + floating back chip, themed card below with the drop // zone + "choose files" button. // import AppKit import SwiftUI struct ExpandedView: View { @ObservedObject private var state: AirDropState = .shared private static let ink = Color.white private static let base = Color(red: 0x0A / 255.0, green: 0x0A / 255.0, blue: 0x0A / 255.0) // MARK: - Body var body: some View { Group { if HostVersionCheck.isOK() { playingCard } else { hostUpgradeCard } } .animation(.easeInOut(duration: 0.2), value: state.phase) } // MARK: - Main panel (when host version OK) private var playingCard: some View { // Layout (panel 440×280): // 40 top transparent (notch + back chevron area) // 20 margin // 180 card (14 pad + ~135 content + 14 pad) // 20 margin // = 260pt used, 20pt buffer for SwiftUI rounding. VStack(spacing: 0) { Color.clear.frame(height: 40) // notch strip Color.clear.frame(height: 20) // margin top cardContent .padding(EdgeInsets(top: 14, leading: 16, bottom: 14, trailing: 16)) .frame(maxWidth: .infinity, maxHeight: .infinity) .background( RoundedRectangle(cornerRadius: 14, style: .continuous) .fill(Self.base.opacity(0.88)) ) .overlay( RoundedRectangle(cornerRadius: 14, style: .continuous) .strokeBorder(Color.white.opacity(0.12), lineWidth: 0.5) ) .clipShape(RoundedRectangle(cornerRadius: 14, style: .continuous)) Color.clear.frame(height: 20) // margin bottom } .padding(.horizontal, 16) } private var cardContent: some View { VStack(spacing: 10) { // Header row — just the title. The whole DropZoneView // below is the tap target now; no redundant chip button. HStack(alignment: .center, spacing: 6) { Image(systemName: "airplayaudio") .font(.system(size: 13, weight: .semibold)) .foregroundColor(Self.ink.opacity(0.9)) Text(L10n.title) .font(.system(size: 14, weight: .semibold)) .foregroundColor(Self.ink.opacity(0.95)) Spacer() } // Big tap target for the whole card body. DropZoneView() } } // MARK: - Host upgrade card private var hostUpgradeCard: some View { VStack(spacing: 0) { Color.clear.frame(height: 40) Color.clear.frame(height: 20) VStack(spacing: 12) { HStack(spacing: 14) { Image(systemName: "exclamationmark.triangle.fill") .font(.system(size: 24, weight: .regular)) .foregroundColor(.orange) .frame(width: 48, height: 48) .background( RoundedRectangle(cornerRadius: 10, style: .continuous) .fill(Color.orange.opacity(0.12)) ) VStack(alignment: .leading, spacing: 4) { Text(L10n.hostUpgradeTitle) .font(.system(size: 14, weight: .semibold)) .foregroundColor(Self.ink.opacity(0.9)) Text(L10n.hostUpgradeHint) .font(.system(size: 11)) .foregroundColor(Self.ink.opacity(0.55)) .lineLimit(2) .fixedSize(horizontal: false, vertical: true) } .frame(maxWidth: .infinity, alignment: .leading) } Text("Host: v\(HostVersionCheck.hostVersion()) · required: v\(HostVersionCheck.minHost)+") .font(.system(size: 10, design: .monospaced)) .foregroundColor(Self.ink.opacity(0.4)) .frame(maxWidth: .infinity, alignment: .leading) } .padding(EdgeInsets(top: 18, leading: 16, bottom: 18, trailing: 16)) .frame(maxWidth: .infinity, maxHeight: .infinity) .background( RoundedRectangle(cornerRadius: 14, style: .continuous) .fill(Self.base.opacity(0.88)) ) .overlay( RoundedRectangle(cornerRadius: 14, style: .continuous) .strokeBorder(Color.white.opacity(0.12), lineWidth: 0.5) ) .clipShape(RoundedRectangle(cornerRadius: 14, style: .continuous)) Color.clear.frame(height: 20) } .padding(.horizontal, 16) } }