123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332 |
- /**
- * SPDX-FileCopyrightText: 2020 Nextcloud GmbH and Nextcloud contributors
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
- #import "CallParticipantViewCell.h"
- #import "CallViewController.h"
- #import "NCAPIController.h"
- #import "NCDatabaseManager.h"
- #import "NextcloudTalk-Swift.h"
- NSString *const kCallParticipantCellIdentifier = @"CallParticipantCellIdentifier";
- NSString *const kCallParticipantCellNibName = @"CallParticipantViewCell";
- CGFloat const kCallParticipantCellMinHeight = 128;
- @interface CallParticipantViewCell()
- {
- UIView<RTCVideoRenderer> *_videoView;
- CGSize _remoteVideoSize;
- NSTimer *_disconnectedTimer;
- }
- @end
- @implementation CallParticipantViewCell
- - (void)awakeFromNib
- {
- [super awakeFromNib];
-
- self.audioOffIndicator.hidden = YES;
- self.screensharingIndicator.hidden = YES;
- self.raisedHandIndicator.hidden = YES;
-
- self.audioOffIndicator.layer.cornerRadius = 4;
- self.audioOffIndicator.clipsToBounds = YES;
- self.screensharingIndicator.layer.cornerRadius = 4;
- self.screensharingIndicator.clipsToBounds = YES;
- self.activityIndicator.radius = 50.0f;
- self.activityIndicator.cycleColors = @[UIColor.lightGrayColor];
- self.peerAvatarImageView.hidden = YES;
- self.peerAvatarImageView.layer.cornerRadius = self.peerAvatarImageView.bounds.size.width / 2;
- self.peerAvatarImageView.layer.masksToBounds = YES;
- self.layer.cornerRadius = 22.0f;
- [self.layer setMasksToBounds:YES];
-
- _showOriginalSize = NO;
- UITapGestureRecognizer *tapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(toggleZoom)];
- [tapGestureRecognizer setNumberOfTapsRequired:2];
- [self.contentView addGestureRecognizer:tapGestureRecognizer];
- }
- - (void)prepareForReuse
- {
- [super prepareForReuse];
- [_peerAvatarImageView cancelCurrentRequest];
- _peerAvatarImageView.image = nil;
- _peerAvatarImageView.alpha = 1;
- _displayName = nil;
- _peerNameLabel.text = nil;
- [_videoView removeFromSuperview];
- _videoView = nil;
- _showOriginalSize = NO;
- self.layer.borderWidth = 0.0f;
- [self hideLoadingSpinner];
- [self invalidateDisconnectedTimer];
- }
- - (void)applyLayoutAttributes:(UICollectionViewLayoutAttributes *)layoutAttributes
- {
- [super applyLayoutAttributes:layoutAttributes];
-
- [self resizeRemoteVideoView];
- }
- - (void)layoutSubviews
- {
- [super layoutSubviews];
- CGRect bounds = self.bounds;
- // Usually we have a padding to the side of the cell of 22 (= cornerRadius)
- // But when the cell is really small adjust the padding to be 11 (= cornerRadius / 2)
- if (bounds.size.width <= 200 || bounds.size.height <= 200) {
- self.stackViewLeftConstraint.constant = 11;
- self.stackViewRightConstraint.constant = 11;
- self.stackViewBottomConstraint.constant = 11;
- self.screensharingIndiciatorTopConstraint.constant = 11;
- self.screensharingIndiciatorRightConstraint.constant = 11;
- } else {
- self.stackViewLeftConstraint.constant = 22;
- self.stackViewRightConstraint.constant = 22;
- self.stackViewBottomConstraint.constant = 22;
- self.screensharingIndiciatorTopConstraint.constant = 22;
- self.screensharingIndiciatorRightConstraint.constant = 22;
- }
- [self.contentView layoutSubviews];
- self.peerAvatarImageView.layer.cornerRadius = self.peerAvatarImageView.bounds.size.width / 2;
- self.activityIndicator.radius = self.peerAvatarImageView.bounds.size.width / 2;
- }
- - (void)toggleZoom
- {
- _showOriginalSize = !_showOriginalSize;
- [self.actionsDelegate cellWantsToChangeZoom:self showOriginalSize:_showOriginalSize];
- [self resizeRemoteVideoView];
- }
- - (void)setAvatarForActor:(TalkActor * _Nullable)actor
- {
- if (actor.id == nil || actor.id.length == 0) {
- [self setBackgroundColor:[UIColor colorWithWhite:0.5 alpha:1]];
- } else if (actor.displayName && actor.displayName.length > 0) {
- [self setBackgroundColor:[[ColorGenerator shared] usernameToColor:actor.displayName]];
- } else {
- [self setBackgroundColor:[[ColorGenerator shared] usernameToColor:actor.id]];
- }
- [self.peerAvatarImageView setActorAvatarForId:actor.id withType:actor.type withDisplayName:actor.displayName withRoomToken:nil];
- }
- - (void)setDisplayName:(NSString *)displayName
- {
- _displayName = displayName;
- if (!displayName || [displayName isKindOfClass:[NSNull class]] || [displayName isEqualToString:@""]) {
- _displayName = NSLocalizedString(@"Guest", nil);
- }
- if ([self.peerNameLabel.text isEqualToString:_displayName]) {
- return;
- }
- dispatch_async(dispatch_get_main_queue(), ^{
- self.peerNameLabel.text = self->_displayName;
- [self setBackgroundColor:[[ColorGenerator shared] usernameToColor:self->_displayName]];
- });
- }
- - (void)setAudioDisabled:(BOOL)audioDisabled
- {
- _audioDisabled = audioDisabled;
- dispatch_async(dispatch_get_main_queue(), ^{
- [self configureParticipantButtons];
- });
- }
- - (void)setScreenShared:(BOOL)screenShared
- {
- _screenShared = screenShared;
- dispatch_async(dispatch_get_main_queue(), ^{
- [self configureParticipantButtons];
- });
- }
- - (void)setConnectionState:(RTCIceConnectionState)connectionState
- {
- _connectionState = connectionState;
- [self invalidateDisconnectedTimer];
- if (connectionState == RTCIceConnectionStateDisconnected) {
- [self setDisconnectedTimer];
- } else if (connectionState == RTCIceConnectionStateFailed) {
- [self setFailedConnectionUI];
- } else if (connectionState != RTCIceConnectionStateCompleted && connectionState != RTCIceConnectionStateConnected) {
- [self setConnectingUI];
- } else {
- [self setConnectedUI];
- }
- }
- - (void)setDisconnectedTimer
- {
- _disconnectedTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(setDisconnectedUI) userInfo:nil repeats:NO];
- }
- - (void)invalidateDisconnectedTimer
- {
- [_disconnectedTimer invalidate];
- _disconnectedTimer = nil;
- }
- - (void)setDisconnectedUI
- {
- if (_connectionState == RTCIceConnectionStateDisconnected) {
- dispatch_async(dispatch_get_main_queue(), ^{
- self.peerNameLabel.text = [NSString stringWithFormat:NSLocalizedString(@"Connecting to %@ …", nil), self->_displayName];
- self.peerAvatarImageView.alpha = 0.3;
- [self hideLoadingSpinner];
- });
- }
- }
- - (void)setConnectingUI
- {
- dispatch_async(dispatch_get_main_queue(), ^{
- self.peerAvatarImageView.alpha = 0.3;
- [self showLoadingSpinner];
- });
- }
- - (void)setFailedConnectionUI
- {
- dispatch_async(dispatch_get_main_queue(), ^{
- self.peerNameLabel.text = [NSString stringWithFormat:NSLocalizedString(@"Failed to connect to %@", nil), self->_displayName];
- self.peerAvatarImageView.alpha = 0.3;
- });
- }
- - (void)setConnectedUI
- {
- dispatch_async(dispatch_get_main_queue(), ^{
- self.peerNameLabel.text = self->_displayName;
- self.peerAvatarImageView.alpha = 1;
- [self hideLoadingSpinner];
- });
- }
- - (void)showLoadingSpinner
- {
- [self.activityIndicator startAnimating];
- [self.activityIndicator setHidden:NO];
- }
- - (void)hideLoadingSpinner
- {
- [self.activityIndicator stopAnimating];
- [self.activityIndicator setHidden:YES];
- }
- - (IBAction)screenSharingButtonPressed:(id)sender
- {
- [self.actionsDelegate cellWantsToPresentScreenSharing:self];
- }
- - (void)configureParticipantButtons
- {
- self.audioOffIndicator.hidden = !_audioDisabled;
- self.screensharingIndicator.hidden = !_screenShared;
- }
- - (void)setVideoDisabled:(BOOL)videoDisabled
- {
- _videoDisabled = videoDisabled;
- if (videoDisabled) {
- [_videoView setHidden:YES];
- [_peerAvatarImageView setHidden:NO];
- } else {
- [_peerAvatarImageView setHidden:YES];
- [_videoView setHidden:NO];
- }
- }
- - (void)setSpeaking:(BOOL)speaking
- {
- if (speaking) {
- self.layer.borderColor = [UIColor whiteColor].CGColor;
- self.layer.borderWidth = 2.0f;
- } else {
- self.layer.borderWidth = 0.0f;
- }
- }
- - (void)setRaiseHand:(BOOL)raised
- {
- dispatch_async(dispatch_get_main_queue(), ^{
- self.raisedHandIndicator.hidden = !raised;
- });
- }
- - (void)setVideoView:(RTCMTLVideoView *)videoView
- {
- dispatch_async(dispatch_get_main_queue(), ^{
- if (videoView == self->_videoView) {
- return;
- }
- [self->_videoView removeFromSuperview];
- self->_videoView = nil;
- self->_videoView = videoView;
- [self->_peerVideoView addSubview:self->_videoView];
- [self->_videoView setHidden:self->_videoDisabled];
- [self resizeRemoteVideoView];
- });
- }
- - (CGSize)getRemoteVideoSize
- {
- return self->_remoteVideoSize;
- }
- - (void)setRemoteVideoSize:(CGSize)size
- {
- self->_remoteVideoSize = size;
- [self resizeRemoteVideoView];
- }
- - (void)resizeRemoteVideoView
- {
- CGRect bounds = self.bounds;
- CGSize videoSize = _remoteVideoSize;
-
- if (videoSize.width > 0 && videoSize.height > 0) {
- // Aspect fill remote video into bounds.
- CGRect remoteVideoFrame = AVMakeRectWithAspectRatioInsideRect(videoSize, bounds);
- CGFloat scale = 1;
-
- if (!_showOriginalSize) {
- CGFloat scaleHeight = bounds.size.height / remoteVideoFrame.size.height;
- CGFloat scaleWidth = bounds.size.width / remoteVideoFrame.size.width;
- // Always grab the bigger scale to make video cover the whole cell
- scale = (scaleHeight > scaleWidth) ? scaleHeight : scaleWidth;
- }
-
- remoteVideoFrame.size.height *= scale;
- remoteVideoFrame.size.width *= scale;
- _videoView.frame = remoteVideoFrame;
- _videoView.center = CGPointMake(CGRectGetMidX(bounds), CGRectGetMidY(bounds));
- } else {
- _videoView.frame = bounds;
- }
- }
- @end
|