//
|
// LiveActivity.swift
|
// LiveProject
|
//
|
// Created by 倪路朋 on 6/25/25.
|
//
|
|
import UIKit
|
import AVFoundation
|
import SwiftUI
|
import MetalKit
|
|
struct LiveActivity: View {
|
|
@State private var showDeviceDialog = false
|
@State private var showInputDialog = false
|
|
@State private var streamRate = Float(9/16.0);
|
@State private var fpsState = 30;
|
@State private var mainSize: CGSize = .init(width: 100, height: 100)
|
|
@State private var displaySize : CGSize = .zero;
|
|
@State private var devices = [DeviceInfo(name: "相机", type: .CAMERA, deviceId: UUID().uuidString,icon: Icons.CAMERA),
|
DeviceInfo(name: "话筒", type: .MICROPHONE,deviceId: UUID().uuidString,icon: Icons.MIC),
|
DeviceInfo(name: "系统", type: .SYSTEM,deviceId : UUID().uuidString,icon: Icons.PORTRAIT)]
|
|
|
@StateObject private var mViewModel = LiveViewModel()
|
|
var body: some View {
|
ZStack{
|
Color.clear
|
.ignoresSafeArea() // 填满全屏
|
VStack{
|
VideoRendererView(pixelBuffer: $mViewModel.pixelBuffer).background(Color.black).frame(width: mainSize.width,height:mainSize.height)
|
Spacer()
|
}.border(Color.blue)
|
VStack{
|
Spacer()
|
BottomBtns().frame(alignment: .bottom).border(Color.green)
|
}
|
if showInputDialog{
|
DialogInput()
|
}
|
}.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
|
.background(
|
GeometryReader { geometry in
|
Color.clear
|
.onAppear {
|
displaySize = geometry.size;
|
updateWindowSize()
|
print("displaySize:\(displaySize)")
|
}
|
.onChange(of: geometry.size) { newSize in
|
displaySize = newSize;
|
updateWindowSize()
|
print("displaySize:\(displaySize)")
|
}
|
})
|
.border(Color.red)
|
.onDisappear {
|
print("onDisappear 视图消失了!")
|
|
}.onAppear {
|
print("onAppear 视图出现了!")
|
}
|
}
|
|
func updateWindowSize(){
|
var rate : Float = Float(displaySize.width)/Float(displaySize.height);
|
if(rate != streamRate) {
|
var mainWidth = 0.0;
|
var mainHeight = 0.0;
|
if(rate < streamRate){
|
mainWidth = displaySize.width;
|
if(9.0/16 == streamRate){
|
mainHeight = (mainWidth / 9.0 * 16);
|
}else{
|
mainHeight = (mainWidth / 16.0 * 9);
|
}
|
}else{
|
mainHeight = displaySize.height;
|
if(9.0 / 16 == streamRate){
|
mainWidth = (mainHeight / 16.0 * 9);
|
}else{
|
mainWidth = (mainHeight / 9.0 * 16);
|
}
|
}
|
if(mainSize.width != CGFloat(mainWidth) || mainSize.height != CGFloat(mainHeight)){
|
mainSize = .init(width: mainWidth, height: mainHeight);
|
}
|
}else{
|
if(mainSize.width != displaySize.width || mainSize.height != displaySize.height){
|
mainSize = .init(width: displaySize.width, height: displaySize.height);
|
}
|
}
|
print("updateWindow:\(mainSize)")
|
}
|
|
func DialogInput(onCancel:() ->Void = {},onConfirm:() -> Void = {}) -> some View{
|
ZStack{
|
Color.black.opacity(0.4)
|
.edgesIgnoringSafeArea(.all)
|
.onTapGesture {
|
withAnimation {
|
showInputDialog = false
|
}
|
}
|
VStack {
|
VStack(alignment: .leading, spacing: 40) {
|
Text("请输入直播地址")
|
.font(Font.system(size: 20))
|
LTextField().environmentObject(LText())
|
HStack{
|
Spacer()
|
Button(action:{
|
showInputDialog.toggle();
|
}){
|
Text("取消")
|
.font(Font.system(size: 20))
|
.foregroundColor(Color.gray)
|
}
|
|
Spacer().frame(width: 30)
|
Button(action:{
|
showInputDialog.toggle();
|
}){
|
Text("确认")
|
.font(Font.system(size: 20))
|
.foregroundColor(Color.colorTextLink)
|
}
|
|
}
|
}
|
.padding(30)
|
.background(Color.white)
|
.cornerRadius(20)
|
.transition(.move(edge: .bottom))
|
}
|
.padding(60)
|
.zIndex(1)
|
.animation(.default, value: devices)
|
}
|
}
|
|
func DialogDevices() -> some View{
|
VStack{
|
VStack(spacing: 20) {
|
Spacer().frame(height:20)
|
FlowLayout(){
|
|
ForEach(devices, id: \.self) { device in
|
MButton(icon: device.icon,text: device.name){
|
mViewModel.newWindowAction(device: device){ status in
|
withAnimation{
|
showDeviceDialog = false;
|
}
|
}
|
print("\(device.name) click")
|
}
|
}
|
}
|
}
|
.frame(maxWidth: .infinity,alignment:.leading)
|
.padding()
|
}
|
.frame(maxHeight: .infinity,alignment:.topLeading)
|
}
|
|
func BottomBtns() -> some View{
|
VStack{
|
|
HStack(){
|
//横竖屏控制
|
MButton(icon:streamRate == (9/16.0) ? Icons.PORTRAIT : Icons.LANDSCAPE ){
|
streamRate = streamRate == (9/16.0) ? (16/9.0) : (9/16.0)
|
updateWindowSize()
|
}
|
// fps 控制
|
MButton(text: "\(fpsState)帧"){
|
fpsState = fpsState == 30 ? 60 : 30;
|
}
|
//添加推流地址
|
MButton(valid: .INVALID,text: "+"){
|
|
}
|
}
|
HStack{
|
LButton(text: "设备"){
|
print("Click 设备 button")
|
showDeviceDialog.toggle()
|
}.sheet(isPresented:$showDeviceDialog, content: {
|
VStack {
|
ScrollView {
|
DialogDevices()
|
}
|
}
|
.presentationDetents([.height(200),.medium])
|
})
|
LButton(text: "RTMP"){
|
print("Click RTMP button")
|
withAnimation{
|
showInputDialog.toggle()
|
}
|
}
|
/*flLButton(text: "文件"){
|
|
}*/
|
LButton(text: "文本"){
|
print("Click 文本 button")
|
withAnimation{
|
showInputDialog.toggle()
|
}
|
}
|
}
|
HStack{
|
Text("编码正常").font(Font.system(size: 14)).foregroundColor(Color.init("ColorGreen"))
|
Text("推流正常").font(Font.system(size: 14)).foregroundColor(Color.init("ColorGreen"))
|
Text("内存正常").font(Font.system(size: 14)).foregroundColor(Color.init("ColorGreen"))
|
}
|
}
|
}
|
}
|
|
|
struct LiveActivity_BottomBtns_Previews: PreviewProvider{
|
static var previews: some View {
|
LiveActivity();
|
}
|
|
}
|