From c04f4471755844a13e58ca550f811c1fb9bd4cb1 Mon Sep 17 00:00:00 2001
From: kkostiuk <kateryna.kostiuk@savoirfairelinux.com>
Date: Mon, 25 Jan 2021 09:32:18 -0500
Subject: [PATCH] conference: add actions

This patch adds more actions to conference management
- hangup participant for moderator
- set moderator
- mute participant audio

Gitlab: #269

Change-Id: I2dd50ccce6583abf8d15f1c35f96a08f62134669
---
 src/CurrentCallVC.mm               | 35 ++++++++++++++++++++++++++++++
 src/views/ConferenceOverlayView.h  |  7 ++++++
 src/views/ConferenceOverlayView.mm | 25 ++++++++++++++++++---
 ui/Base.lproj/Localizable.strings  | 12 ++++++++++
 4 files changed, 76 insertions(+), 3 deletions(-)

diff --git a/src/CurrentCallVC.mm b/src/CurrentCallVC.mm
index 8d204819..edd7340a 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 3cf19ba5..ab2d9a52 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 26858e49..b6afaac9 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 4aa94eb8..31d8f2f8 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";
 
-- 
GitLab