-
Notifications
You must be signed in to change notification settings - Fork 21
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[UI/UX]Fix discrepancies between Screensharing/Spotlight
Pull Request: #209 # Conflicts: # StreamVideo.xcodeproj/project.pbxproj
- Loading branch information
1 parent
22c5425
commit 2fabfdd
Showing
22 changed files
with
451 additions
and
134 deletions.
There are no files selected for viewing
114 changes: 114 additions & 0 deletions
114
...s/StreamVideoSwiftUI/CallView/LayoutComponents/BottomParticipantsBarLayoutComponent.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
// | ||
// Copyright © 2023 Stream.io Inc. All rights reserved. | ||
// | ||
|
||
import StreamVideo | ||
import SwiftUI | ||
|
||
/// `BottomParticipantsBarLayoutComponent` represents a horizontally scrollable view of participant thumbnails. | ||
/// This component lays out participant thumbnails in a bar at the bottom of the associated view. | ||
public struct BottomParticipantsBarLayoutComponent<Factory: ViewFactory>: View { | ||
|
||
// MARK: - Properties | ||
|
||
/// Factory for creating views. | ||
public var viewFactory: Factory | ||
|
||
/// List of participants to display. | ||
public var participants: [CallParticipant] | ||
|
||
/// Frame in which the component will be laid out. | ||
public var frame: CGRect | ||
|
||
/// Information about the call (if available). | ||
public var call: Call? | ||
|
||
/// Size of each participant thumbnail. | ||
public var thumbnailSize: CGFloat | ||
|
||
/// Flag to determine if all participant information should be shown. | ||
public var showAllInfo: Bool | ||
|
||
/// Closure called to change visibility of a participant's track. | ||
public var onChangeTrackVisibility: @MainActor(CallParticipant, Bool) -> Void | ||
|
||
// Private computed properties for laying out the view. | ||
private let barFrame: CGRect | ||
private let itemFrame: CGRect | ||
|
||
// MARK: - Initialization | ||
|
||
/// Creates a new instance of `BottomParticipantsBarLayoutComponent`. | ||
public init( | ||
viewFactory: Factory, | ||
participants: [CallParticipant], | ||
frame: CGRect, | ||
call: Call?, | ||
thumbnailSize: CGFloat = 120, | ||
showAllInfo: Bool = false, | ||
onChangeTrackVisibility: @escaping (CallParticipant, Bool) -> Void | ||
) { | ||
self.viewFactory = viewFactory | ||
self.participants = participants | ||
self.frame = frame | ||
self.call = call | ||
self.thumbnailSize = thumbnailSize | ||
self.showAllInfo = showAllInfo | ||
self.onChangeTrackVisibility = onChangeTrackVisibility | ||
|
||
// Calculate the frame for the bar at the bottom. | ||
self.barFrame = .init( | ||
origin: .init(x: frame.origin.x, y: frame.maxY - thumbnailSize), | ||
size: CGSize(width: frame.size.width, height: thumbnailSize) | ||
) | ||
|
||
// Calculate the frame for each item in the bar. | ||
self.itemFrame = .init( | ||
origin: .zero, | ||
size: .init( | ||
width: barFrame.height, | ||
height: barFrame.height | ||
) | ||
) | ||
} | ||
|
||
// MARK: - View Body | ||
|
||
/// Defines the structure and layout of the view. | ||
public var body: some View { | ||
// Scroll view to accommodate multiple participant thumbnails. | ||
ScrollView(.horizontal) { | ||
// Container for horizontal alignment. | ||
HorizontalContainer { | ||
// Loop through each participant and display their thumbnail. | ||
ForEach(participants) { participant in | ||
viewFactory.makeVideoParticipantView( | ||
participant: participant, | ||
id: participant.id, | ||
availableFrame: itemFrame, | ||
contentMode: .scaleAspectFill, | ||
customData: [:], | ||
call: call | ||
) | ||
.modifier( | ||
viewFactory.makeVideoCallParticipantModifier( | ||
participant: participant, | ||
call: call, | ||
availableFrame: itemFrame, | ||
ratio: itemFrame.width / itemFrame.height, | ||
showAllInfo: showAllInfo | ||
) | ||
) | ||
// Observe visibility changes. | ||
.visibilityObservation(in: barFrame) { onChangeTrackVisibility(participant, $0) } | ||
.cornerRadius(8) | ||
.accessibility(identifier: "bottomParticipantsBarParticipipant") | ||
} | ||
} | ||
.frame(height: barFrame.height) | ||
.cornerRadius(8) | ||
} | ||
.padding() | ||
.accessibility(identifier: "bottomParticipantsBar") | ||
} | ||
} |
84 changes: 84 additions & 0 deletions
84
Sources/StreamVideoSwiftUI/CallView/LayoutComponents/DominantSpeakerLayoutComponent.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
// | ||
// Copyright © 2023 Stream.io Inc. All rights reserved. | ||
// | ||
|
||
import StreamVideo | ||
import SwiftUI | ||
|
||
/// `DominantSpeakerLayoutComponent` represents a view for the dominant speaker's thumbnail. | ||
public struct DominantSpeakerLayoutComponent<Factory: ViewFactory>: View { | ||
|
||
// MARK: - Properties | ||
|
||
/// Factory for creating views. | ||
public var viewFactory: Factory | ||
|
||
/// The dominant speaker participant whose thumbnail will be displayed. | ||
public var participant: CallParticipant | ||
|
||
/// Suffix for constructing the view ID. | ||
public var viewIdSuffix: String | ||
|
||
/// Information about the call (if available). | ||
public var call: Call? | ||
|
||
/// Frame in which the dominant speaker's thumbnail will be displayed. | ||
public var availableFrame: CGRect | ||
|
||
/// Closure called to change visibility of the dominant speaker's track. | ||
public var onChangeTrackVisibility: (CallParticipant, Bool) -> Void | ||
|
||
/// Computed property to generate a unique view ID for the dominant speaker. | ||
var viewId: String { participant.id + (!viewIdSuffix.isEmpty ? "-\(viewIdSuffix)" : "") } | ||
|
||
// MARK: - Initialization | ||
|
||
/// Creates a new instance of `DominantSpeakerLayoutComponent`. | ||
public init( | ||
viewFactory: Factory, | ||
participant: CallParticipant, | ||
viewIdSuffix: String, | ||
call: Call?, | ||
availableFrame: CGRect, | ||
onChangeTrackVisibility: @escaping (CallParticipant, Bool) -> Void | ||
) { | ||
self.viewFactory = viewFactory | ||
self.participant = participant | ||
self.viewIdSuffix = viewIdSuffix | ||
self.call = call | ||
self.availableFrame = availableFrame | ||
self.onChangeTrackVisibility = onChangeTrackVisibility | ||
} | ||
|
||
// MARK: - View Body | ||
|
||
/// Defines the structure and layout of the view. | ||
public var body: some View { | ||
// Creates the video view for the dominant speaker. | ||
viewFactory.makeVideoParticipantView( | ||
participant: participant, | ||
id: viewId, | ||
availableFrame: availableFrame, | ||
contentMode: .scaleAspectFill, | ||
customData: [:], | ||
call: call | ||
) | ||
// Modifies the video view based on the participant's details and the call's state. | ||
.modifier( | ||
viewFactory.makeVideoCallParticipantModifier( | ||
participant: participant, | ||
call: call, | ||
availableFrame: availableFrame, | ||
ratio: availableFrame.width / availableFrame.height, | ||
showAllInfo: true | ||
) | ||
) | ||
// Applies changes to the participant's video track. | ||
.modifier(ParticipantChangeModifier( | ||
participant: participant, | ||
onChangeTrackVisibility: onChangeTrackVisibility) | ||
) | ||
// Observes visibility changes of the dominant speaker's video track. | ||
.visibilityObservation(in: availableFrame) { onChangeTrackVisibility(participant, $0) } | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.