diff --git a/src/CurrentCallVC.mm b/src/CurrentCallVC.mm index 8d2048194f981d958b5e03c72cb0d7bd2d24a320..edd7340a44851aae572050b3293898bcfd7bc876 100644 --- a/src/CurrentCallVC.mm +++ b/src/CurrentCallVC.mm @@ -422,6 +422,10 @@ CVPixelBufferRef pixelBufferPreview; conferenceParticipant.bestName = bestNameForContact(contact); } catch (...) {} } + conferenceParticipant.videoMuted = participant["videoMuted"] == "true"; + conferenceParticipant.audioLocalMuted = participant["audioLocalMuted"] == "true"; + conferenceParticipant.audioModeratorMuted = participant["audioModeratorMuted"] == "true"; + conferenceParticipant.isModerator = participant["isModerator"] == "true"; if (participantsOverlays[conferenceParticipant.uri] != nil) { ConferenceOverlayView* overlay = participantsOverlays[conferenceParticipant.uri]; overlay.framesize = framesize; @@ -1370,6 +1374,23 @@ CVPixelBufferRef pixelBufferPreview; return callModel->isModerator([self getcallID]); } +-(BOOL)isParticipantHost:(NSString*)uri { + if (accountInfo_ == nil) + return false; + if ([self isMasterCall]) { + return accountInfo_->profileInfo.uri == QString::fromNSString(uri); + } + auto convOpt = getConversationFromUid(convUid_, *accountInfo_->conversationModel.get()); + if (!convOpt.has_value()) + return false; + lrc::api::conversation::Info& conv = *convOpt; + auto* callModel = accountInfo_->callModel.get(); + try { + auto call = callModel->getCall(conv.callId); + return call.peerUri.remove("ring:") == QString::fromNSString(uri); + } catch (...) {} + return true; +} -(void)maximizeParticipant:(NSString*)uri active:(BOOL)isActive { if (accountInfo_ == nil) @@ -1399,6 +1420,20 @@ CVPixelBufferRef pixelBufferPreview; } catch (...) {} } +-(void)muteParticipantAudio:(NSString*)uri state:(BOOL)state { + if (accountInfo_ == nil) + return; + auto* callModel = accountInfo_->callModel.get(); + callModel->muteParticipant([self getcallID], QString::fromNSString(uri), state); +} + +-(void)setModerator:(NSString*)uri state:(BOOL)state { + if (accountInfo_ == nil) + return; + auto* callModel = accountInfo_->callModel.get(); + callModel->setModerator([self getcallID], QString::fromNSString(uri), state); +} + #pragma mark Popover delegate - (void)popoverWillClose:(NSNotification *)notification diff --git a/src/views/ConferenceOverlayView.h b/src/views/ConferenceOverlayView.h index 3cf19ba55260d91f90d54896b21fa0609acd75fb..ab2d9a527a7845db48026a157f92bea579c57e0f 100644 --- a/src/views/ConferenceOverlayView.h +++ b/src/views/ConferenceOverlayView.h @@ -27,9 +27,12 @@ NS_ASSUME_NONNULL_BEGIN -(void)hangUpParticipant:(NSString*)uri; -(void)minimizeParticipant; -(void)maximizeParticipant:(NSString*)uri active:(BOOL)isActive; +-(void)muteParticipantAudio:(NSString*)uri state:(BOOL)state; +-(void)setModerator:(NSString*)uri state:(BOOL)state; -(int)getCurrentLayout; -(BOOL)isMasterCall; -(BOOL)isCallModerator; +-(BOOL)isParticipantHost:(NSString*)uri; @end struct ConferenceParticipant { @@ -41,6 +44,10 @@ struct ConferenceParticipant { NSString* bestName; bool active; bool isLocal; + bool isModerator; + bool audioLocalMuted; + bool audioModeratorMuted; + bool videoMuted; }; @interface ConferenceOverlayView: NSView { diff --git a/src/views/ConferenceOverlayView.mm b/src/views/ConferenceOverlayView.mm index 26858e49f4ce3be67640b15af0edfd9349fd2b75..b6afaac948f623d637cdaa8c697985a1d7e3ecf8 100644 --- a/src/views/ConferenceOverlayView.mm +++ b/src/views/ConferenceOverlayView.mm @@ -87,7 +87,8 @@ CGFloat const controlSize = 40; int layout = [self.delegate getCurrentLayout]; if (layout < 0) return; - BOOL showHangUp = !self.participant.isLocal && [self.delegate isMasterCall]; + BOOL showConferenceHostOnly = !self.participant.isLocal && [self.delegate isMasterCall]; + BOOL showHangup = !self.participant.isLocal && [self.delegate isParticipantHost:self.participant.uri]; BOOL showMaximized = layout != 2; BOOL showMinimized = !(layout == 0 || (layout == 1 && !self.participant.active)); contextualMenu = [[NSMenu alloc] initWithTitle:@""]; @@ -101,7 +102,17 @@ CGFloat const controlSize = 40; [menuItem setTarget:self]; [contextualMenu insertItem:menuItem atIndex:contextualMenu.itemArray.count]; } - if (showHangUp) { + if (showConferenceHostOnly) { + auto setModeratorTitle = self.participant.isModerator ? NSLocalizedString(@"Unset moderator", @"Conference action") : NSLocalizedString(@"Set moderator", @"Conference action"); + NSMenuItem *menuItemModerator = [[NSMenuItem alloc] initWithTitle: setModeratorTitle action:@selector(setModerator:) keyEquivalent:@""]; + [menuItemModerator setTarget:self]; + [contextualMenu insertItem:menuItemModerator atIndex:contextualMenu.itemArray.count]; + } + auto audioTitle = self.participant.audioModeratorMuted ? NSLocalizedString(@"Unmute audio", @"Conference action") : NSLocalizedString(@"Mute audio", @"Conference action"); + NSMenuItem *menuItemAudio = [[NSMenuItem alloc] initWithTitle: audioTitle action:@selector(muteAudio:) keyEquivalent:@""]; + [menuItemAudio setTarget:self]; + [contextualMenu insertItem:menuItemAudio atIndex:contextualMenu.itemArray.count]; + if (showHangup) { NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Hangup", @"Conference action") action:@selector(finishCall:) keyEquivalent:@""]; [menuItem setTarget:self]; [contextualMenu insertItem:menuItem atIndex:contextualMenu.itemArray.count]; @@ -118,7 +129,15 @@ CGFloat const controlSize = 40; } - (void)finishCall:(NSMenuItem*) sender { - [self.delegate hangUpParticipant:self.participant.uri]; + [self.delegate hangUpParticipant: self.participant.uri]; +} + +- (void)muteAudio:(NSMenuItem*) sender { + [self.delegate muteParticipantAudio: self.participant.uri state: !self.participant.audioModeratorMuted]; +} + +- (void)setModerator:(NSMenuItem*) sender { + [self.delegate setModerator:self.participant.uri state: !self.participant.isModerator]; } - (void)sizeChanged { diff --git a/ui/Base.lproj/Localizable.strings b/ui/Base.lproj/Localizable.strings index 4aa94eb8d14a5f295b3755041535fa714e55ae5d..31d8f2f80404b856800d6151cbf67658a9b7980e 100644 --- a/ui/Base.lproj/Localizable.strings +++ b/ui/Base.lproj/Localizable.strings @@ -223,6 +223,18 @@ /* Conference action */ "Hangup" = "Hangup"; +/* Conference action */ +"Mute audio" = "Mute audio"; + +/* Conference action */ +"Set moderator" = "Set moderator"; + +/* Conference action */ +"Unmute audio" = "Unmute audio"; + +/* Conference action */ +"Unset moderator" = "Unset moderator"; + /* Conference name */ "Me" = "Me";