feat: fullscreen video + click icon to toggle control toolbar
- Video fills entire window via VideoPlayerRepresentable - MiniPlayerIcon in top-left corner toggles ControlToolbar visibility - ControlToolbar slides up from bottom with animation - Removed Bricks JSON UI dependency for main view - All toolbar features preserved: open/prev/play/next/volume/tracks/repeat/fullscreen/playlist
This commit is contained in:
parent
e7bca7269e
commit
20f4dec0b9
@ -129,23 +129,37 @@ struct MiniPlayerApp: App {
|
|||||||
struct BricksAppView: View {
|
struct BricksAppView: View {
|
||||||
@ObservedObject var bridge: PlayerBridge
|
@ObservedObject var bridge: PlayerBridge
|
||||||
@ObservedObject var engine: BricksEngine
|
@ObservedObject var engine: BricksEngine
|
||||||
@State private var jsonString: String?
|
@State private var showToolbar = false
|
||||||
|
@State private var isHoveringIcon = false
|
||||||
|
|
||||||
var body: some View {
|
var body: some View {
|
||||||
ZStack(alignment: .topLeading) {
|
ZStack(alignment: .topLeading) {
|
||||||
if let json = jsonString {
|
// 视频占满全屏
|
||||||
BricksView(json: json, engine: engine)
|
VideoPlayerRepresentable(player: bridge.player)
|
||||||
} else {
|
.ignoresSafeArea()
|
||||||
ProgressView("Loading UI...")
|
|
||||||
.task {
|
|
||||||
jsonString = loadJSONString()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 左上角应用图标
|
// 左上角应用图标 — 点击切换控制栏
|
||||||
MiniPlayerIcon()
|
MiniPlayerIcon()
|
||||||
.frame(width: 32, height: 32)
|
.frame(width: 32, height: 32)
|
||||||
.padding(12)
|
.padding(12)
|
||||||
|
.opacity(isHoveringIcon ? 1.0 : 0.6)
|
||||||
|
.onHover { isHoveringIcon = $0 }
|
||||||
|
.onTapGesture {
|
||||||
|
withAnimation(.easeInOut(duration: 0.25)) {
|
||||||
|
showToolbar.toggle()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 底部控制栏 — 点击图标显示/隐藏
|
||||||
|
VStack {
|
||||||
|
Spacer()
|
||||||
|
if showToolbar {
|
||||||
|
ControlToolbar(bridge: bridge, isHovering: .constant(false)) {
|
||||||
|
// onTouch: 保持显示
|
||||||
|
}
|
||||||
|
.transition(.move(edge: .bottom).combined(with: .opacity))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.sheet(isPresented: $bridge.showURLDialog) {
|
.sheet(isPresented: $bridge.showURLDialog) {
|
||||||
URLInputDialog(bridge: bridge)
|
URLInputDialog(bridge: bridge)
|
||||||
@ -157,20 +171,6 @@ struct BricksAppView: View {
|
|||||||
PlaylistWindowView(bridge: bridge)
|
PlaylistWindowView(bridge: bridge)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func loadJSONString() -> String {
|
|
||||||
// 从 Resources 加载 miniplayer.ui
|
|
||||||
if let url = Bundle.module.url(forResource: "miniplayer", withExtension: "ui"),
|
|
||||||
let data = try? Data(contentsOf: url),
|
|
||||||
let str = String(data: data, encoding: .utf8) {
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fallback: 最小化 schema
|
|
||||||
return """
|
|
||||||
{"widgettype":"VBox","options":{"width":"100%","height":"100%"},"subwidgets":[{"widgettype":"Text","options":{"text":"Failed to load UI schema"}}]}
|
|
||||||
"""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user