AzureCommunicationUI/sdk/AzureCommunicationUICalling/Sources/Presentation/SwiftUI/Setup/SetupView.swift (151 lines of code) (raw):

// // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. // import SwiftUI import Combine import FluentUI struct SetupView: View { @ObservedObject var viewModel: SetupViewModel let viewManager: VideoViewManager @Environment(\.horizontalSizeClass) var widthSizeClass: UserInterfaceSizeClass? @Environment(\.verticalSizeClass) var heightSizeClass: UserInterfaceSizeClass? @Orientation var orientation: UIDeviceOrientation let avatarManager: AvatarViewManagerProtocol enum LayoutConstant { static let spacing: CGFloat = 24 static let spacingLarge: CGFloat = 40 static let startCallButtonHeight: CGFloat = 52 static let iPadLarge: CGFloat = 469.0 static let iPadSmall: CGFloat = 375.0 static let iPadSmallHeightWithMargin: CGFloat = iPadSmall + spacingLarge + startCallButtonHeight static let iPadLargeHeightWithMargin: CGFloat = iPadLarge + spacingLarge + startCallButtonHeight } var body: some View { ZStack { VStack(spacing: LayoutConstant.spacing) { SetupTitleView(viewModel: viewModel) GeometryReader { geometry in ZStack(alignment: .bottomLeading) { VStack(alignment: .center, spacing: getSizeClass() == .ipadScreenSize ? LayoutConstant.spacingLarge : LayoutConstant.spacing) { ZStack(alignment: .center) { PreviewAreaView(viewModel: viewModel.previewAreaViewModel, viewManager: viewManager, avatarManager: avatarManager) if viewModel.shouldShowSetupControlBarView() { SetupControlBarView(viewModel: viewModel.setupControlBarViewModel) } } .background(Color(StyleProvider.color.surface)) .cornerRadius(4) .accessibilityElement(children: .contain) joinCallView .padding(.bottom) } .padding(.vertical, setupViewVerticalPadding(parentSize: geometry.size)) errorInfoView .padding(.bottom, setupViewVerticalPadding(parentSize: geometry.size)) } .padding(.horizontal, setupViewHorizontalPadding(parentSize: geometry.size)) } } BottomDrawer(isPresented: viewModel.audioDeviceListViewModel.isDisplayed, hideDrawer: viewModel.dismissAudioDevicesDrawer) { AudioDevicesListView(viewModel: viewModel.audioDeviceListViewModel, avatarManager: avatarManager) } } } var joinCallView: some View { Group { if viewModel.isJoinRequested { JoiningCallActivityView(viewModel: viewModel.joiningCallActivityViewModel) } else { PrimaryButton(viewModel: viewModel.joinCallButtonViewModel) .frame(height: 52) .accessibilityIdentifier(AccessibilityIdentifier.joinCallAccessibilityID.rawValue) } } } var errorInfoView: some View { VStack { Spacer() ErrorInfoView(viewModel: viewModel.errorInfoViewModel) .padding(EdgeInsets(top: 0, leading: 0, bottom: LayoutConstant.startCallButtonHeight + LayoutConstant.spacing, trailing: 0) ) .accessibilityElement(children: .contain) .accessibilityAddTraits(.isModal) } } private func setupViewHorizontalPadding(parentSize: CGSize) -> CGFloat { let isIpad = getSizeClass() == .ipadScreenSize guard isIpad else { return 16 } let isLandscape = orientation.isLandscape let screenSize = isLandscape ? LayoutConstant.iPadLarge : LayoutConstant.iPadSmall let horizontalPadding = (parentSize.width - screenSize) / 2.0 return horizontalPadding } private func setupViewVerticalPadding(parentSize: CGSize) -> CGFloat { let isIpad = getSizeClass() == .ipadScreenSize guard isIpad else { return 16 } let isLandscape = orientation.isLandscape let verticalPadding = (parentSize.height - (isLandscape ? LayoutConstant.iPadSmallHeightWithMargin : LayoutConstant.iPadLargeHeightWithMargin)) / 2.0 return verticalPadding } private func getSizeClass() -> ScreenSizeClassType { switch (widthSizeClass, heightSizeClass) { case (.compact, .regular): return .iphonePortraitScreenSize case (.compact, .compact), (.regular, .compact): return .iphoneLandscapeScreenSize default: return .ipadScreenSize } } } struct SetupTitleView: View { let viewHeight: CGFloat = 44 let padding: CGFloat = 34.0 let verticalSpacing: CGFloat = 0 var viewModel: SetupViewModel @Environment(\.sizeCategory) var sizeCategory: ContentSizeCategory var body: some View { VStack(spacing: verticalSpacing) { ZStack(alignment: .leading) { IconButton(viewModel: viewModel.dismissButtonViewModel) .flipsForRightToLeftLayoutDirection(true) .accessibilityIdentifier(AccessibilityIdentifier.dismissButtonAccessibilityID.rawValue) HStack { Spacer() VStack { Text(viewModel.title) .font(Fonts.headline.font) .foregroundColor(Color(StyleProvider.color.onBackground)) .lineLimit(1) .minimumScaleFactor(sizeCategory.isAccessibilityCategory ? 0.4 : 1) .accessibilityAddTraits(.isHeader) if let subtitle = viewModel.subTitle, !subtitle.isEmpty { Text(subtitle) .font(Fonts.caption1.font) .foregroundColor(Color(StyleProvider.color.onNavigationSecondary)) .lineLimit(1) .minimumScaleFactor(sizeCategory.isAccessibilityCategory ? 0.4 : 1) .accessibilityAddTraits(.isHeader) } } Spacer() }.accessibilitySortPriority(1) .padding(padding) }.frame(height: viewHeight) Divider() } } }