AzureCommunicationUI/sdk/AzureCommunicationUICalling/Sources/Presentation/SwiftUI/ViewComponents/VideoView/LocalVideoView.swift (118 lines of code) (raw):

// // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // import SwiftUI import FluentUI enum LocalVideoViewType { case preview case localVideoPip case localVideofull var cameraSwitchButtonAlignment: Alignment { switch self { case .localVideoPip: return .topTrailing case .localVideofull: return .bottomTrailing case .preview: return .trailing } } var avatarSize: MSFAvatarSize { switch self { case .localVideofull, .preview: return .size72 case .localVideoPip: return .size40 } } var showDisplayNameTitleView: Bool { switch self { case .localVideoPip, .preview: return false case .localVideofull: return true } } var hasGradient: Bool { switch self { case .localVideoPip, .localVideofull: return false case .preview: return true } } } struct LocalVideoView: View { @ObservedObject var viewModel: LocalVideoViewModel let viewManager: VideoViewManager let viewType: LocalVideoViewType let avatarManager: AvatarViewManagerProtocol @Environment(\.screenSizeClass) var screenSizeClass: ScreenSizeClassType @State private var avatarImage: UIImage? @State private var localVideoStreamId: String? var body: some View { Group { GeometryReader { geometry in if viewModel.cameraOperationalStatus == .on, let streamId = localVideoStreamId, let rendererView = viewManager.getLocalVideoRendererView(streamId) { ZStack(alignment: viewType.cameraSwitchButtonAlignment) { VideoRendererView(rendererView: rendererView) .frame(width: geometry.size.width, height: geometry.size.height) if viewType.hasGradient { GradientView() } if !viewModel.isInPip { cameraSwitchButton } } } else { VStack(alignment: .center, spacing: 5) { CompositeAvatar(displayName: $viewModel.displayName, avatarImage: Binding.constant(avatarManager .localParticipantViewData? .avatarImage), isSpeaking: false, avatarSize: viewType.avatarSize) if viewType.showDisplayNameTitleView { Spacer().frame(height: 10) ParticipantTitleView(displayName: $viewModel.displayName, isMuted: $viewModel.isMuted, isHold: .constant(false), titleFont: Fonts.caption1.font, mutedIconSize: 16) } else if screenSizeClass == .iphonePortraitScreenSize { Spacer() .frame(height: 20) } } .frame(width: geometry.size.width, height: geometry.size.height) .accessibilityElement(children: .combine) } } }.onReceive(viewModel.$localVideoStreamId) { viewManager.updateDisplayedLocalVideoStream($0) if localVideoStreamId != $0 { localVideoStreamId = $0 } }.accessibilityIgnoresInvertColors(true) } var cameraSwitchButton: some View { let cameraSwitchButtonPaddingPip: CGFloat = -4 let cameraSwitchButtonPaddingFull: CGFloat = 4 return Group { switch viewType { case .localVideoPip: IconButton(viewModel: viewModel.cameraSwitchButtonPipViewModel) .padding(cameraSwitchButtonPaddingPip) case .localVideofull: IconButton(viewModel: viewModel.cameraSwitchButtonFullViewModel) .padding(cameraSwitchButtonPaddingFull) default: EmptyView() } } } }