Add OperatingArea and PilotCertification modules with live push readiness.

Migrate operating area and pilot certification from home placeholders, extend Live with playback and push readiness flows, and add pilot certificate OSS upload.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-06-25 18:15:59 +08:00
parent fdf4659048
commit 41dda3cc9b
33 changed files with 3455 additions and 37 deletions

View File

@ -5,6 +5,7 @@
// Created by Codex on 2026/6/25.
//
import AVKit
import PhotosUI
import SwiftUI
import UniformTypeIdentifiers
@ -459,13 +460,17 @@ struct LiveAlbumPreviewView: View {
private struct LiveAlbumPreviewPage: View {
let file: LiveAlbumFileItem
@Environment(ToastCenter.self) private var toastCenter
@State private var playbackViewModel: LivePlaybackViewModel
init(file: LiveAlbumFileItem) {
self.file = file
_playbackViewModel = State(initialValue: LivePlaybackViewModel(urlString: file.url))
}
var body: some View {
VStack(spacing: AppMetrics.Spacing.medium) {
if file.isVideo && file.coverImg?.liveTrimmed.isEmpty != false {
Image(systemName: "play.circle.fill")
.font(.system(size: 72, weight: .semibold))
.foregroundStyle(.white)
if file.isVideo {
videoContent
} else {
RemoteImage(urlString: file.previewURL, contentMode: .fit) {
ProgressView()
@ -487,6 +492,33 @@ private struct LiveAlbumPreviewPage: View {
.frame(maxWidth: .infinity, maxHeight: .infinity)
.padding(AppMetrics.Spacing.medium)
.background(Color.black)
.onDisappear {
playbackViewModel.release()
}
}
@ViewBuilder
private var videoContent: some View {
if let player = playbackViewModel.player, playbackViewModel.playableURL != nil {
VideoPlayer(player: player)
.aspectRatio(16.0 / 9.0, contentMode: .fit)
.frame(maxWidth: .infinity)
.clipShape(RoundedRectangle(cornerRadius: AppMetrics.CornerRadius.card))
} else if file.coverImg?.liveTrimmed.isEmpty == false {
RemoteImage(urlString: file.previewURL, contentMode: .fit) {
ProgressView()
.tint(.white)
}
} else {
VStack(spacing: AppMetrics.Spacing.small) {
Image(systemName: "play.slash.fill")
.font(.system(size: 62, weight: .semibold))
.foregroundStyle(.white)
Text("当前视频地址暂不可播放")
.font(.system(size: AppMetrics.FontSize.subheadline, weight: .semibold))
.foregroundStyle(.white)
}
}
}
}