Skip to content
Snippets Groups Projects
Commit 3380a267 authored by Aline Gondim Santos's avatar Aline Gondim Santos
Browse files

conference: improve participant overlay

- In another participant video, if I am moderator, I will see local state at bottom and moderator state on top;
- In another participant video, if I am NOT moderator, I will see only one state at bottom representing both local and moderator;
- In my own video, if I am NOT moderator, I will have my local state at bottom left and moderator state top left with a tooltip but no action;
- In my own video, if I am moderator, I will have my local state at bottom left and moderator state top left with an action.

Change-Id: I649d4aeefdd15aa3b554d78948849804ad94a9cd
GitLab: #593
parent a28c88be
Branches
Tags
No related merge requests found
......@@ -205,8 +205,6 @@ Item {
property string areRecording: qsTr("are recording")
property string peerStoppedRecording: qsTr("Peer stopped recording")
property string isCallingYou: qsTr("is calling you")
// CallOverlay
property string mute: qsTr("Mute")
property string unmute: qsTr("Unmute")
property string hangup: qsTr("End call")
......@@ -218,6 +216,15 @@ Item {
property string chat: qsTr("Chat")
property string moreOptions: qsTr("More options")
property string mosaic: qsTr("Mosaic")
property string participantMicIsStillMuted: qsTr("Participant is still muted on his local machine")
property string mutedLocally: qsTr("You are still muted on your local machine")
property string participantModIsStillMuted: qsTr("You are still muted by moderator")
property string mutedByModerator: qsTr("You are muted by a moderator")
property string moderator: qsTr("Moderator")
property string host: qsTr("Host")
property string bothMuted: qsTr("Local and Moderator muted")
property string moderatorMuted: qsTr("Moderator muted")
property string notMuted: qsTr("Not muted")
// LineEditContextMenu
property string copy: qsTr("Copy")
......@@ -540,7 +547,7 @@ Item {
property string maximizeParticipant: qsTr("Maximize")
property string minimizeParticipant: qsTr("Minimize")
property string hangupParticipant: qsTr("Hangup")
property string localMuted: qsTr("local muted")
property string localMuted: qsTr("Local muted")
// Settings moderation
property string conferenceModeration: qsTr("Conference moderation")
......
......@@ -94,6 +94,7 @@ Item {
property color refuseRedTransparent: rgba256(204, 0, 34, 56)
property color mosaicButtonNormalColor: "#272727"
property color whiteColorTransparent: rgba256(255, 255, 255, 50)
property color raiseHandColor: rgba256(0, 184, 255, 77)
property color closeButtonLighterBlack: "#4c4c4c"
......
......@@ -156,7 +156,16 @@ Control {
property list<Action> primaryActions: [
Action {
id: muteAudioAction
onTriggered: CallAdapter.muteThisCallToggle(!isAudioMuted)
onTriggered: {
var muteState = CallAdapter.getMuteState(CurrentAccount.uri)
var modMuted = muteState === CallAdapter.MODERATOR_MUTED
|| muteState === CallAdapter.BOTH_MUTED
if (isAudioMuted && modMuted) {
muteAlertActive = true
muteAlertMessage = JamiStrings.participantModIsStillMuted
}
CallAdapter.muteThisCallToggle(!isAudioMuted)
}
checkable: true
icon.source: checked ?
JamiResources.micro_off_black_24dp_svg :
......@@ -263,7 +272,7 @@ Control {
onTriggered: CallAdapter.setHandRaised("", !CallAdapter.isHandRaised())
checkable: true
icon.source: JamiResources.hand_black_24dp_svg
icon.color: checked ? "red" : "white"
icon.color: checked ? JamiTheme.raiseHandColor : "white"
text: checked ?
JamiStrings.lowerHand :
JamiStrings.raiseHand
......
......@@ -42,6 +42,15 @@ Item {
callActionBar.subMenuOpen ||
participantCallInStatusView.visible
property string muteAlertMessage: ""
property bool muteAlertActive: false
onMuteAlertActiveChanged: {
if (muteAlertActive) {
alertTimer.restart()
}
}
opacity: 0
// (un)subscribe to an app-wide mouse move event trap filtered
......@@ -227,6 +236,40 @@ Item {
anchors.bottomMargin: 20
}
Rectangle {
id: alertMessage
anchors.bottom: __callActionBar.top
anchors.bottomMargin: 16
anchors.horizontalCenter: __callActionBar.horizontalCenter
width: alertMessageTxt.width + 16
height: alertMessageTxt.contentHeight + 16
radius: 5
visible: root.muteAlertActive
color: JamiTheme.darkGreyColorOpacity
Text {
id: alertMessageTxt
text: root.muteAlertMessage
anchors.centerIn: parent
width: Math.min(root.width, contentWidth)
color: JamiTheme.whiteColor
font.pointSize: JamiTheme.textFontSize
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
// Timer to decide when ParticipantOverlay fade out
Timer {
id: alertTimer
interval: JamiTheme.overlayFadeDelay
onTriggered: {
root.muteAlertActive = false
}
}
}
CallActionBar {
id: __callActionBar
......
......@@ -24,7 +24,7 @@ import net.jami.Constants 1.1
import "../../commoncomponents"
RowLayout {
id: buttonsRect
id: root
property int visibleButtons: toggleModerator.visible
+ toggleMute.visible
......@@ -55,9 +55,25 @@ RowLayout {
source: showModeratorMute ?
JamiResources.micro_black_24dp_svg :
JamiResources.micro_off_black_24dp_svg
onClicked: CallAdapter.muteParticipant(uri, showModeratorMute)
toolTipText: showModeratorMute? JamiStrings.muteParticipant
: JamiStrings.unmuteParticipant
checkable: meModerator
onClicked: {
if (participantIsModeratorMuted && isLocalMuted) {
if (isMe)
muteAlertMessage = JamiStrings.mutedLocally
else
muteAlertMessage = JamiStrings.participantMicIsStillMuted
muteAlertActive = true
}
CallAdapter.muteParticipant(uri, showModeratorMute)
}
toolTipText: {
if (!checkable && participantIsModeratorMuted)
return JamiStrings.mutedByModerator
if (showModeratorMute)
return JamiStrings.muteParticipant
else
return JamiStrings.unmuteParticipant
}
}
ParticipantOverlayButton {
......@@ -84,18 +100,6 @@ RowLayout {
toolTipText: JamiStrings.minimizeParticipant
}
ParticipantOverlayButton {
id: lowerHandParticipant
visible: showLowerHand
preferredSize: iconButtonPreferredSize
Layout.preferredHeight: buttonPreferredSize
Layout.preferredWidth: buttonPreferredSize
source: JamiResources.hand_black_24dp_svg
onClicked: CallAdapter.setHandRaised(uri, false)
toolTipText: JamiStrings.lowerHand
}
ParticipantOverlayButton {
id: hangupParticipant
......
......@@ -31,8 +31,8 @@ Item {
id: root
// svg path for the participant indicators background shape
property int shapeWidth: indicatorsRowLayout.width + 8
property int shapeHeight: 16
property int shapeWidth: participantFootInfo.width + 8
property int shapeHeight: 30
property int shapeRadius: 6
property string pathShape: "M0,0 h%1 q%2,0 %2,%2 v%3 h-%4 z"
.arg(shapeWidth - shapeRadius)
......@@ -41,6 +41,7 @@ Item {
.arg(shapeWidth)
property string uri: overlayMenu.uri
property string bestName: ""
property bool participantIsActive: false
property bool participantIsHost: false
property bool participantIsModerator: false
......@@ -48,6 +49,18 @@ Item {
property bool participantIsModeratorMuted: false
property bool participantHandIsRaised: false
property bool meModerator: false
property bool isMe: false
property string muteAlertMessage: ""
property bool muteAlertActive: false
onMuteAlertActiveChanged: {
if (muteAlertActive) {
alertTimer.restart()
}
}
z: 1
function setAvatar(show, uri, isLocal) {
......@@ -63,10 +76,11 @@ Item {
function setMenu(newUri, bestName, isLocal, isActive, showMax) {
overlayMenu.uri = newUri
overlayMenu.bestName = bestName
root.bestName = bestName
isMe = overlayMenu.uri === CurrentAccount.uri
var isHost = CallAdapter.isCurrentHost()
var isModerator = CallAdapter.isCurrentModerator()
meModerator = CallAdapter.isCurrentModerator()
participantIsHost = CallAdapter.participantIsHost(overlayMenu.uri)
participantIsModerator = CallAdapter.isModerator(overlayMenu.uri)
participantIsActive = isActive
......@@ -77,104 +91,22 @@ Item {
var muteState = CallAdapter.getMuteState(overlayMenu.uri)
overlayMenu.isLocalMuted = muteState === CallAdapter.LOCAL_MUTED
|| muteState === CallAdapter.BOTH_MUTED
var isModeratorMuted = muteState === CallAdapter.MODERATOR_MUTED
participantIsModeratorMuted = muteState === CallAdapter.MODERATOR_MUTED
|| muteState === CallAdapter.BOTH_MUTED
participantIsMuted = overlayMenu.isLocalMuted || isModeratorMuted
participantIsMuted = overlayMenu.isLocalMuted || participantIsModeratorMuted
overlayMenu.showModeratorMute = isModerator && !isModeratorMuted
overlayMenu.showModeratorUnmute = isModerator && isModeratorMuted
overlayMenu.showMaximize = isModerator && showMax
overlayMenu.showMinimize = isModerator && participantIsActive
overlayMenu.showHangup = isModerator && !isLocal && !participantIsHost
overlayMenu.showLowerHand = isModerator && participantHandIsRaised
overlayMenu.showModeratorMute = meModerator && !participantIsModeratorMuted
overlayMenu.showModeratorUnmute = (meModerator || isMe) && participantIsModeratorMuted
overlayMenu.showMaximize = meModerator && showMax
overlayMenu.showMinimize = meModerator && participantIsActive
overlayMenu.showHangup = meModerator && !isLocal && !participantIsHost
}
// Participant header with host, moderator and mute indicators
Rectangle {
id: participantIndicators
width: indicatorsRowLayout.width
height: shapeHeight
visible: participantIsHost || participantIsModerator || participantIsMuted
color: "transparent"
anchors.bottom: parent.bottom
Shape {
id: backgroundShape
ShapePath {
id: backgroundShapePath
strokeColor: "transparent"
fillColor: JamiTheme.darkGreyColorOpacity
capStyle: ShapePath.RoundCap
PathSvg { path: pathShape }
}
}
RowLayout {
id: indicatorsRowLayout
height: parent.height
anchors.verticalCenter: parent.verticalCenter
ResponsiveImage {
id: isHostIndicator
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: 6
containerHeight: 12
containerWidth: 12
visible: participantIsHost
source: JamiResources.star_outline_24dp_svg
color: JamiTheme.whiteColor
}
ResponsiveImage {
id: isModeratorIndicator
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: 6
containerHeight: 12
containerWidth: 12
visible: participantIsModerator
source: JamiResources.moderator_svg
color: JamiTheme.whiteColor
}
ResponsiveImage {
id: isMutedIndicator
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: 6
containerHeight: 12
containerWidth: 12
visible: participantIsMuted
source: JamiResources.micro_off_black_24dp_svg
color: JamiTheme.whiteColor
}
ResponsiveImage {
id: isHandRaisedIndicator
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: 6
containerHeight: 12
containerWidth: 12
visible: participantHandIsRaised
source: JamiResources.hand_black_24dp_svg
color: JamiTheme.whiteColor
}
}
TextMetrics {
id: nameTextMetrics
text: bestName
font.pointSize: JamiTheme.participantFontSize
}
Loader {
......@@ -242,8 +174,187 @@ Item {
}
}
ParticipantOverlayMenu { id: overlayMenu }
ParticipantOverlayMenu {
id: overlayMenu
visible: isMe || meModerator
}
// Participant footer with host, moderator and mute indicators
// Mute indicator is as follow:
// - In another participant, if i am not moderator, the mute state is isLocalMuted || participantIsModeratorMuted
// - In another participant, if i am moderator, the mute state is isLocalMuted
// - In my video, the mute state is isLocalMuted
Rectangle {
id: participantIndicators
width: participantRect.width
height: shapeHeight
color: "transparent"
anchors.bottom: parent.bottom
Shape {
id: backgroundShape
ShapePath {
id: backgroundShapePath
strokeColor: "transparent"
fillColor: JamiTheme.darkGreyColorOpacity
capStyle: ShapePath.RoundCap
PathSvg { path: pathShape }
}
}
RowLayout {
id: participantFootInfo
height: parent.height
anchors.verticalCenter: parent.verticalCenter
Text {
id: bestNameLabel
Layout.leftMargin: 8
Layout.preferredWidth: Math.min(nameTextMetrics.boundingRect.width + 8,
participantIndicators.width - indicatorsRowLayout.width - 16)
Layout.preferredHeight: shapeHeight
text: bestName
elide: Text.ElideRight
color: JamiTheme.whiteColor
font.pointSize: JamiTheme.participantFontSize
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
HoverHandler { id: hoverName }
MaterialToolTip {
visible: hoverName.hovered && (text.length > 0)
text: bestNameLabel.truncated ? bestName : ""
}
}
RowLayout {
id: indicatorsRowLayout
height: parent.height
Layout.alignment: Qt.AlignVCenter
ResponsiveImage {
id: isHostIndicator
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: 6
containerHeight: 12
containerWidth: 12
visible: participantIsHost
source: JamiResources.star_outline_24dp_svg
color: JamiTheme.whiteColor
HoverHandler { id: hoverHost }
MaterialToolTip {
visible: hoverHost.hovered
text: JamiStrings.host
}
}
ResponsiveImage {
id: isModeratorIndicator
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: 6
containerHeight: 12
containerWidth: 12
visible: !participantIsHost && participantIsModerator
source: JamiResources.moderator_svg
color: JamiTheme.whiteColor
HoverHandler { id: hoverModerator }
MaterialToolTip {
visible: hoverModerator.hovered
text: JamiStrings.moderator
}
}
ResponsiveImage {
id: isMutedIndicator
Layout.alignment: Qt.AlignVCenter
Layout.leftMargin: 6
containerHeight: 12
containerWidth: 12
visible: (!isMe && !meModerator) ? participantIsMuted : overlayMenu.isLocalMuted
source: JamiResources.micro_off_black_24dp_svg
color: "red"
HoverHandler { id: hoverMicrophone }
MaterialToolTip {
visible: hoverMicrophone.hovered
text: {
if (!isMe && !meModerator && participantIsModeratorMuted && overlayMenu.isLocalMuted)
return JamiStrings.bothMuted
if (overlayMenu.isLocalMuted)
return JamiStrings.localMuted
if (!isMe && !meModerator && participantIsModeratorMuted)
return JamiStrings.moderatorMuted
return JamiStrings.notMuted
}
}
}
}
}
}
Behavior on opacity { NumberAnimation { duration: JamiTheme.shortFadeDuration }}
}
PushButton {
id: isRaiseHandIndicator
source: JamiResources.hand_black_24dp_svg
imageColor: JamiTheme.whiteColor
preferredSize: shapeHeight
visible: root.participantHandIsRaised
anchors.right: parent.right
checkable: root.meModerator
pressedColor: JamiTheme.raiseHandColor
hoveredColor: JamiTheme.raiseHandColor
normalColor: JamiTheme.raiseHandColor
z: participantRect.z + 1
toolTipText: root.meModerator ? JamiStrings.lowerHand : ""
onClicked: CallAdapter.setHandRaised(uri, false)
radius: 5
}
Rectangle {
id: alertMessage
anchors.centerIn: parent
width: alertMessageTxt.width + 16
height: alertMessageTxt.contentHeight + 16
radius: 5
visible: root.muteAlertActive
color: JamiTheme.darkGreyColorOpacity
Text {
id: alertMessageTxt
text: root.muteAlertMessage
anchors.centerIn: parent
width: Math.min(participantRect.width, contentWidth)
color: JamiTheme.whiteColor
font.pointSize: JamiTheme.textFontSize
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
// Timer to decide when ParticipantOverlay fade out
Timer {
id: alertTimer
interval: JamiTheme.overlayFadeDelay
onTriggered: {
root.muteAlertActive = false
}
}
}
}
......@@ -31,7 +31,6 @@ Item {
id: root
property string uri: ""
property string bestName: ""
property bool isLocalMuted: true
property bool showSetModerator: false
property bool showUnsetModerator: false
......@@ -40,7 +39,6 @@ Item {
property bool showMaximize: false
property bool showMinimize: false
property bool showHangup: false
property bool showLowerHand: false
property int shapeHeight: 30
property int shapeRadius: 8
......@@ -57,12 +55,6 @@ Item {
Loader { sourceComponent: isBarLayout ? barComponent : rectComponent }
TextMetrics {
id: nameTextMetrics
text: bestName
font.pointSize: JamiTheme.participantFontSize
}
Component {
id: rectComponent
......@@ -86,24 +78,8 @@ Item {
}
ColumnLayout {
anchors.centerIn: parent
Text {
id: bestNameLabel
Layout.alignment: Qt.AlignHCenter | Qt.AlignVCenter
Layout.preferredWidth: Math.min(nameTextMetrics.boundingRect.width + 8,
root.width - 16)
Layout.preferredHeight: shapeHeight
text: bestName
elide: Text.ElideRight
color: JamiTheme.whiteColor
font.pointSize: JamiTheme.participantFontSize
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
}
ParticipantControlLayout {
id: buttonsRect
......@@ -119,7 +95,7 @@ Item {
id: barComponent
Control {
width: rowLayout.implicitWidth
width: buttonsRect.implicitWidth
height: shapeHeight
onHoveredChanged: root.hovered = hovered
......@@ -137,34 +113,12 @@ Item {
}
}
RowLayout {
id: rowLayout
spacing: 8
Text {
id: bestNameLabel
ParticipantControlLayout {
id: buttonsRect
Layout.leftMargin: 8
Layout.preferredWidth: Math.min(nameTextMetrics.boundingRect.width + 8,
root.width - buttonsRect.implicitWidth - 16)
Layout.preferredHeight: shapeHeight
text: bestName
elide: Text.ElideRight
color: JamiTheme.whiteColor
font.pointSize: JamiTheme.participantFontSize
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
}
ParticipantControlLayout {
id: buttonsRect
Layout.rightMargin: 8
Layout.preferredWidth: implicitWidth
Layout.preferredHeight: shapeHeight
}
Layout.rightMargin: 8
Layout.preferredWidth: implicitWidth
Layout.preferredHeight: shapeHeight
}
}
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment