Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature] Display remote participants persona data in the grid view #171

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
68c9d09
Added the event when remote participants joined a call
vhuseinova-msft Apr 26, 2022
0c41880
Added RemoteParticipantsManager
vhuseinova-msft Apr 27, 2022
654eb19
Updated CallingSDKEventsHandling.
vhuseinova-msft Apr 27, 2022
169f5f3
Fixed comment
vhuseinova-msft Apr 28, 2022
34aea3f
Code review updates
vhuseinova-msft Apr 28, 2022
258621b
Renamed RemoteParticipantsManager
vhuseinova-msft Apr 28, 2022
56a31b9
Code review updates
vhuseinova-msft Apr 29, 2022
5b122c1
Code review updates
vhuseinova-msft Apr 29, 2022
581a3a1
Added a function for setting a remote participant's persona data
vhuseinova-msft Apr 29, 2022
6337e72
Updated avatarStorage type
vhuseinova-msft May 2, 2022
05d166c
Added tests. Renamed AvatarViewManager
vhuseinova-msft May 3, 2022
f53a9c3
Merge branch 'feature/customdatamodel' of https://github.com/Azure/co…
vhuseinova-msft May 3, 2022
ae1449f
Updated return type
vhuseinova-msft May 3, 2022
8fc6d1f
Updated setRemoteParticipantPersonaData func signature
vhuseinova-msft May 3, 2022
a352c99
Merge branch 'feature/customdatamodel' of https://github.com/Azure/co…
vhuseinova-msft May 3, 2022
5d9525b
Code review updates
vhuseinova-msft May 4, 2022
e823ccd
Added injection option for the demo app
vhuseinova-msft May 4, 2022
6836bc6
Added remote participants' persona data update
vhuseinova-msft May 5, 2022
61410dd
Merge branch 'feature/customdatamodel' of https://github.com/Azure/co…
vhuseinova-msft May 5, 2022
1422c27
Updated local and remote avatar injection
vhuseinova-msft May 5, 2022
41afe16
Merge branch 'feature/customdatamodel' of https://github.com/Azure/co…
vhuseinova-msft May 5, 2022
bf02005
Merge branch 'feature/customdatamodel' of https://github.com/Azure/co…
vhuseinova-msft May 9, 2022
0e89ee9
Updated participants names
vhuseinova-msft May 9, 2022
eaac125
Updated useCustomRemoteParticipantsPersonaData default value
vhuseinova-msft May 9, 2022
4308f19
Merge branch 'feature/customdatamodel' of https://github.com/Azure/co…
vhuseinova-msft May 9, 2022
0ee3db0
Updated participants' renderer name setup
vhuseinova-msft May 11, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@
A8C69FBD2728AE1C00143DB7 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = A8C69FBC2728AE1C00143DB7 /* Assets.xcassets */; };
A8C69FC02728AE1C00143DB7 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = A8C69FBE2728AE1C00143DB7 /* LaunchScreen.storyboard */; };
A8FB819C272A082B00AA0930 /* DemoInputTypes.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8FB819B272A082B00AA0930 /* DemoInputTypes.swift */; };
FA7B53EC282330F2001DFAB8 /* RemoteParticipantAvatarHelper.swift in Sources */ = {isa = PBXBuildFile; fileRef = FA7B53EB282330F2001DFAB8 /* RemoteParticipantAvatarHelper.swift */; };
FAA448A0282585F700BD0DC0 /* AzureCommunicationUICalling.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAA4489F282585F700BD0DC0 /* AzureCommunicationUICalling.framework */; };
FAA448A1282585F700BD0DC0 /* AzureCommunicationUICalling.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = FAA4489F282585F700BD0DC0 /* AzureCommunicationUICalling.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
FAA448A42825931500BD0DC0 /* AccessibilityIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAA448A32825931500BD0DC0 /* AccessibilityIdentifier.swift */; };
FAA448A52825931500BD0DC0 /* AccessibilityIdentifier.swift in Sources */ = {isa = PBXBuildFile; fileRef = FAA448A32825931500BD0DC0 /* AccessibilityIdentifier.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -100,6 +100,7 @@
A8C69FBF2728AE1C00143DB7 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
A8C69FC12728AE1C00143DB7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
A8FB819B272A082B00AA0930 /* DemoInputTypes.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DemoInputTypes.swift; sourceTree = "<group>"; };
FA7B53EB282330F2001DFAB8 /* RemoteParticipantAvatarHelper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RemoteParticipantAvatarHelper.swift; sourceTree = "<group>"; };
FAA4489F282585F700BD0DC0 /* AzureCommunicationUICalling.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AzureCommunicationUICalling.framework; sourceTree = BUILT_PRODUCTS_DIR; };
FAA448A32825931500BD0DC0 /* AccessibilityIdentifier.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AccessibilityIdentifier.swift; path = ../sdk/AzureCommunicationUICalling/AzureCommunicationUICalling/Utilities/AccessibilityIdentifier.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
Expand Down Expand Up @@ -211,6 +212,7 @@
A8FB819D272A0B3500AA0930 /* Views */,
5075FE9B27FFA84B00136B34 /* Localization */,
A8849E522732FFA10049FB1A /* AuthenticationHelper.swift */,
FA7B53EB282330F2001DFAB8 /* RemoteParticipantAvatarHelper.swift */,
A8FB819B272A082B00AA0930 /* DemoInputTypes.swift */,
A85DDCB22728B140001297B4 /* ThemeConfig.swift */,
A85DDCAF2728B12D001297B4 /* EnvConfig.swift */,
Expand Down Expand Up @@ -496,6 +498,7 @@
1F8881CD279B456E001427F0 /* Extension.swift in Sources */,
5027C1C62821A07500DC7131 /* AccessibilityId.swift in Sources */,
A85DDCB12728B12D001297B4 /* EnvConfig.swift in Sources */,
FA7B53EC282330F2001DFAB8 /* RemoteParticipantAvatarHelper.swift in Sources */,
A85DDCB32728B140001297B4 /* ThemeConfig.swift in Sources */,
A85DDCB82728B23B001297B4 /* UIKitDemoViewController.swift in Sources */,
A8C69FB62728AE1A00143DB7 /* SceneDelegate.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class EnvConfigSubject: ObservableObject {
@Published var localeIdentifier: String = ""
@Published var isRightToLeft: Bool = false
@Published var useCustomColors: Bool = false
@Published var useCustomRemoteParticipantsPersonaData: Bool = false
@Published var primaryColor: Color = .blue
@Published var tint10: Color = .blue
@Published var tint20: Color = .blue
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//

import Foundation
import AzureCommunicationCommon
import AzureCommunicationUICalling

struct RemoteParticipantAvatarHelper {
private static func getRemoteParticipantId(_ identifier: CommunicationIdentifier) -> String? {
switch identifier {
case is CommunicationUserIdentifier:
return (identifier as? CommunicationUserIdentifier)?.identifier
case is UnknownIdentifier:
return (identifier as? UnknownIdentifier)?.identifier
case is PhoneNumberIdentifier:
return (identifier as? PhoneNumberIdentifier)?.phoneNumber
case is MicrosoftTeamsUserIdentifier:
return (identifier as? MicrosoftTeamsUserIdentifier)?.userId
default:
return nil
}
}

static func didRemoteParticipantsJoin(to callComposite: CallComposite, identifiers: [CommunicationIdentifier]) {
let avatars = ["cat", "fox", "koala", "monkey", "mouse", "octopus"]
for identifier in identifiers {
let id = getRemoteParticipantId(identifier)
let nameIdValue = id != nil ? " \(id?.suffix(4) ?? "")" : ""
var avatarImage: UIImage?
var selectedAvatarName = ""
if let lastSymbol = id?.last,
let index = Int(String(lastSymbol)),
index < avatars.count {
selectedAvatarName = avatars[index]
avatarImage = UIImage(named: selectedAvatarName)
}
let personaData = PersonaData(avatar: avatarImage,
renderDisplayName: selectedAvatarName + nameIdValue)
callComposite.setRemoteParticipantPersonaData(for: identifier,
personaData: personaData)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ struct SettingsView: View {
Form {
localizationSettings
avatarSettings
remoteParticipantsAvatarsSettings
themeSettings
}.navigationTitle("UI Library - Settings")
}
Expand Down Expand Up @@ -68,6 +69,12 @@ struct SettingsView: View {
}
}

var remoteParticipantsAvatarsSettings: some View {
Section(header: Text("Remote Participant Persona")) {
Toggle("Inject avatars", isOn: $envConfigSubject.useCustomRemoteParticipantsPersonaData)
}
}

var themeSettings: some View {
Section(header: Text("Theme")) {
Toggle("Use Custom Theme Colors", isOn: $envConfigSubject.useCustomColors)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,13 @@ extension SwiftUIDemoView {
: Theming(envConfigSubject: envConfigSubject),
localization: localizationConfig)
let callComposite = CallComposite(withOptions: callCompositeOptions)
let didRemoteParticipantsJoin: ([CommunicationIdentifier]) -> Void = { [weak callComposite] identifiers in
guard let composite = callComposite else {
return
}

self.didRemoteParticipantsJoin(to: composite, identifiers: identifiers)
}
callComposite.setTarget(didFail: didFail, didRemoteParticipantsJoin: didRemoteParticipantsJoin)
let renderDisplayName = envConfigSubject.renderedDisplayName.isEmpty ?
nil:envConfigSubject.renderedDisplayName
Expand Down Expand Up @@ -235,7 +242,13 @@ extension SwiftUIDemoView {
showError(for: error.code)
}

func didRemoteParticipantsJoin(_ identifiers: [CommunicationIdentifier]) {
func didRemoteParticipantsJoin(to callComposite: CallComposite, identifiers: [CommunicationIdentifier]) {
print("::::SwiftUIDemoView::getEventsHandler::didRemoteParticipantsJoin \(identifiers)")
guard envConfigSubject.useCustomRemoteParticipantsPersonaData else {
return
}

RemoteParticipantAvatarHelper.didRemoteParticipantsJoin(to: callComposite,
identifiers: identifiers)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -133,8 +133,14 @@ class UIKitDemoViewController: UIViewController {
print("::::UIKitDemoView error.code \(error.code)")
}

func didRemoteParticipantsJoin(_ identifiers: [CommunicationIdentifier]) {
func didRemoteParticipantsJoin(to callComposite: CallComposite, identifiers: [CommunicationIdentifier]) {
print("::::UIKitDemoView::getEventsHandler::didRemoteParticipantsJoin \(identifiers)")
guard envConfigSubject.useCustomRemoteParticipantsPersonaData else {
return
}

RemoteParticipantAvatarHelper.didRemoteParticipantsJoin(to: callComposite,
identifiers: identifiers)
}

func startExperience(with link: String) {
Expand All @@ -156,14 +162,19 @@ class UIKitDemoViewController: UIViewController {
: Theming(envConfigSubject: envConfigSubject),
localization: localizationConfig)
callComposite = CallComposite(withOptions: callCompositeOptions)

let didRemoteParticipantsJoin: ([CommunicationIdentifier]) -> Void = { [weak callComposite] identifiers in
guard let composite = callComposite else {
return
}
self.didRemoteParticipantsJoin(to: composite, identifiers: identifiers)
}
guard let callComposite = callComposite else {
return
}

callComposite.setTarget(didFail: didFail, didRemoteParticipantsJoin: didRemoteParticipantsJoin)
let renderDisplayName = envConfigSubject.renderedDisplayName.isEmpty ?
nil : envConfigSubject.renderedDisplayName
nil : envConfigSubject.renderedDisplayName
let persona = PersonaData(avatar: UIImage(named: envConfigSubject.avatarImageName),
renderDisplayName: renderDisplayName)
let localOptions = CommunicationUILocalDataOptions(persona)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public class CallComposite {
callCompositeEventsHandler: callCompositeEventsHandler,
callingSDKWrapper: dependencyContainer.resolve())
self.remoteParticipantsManager = remoteParticipantsManager
avatarViewManager = dependencyContainer.resolve() as AvatarViewManagerProtocol
avatarViewManager = dependencyContainer.resolve() as AvatarViewManager
}

private func cleanUpManagers() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ final class DependencyContainer {
register(AccessibilityProvider() as AccessibilityProviderProtocol)
register(LocalizationProvider(logger: resolve()) as LocalizationProviderProtocol)
register(AvatarViewManager(store: resolve(),
localDataOptions: localDataOptions) as AvatarViewManagerProtocol)
localDataOptions: localDataOptions) as AvatarViewManager)
register(CompositeViewModelFactory(logger: resolve(),
store: resolve(),
localizationProvider: resolve(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,11 @@ protocol CompositeViewFactoryProtocol {
struct CompositeViewFactory: CompositeViewFactoryProtocol {
private let logger: Logger
private let compositeViewModelFactory: CompositeViewModelFactoryProtocol
private let avatarManager: AvatarViewManagerProtocol
private let avatarManager: AvatarViewManager
private let videoViewManager: VideoViewManager

init(logger: Logger,
avatarManager: AvatarViewManagerProtocol,
avatarManager: AvatarViewManager,
videoViewManager: VideoViewManager,
compositeViewModelFactory: CompositeViewModelFactoryProtocol) {
self.logger = logger
Expand All @@ -28,8 +28,8 @@ struct CompositeViewFactory: CompositeViewFactoryProtocol {

func makeSetupView() -> SetupView {
return SetupView(viewModel: compositeViewModelFactory.getSetupViewModel(),
localPersonaData: avatarManager.getLocalPersonaData(),
viewManager: videoViewManager)
viewManager: videoViewManager,
avatarManager: avatarManager)
}

func makeCallingView() -> CallingView {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,9 @@ import FluentUI

struct CompositeAvatar: View {
@Binding var displayName: String?
@Binding var avatarImage: UIImage?
var isSpeaking: Bool
var avatarSize: MSFAvatarSize = .xxlarge
var avatarImage: UIImage?
var body: some View {
let isNameEmpty = displayName == nil
|| displayName?.trimmingCharacters(in: .whitespaces).isEmpty == true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@ import AzureCommunicationCommon
import Combine

protocol AvatarViewManagerProtocol {
func getLocalPersonaData() -> PersonaData?
func setRemoteParticipantPersonaData(for identifier: CommunicationIdentifier,
personaData: PersonaData) -> Result<Void, Error>
}

class AvatarViewManager: AvatarViewManagerProtocol {
private let store: Store<AppState>
private(set) var avatarStorage = MappedSequence<String, PersonaData>()
private(set) var localDataOptions: CommunicationUILocalDataOptions?
@Published private(set) var avatarStorage = MappedSequence<String, PersonaData>()
@Published private(set) var localDataOptions: CommunicationUILocalDataOptions?
var cancellables = Set<AnyCancellable>()

init(store: Store<AppState>,
localDataOptions: CommunicationUILocalDataOptions?) {
self.store = store
self.localDataOptions = localDataOptions
store.$state
.receive(on: DispatchQueue.main)
.sink { [weak self] state in
self?.receive(state: state)
}.store(in: &cancellables)
Expand All @@ -38,14 +38,6 @@ class AvatarViewManager: AvatarViewManagerProtocol {
avatarStorage = MappedSequence<String, PersonaData>()
}

func getLocalPersonaData() -> PersonaData? {
guard let localPersona = localDataOptions?.localPersona else {
return nil
}

return localPersona
}

func setRemoteParticipantPersonaData(for identifier: CommunicationIdentifier,
personaData: PersonaData) -> Result<Void, Error> {
guard let idStringValue = identifier.stringValue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import FluentUI

struct CallingView: View {
@ObservedObject var viewModel: CallingViewModel
let avatarManager: AvatarViewManagerProtocol
let avatarManager: AvatarViewManager
let viewManager: VideoViewManager

let leaveCallConfirmationListSourceView = UIView()
Expand Down Expand Up @@ -103,9 +103,9 @@ struct CallingView: View {

return Group {
LocalVideoView(viewModel: viewModel.localVideoViewModel,
personaData: avatarManager.getLocalPersonaData(),
viewManager: viewManager,
viewType: .localVideoPip)
viewType: .localVideoPip,
avatarManager: avatarManager)
.frame(width: size.width, height: size.height, alignment: .center)
.background(Color(StyleProvider.color.backgroundColor))
.clipShape(RoundedRectangle(cornerRadius: shapeCornerRadius))
Expand Down Expand Up @@ -153,6 +153,7 @@ struct CallingView: View {

var participantGridsView: some View {
ParticipantGridView(viewModel: viewModel.participantGridsViewModel,
avatarViewManager: avatarManager,
videoViewManager: viewManager,
screenSize: getSizeClass())
.edgesIgnoringSafeArea(safeAreaIgnoreArea)
Expand All @@ -161,9 +162,9 @@ struct CallingView: View {
var localVideoFullscreenView: some View {
return Group {
LocalVideoView(viewModel: viewModel.localVideoViewModel,
personaData: avatarManager.getLocalPersonaData(),
viewManager: viewManager,
viewType: .localVideofull)
viewType: .localVideofull,
avatarManager: avatarManager)
.background(Color(StyleProvider.color.surface))
.edgesIgnoringSafeArea(safeAreaIgnoreArea)
}
Expand Down
Loading