139 lines
4.6 KiB
Swift
139 lines
4.6 KiB
Swift
import SwiftUI
|
|
import SwiftBricks
|
|
|
|
@main
|
|
struct MiniPlayerApp: App {
|
|
@StateObject private var bridge = PlayerBridge()
|
|
|
|
var body: some Scene {
|
|
WindowGroup {
|
|
ContentView(bridge: bridge)
|
|
.frame(minWidth: 900, minHeight: 600)
|
|
.onAppear { bridge.setup() }
|
|
}
|
|
#if os(macOS)
|
|
.commands {
|
|
CommandGroup(replacing: .newItem) {}
|
|
CommandMenu("播放") {
|
|
Button("播放/暂停") { bridge.togglePlayPause() }
|
|
.keyboardShortcut(" ", modifiers: [])
|
|
Divider()
|
|
Button("上一首") { bridge.playPrev() }
|
|
.keyboardShortcut("[", modifiers: [])
|
|
Button("下一首") { bridge.playNext() }
|
|
.keyboardShortcut("]", modifiers: [])
|
|
Divider()
|
|
Button("全屏") { bridge.toggleFullscreen() }
|
|
.keyboardShortcut("f", modifiers: .command)
|
|
Divider()
|
|
Button("循环模式") { bridge.cycleRepeatMode() }
|
|
.keyboardShortcut("r", modifiers: .command)
|
|
}
|
|
CommandMenu("文件") {
|
|
Button("打开文件...") { bridge.openFileDialog() }
|
|
.keyboardShortcut("o", modifiers: .command)
|
|
Divider()
|
|
Button("添加URL...") { bridge.showURLDialog = true }
|
|
.keyboardShortcut("u", modifiers: .command)
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/// 主内容视图 — 加载BricksJSON + 注册自定义widget
|
|
struct ContentView: View {
|
|
@ObservedObject var bridge: PlayerBridge
|
|
|
|
var body: some View {
|
|
Group {
|
|
if let engine = bridge.engine, let schema = bridge.schema {
|
|
BricksView(schema: schema, engine: engine)
|
|
.overlay(alignment: .top) {
|
|
if let error = bridge.toastMessage {
|
|
Text(error)
|
|
.padding(8)
|
|
.background(.black.opacity(0.7))
|
|
.foregroundColor(.white)
|
|
.cornerRadius(6)
|
|
.padding(.top, 8)
|
|
.transition(.opacity)
|
|
}
|
|
}
|
|
.sheet(isPresented: $bridge.showURLDialog) {
|
|
URLInputDialog(bridge: bridge)
|
|
}
|
|
#if os(macOS)
|
|
.sheet(isPresented: $bridge.showTrackDialog) {
|
|
TrackSelectDialog(bridge: bridge)
|
|
}
|
|
#endif
|
|
} else {
|
|
ProgressView("初始化...")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/// URL输入弹窗
|
|
struct URLInputDialog: View {
|
|
@ObservedObject var bridge: PlayerBridge
|
|
@State private var url = ""
|
|
@Environment(\.dismiss) private var dismiss
|
|
|
|
var body: some View {
|
|
VStack(spacing: 16) {
|
|
Text("添加媒体URL").font(.headline)
|
|
TextField("https://example.com/video.m3u8", text: $url)
|
|
.textFieldStyle(.roundedBorder)
|
|
HStack {
|
|
Button("取消") { dismiss() }
|
|
Spacer()
|
|
Button("添加") {
|
|
if !url.isEmpty {
|
|
bridge.addURL(url)
|
|
dismiss()
|
|
}
|
|
}
|
|
.keyboardShortcut(.defaultAction)
|
|
.disabled(url.isEmpty)
|
|
}
|
|
}
|
|
.padding(20)
|
|
.frame(width: 400)
|
|
}
|
|
}
|
|
|
|
/// 音轨选择弹窗
|
|
struct TrackSelectDialog: View {
|
|
@ObservedObject var bridge: PlayerBridge
|
|
@Environment(\.dismiss) private var dismiss
|
|
|
|
var body: some View {
|
|
VStack(spacing: 12) {
|
|
Text("选择音轨").font(.headline)
|
|
ForEach(Array(bridge.availableTracks.enumerated()), id: \.offset) { idx, track in
|
|
Button(action: {
|
|
bridge.selectTrack(index: idx)
|
|
dismiss()
|
|
}) {
|
|
HStack {
|
|
Text("Track \(idx + 1)")
|
|
Spacer()
|
|
if idx == bridge.currentTrackIndex {
|
|
Text("✓").foregroundColor(.green)
|
|
}
|
|
}
|
|
.padding(8)
|
|
.contentShape(Rectangle())
|
|
}
|
|
.buttonStyle(.plain)
|
|
}
|
|
Divider()
|
|
Button("关闭") { dismiss() }
|
|
}
|
|
.padding(20)
|
|
.frame(minWidth: 250)
|
|
}
|
|
}
|