ce55be4a-fb5f-4981-b507-0f4.../Sources/ui/ExpandedView.swift

136 lines
5.0 KiB
Swift
Raw Permalink Normal View History

//
// 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)
}
}