AzureCommunicationUI/sdk/AzureCommunicationUICalling/Sources/Presentation/SwiftUI/Calling/CallingViewComponent/CaptionsRtt/CaptionsRttInfoCellView.swift (105 lines of code) (raw):
//
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.
//
import SwiftUI
struct CaptionsRttInfoCellView: View {
var avatarViewManager: AvatarViewManagerProtocol
var displayData: CaptionsRttRecord
@State private var avatarImage: UIImage?
@State private var displayName: String?
@State private var isRTL = false
private let localizationProvider: LocalizationProviderProtocol
init(displayData: CaptionsRttRecord,
avatarViewManager: AvatarViewManagerProtocol,
localizationProvider: LocalizationProviderProtocol
) {
self.displayData = displayData
self.avatarViewManager = avatarViewManager
self.localizationProvider = localizationProvider
}
var body: some View {
HStack(alignment: .top) {
// Left-side blue indicator spanning the whole cell height
if !displayData.isFinal, displayData.captionsRttType == .rtt {
RoundedRectangle(cornerRadius: 2)
.fill(Color(StyleProvider.color.primaryColorTint20))
.frame(width: 4)
}
avatarView
VStack(alignment: isRTL ? .trailing : .leading, spacing: 4) {
// Display Name and Typing Logo on the same line
HStack(spacing: 8) {
Text(displayData.displayName)
.font(.caption)
.foregroundColor(Color(StyleProvider.color.textSecondary))
.lineLimit(1)
if displayData.captionsRttType == .rtt && !displayData.isFinal {
Text(localizationProvider.getLocalizedString(.rttTyping))
.font(.caption2)
.foregroundColor(Color(StyleProvider.color.textSecondary))
.padding(.horizontal, 4)
.background(
RoundedRectangle(cornerRadius: 4)
.fill(Color(StyleProvider.color.surface))
)
}
}
.frame(maxWidth: .infinity, alignment: .leading)
// Display Text on the next line
Text(displayText)
.font(.callout)
.foregroundColor(.primary)
.multilineTextAlignment(isRTL ? .trailing : .leading)
.lineLimit(nil) // Wrap text to multiple lines
.fixedSize(horizontal: false, vertical: true)
.environment(\.locale, Locale(identifier: language))
}
.frame(maxWidth: .infinity, alignment: isRTL ? .trailing : .leading)
}
.frame(maxWidth: .infinity)
.padding(.horizontal)
.fixedSize(horizontal: false, vertical: true) // Limit height to content
.padding(.vertical, 4) // Add padding for vertical spacing
.background(Color(StyleProvider.color.drawerColor))
.accessibilityElement(children: .combine)
.onAppear {
updateAvatar()
determineTextDirection()
}
.accessibilityHidden(!displayData.isFinal)
}
private var avatarView: some View {
CompositeAvatar(displayName: $displayName,
avatarImage: $avatarImage,
isSpeaking: false,
avatarSize: .size24)
}
// Display text based on caption availability
private var displayText: String {
if displayData.captionsRttType == .rtt {
return displayData.text
} else {
return (displayData.captionsText?.isEmpty ?? true) ? displayData.spokenText : displayData.captionsText ?? ""
}
}
private var language: String {
(displayData.captionsText?.isEmpty ?? true) ? displayData.spokenLanguage : displayData.captionsLanguage ?? ""
}
private func updateAvatar() {
// Attempt to get the avatar image directly from the avatar storage for the given speaker's ID.
if displayData.isLocal {
avatarImage = avatarViewManager.localParticipantViewData?.avatarImage
displayName = avatarViewManager.localParticipantViewData?.displayName ?? displayData.displayName
} else {
if let participantViewDataAvatar = avatarViewManager.avatarStorage.value(
forKey: displayData.displayRawId)?.avatarImage {
// If an avatar image exists, set it.
avatarImage = participantViewDataAvatar
} else {
avatarImage = nil
displayName = displayData.displayName
}
}
}
private func determineTextDirection() {
let activeLanguageCode = (displayData.captionsLanguage?.isEmpty ?? true) ?
displayData.spokenLanguage : displayData.captionsLanguage ?? displayData.spokenLanguage
isRTL = isRightToLeftLanguage(activeLanguageCode)
}
// Function to determine if the language is right-to-left
private func isRightToLeftLanguage(_ languageCode: String) -> Bool {
let rtlLanguages = ["ar", "he", "fa", "ur"] // Add more as needed
let locale = Locale(identifier: languageCode)
return rtlLanguages.contains(locale.languageCode ?? "")
}
}