wake-ios/wake/View/Examples/MediaDemo.swift
2025-08-22 18:58:08 +08:00

187 lines
7.8 KiB
Swift
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import SwiftUI
struct MediaUploadDemo: View {
@StateObject private var uploadManager = MediaUploadManager()
@State private var showMediaPicker = false
@State private var showUploadAlert = false
@State private var isUploading = false
var body: some View {
NavigationView {
VStack(spacing: 20) {
//
Button(action: {
showMediaPicker = true
}) {
Label("添加图片或视频", systemImage: "plus.circle.fill")
.font(.headline)
.frame(maxWidth: .infinity)
.padding()
.background(Color.blue)
.foregroundColor(.white)
.cornerRadius(10)
}
.padding(.horizontal)
.sheet(isPresented: $showMediaPicker) {
MediaPicker(
selectedMedia: $uploadManager.selectedMedia,
imageSelectionLimit: 1,
videoSelectionLimit: 0,
allowedMediaTypes: .imagesOnly, // This needs to come before selectionMode
selectionMode: .single, // This was moved after allowedMediaTypes
onDismiss: {
showMediaPicker = false
//
if !uploadManager.selectedMedia.isEmpty {
isUploading = true
uploadManager.startUpload()
}
}
)
}
//
if uploadManager.selectedMedia.isEmpty {
VStack(spacing: 16) {
Image(systemName: "photo.on.rectangle.angled")
.font(.system(size: 60))
.foregroundColor(.gray)
Text("暂无媒体文件")
.font(.headline)
.foregroundColor(.gray)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
} else {
ScrollView {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 120), spacing: 10)], spacing: 10) {
ForEach(0..<uploadManager.selectedMedia.count, id: \.self) { index in
MediaItemView(
media: uploadManager.selectedMedia[index],
status: uploadManager.uploadStatus["\(index)"] ?? .pending
)
.onTapGesture {
//
if case .video = uploadManager.selectedMedia[index] {
//
print("Play video at index \(index)")
}
}
}
}
.padding()
}
}
//
if isUploading {
VStack {
//
if let progress = uploadManager.uploadStatus.values.compactMap({ status -> Double? in
if case .uploading(let progress) = status { return progress }
return nil
}).first {
ProgressView(value: progress, total: 1.0)
.padding(.horizontal)
Text("上传中 \(Int(progress * 100))%")
.font(.subheadline)
.foregroundColor(.gray)
} else {
ProgressView()
.progressViewStyle(CircularProgressViewStyle())
.scaleEffect(1.5)
Text("正在准备上传...")
.font(.subheadline)
.foregroundColor(.gray)
.padding(.top, 8)
}
}
.frame(maxWidth: .infinity)
.padding()
}
}
.alert(isPresented: $showUploadAlert) {
Alert(
title: Text(uploadManager.isAllUploaded ? "上传完成" : "上传状态"),
message: Text(uploadManager.isAllUploaded ?
"所有文件上传完成!" :
"正在处理上传..."),
dismissButton: .default(Text("确定"))
)
}
.onChange(of: uploadManager.uploadStatus) { _ in
//
let allFinished = uploadManager.uploadStatus.values.allSatisfy { status in
if case .completed = status { return true }
if case .failed = status { return true }
return false
}
if allFinished && !uploadManager.uploadStatus.isEmpty {
isUploading = false
showUploadAlert = true
}
}
}
}
}
//
struct MediaItemView: View {
let media: MediaType
let status: MediaUploadStatus
var body: some View {
ZStack(alignment: .bottom) {
//
if let thumbnail = media.thumbnail {
Image(uiImage: thumbnail)
.resizable()
.scaledToFill()
.frame(width: 120, height: 120)
.cornerRadius(8)
.clipped()
//
if media.isVideo {
Image(systemName: "play.circle.fill")
.font(.system(size: 30))
.foregroundColor(.white)
.shadow(radius: 5)
}
//
VStack {
Spacer()
if case .uploading(let progress) = status {
ProgressView(value: progress, total: 1.0)
.progressViewStyle(LinearProgressViewStyle())
.frame(height: 4)
.padding(.horizontal, 4)
} else if case .completed = status {
Image(systemName: "checkmark.circle.fill")
.foregroundColor(.green)
.padding(4)
.background(Circle().fill(Color.white))
} else if case .failed = status {
Image(systemName: "exclamationmark.circle.fill")
.foregroundColor(.red)
.padding(4)
.background(Circle().fill(Color.white))
}
}
.padding(4)
}
}
.frame(width: 120, height: 120)
.overlay(
RoundedRectangle(cornerRadius: 8)
.stroke(Color.gray.opacity(0.3), lineWidth: 1)
)
}
}
//
#Preview {
MediaUploadDemo()
.environmentObject(AuthState.shared)
}