Runt
2025-06-27 e21b1c797955a231f2bcf71818e0259fbb6aeba1
LiveProject/activity/stream/LiveActivity.swift
@@ -5,44 +5,167 @@
//  Created by 倪路朋 on 6/25/25.
//
import Foundation
import UIKit
import AVFoundation
import SwiftUI
import MetalKit
struct LiveActivity: View {
    @State private var pixelBuffer: CVPixelBuffer?
    @State private var showDeviceDialog = 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: IconCamera()),
                                  DeviceInfo(name: "话筒", type: .MICROPHONE,deviceId: UUID().uuidString,icon: IconMic()),
                                  DeviceInfo(name: "系统", type: .SYSTEM,deviceId : UUID().uuidString,icon: IconPortrait())]
    private let mViewModel = LiveViewModel()
    var body: some View {
        NavigationView{
            ZStack{
        ZStack{
            Color.clear
                .ignoresSafeArea() // 填满全屏
            VStack{
                VideoRendererView(renderer:mViewModel.renderer).background(Color.black).frame(width: mainSize.width,height:mainSize.height)
                Spacer()
            }.border(Color.blue)
            VStack{
                Spacer()
                BottomBtns().frame(alignment: .bottom).border(Color.green)
            }
            if showDeviceDialog {
                DialogDevices()
            }
        }.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)")
    }
}
struct Bottombtns:View {
    var body: some View {
    func DialogDevices() -> some View{
        ZStack{
            Color.black.opacity(0.4)
                .edgesIgnoringSafeArea(.all)
                .onTapGesture {
                    withAnimation {
                        showDeviceDialog = false
                    }
                }
            VStack {
                Spacer()
                VStack(spacing: 20) {
                    Spacer().frame(height:40)
                    FlowLayout(devices){ device in
                        MButton(icon: device.icon,text: device.name){
                            mViewModel.newWindowAction(device: device){ status in
                                withAnimation{
                                    showDeviceDialog = false;
                                }
                            }
                            print("\(device.name) click")
                        }
                    }
                    .padding()
                }
                .frame(maxWidth: .infinity)
                .padding()
                .background(Color.white)
                .cornerRadius(20)
                .transition(.move(edge: .bottom))
            }
            .zIndex(1)
            .animation(.default, value: devices)
        }
    }
    func BottomBtns() -> some View{
        VStack{
            HStack(){
                MButton(icon: IconPortrait()){
                //横竖屏控制
                MButton(icon:streamRate == (9/16.0) ? IconPortrait() : IconLandscape() ){
                    streamRate = streamRate == (9/16.0) ? (16/9.0) : (9/16.0)
                    updateWindowSize()
                }
                MButton(text: "30帧"){
                // fps 控制
                MButton(text: "\(fpsState)帧"){
                    fpsState = fpsState == 30 ? 60 : 30;
                }
                //添加推流地址
                MButton(valid: .INVALID,text: "+"){
                    
                }
            }
            HStack{
                LButton(text: "设备"){
                    print("Click 设备 button")
                    withAnimation{
                        showDeviceDialog.toggle()
                    }
                }
                LButton(text: "RTMP"){
                    
                }
                LButton(text: "文件"){
                /*flLButton(text: "文件"){
                    
                }
                }*/
                LButton(text: "文本"){
                    
                }
@@ -56,9 +179,10 @@
    }
}
struct LiveActivity_Previews: PreviewProvider{
struct LiveActivity_BottomBtns_Previews: PreviewProvider{
    static var previews: some View {
        Bottombtns();
        LiveActivity();
    }
    
}