1
0
Fork 0
mirror of https://git.jami.net/savoirfairelinux/jami-client-qt.git synced 2025-04-21 21:52:03 +02:00

callview: redesign

Change-Id: I8ce1e02be798104aaca9d09d9dc5d931133ada6d
This commit is contained in:
Sébastien Blin 2020-07-23 17:03:11 -04:00
parent 5f35e19260
commit 8940f3c46e
32 changed files with 750 additions and 687 deletions

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 3H5c-1.11 0-2 .9-2 2v14c0 1.1.89 2 2 2h14c1.11 0 2-.9 2-2V5c0-1.1-.89-2-2-2zm-9 14l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>

After

Width:  |  Height:  |  Size: 269 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M19 5v14H5V5h14m0-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2V5c0-1.1-.9-2-2-2z"/></svg>

After

Width:  |  Height:  |  Size: 228 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><rect fill="none" height="24" width="24"/><path d="M22,3.41l-5.29,5.29L20,12h-8V4l3.29,3.29L20.59,2L22,3.41z M3.41,22l5.29-5.29L12,20v-8H4l3.29,3.29L2,20.59L3.41,22z"/></svg>

After

Width:  |  Height:  |  Size: 291 B

View file

@ -0,0 +1,4 @@
<svg fill="#ffffff" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M12 9c-1.6 0-3.15.25-4.6.72v3.1c0 .39-.23.74-.56.9-.98.49-1.87 1.12-2.66 1.85-.18.18-.43.28-.7.28-.28 0-.53-.11-.71-.29L.29 13.08c-.18-.17-.29-.42-.29-.7 0-.28.11-.53.29-.71C3.34 8.78 7.46 7 12 7s8.66 1.78 11.71 4.67c.18.18.29.43.29.71 0 .28-.11.53-.29.71l-2.48 2.48c-.18.18-.43.29-.71.29-.27 0-.52-.11-.7-.28-.79-.74-1.69-1.36-2.67-1.85-.33-.16-.56-.5-.56-.9v-3.1C15.15 9.25 13.6 9 12 9z"/>
</svg>

After

Width:  |  Height:  |  Size: 553 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

View file

@ -0,0 +1,4 @@
<svg fill="#000000" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
<path d="M0 0h24v24H0z" fill="none"/>
<path d="M19 4H5c-1.11 0-2 .9-2 2v12c0 1.1.89 2 2 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-8 11H9.5v-2h-2v2H6V9h1.5v2.5h2V9H11v6zm7-1c0 .55-.45 1-1 1h-.75v1.5h-1.5V15H14c-.55 0-1-.45-1-1v-4c0-.55.45-1 1-1h3c.55 0 1 .45 1 1v4zm-3.5-.5h2v-3h-2v3z"/>
</svg>

After

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 218 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M21 19V5c0-1.1-.9-2-2-2H5c-1.1 0-2 .9-2 2v14c0 1.1.9 2 2 2h14c1.1 0 2-.9 2-2zM8.5 13.5l2.5 3.01L14.5 12l4.5 6H5l3.5-4.5z"/></svg>

After

Width:  |  Height:  |  Size: 258 B

View file

@ -0,0 +1,3 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/>
<path fill="white" d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>
</svg>

After

Width:  |  Height:  |  Size: 302 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" height="24" viewBox="0 0 24 24" width="24"><rect fill="none" height="24" width="24"/><polygon points="21,11 21,3 13,3 16.29,6.29 6.29,16.29 3,13 3,21 11,21 7.71,17.71 17.71,7.71"/></svg>

After

Width:  |  Height:  |  Size: 260 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M9 16h2V8H9v8zm3-14C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm1-4h2V8h-2v8z"/></svg>

After

Width:  |  Height:  |  Size: 290 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M18 11l5-5-5-5v3h-4v4h4v3zm2 4.5c-1.25 0-2.45-.2-3.57-.57-.35-.11-.74-.03-1.02.24l-2.2 2.2c-2.83-1.44-5.15-3.75-6.59-6.59l2.2-2.21c.28-.26.36-.65.25-1C8.7 6.45 8.5 5.25 8.5 4c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1 0 9.39 7.61 17 17 17 .55 0 1-.45 1-1v-3.5c0-.55-.45-1-1-1z"/></svg>

After

Width:  |  Height:  |  Size: 406 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M10 16.5l6-4.5-6-4.5v9zM12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8z"/></svg>

After

Width:  |  Height:  |  Size: 285 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0V0z" fill="none"/><path d="M20 18c1.1 0 1.99-.9 1.99-2L22 6c0-1.11-.9-2-2-2H4c-1.11 0-2 .89-2 2v10c0 1.1.89 2 2 2H0v2h24v-2h-4zm-7-3.53v-2.19c-2.78 0-4.61.85-6 2.72.56-2.67 2.11-5.33 6-5.87V7l4 3.73-4 3.74z"/></svg>

After

Width:  |  Height:  |  Size: 319 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M17 10.5V7c0-.55-.45-1-1-1H4c-.55 0-1 .45-1 1v10c0 .55.45 1 1 1h12c.55 0 1-.45 1-1v-3.5l4 4v-11l-4 4z"/></svg>

After

Width:  |  Height:  |  Size: 239 B

View file

@ -66,6 +66,7 @@
<file>src/mainview/js/incomingcallpagecreation.js</file> <file>src/mainview/js/incomingcallpagecreation.js</file>
<file>src/mainview/components/ContactSearchBar.qml</file> <file>src/mainview/components/ContactSearchBar.qml</file>
<file>src/mainview/components/VideoCallPage.qml</file> <file>src/mainview/components/VideoCallPage.qml</file>
<file>src/mainview/components/CallAdvancedOptions.qml</file>
<file>src/mainview/components/ChangeLogScrollView.qml</file> <file>src/mainview/components/ChangeLogScrollView.qml</file>
<file>src/mainview/components/ProjectCreditsScrollView.qml</file> <file>src/mainview/components/ProjectCreditsScrollView.qml</file>
<file>src/mainview/components/AccountComboBoxPopup.qml</file> <file>src/mainview/components/AccountComboBoxPopup.qml</file>
@ -75,9 +76,9 @@
<file>src/mainview/components/WelcomePageQrDialog.qml</file> <file>src/mainview/components/WelcomePageQrDialog.qml</file>
<file>src/commoncomponents/GeneralMenuItem.qml</file> <file>src/commoncomponents/GeneralMenuItem.qml</file>
<file>src/mainview/components/ConversationSmartListContextMenu.qml</file> <file>src/mainview/components/ConversationSmartListContextMenu.qml</file>
<file>src/mainview/components/CallViewContextMenu.qml</file>
<file>src/commoncomponents/GeneralMenuSeparator.qml</file> <file>src/commoncomponents/GeneralMenuSeparator.qml</file>
<file>src/mainview/components/UserProfile.qml</file> <file>src/mainview/components/UserProfile.qml</file>
<file>src/mainview/components/VideoCallPageContextMenu.qml</file>
<file>src/mainview/js/videodevicecontextmenuitemcreation.js</file> <file>src/mainview/js/videodevicecontextmenuitemcreation.js</file>
<file>src/mainview/components/VideoCallPageContextMenuDeviceItem.qml</file> <file>src/mainview/components/VideoCallPageContextMenuDeviceItem.qml</file>
<file>src/mainview/components/SelectScreen.qml</file> <file>src/mainview/components/SelectScreen.qml</file>

View file

@ -32,22 +32,23 @@
<file>images/icons/ic_arrow_tab_next_black_9dp_2x.png</file> <file>images/icons/ic_arrow_tab_next_black_9dp_2x.png</file>
<file>images/icons/ic_arrow_tab_previous_black_9dp_2x.png</file> <file>images/icons/ic_arrow_tab_previous_black_9dp_2x.png</file>
<file>images/icons/ic_block_24px.svg</file> <file>images/icons/ic_block_24px.svg</file>
<file>images/icons/ic_call_transfer_white_24px.png</file> <file>images/icons/phone_forwarded-24px.svg</file>
<file>images/icons/ic_chat_black_24dp_2x.png</file> <file>images/icons/ic_chat_black_24dp_2x.png</file>
<file>images/icons/ic_chat_white_24dp.png</file> <file>images/icons/ic_chat_white_24dp.png</file>
<file>images/icons/more_vert-24px.svg</file>
<file>images/icons/ic_check_white_18dp_2x.png</file> <file>images/icons/ic_check_white_18dp_2x.png</file>
<file>images/icons/ic_clear_24px.svg</file> <file>images/icons/ic_clear_24px.svg</file>
<file>images/icons/ic_close_white_24dp.png</file> <file>images/icons/ic_close_white_24dp.png</file>
<file>images/icons/ic_content_copy.svg</file> <file>images/icons/ic_content_copy.svg</file>
<file>images/icons/ic_delete_black_18dp_2x.png</file> <file>images/icons/ic_delete_black_18dp_2x.png</file>
<file>images/icons/ic_done_white_24dp.png</file> <file>images/icons/ic_done_white_24dp.png</file>
<file>images/icons/ic_exit_full_screen_black.png</file>
<file>images/icons/ic_folder_black_18dp_2x.png</file> <file>images/icons/ic_folder_black_18dp_2x.png</file>
<file>images/icons/ic_full_screen_black.png</file> <file>images/icons/open_in_full-24px.svg</file>
<file>images/icons/close_fullscreen-24px.svg</file>
<file>images/icons/ic_group_add_white_24dp.png</file> <file>images/icons/ic_group_add_white_24dp.png</file>
<file>images/icons/ic_high_quality_white_24dp.png</file>
<file>images/icons/ic_mic_off_white_24dp.png</file> <file>images/icons/ic_mic_off_white_24dp.png</file>
<file>images/icons/ic_pause_white_24dp.png</file> <file>images/icons/pause_circle_outline-24px.svg</file>
<file>images/icons/play_circle_outline-24px.svg</file>
<file>images/icons/ic_pause_white_100px.png</file> <file>images/icons/ic_pause_white_100px.png</file>
<file>images/icons/ic_person_add_black_24dp_2x.png</file> <file>images/icons/ic_person_add_black_24dp_2x.png</file>
<file>images/icons/ic_person_add_white_24dp.png</file> <file>images/icons/ic_person_add_white_24dp.png</file>
@ -62,6 +63,7 @@
<file>images/icons/ic_videocam_off_white_24dp.png</file> <file>images/icons/ic_videocam_off_white_24dp.png</file>
<file>images/icons/ic_videocam_white.png</file> <file>images/icons/ic_videocam_white.png</file>
<file>images/icons/ic_voicemail_white_24dp_2x.png</file> <file>images/icons/ic_voicemail_white_24dp_2x.png</file>
<file>images/icons/ic_call_end_white_24px.svg</file>
<file>images/icons/round-add-24px.svg</file> <file>images/icons/round-add-24px.svg</file>
<file>images/icons/round-arrow_drop_down-24px.svg</file> <file>images/icons/round-arrow_drop_down-24px.svg</file>
<file>images/icons/round-arrow_drop_up-24px.svg</file> <file>images/icons/round-arrow_drop_up-24px.svg</file>
@ -89,6 +91,9 @@
<file>images/icons/ic_show_password.png</file> <file>images/icons/ic_show_password.png</file>
<file>images/icons/baseline-desktop_windows-24px.svg</file> <file>images/icons/baseline-desktop_windows-24px.svg</file>
<file>images/icons/baseline-people-24px.svg</file> <file>images/icons/baseline-people-24px.svg</file>
<file>images/icons/ic_high_quality_24px.svg</file>
<file>images/icons/insert_photo-24px.svg</file>
<file>images/icons/screen_share-24px.svg</file>
<file>images/icons/round-add_a_photo-24px.svg</file> <file>images/icons/round-add_a_photo-24px.svg</file>
<file>images/icons/ic_mic_white_24dp.png</file> <file>images/icons/ic_mic_white_24dp.png</file>
<file>images/icons/icon-keypad-24.png</file> <file>images/icons/icon-keypad-24.png</file>
@ -104,6 +109,8 @@
<file>images/icons/av_icons/send-24px.svg</file> <file>images/icons/av_icons/send-24px.svg</file>
<file>images/icons/av_icons/stop-24px.svg</file> <file>images/icons/av_icons/stop-24px.svg</file>
<file>images/icons/av_icons/mic-24px.svg</file> <file>images/icons/av_icons/mic-24px.svg</file>
<file>images/icons/check_box-24px.svg</file>
<file>images/icons/check_box_outline_blank-24px.svg</file>
<file>images/icons/ic_close_black_24dp.png</file> <file>images/icons/ic_close_black_24dp.png</file>
<file>images/icons/extension_24dp.svg</file> <file>images/icons/extension_24dp.svg</file>
<file>images/icons/settings_backup_restore-black-18dp.svg</file> <file>images/icons/settings_backup_restore-black-18dp.svg</file>

View file

@ -1,11 +1,12 @@
/* /*
* Copyright (C) 2020 by Savoir-faire Linux * Copyright (C) 2020 by Savoir-faire Linux
* Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com> * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>
* Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com> * Author: Anthony Léonard <anthony.leonard@savoirfairelinux.com>
* Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com> * Author: Olivier Soldano <olivier.soldano@savoirfairelinux.com>
* Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com> * Author: Andreas Traczyk <andreas.traczyk@savoirfairelinux.com>
* Author: Isa Nanic <isa.nanic@savoirfairelinux.com> * Author: Isa Nanic <isa.nanic@savoirfairelinux.com>
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -333,7 +334,6 @@ CallAdapter::updateCallOverlay(const lrc::api::conversation::Info &convInfo)
QObject::disconnect(oneSecondTimer_); QObject::disconnect(oneSecondTimer_);
QObject::connect(oneSecondTimer_, &QTimer::timeout, [this] { setTime(accountId_, convUid_); }); QObject::connect(oneSecondTimer_, &QTimer::timeout, [this] { setTime(accountId_, convUid_); });
oneSecondTimer_->start(20); oneSecondTimer_->start(20);
auto &accInfo = LRCInstance::accountModel().getAccountInfo(accountId_); auto &accInfo = LRCInstance::accountModel().getAccountInfo(accountId_);
auto call = LRCInstance::getCallInfoForConversation(convInfo); auto call = LRCInstance::getCallInfoForConversation(convInfo);
@ -384,6 +384,15 @@ CallAdapter::hangUpThisCall()
} }
} }
bool
CallAdapter::isRecordingThisCall()
{
auto &accInfo = LRCInstance::accountModel().getAccountInfo(accountId_);
auto convInfo = LRCInstance::getConversationFromConvUid(convUid_, accountId_);
return accInfo.callModel->isRecording(convInfo.confId)
|| accInfo.callModel->isRecording(convInfo.callId);
}
void void
CallAdapter::holdThisCallToggle() CallAdapter::holdThisCallToggle()
{ {

View file

@ -1,6 +1,7 @@
/* /*
* Copyright (C) 2020 by Savoir-faire Linux * Copyright (C) 2020 by Savoir-faire Linux
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -53,6 +54,7 @@ public:
Q_INVOKABLE void muteThisCallToggle(); Q_INVOKABLE void muteThisCallToggle();
Q_INVOKABLE void recordThisCallToggle(); Q_INVOKABLE void recordThisCallToggle();
Q_INVOKABLE void videoPauseThisCallToggle(); Q_INVOKABLE void videoPauseThisCallToggle();
Q_INVOKABLE bool isRecordingThisCall();
signals: signals:
void showOutgoingCallPage(const QString &accountId, const QString &convUid); void showOutgoingCallPage(const QString &accountId, const QString &convUid);
@ -106,8 +108,7 @@ private:
/* /*
* For Call Overlay * For Call Overlay
*/ */
void setTime(const QString &accountId, const QString &convUid);
void updateCallOverlay(const lrc::api::conversation::Info &convInfo); void updateCallOverlay(const lrc::api::conversation::Info &convInfo);
void setTime(const QString &accountId, const QString &convUid);
QTimer *oneSecondTimer_; QTimer *oneSecondTimer_;
}; };

View file

@ -19,6 +19,7 @@
import QtQuick 2.14 import QtQuick 2.14
import QtQuick.Controls 2.14 import QtQuick.Controls 2.14
import net.jami.Models 1.0 import net.jami.Models 1.0
import QtGraphicalEffects 1.15
/* /*
@ -31,6 +32,9 @@ import net.jami.Models 1.0
Button { Button {
id: hoverableButton id: hoverableButton
checkable: true
checked: false
property int fontPointSize: 9 property int fontPointSize: 9
property int buttonImageHeight: hoverableButtonBackground.height - 10 property int buttonImageHeight: hoverableButtonBackground.height - 10
property int buttonImageWidth: hoverableButtonBackground.width - 10 property int buttonImageWidth: hoverableButtonBackground.width - 10
@ -43,6 +47,11 @@ Button {
property alias radius: hoverableButtonBackground.radius property alias radius: hoverableButtonBackground.radius
property alias source: hoverableButtonImage.source property alias source: hoverableButtonImage.source
property var checkedImage: null
property var baseImage: null
property var checkedColor: null
property var baseColor: null
property alias color: hoverableButton.baseColor
font.pointSize: fontPointSize font.pointSize: fontPointSize
@ -64,18 +73,31 @@ Button {
fillMode: Image.PreserveAspectFit fillMode: Image.PreserveAspectFit
mipmap: true mipmap: true
asynchronous: true asynchronous: true
source: hoverableButton.checked && checkedImage? checkedImage : baseImage
layer {
enabled: true
effect: ColorOverlay {
id: overlay
color: hoverableButton.checked && checkedColor?
checkedColor :
(baseColor? baseColor : "transparent")
}
}
} }
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
hoverEnabled: true hoverEnabled: false
onPressed: { onPressed: {
hoverableButtonBackground.color = onPressColor hoverableButtonBackground.color = onPressColor
} }
onReleased: { onReleased: {
hoverableButtonBackground.color = onReleaseColor hoverableButtonBackground.color = onReleaseColor
hoverableButton.toggle()
hoverableButton.clicked() hoverableButton.clicked()
} }
onEntered: { onEntered: {

View file

@ -113,12 +113,14 @@ Window {
function onCloseCallStack(accountId, convUid) { function onCloseCallStack(accountId, convUid) {
var responsibleCallId = ClientWrapper.utilsAdaptor.getCallId(
callStackView.responsibleAccountId, callStackView.responsibleConvUid)
var callId = ClientWrapper.utilsAdaptor.getCallId(
callStackView.responsibleAccountId, convUid)
/* /*
* Check if call stack view is on any of the stackview. * Check if call stack view is on any of the stackview.
*/ */
if (callStackView.responsibleAccountId === accountId if (responsibleCallId === callId || responsibleCallId.length === 0) {
&& callStackView.responsibleConvUid === convUid) {
if (welcomeViewStack.find(function (item, index) { if (welcomeViewStack.find(function (item, index) {
return item.objectName === "callStackViewObject" return item.objectName === "callStackViewObject"
}) || sidePanelViewStack.find(function (item, index) { }) || sidePanelViewStack.find(function (item, index) {
@ -156,7 +158,7 @@ Window {
communicationPageMessageWebView.headerUserUserNameLabelText = (name !== id) ? id : "" communicationPageMessageWebView.headerUserUserNameLabelText = (name !== id) ? id : ""
callStackView.needToCloseInCallConversationAndPotentialWindow() callStackView.needToCloseInCallConversationAndPotentialWindow()
callStackView.setCorrspondingMessageWebView( callStackView.setLinkedWebview(
communicationPageMessageWebView) communicationPageMessageWebView)
callStackView.responsibleAccountId = accountId callStackView.responsibleAccountId = accountId
@ -283,7 +285,7 @@ Window {
* Set up chatview. * Set up chatview.
*/ */
MessagesAdapter.setupChatView(currentUID) MessagesAdapter.setupChatView(currentUID)
callStackView.setCorrspondingMessageWebView( callStackView.setLinkedWebview(
communicationPageMessageWebView) communicationPageMessageWebView)
if (welcomeViewStack.find(function (item, index) { if (welcomeViewStack.find(function (item, index) {
@ -363,22 +365,6 @@ Window {
visible: false visible: false
objectName: "callStackViewObject" objectName: "callStackViewObject"
onCallPageBackButtonIsClicked: {
mainViewWindowSidePanel.deselectConversationSmartList()
if (welcomeViewStack.visible)
welcomeViewStack.pop(welcomePage)
else if (sidePanelViewStack.visible)
sidePanelViewStack.pop(mainViewWindowSidePanel)
}
onOutgoingCallPageBackButtonIsClicked: {
mainViewWindowSidePanel.deselectConversationSmartList()
if (welcomeViewStack.visible)
welcomeViewStack.pop(welcomePage)
else if (sidePanelViewStack.visible)
sidePanelViewStack.pop(mainViewWindowSidePanel)
}
} }
WelcomePage { WelcomePage {

View file

@ -31,9 +31,7 @@ Rectangle {
property string bestName: "Best Name" property string bestName: "Best Name"
property string bestId: "Best Id" property string bestId: "Best Id"
property var corrspondingMessageWebView: null property var linkedWebview: null
signal audioCallPageBackButtonIsClicked
function updateUI(accountId, convUid) { function updateUI(accountId, convUid) {
contactImgSource = "data:image/png;base64," + ClientWrapper.utilsAdaptor.getContactImageString( contactImgSource = "data:image/png;base64," + ClientWrapper.utilsAdaptor.getContactImageString(
@ -44,19 +42,19 @@ Rectangle {
bestId = (bestName !== id) ? id : "" bestId = (bestName !== id) ? id : ""
} }
function setAudioCallPageCorrspondingMessageWebView(webViewId) { function setLinkedWebview(webViewId) {
corrspondingMessageWebView = webViewId linkedWebview = webViewId
corrspondingMessageWebView.needToHideConversationInCall.disconnect( linkedWebview.needToHideConversationInCall.disconnect(
closeInCallConversation) closeInCallConversation)
corrspondingMessageWebView.needToHideConversationInCall.connect( linkedWebview.needToHideConversationInCall.connect(
closeInCallConversation) closeInCallConversation)
} }
function closeInCallConversation() { function closeInCallConversation() {
if (inAudioCallMessageWebViewStack.visible) { if (inAudioCallMessageWebViewStack.visible) {
corrspondingMessageWebView.resetMessagingHeaderBackButtonSource( linkedWebview.resetMessagingHeaderBackButtonSource(
true) true)
corrspondingMessageWebView.setMessagingHeaderButtonsVisible(true) linkedWebview.setMessagingHeaderButtonsVisible(true)
inAudioCallMessageWebViewStack.visible = false inAudioCallMessageWebViewStack.visible = false
inAudioCallMessageWebViewStack.clear() inAudioCallMessageWebViewStack.clear()
} }
@ -109,7 +107,7 @@ Rectangle {
isVideoMuted, isVideoMuted,
isRecording, isSIP, isRecording, isSIP,
isConferenceCall) isConferenceCall)
audioCallOverlay.bestName = bestName audioCallPageRect.bestName = bestName
} }
function onShowOnHoldLabel(isPaused) { function onShowOnHoldLabel(isPaused) {
@ -118,34 +116,22 @@ Rectangle {
} }
} }
onBackButtonIsClicked: {
if (inAudioCallMessageWebViewStack.visible) {
corrspondingMessageWebView.resetMessagingHeaderBackButtonSource(
true)
corrspondingMessageWebView.setMessagingHeaderButtonsVisible(
true)
inAudioCallMessageWebViewStack.visible = false
inAudioCallMessageWebViewStack.clear()
}
audioCallPageRect.audioCallPageBackButtonIsClicked()
}
onOverlayChatButtonClicked: { onOverlayChatButtonClicked: {
if (inAudioCallMessageWebViewStack.visible) { if (inAudioCallMessageWebViewStack.visible) {
corrspondingMessageWebView.resetMessagingHeaderBackButtonSource( linkedWebview.resetMessagingHeaderBackButtonSource(
true) true)
corrspondingMessageWebView.setMessagingHeaderButtonsVisible( linkedWebview.setMessagingHeaderButtonsVisible(
true) true)
inAudioCallMessageWebViewStack.visible = false inAudioCallMessageWebViewStack.visible = false
inAudioCallMessageWebViewStack.clear() inAudioCallMessageWebViewStack.clear()
} else { } else {
corrspondingMessageWebView.resetMessagingHeaderBackButtonSource( linkedWebview.resetMessagingHeaderBackButtonSource(
false) false)
corrspondingMessageWebView.setMessagingHeaderButtonsVisible( linkedWebview.setMessagingHeaderButtonsVisible(
false) false)
inAudioCallMessageWebViewStack.visible = true inAudioCallMessageWebViewStack.visible = true
inAudioCallMessageWebViewStack.push( inAudioCallMessageWebViewStack.push(
corrspondingMessageWebView) linkedWebview)
} }
} }
} }

View file

@ -0,0 +1,146 @@
/*
* Copyright (C) 2020 by Savoir-faire Linux
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtQuick.Layouts 1.14
import QtQuick.Controls.Universal 2.12
import net.jami.Models 1.0
import "../../commoncomponents"
Popup {
id: contactPickerPopup
property int type: ContactPicker.ContactPickerType.JAMICONFERENCE
/*
* Important to keep it one, since enum in c++ starts at one for conferences.
*/
enum ContactPickerType {
JAMICONFERENCE = 1,
SIPTRANSFER
}
contentWidth: 250
contentHeight: contactPickerPopupRectColumnLayout.height + 50
padding: 0
modal: true
contentItem: Rectangle {
id: contactPickerPopupRect
width: 250
HoverableButton {
id: closeButton
anchors.top: contactPickerPopupRect.top
anchors.topMargin: 5
anchors.right: contactPickerPopupRect.right
anchors.rightMargin: 5
width: 30
height: 30
radius: 30
source: "qrc:/images/icons/ic_close_black_24dp.png"
onClicked: {
contactPickerPopup.close()
}
}
ColumnLayout {
id: contactPickerPopupRectColumnLayout
anchors.top: contactPickerPopupRect.top
anchors.topMargin: 15
Text {
id: contactPickerTitle
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: contactPickerPopupRect.width
Layout.preferredHeight: 30
font.pointSize: JamiTheme.textFontSize
font.bold: true
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
text: type === ContactPicker.ContactPickerType.JAMICONFERENCE ? qsTr("Add to conference") : qsTr("Transfer this call")
}
ContactSearchBar {
id: contactPickerContactSearchBar
Layout.alignment: Qt.AlignCenter
Layout.topMargin: 5
Layout.bottomMargin: 5
Layout.preferredWidth: contactPickerPopupRect.width - 10
Layout.preferredHeight: 35
onContactSearchBarTextChanged: {
ContactAdapter.setSearchFilter(text)
}
Component.onCompleted: {
contactPickerContactSearchBar.setPlaceholderString(
qsTr("Search contacts"))
}
}
ListView {
id: contactPickerListView
Layout.alignment: Qt.AlignCenter
Layout.preferredWidth: contactPickerPopupRect.width
Layout.preferredHeight: 200
model: ContactAdapter.getContactSelectableModel(type)
clip: true
delegate: ContactPickerItemDelegate {
id: contactPickerItemDelegate
}
ScrollIndicator.vertical: ScrollIndicator {}
}
}
radius: 10
color: "white"
}
onAboutToShow: {
// Reset the model on each show.
contactPickerListView.model = ContactAdapter.getContactSelectableModel(
type)
}
background: Rectangle {
color: "transparent"
}
}

View file

@ -2,6 +2,7 @@
/* /*
* Copyright (C) 2020 by Savoir-faire Linux * Copyright (C) 2020 by Savoir-faire Linux
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -30,13 +31,21 @@ import "../../commoncomponents"
Rectangle { Rectangle {
id: callOverlayRect id: callOverlayRect
property string bestName: "Best Name"
property string timeText: "00:00" property string timeText: "00:00"
signal backButtonIsClicked
signal overlayChatButtonClicked signal overlayChatButtonClicked
function setRecording(isRecording) {
callViewContextMenu.isRecording = isRecording
recordingRect.visible = isRecording
}
function updateButtonStatus(isPaused, isAudioOnly, isAudioMuted, isVideoMuted, isRecording, isSIP, isConferenceCall) { function updateButtonStatus(isPaused, isAudioOnly, isAudioMuted, isVideoMuted, isRecording, isSIP, isConferenceCall) {
callViewContextMenu.isSIP = isSIP
callViewContextMenu.isPaused = isPaused
callViewContextMenu.isAudioOnly = isAudioOnly
callViewContextMenu.isRecording = isRecording
recordingRect.visible = isRecording
callOverlayButtonGroup.setButtonStatus(isPaused, isAudioOnly, callOverlayButtonGroup.setButtonStatus(isPaused, isAudioOnly,
isAudioMuted, isVideoMuted, isAudioMuted, isVideoMuted,
isRecording, isSIP, isRecording, isSIP,
@ -51,10 +60,6 @@ Rectangle {
ContactPickerCreation.closeContactPicker() ContactPickerCreation.closeContactPicker()
} }
function setBackTintedButtonVisible(visible) {
backTintedButton.visible = visible
}
anchors.fill: parent anchors.fill: parent
@ -88,37 +93,17 @@ Rectangle {
anchors.fill: parent anchors.fill: parent
TintedButton {
id: backTintedButton
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.leftMargin: 5
Layout.preferredWidth: 30
Layout.preferredHeight: 30
tintColor: JamiTheme.buttonTintedBlue
normalPixmapSource: "qrc:/images/icons/ic_arrow_back_white_24dp.png"
selectedPixmapSource: "qrc:/images/icons/ic_arrow_back_white_24dp.png"
onClicked: {
callOverlayRect.backButtonIsClicked()
}
onButtonEntered: {
callOverlayRectMouseArea.entered()
}
}
Text { Text {
id: jamiBestNameText id: jamiBestNameText
Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft Layout.alignment: Qt.AlignVCenter | Qt.AlignLeft
Layout.preferredWidth: overlayUpperPartRect.width / 3 Layout.preferredWidth: overlayUpperPartRect.width / 3
Layout.preferredHeight: 50 Layout.preferredHeight: 50
leftPadding: 16
font.pointSize: JamiTheme.textFontSize font.pointSize: JamiTheme.textFontSize
horizontalAlignment: Text.AlignHCenter horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: textMetricsjamiBestNameText.elidedText text: textMetricsjamiBestNameText.elidedText
@ -127,35 +112,50 @@ Rectangle {
TextMetrics { TextMetrics {
id: textMetricsjamiBestNameText id: textMetricsjamiBestNameText
font: jamiBestNameText.font font: jamiBestNameText.font
text: bestName text: videoCallPageRect.bestName
elideWidth: overlayUpperPartRect.width / 3 elideWidth: overlayUpperPartRect.width / 3
elide: Qt.ElideMiddle elide: Qt.ElideRight
} }
} }
Text { Text {
id: callTimerText id: callTimerText
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
Layout.preferredWidth: overlayUpperPartRect.width / 3 Layout.preferredWidth: overlayUpperPartRect.width / 3
Layout.preferredHeight: 50 Layout.preferredHeight: 48
font.pointSize: JamiTheme.textFontSize font.pointSize: JamiTheme.textFontSize
horizontalAlignment: Text.AlignRight
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter verticalAlignment: Text.AlignVCenter
text: textMetricscallTimerText.elidedText text: textMetricscallTimerText.elidedText
color: "white" color: "white"
TextMetrics { TextMetrics {
id: textMetricscallTimerText id: textMetricscallTimerText
font: callTimerText.font font: callTimerText.font
text: timeText text: timeText
elideWidth: overlayUpperPartRect.width / 3 elideWidth: overlayUpperPartRect.width / 3
elide: Qt.ElideMiddle elide: Qt.ElideRight
} }
} }
Rectangle {
id: recordingRect
Layout.alignment: Qt.AlignVCenter | Qt.AlignRight
height: 16
width: 16
radius: height / 2
color: "red"
SequentialAnimation on color {
loops: Animation.Infinite
running: true
ColorAnimation { from: "red"; to: "transparent"; duration: 500 }
ColorAnimation { from: "transparent"; to: "red"; duration: 500 }
}
}
Item {
width: 8
}
} }
color: "transparent" color: "transparent"
@ -215,8 +215,8 @@ Rectangle {
anchors.bottomMargin: 10 anchors.bottomMargin: 10
anchors.horizontalCenter: callOverlayRect.horizontalCenter anchors.horizontalCenter: callOverlayRect.horizontalCenter
width: callOverlayRect.width / 3 * 2 height: 56
height: 60 width: callOverlayRect.width
opacity: 0 opacity: 0
onChatButtonClicked: { onChatButtonClicked: {
@ -224,8 +224,6 @@ Rectangle {
} }
onAddToConferenceButtonClicked: { onAddToConferenceButtonClicked: {
/* /*
* Create contact picker - conference. * Create contact picker - conference.
*/ */
@ -237,24 +235,6 @@ Rectangle {
ContactPickerCreation.openContactPicker() ContactPickerCreation.openContactPicker()
} }
onTransferCallButtonClicked: {
/*
* Create contact picker - sip transfer.
*/
ContactPickerCreation.createContactPickerObjects(
ContactPicker.ContactPickerType.SIPTRANSFER,
callOverlayRect)
ContactPickerCreation.calculateCurrentGeo(
callOverlayRect.width / 2, callOverlayRect.height / 2)
ContactPickerCreation.openContactPicker()
}
onButtonEntered: {
callOverlayRectMouseArea.entered()
}
states: [ states: [
State { State {
name: "entered" name: "entered"
@ -365,10 +345,6 @@ Rectangle {
color: "transparent" color: "transparent"
onBestNameChanged: {
ContactAdapter.setCalleeDisplayName(bestName)
}
onWidthChanged: { onWidthChanged: {
ContactPickerCreation.calculateCurrentGeo(callOverlayRect.width / 2, ContactPickerCreation.calculateCurrentGeo(callOverlayRect.width / 2,
callOverlayRect.height / 2) callOverlayRect.height / 2)
@ -378,4 +354,20 @@ Rectangle {
ContactPickerCreation.calculateCurrentGeo(callOverlayRect.width / 2, ContactPickerCreation.calculateCurrentGeo(callOverlayRect.width / 2,
callOverlayRect.height / 2) callOverlayRect.height / 2)
} }
CallViewContextMenu {
id: callViewContextMenu
onTransferCallButtonClicked: {
/*
* Create contact picker - sip transfer.
*/
ContactPickerCreation.createContactPickerObjects(
ContactPicker.ContactPickerType.SIPTRANSFER,
callOverlayRect)
ContactPickerCreation.calculateCurrentGeo(
callOverlayRect.width / 2, callOverlayRect.height / 2)
ContactPickerCreation.openContactPicker()
}
}
} }

View file

@ -1,6 +1,7 @@
/* /*
* Copyright (C) 2020 by Savoir-faire Linux * Copyright (C) 2020 by Savoir-faire Linux
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
@ -26,286 +27,193 @@ import net.jami.Models 1.0
import "../../commoncomponents" import "../../commoncomponents"
Rectangle { Rectangle {
id: callOverlayButtonGroupRect id: root
/* /*
* ButtonCounts here is to make sure that flow layout margin is calculated correctly, * ButtonCounts here is to make sure that flow layout margin is calculated correctly,
* since no other methods can make buttons at the layout center. * since no other methods can make buttons at the layout center.
*/ */
property int buttonCounts: 9 property int buttonPreferredSize: 24
property int buttonPreferredSize: 30
signal buttonEntered
signal chatButtonClicked signal chatButtonClicked
signal addToConferenceButtonClicked signal addToConferenceButtonClicked
signal transferCallButtonClicked
function setButtonStatus(isPaused, isAudioOnly, isAudioMuted, isVideoMuted, isRecording, isSIP, isConferenceCall) { function setButtonStatus(isPaused, isAudioOnly, isAudioMuted, isVideoMuted, isRecording, isSIP, isConferenceCall) {
noVideoButton.visible = !isAudioOnly noVideoButton.visible = !isAudioOnly
addToConferenceButton.visible = !isSIP addToConferenceButton.visible = !isSIP
transferCallButton.visible = isSIP
sipInputPanelButton.visible = isSIP
noMicButton.setChecked(isAudioMuted) noMicButton.checked = isAudioMuted
noVideoButton.setChecked(isVideoMuted) noVideoButton.checked = isVideoMuted
recButton.setChecked(isRecording)
holdButton.setChecked(isPaused)
holdButton.visible = !isConferenceCall
} }
function calculateFlowMargin() { color: "transparent"
return (callOverlayButtonGroupRect.width - buttonCounts * buttonPreferredSize z: 2
- callOverlayButtonGroupRectFlow.spacing * (buttonCounts - 1)) / 2
}
Flow { RowLayout {
id: callOverlayButtonGroupRectFlow id: callOverlayButtonGroup
spacing: 8
height: 56
anchors.fill: parent anchors.fill: parent
Item {
/* Layout.preferredWidth: {
* Minus 1 is to make sure that button will not flick when doing flow layout. // 6 is the number of button
*/ // If ~ 500px, go into wide mode
anchors.leftMargin: calculateFlowMargin( (callOverlayButtonGroup.width < buttonPreferredSize * 12 - callOverlayButtonGroup.spacing * 6 + 300)?
) < 0 ? 0 : calculateFlowMargin() - 1 0 : callOverlayButtonGroup.width / 2 - buttonPreferredSize * 3 - callOverlayButtonGroup.spacing
anchors.rightMargin: calculateFlowMargin(
) < 0 ? 0 : calculateFlowMargin() - 1
spacing: 10
TintedButton {
id: hangUpButton
width: buttonPreferredSize
height: buttonPreferredSize
tintColor: JamiTheme.hangUpButtonTintedRed
normalPixmapSource: "qrc:/images/icons/ic_close_white_24dp.png"
selectedPixmapSource: "qrc:/images/icons/ic_close_white_24dp.png"
onButtonEntered: {
callOverlayButtonGroupRect.buttonEntered()
}
onClicked: {
CallAdapter.hangUpThisCall()
}
onVisibleChanged: {
if (this.visible)
buttonCounts++
else
buttonCounts--
} }
} }
TintedButton { HoverableButton {
id: holdButton
width: buttonPreferredSize
height: buttonPreferredSize
tintColor: JamiTheme.buttonTintedBlue
normalPixmapSource: "qrc:/images/icons/ic_pause_white_24dp.png"
selectedPixmapSource: "qrc:/images/icons/ic_play_white_24dp.png"
onClicked: {
CallAdapter.holdThisCallToggle()
}
onButtonEntered: {
callOverlayButtonGroupRect.buttonEntered()
}
onVisibleChanged: {
if (this.visible)
buttonCounts++
else
buttonCounts--
}
}
TintedButton {
id: addToConferenceButton
width: buttonPreferredSize
height: buttonPreferredSize
tintColor: JamiTheme.buttonTintedBlue
normalPixmapSource: "qrc:/images/icons/ic_group_add_white_24dp.png"
selectedPixmapSource: "qrc:/images/icons/ic_group_add_white_24dp.png"
onButtonEntered: {
callOverlayButtonGroupRect.buttonEntered()
}
onClicked: {
callOverlayButtonGroupRect.addToConferenceButtonClicked()
}
onVisibleChanged: {
if (this.visible)
buttonCounts++
else
buttonCounts--
}
}
TintedButton {
id: transferCallButton
width: buttonPreferredSize
height: buttonPreferredSize
tintColor: JamiTheme.buttonTintedBlue
normalPixmapSource: "qrc:/images/icons/ic_call_transfer_white_24px.png"
selectedPixmapSource: "qrc:/images/icons/ic_call_transfer_white_24px.png"
onButtonEntered: {
callOverlayButtonGroupRect.buttonEntered()
}
onClicked: {
callOverlayButtonGroupRect.transferCallButtonClicked()
}
onVisibleChanged: {
if (this.visible)
buttonCounts++
else
buttonCounts--
}
}
TintedButton {
id: chatButton
width: buttonPreferredSize
height: buttonPreferredSize
tintColor: JamiTheme.buttonTintedBlue
normalPixmapSource: "qrc:/images/icons/ic_chat_white_24dp.png"
selectedPixmapSource: "qrc:/images/icons/ic_chat_white_24dp.png"
onClicked: {
callOverlayButtonGroupRect.chatButtonClicked()
}
onButtonEntered: {
callOverlayButtonGroupRect.buttonEntered()
}
onVisibleChanged: {
if (this.visible)
buttonCounts++
else
buttonCounts--
}
}
TintedButton {
id: noMicButton id: noMicButton
width: buttonPreferredSize Layout.preferredWidth: buttonPreferredSize * 2
height: buttonPreferredSize Layout.preferredHeight: buttonPreferredSize * 2
tintColor: JamiTheme.buttonTintedBlue backgroundColor: Qt.rgba(0, 0, 0, 0.75)
normalPixmapSource: "qrc:/images/icons/ic_mic_white_24dp.png" onEnterColor: Qt.rgba(0, 0, 0, 0.6)
selectedPixmapSource: "qrc:/images/icons/ic_mic_off_white_24dp.png" onPressColor: Qt.rgba(0, 0, 0, 0.5)
onReleaseColor: Qt.rgba(0, 0, 0, 0.6)
onExitColor: Qt.rgba(0, 0, 0, 0.75)
buttonImageHeight: buttonPreferredSize
buttonImageWidth: buttonPreferredSize
baseImage: "qrc:/images/icons/ic_mic_white_24dp.png"
checkedImage: "qrc:/images/icons/ic_mic_off_white_24dp.png"
baseColor: "white"
checkedColor: JamiTheme.declineButtonPressedRed
radius: 30
onClicked: { onClicked: {
CallAdapter.muteThisCallToggle() CallAdapter.muteThisCallToggle()
} }
}
onButtonEntered: { HoverableButton {
callOverlayButtonGroupRect.buttonEntered() id: hangUpButton
}
onVisibleChanged: { Layout.preferredWidth: buttonPreferredSize * 2
if (this.visible) Layout.preferredHeight: buttonPreferredSize * 2
buttonCounts++
else backgroundColor: JamiTheme.declineButtonRed
buttonCounts-- onEnterColor: JamiTheme.declineButtonHoverRed
onPressColor: JamiTheme.declineButtonPressedRed
onReleaseColor: JamiTheme.declineButtonHoverRed
onExitColor: JamiTheme.declineButtonRed
buttonImageHeight: buttonPreferredSize
buttonImageWidth: buttonPreferredSize
source: "qrc:/images/icons/ic_call_end_white_24px.svg"
color: "white"
radius: 30
onClicked: {
CallAdapter.hangUpThisCall()
} }
} }
TintedButton { HoverableButton {
id: noVideoButton id: noVideoButton
width: buttonPreferredSize Layout.preferredWidth: buttonPreferredSize * 2
height: buttonPreferredSize Layout.preferredHeight: buttonPreferredSize * 2
tintColor: JamiTheme.buttonTintedBlue backgroundColor: Qt.rgba(0, 0, 0, 0.75)
normalPixmapSource: "qrc:/images/icons/ic_videocam_white.png" onEnterColor: Qt.rgba(0, 0, 0, 0.6)
selectedPixmapSource: "qrc:/images/icons/ic_videocam_off_white_24dp.png" onPressColor: Qt.rgba(0, 0, 0, 0.5)
onReleaseColor: Qt.rgba(0, 0, 0, 0.6)
onExitColor: Qt.rgba(0, 0, 0, 0.75)
onButtonEntered: { buttonImageHeight: buttonPreferredSize
callOverlayButtonGroupRect.buttonEntered() buttonImageWidth: buttonPreferredSize
} baseImage: "qrc:/images/icons/ic_videocam_white.png"
checkedImage: "qrc:/images/icons/ic_videocam_off_white_24dp.png"
baseColor: "white"
checkedColor: JamiTheme.declineButtonPressedRed
radius: 30
onClicked: { onClicked: {
CallAdapter.videoPauseThisCallToggle() CallAdapter.videoPauseThisCallToggle()
} }
onVisibleChanged: {
if (this.visible)
buttonCounts++
else
buttonCounts--
}
} }
TintedButton { Item {
id: recButton Layout.fillWidth: true
}
width: buttonPreferredSize HoverableButton {
height: buttonPreferredSize id: addToConferenceButton
tintColor: JamiTheme.buttonTintedBlue Layout.preferredWidth: buttonPreferredSize * 2
normalPixmapSource: "qrc:/images/icons/ic_voicemail_white_24dp_2x.png" Layout.preferredHeight: buttonPreferredSize * 2
selectedPixmapSource: "qrc:/images/icons/ic_voicemail_white_24dp_2x.png"
onButtonEntered: { backgroundColor: Qt.rgba(0, 0, 0, 0.75)
callOverlayButtonGroupRect.buttonEntered() onEnterColor: Qt.rgba(0, 0, 0, 0.6)
} onPressColor: Qt.rgba(0, 0, 0, 0.5)
onReleaseColor: Qt.rgba(0, 0, 0, 0.6)
onExitColor: Qt.rgba(0, 0, 0, 0.75)
buttonImageHeight: buttonPreferredSize
buttonImageWidth: buttonPreferredSize
color: "white"
source: "qrc:/images/icons/ic_group_add_white_24dp.png"
radius: 30
onClicked: { onClicked: {
CallAdapter.recordThisCallToggle() root.addToConferenceButtonClicked()
}
onVisibleChanged: {
if (this.visible)
buttonCounts++
else
buttonCounts--
} }
} }
TintedButton { HoverableButton {
id: sipInputPanelButton id: chatButton
width: buttonPreferredSize Layout.preferredWidth: buttonPreferredSize * 2
height: buttonPreferredSize Layout.preferredHeight: buttonPreferredSize * 2
tintColor: JamiTheme.buttonTintedBlue backgroundColor: Qt.rgba(0, 0, 0, 0.75)
normalPixmapSource: "qrc:/images/icons/icon-keypad-24-2x.png" onEnterColor: Qt.rgba(0, 0, 0, 0.6)
selectedPixmapSource: "qrc:/images/icons/icon-keypad-24-2x.png" onPressColor: Qt.rgba(0, 0, 0, 0.5)
onReleaseColor: Qt.rgba(0, 0, 0, 0.6)
onExitColor: Qt.rgba(0, 0, 0, 0.75)
onButtonEntered: { buttonImageHeight: buttonPreferredSize
callOverlayButtonGroupRect.buttonEntered() buttonImageWidth: buttonPreferredSize
} color: "white"
source: "qrc:/images/icons/ic_chat_white_24dp.png"
radius: 30
onVisibleChanged: { onClicked: {
if (this.visible) root.chatButtonClicked()
buttonCounts++
else
buttonCounts--
} }
} }
HoverableButton {
id: optionsButton
Layout.preferredWidth: buttonPreferredSize * 2
Layout.preferredHeight: buttonPreferredSize * 2
backgroundColor: Qt.rgba(0, 0, 0, 0.75)
onEnterColor: Qt.rgba(0, 0, 0, 0.6)
onPressColor: Qt.rgba(0, 0, 0, 0.5)
onReleaseColor: Qt.rgba(0, 0, 0, 0.6)
onExitColor: Qt.rgba(0, 0, 0, 0.75)
buttonImageHeight: buttonPreferredSize
buttonImageWidth: buttonPreferredSize
source: "qrc:/images/icons/more_vert-24px.svg"
radius: 30
onClicked: {
var rectPos = mapToItem(callStackViewWindow, optionsButton.x, optionsButton.y)
callViewContextMenu.activate()
callViewContextMenu.x = rectPos.x + optionsButton.width/2 - callViewContextMenu.width/2
callViewContextMenu.y = rectPos.y - 12 - callViewContextMenu.height
}
}
Item { Layout.preferredWidth: 8 }
} }
color: "transparent"
} }

View file

@ -44,9 +44,6 @@ Rectangle {
property string responsibleConvUid: "" property string responsibleConvUid: ""
property string responsibleAccountId: "" property string responsibleAccountId: ""
signal outgoingCallPageBackButtonIsClicked
signal callPageBackButtonIsClicked
function needToCloseInCallConversationAndPotentialWindow() { function needToCloseInCallConversationAndPotentialWindow() {
audioCallPage.closeInCallConversation() audioCallPage.closeInCallConversation()
videoCallPage.closeInCallConversation() videoCallPage.closeInCallConversation()
@ -58,13 +55,12 @@ Rectangle {
audioCallPage.closeContextMenuAndRelatedWindows() audioCallPage.closeContextMenuAndRelatedWindows()
VideoCallFullScreenWindowContainerCreation.closeVideoCallFullScreenWindowContainer() VideoCallFullScreenWindowContainerCreation.closeVideoCallFullScreenWindowContainer()
videoCallPage.setCallOverlayBackButtonVisible(true)
videoCallPage.closeContextMenuAndRelatedWindows() videoCallPage.closeContextMenuAndRelatedWindows()
} }
function setCorrspondingMessageWebView(webViewId) { function setLinkedWebview(webViewId) {
audioCallPage.setAudioCallPageCorrspondingMessageWebView(webViewId) audioCallPage.setLinkedWebview(webViewId)
videoCallPage.setVideoCallPageCorrspondingMessageWebView(webViewId) videoCallPage.setLinkedWebview(webViewId)
} }
function updateCorrspondingUI() { function updateCorrspondingUI() {
@ -172,10 +168,6 @@ Rectangle {
id: audioCallPage id: audioCallPage
property int stackNumber: 0 property int stackNumber: 0
onAudioCallPageBackButtonIsClicked: {
callStackViewWindow.callPageBackButtonIsClicked()
}
} }
OutgoingCallPage { OutgoingCallPage {
@ -186,32 +178,24 @@ Rectangle {
onCallCancelButtonIsClicked: { onCallCancelButtonIsClicked: {
CallAdapter.hangUpACall(responsibleAccountId, responsibleConvUid) CallAdapter.hangUpACall(responsibleAccountId, responsibleConvUid)
} }
onBackButtonIsClicked: {
callStackViewWindow.outgoingCallPageBackButtonIsClicked()
}
} }
VideoCallPage { VideoCallPage {
id: videoCallPage id: videoCallPage
property int stackNumber: 2 property int stackNumber: 2
property bool isFullscreen: false
onVideoCallPageBackButtonIsClicked: {
callStackViewWindow.callPageBackButtonIsClicked()
}
onNeedToShowInFullScreen: { onNeedToShowInFullScreen: {
isFullscreen = !isFullscreen
VideoCallFullScreenWindowContainerCreation.createvideoCallFullScreenWindowContainerObject() VideoCallFullScreenWindowContainerCreation.createvideoCallFullScreenWindowContainerObject()
if (!VideoCallFullScreenWindowContainerCreation.checkIfVisible()) { if (!VideoCallFullScreenWindowContainerCreation.checkIfVisible()) {
VideoCallFullScreenWindowContainerCreation.setAsContainerChild( VideoCallFullScreenWindowContainerCreation.setAsContainerChild(
videoCallPage) videoCallPage)
videoCallPage.setCallOverlayBackButtonVisible(false)
VideoCallFullScreenWindowContainerCreation.showVideoCallFullScreenWindowContainer() VideoCallFullScreenWindowContainerCreation.showVideoCallFullScreenWindowContainer()
} else { } else {
videoCallPage.parent = callStackMainView videoCallPage.parent = callStackMainView
videoCallPage.setCallOverlayBackButtonVisible(true)
VideoCallFullScreenWindowContainerCreation.closeVideoCallFullScreenWindowContainer() VideoCallFullScreenWindowContainerCreation.closeVideoCallFullScreenWindowContainer()
} }
} }

View file

@ -1,7 +1,7 @@
/* /*
* Copyright (C) 2020 by Savoir-faire Linux * Copyright (C) 2020 by Savoir-faire Linux
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -18,44 +18,45 @@
*/ */
import QtQuick 2.14 import QtQuick 2.14
import QtQuick.Controls 2.14 import QtQuick.Controls 2.14
import QtGraphicalEffects 1.12
import net.jami.Models 1.0 import net.jami.Models 1.0
import "../../commoncomponents" import "../../commoncomponents"
import "../js/videodevicecontextmenuitemcreation.js" as VideoDeviceContextMenuItemCreation import "../js/videodevicecontextmenuitemcreation.js" as VideoDeviceContextMenuItemCreation
import "../js/selectscreenwindowcreation.js" as SelectScreenWindowCreation import "../js/selectscreenwindowcreation.js" as SelectScreenWindowCreation
import "../js/screenrubberbandcreation.js" as ScreenRubberBandCreation
Menu { Menu {
id: contextMenu id: root
property string responsibleAccountId: ""
property string responsibleConvUid: ""
property int generalMenuSeparatorCount: 0 property int generalMenuSeparatorCount: 0
property int commonBorderWidth: 2 property int commonBorderWidth: 1
font.pointSize: JamiTheme.textFontSize+3
signal fullScreenNeeded property bool isSIP: false
property bool isPaused: false
property bool isAudioOnly: false
property bool isRecording: false
signal transferCallButtonClicked
function activate() { function activate() {
var deviceContextMenuInfoMap = AvAdapter.populateVideoDeviceContextMenuItem() var deviceContextMenuInfoMap = AvAdapter.populateVideoDeviceContextMenuItem()
/* /*
* Somehow, the map size is undefined, so use this instead. * Somehow, the map size is undefined, so use this instead.
*/ */
var mapSize = deviceContextMenuInfoMap["size"] var mapSize = deviceContextMenuInfoMap["size"]
var count = 1 var count = 2
for (var deviceName in deviceContextMenuInfoMap) { for (var deviceName in deviceContextMenuInfoMap) {
if (deviceName === "size") if (deviceName === "size" || root.isAudioOnly)
continue continue
if (videoDeviceItem.itemName === "No video device") { if (videoDeviceItem.itemName === "No video device") {
videoDeviceItem.checkable = true videoDeviceItem.checkable = true
videoDeviceItem.itemName = deviceName videoDeviceItem.itemName = deviceName
videoDeviceItem.checked = deviceContextMenuInfoMap[deviceName] videoDeviceItem.checked = deviceContextMenuInfoMap[deviceName]
if (count === mapSize) if (count === mapSize)
contextMenu.open() root.open()
} else { } else {
VideoDeviceContextMenuItemCreation.createVideoDeviceContextMenuItemObjects( VideoDeviceContextMenuItemCreation.createVideoDeviceContextMenuItemObjects(
deviceName, deviceContextMenuInfoMap[deviceName], deviceName, deviceContextMenuInfoMap[deviceName],
@ -63,14 +64,18 @@ Menu {
} }
count++ count++
} }
root.open()
} }
function closePotentialWindows() { Component.onCompleted: {
SelectScreenWindowCreation.destorySelectScreenWindow() VideoDeviceContextMenuItemCreation.setVideoContextMenuObject(root)
ScreenRubberBandCreation.destoryScreenRubberBandWindow()
} }
implicitWidth: 200
onClosed: {
videoDeviceItem.itemName = "No video device"
VideoDeviceContextMenuItemCreation.removeCreatedItems()
}
JamiFileDialog { JamiFileDialog {
id: jamiFileDialog id: jamiFileDialog
@ -78,32 +83,112 @@ Menu {
mode: JamiFileDialog.Mode.OpenFile mode: JamiFileDialog.Mode.OpenFile
onAccepted: { onAccepted: {
var filePath = jamiFileDialog.file // No need to trim file:///.
AvAdapter.shareFile(jamiFileDialog.file)
/*
* No need to trim file:///.
*/
AvAdapter.shareFile(filePath)
} }
} }
/* /*
* All GeneralMenuItems should remain the same width / height. * All GeneralMenuItems should remain the same width / height.
* The first videoDeviceItem is to make sure the border is correct.
*/ */
VideoCallPageContextMenuDeviceItem { GeneralMenuItem {
id: videoDeviceItem id: holdCallButton
topBorderWidth: commonBorderWidth visible: isSIP
contextMenuPreferredWidth: contextMenu.implicitWidth height: isSIP? undefined : 0
itemName: isPaused? qsTr("Resume call") : qsTr("Hold call")
iconSource: isPaused? "qrc:/images/icons/play_circle_outline-24px.svg" : "qrc:/images/icons/pause_circle_outline-24px.svg"
leftBorderWidth: commonBorderWidth
rightBorderWidth: commonBorderWidth
onClicked: {
CallAdapter.holdThisCallToggle()
root.close()
}
}
GeneralMenuItem {
id: transferCallButton
visible: isSIP
height: isSIP? undefined : 0
itemName: qsTr("Transfer call")
iconSource: "qrc:/images/icons/phone_forwarded-24px.svg"
leftBorderWidth: commonBorderWidth
rightBorderWidth: commonBorderWidth
onClicked: {
root.transferCallButtonClicked()
root.close()
}
} }
GeneralMenuSeparator { GeneralMenuSeparator {
preferredWidth: videoDeviceItem.preferredWidth preferredWidth: startRecordingItem.preferredWidth
preferredHeight: commonBorderWidth preferredHeight: commonBorderWidth
visible: isSIP
height: isSIP? undefined : 0
Component.onCompleted: {
generalMenuSeparatorCount++
}
}
GeneralMenuItem {
id: startRecordingItem
itemName: isRecording? qsTr("Stop recording") : qsTr("Start recording")
iconSource: "qrc:/images/icons/ic_video_call_24px.svg"
leftBorderWidth: commonBorderWidth
rightBorderWidth: commonBorderWidth
onClicked: {
root.close()
CallAdapter.recordThisCallToggle()
}
}
GeneralMenuItem {
id: fullScreenItem
itemName: videoCallPage.isFullscreen ? qsTr("Exit full screen") : qsTr(
"Full screen mode")
iconSource: videoCallPage.isFullscreen ? "qrc:/images/icons/close_fullscreen-24px.svg" : "qrc:/images/icons/open_in_full-24px.svg"
leftBorderWidth: commonBorderWidth
rightBorderWidth: commonBorderWidth
onClicked: {
root.close()
videoCallPageRect.needToShowInFullScreen()
}
}
GeneralMenuSeparator {
preferredWidth: startRecordingItem.preferredWidth
preferredHeight: commonBorderWidth
Component.onCompleted: {
generalMenuSeparatorCount++
}
}
VideoCallPageContextMenuDeviceItem {
id: videoDeviceItem
visible: !isAudioOnly
height: !isAudioOnly? undefined : 0
contextMenuPreferredWidth: root.implicitWidth
}
GeneralMenuSeparator {
preferredWidth: startRecordingItem.preferredWidth
preferredHeight: commonBorderWidth
visible: !isAudioOnly
height: !isAudioOnly? undefined : 0
Component.onCompleted: { Component.onCompleted: {
generalMenuSeparatorCount++ generalMenuSeparatorCount++
} }
@ -113,11 +198,14 @@ Menu {
id: shareEntireScreenItem id: shareEntireScreenItem
itemName: qsTr("Share entire screen") itemName: qsTr("Share entire screen")
iconSource: "qrc:/images/icons/screen_share-24px.svg"
leftBorderWidth: commonBorderWidth leftBorderWidth: commonBorderWidth
rightBorderWidth: commonBorderWidth rightBorderWidth: commonBorderWidth
visible: !isAudioOnly
height: !isAudioOnly? undefined : 0
onClicked: { onClicked: {
contextMenu.close() root.close()
if (Qt.application.screens.length === 1) { if (Qt.application.screens.length === 1) {
AvAdapter.shareEntireScreen(0) AvAdapter.shareEntireScreen(0)
} else { } else {
@ -131,11 +219,14 @@ Menu {
id: shareScreenAreaItem id: shareScreenAreaItem
itemName: qsTr("Share screen area") itemName: qsTr("Share screen area")
iconSource: "qrc:/images/icons/screen_share-24px.svg"
leftBorderWidth: commonBorderWidth leftBorderWidth: commonBorderWidth
rightBorderWidth: commonBorderWidth rightBorderWidth: commonBorderWidth
visible: !isAudioOnly
height: !isAudioOnly? undefined : 0
onClicked: { onClicked: {
contextMenu.close() root.close()
if (Qt.application.screens.length === 1) { if (Qt.application.screens.length === 1) {
ScreenRubberBandCreation.createScreenRubberBandWindowObject( ScreenRubberBandCreation.createScreenRubberBandWindowObject(
null, 0) null, 0)
@ -151,59 +242,56 @@ Menu {
id: shareFileItem id: shareFileItem
itemName: qsTr("Share file") itemName: qsTr("Share file")
iconSource: "qrc:/images/icons/insert_photo-24px.svg"
leftBorderWidth: commonBorderWidth leftBorderWidth: commonBorderWidth
rightBorderWidth: commonBorderWidth rightBorderWidth: commonBorderWidth
visible: !isAudioOnly
height: !isAudioOnly? undefined : 0
onClicked: { onClicked: {
contextMenu.close() root.close()
jamiFileDialog.open() jamiFileDialog.open()
} }
} }
GeneralMenuSeparator { /* TODO: In the future we want to implement this
preferredWidth: videoDeviceItem.preferredWidth
preferredHeight: commonBorderWidth
Component.onCompleted: { GeneralMenuItem {
generalMenuSeparatorCount++ id: advancedInfosItem
itemName: qsTr("Advanced informations")
iconSource: "qrc:/images/icons/info-24px.svg"
leftBorderWidth: commonBorderWidth
rightBorderWidth: commonBorderWidth
onClicked: {
root.close()
} }
} }
GeneralMenuItem { GeneralMenuItem {
id: fullScreenItem id: pluginItem
property bool isFullScreen: false itemName: qsTr("Toggle plugin")
iconSource: "qrc:/images/icons/extension_24dp.svg"
itemName: isFullScreen ? qsTr("Exit full screen") : qsTr(
"Full screen mode")
iconSource: isFullScreen ? "qrc:/images/icons/ic_exit_full_screen_black.png" : "qrc:/images/icons/ic_full_screen_black.png"
leftBorderWidth: commonBorderWidth leftBorderWidth: commonBorderWidth
rightBorderWidth: commonBorderWidth rightBorderWidth: commonBorderWidth
bottomBorderWidth: commonBorderWidth
onClicked: { onClicked: {
contextMenu.close() root.close()
contextMenu.fullScreenNeeded()
isFullScreen = !isFullScreen
} }
} }*/
onClosed: {
videoDeviceItem.itemName = "No video device"
VideoDeviceContextMenuItemCreation.removeCreatedItems()
}
Component.onCompleted: {
VideoDeviceContextMenuItemCreation.setVideoContextMenuObject(
contextMenu)
}
background: Rectangle { background: Rectangle {
implicitWidth: contextMenu.implicitWidth implicitWidth: startRecordingItem.preferredWidth
implicitHeight: videoDeviceItem.preferredHeight implicitHeight: startRecordingItem.preferredHeight
* (contextMenu.count - generalMenuSeparatorCount) * (root.count
- (isSIP? 0 : 2)
- (isAudioOnly? 6 : 0)
- generalMenuSeparatorCount)
border.width: commonBorderWidth border.width: commonBorderWidth
border.color: JamiTheme.tabbarBorderColor border.color: JamiTheme.tabbarBorderColor
} }
} }

View file

@ -34,7 +34,6 @@ Rectangle {
property string bestId: "Best Id" property string bestId: "Best Id"
signal callCancelButtonIsClicked signal callCancelButtonIsClicked
signal backButtonIsClicked
function updateUI(accountId, convUid) { function updateUI(accountId, convUid) {
contactImgSource = "data:image/png;base64," + ClientWrapper.utilsAdaptor.getContactImageString( contactImgSource = "data:image/png;base64," + ClientWrapper.utilsAdaptor.getContactImageString(
@ -58,26 +57,6 @@ Rectangle {
acceptedButtons: Qt.RightButton acceptedButtons: Qt.RightButton
} }
TintedButton {
id: backTintedButton
anchors.top: outgoingCallPageRect.top
anchors.topMargin: 10
anchors.left: outgoingCallPageRect.left
anchors.leftMargin: 5
width: 30
height: 30
tintColor: JamiTheme.buttonTintedBlue
normalPixmapSource: "qrc:/images/icons/ic_arrow_back_white_24dp.png"
selectedPixmapSource: "qrc:/images/icons/ic_arrow_back_white_24dp.png"
onClicked: {
outgoingCallPageRect.backButtonIsClicked()
}
}
ColumnLayout { ColumnLayout {
id: outgoingCallPageRectColumnLayout id: outgoingCallPageRectColumnLayout

View file

@ -2,6 +2,7 @@
/* /*
* Copyright (C) 2020 by Savoir-faire Linux * Copyright (C) 2020 by Savoir-faire Linux
* Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com> * Author: Mingrui Zhang <mingrui.zhang@savoirfairelinux.com>
* Author: Sébastien Blin <sebastien.blin@savoirfairelinux.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -32,12 +33,12 @@ Rectangle {
property string bestId: "Best Id" property string bestId: "Best Id"
property variant clickPos: "1,1" property variant clickPos: "1,1"
property int previewMargin: 15 property int previewMargin: 15
property int previewMarginY: previewMargin + 56
property int previewToX: 0 property int previewToX: 0
property int previewToY: 0 property int previewToY: 0
property var corrspondingMessageWebView: null property var linkedWebview: null
signal videoCallPageBackButtonIsClicked
signal needToShowInFullScreen signal needToShowInFullScreen
function updateUI(accountId, convUid) { function updateUI(accountId, convUid) {
@ -51,27 +52,25 @@ Rectangle {
distantRenderer.setRendererId(id) distantRenderer.setRendererId(id)
} }
function setVideoCallPageCorrspondingMessageWebView(webViewId) { function setLinkedWebview(webViewId) {
corrspondingMessageWebView = webViewId linkedWebview = webViewId
corrspondingMessageWebView.needToHideConversationInCall.disconnect( linkedWebview.needToHideConversationInCall.disconnect(
closeInCallConversation) closeInCallConversation)
corrspondingMessageWebView.needToHideConversationInCall.connect( linkedWebview.needToHideConversationInCall.connect(
closeInCallConversation) closeInCallConversation)
} }
function closeInCallConversation() { function closeInCallConversation() {
if (inVideoCallMessageWebViewStack.visible) { if (inVideoCallMessageWebViewStack.visible) {
corrspondingMessageWebView.resetMessagingHeaderBackButtonSource( linkedWebview.resetMessagingHeaderBackButtonSource(
true) true)
corrspondingMessageWebView.setMessagingHeaderButtonsVisible(true) linkedWebview.setMessagingHeaderButtonsVisible(true)
inVideoCallMessageWebViewStack.visible = false inVideoCallMessageWebViewStack.visible = false
inVideoCallMessageWebViewStack.clear() inVideoCallMessageWebViewStack.clear()
} }
} }
function closeContextMenuAndRelatedWindows() { function closeContextMenuAndRelatedWindows() {
videoCallPageContextMenu.closePotentialWindows()
videoCallPageContextMenu.close()
videoCallOverlay.closePotentialContactPicker() videoCallOverlay.closePotentialContactPicker()
} }
@ -99,7 +98,7 @@ Rectangle {
return videoCallPageMainRect.width - previewRenderer.width - previewMargin return videoCallPageMainRect.width - previewRenderer.width - previewMargin
}) })
previewToY = Qt.binding(function () { previewToY = Qt.binding(function () {
return videoCallPageMainRect.height - previewRenderer.height - previewMargin return videoCallPageMainRect.height - previewRenderer.height - previewMarginY
}) })
} else { } else {
@ -110,7 +109,7 @@ Rectangle {
previewToX = Qt.binding(function () { previewToX = Qt.binding(function () {
return videoCallPageMainRect.width - previewRenderer.width - previewMargin return videoCallPageMainRect.width - previewRenderer.width - previewMargin
}) })
previewToY = previewMargin previewToY = previewMarginY
} }
} else { } else {
if (previewRendererCenter.y >= distantRendererCenter.y) { if (previewRendererCenter.y >= distantRendererCenter.y) {
@ -121,7 +120,7 @@ Rectangle {
*/ */
previewToX = previewMargin previewToX = previewMargin
previewToY = Qt.binding(function () { previewToY = Qt.binding(function () {
return videoCallPageMainRect.height - previewRenderer.height - previewMargin return videoCallPageMainRect.height - previewRenderer.height - previewMarginY
}) })
} else { } else {
@ -130,16 +129,12 @@ Rectangle {
* Top left. * Top left.
*/ */
previewToX = previewMargin previewToX = previewMargin
previewToY = previewMargin previewToY = previewMarginY
} }
} }
previewRenderer.state = "geoChanging" previewRenderer.state = "geoChanging"
} }
function setCallOverlayBackButtonVisible(visible) {
videoCallOverlay.setBackTintedButtonVisible(visible)
}
anchors.fill: parent anchors.fill: parent
SplitView { SplitView {
@ -155,182 +150,182 @@ Rectangle {
color: SplitHandle.pressed ? JamiTheme.pressColor : (SplitHandle.hovered ? JamiTheme.hoverColor : JamiTheme.tabbarBorderColor) color: SplitHandle.pressed ? JamiTheme.pressColor : (SplitHandle.hovered ? JamiTheme.hoverColor : JamiTheme.tabbarBorderColor)
} }
Rectangle { Rectangle {
id: videoCallPageMainRect id: videoCallPageMainRect
SplitView.preferredHeight: (videoCallPageRect.height / 3) * 2 SplitView.preferredHeight: (videoCallPageRect.height / 3) * 2
SplitView.minimumHeight: videoCallPageRect.height / 2 + 20 SplitView.minimumHeight: videoCallPageRect.height / 2 + 20
SplitView.fillWidth: true SplitView.fillWidth: true
CallOverlay { MouseArea {
id: videoCallOverlay
anchors.fill: parent anchors.fill: parent
hoverEnabled: true
propagateComposedEvents: true
Connections { acceptedButtons: Qt.LeftButton
target: CallAdapter
function onUpdateTimeText(time) { onDoubleClicked: {
videoCallOverlay.timeText = time needToShowInFullScreen()
}
function onUpdateOverlay(isPaused, isAudioOnly, isAudioMuted, isVideoMuted, isRecording, isSIP, isConferenceCall, bestName) {
videoCallOverlay.showOnHoldImage(isPaused)
videoCallOverlay.updateButtonStatus(isPaused,
isAudioOnly,
isAudioMuted,
isVideoMuted,
isRecording, isSIP,
isConferenceCall)
videoCallOverlay.bestName = bestName
}
function onShowOnHoldLabel(isPaused) {
videoCallOverlay.showOnHoldImage(isPaused)
}
} }
onBackButtonIsClicked: { CallOverlay {
if (inVideoCallMessageWebViewStack.visible) { id: videoCallOverlay
corrspondingMessageWebView.resetMessagingHeaderBackButtonSource(
true)
corrspondingMessageWebView.setMessagingHeaderButtonsVisible(
true)
inVideoCallMessageWebViewStack.visible = false
inVideoCallMessageWebViewStack.clear()
}
videoCallPageRect.videoCallPageBackButtonIsClicked()
}
onOverlayChatButtonClicked: { anchors.fill: parent
if (inVideoCallMessageWebViewStack.visible) {
corrspondingMessageWebView.resetMessagingHeaderBackButtonSource(
true)
corrspondingMessageWebView.setMessagingHeaderButtonsVisible(
true)
inVideoCallMessageWebViewStack.visible = false
inVideoCallMessageWebViewStack.clear()
} else {
corrspondingMessageWebView.resetMessagingHeaderBackButtonSource(
false)
corrspondingMessageWebView.setMessagingHeaderButtonsVisible(
false)
inVideoCallMessageWebViewStack.visible = true
inVideoCallMessageWebViewStack.push(
corrspondingMessageWebView)
}
}
}
DistantRenderer { Connections {
id: distantRenderer target: CallAdapter
anchors.centerIn: videoCallPageMainRect function onUpdateTimeText(time) {
z: -1 videoCallOverlay.timeText = time
videoCallOverlay.setRecording(CallAdapter.isRecordingThisCall())
}
width: videoCallPageMainRect.width function onUpdateOverlay(isPaused, isAudioOnly, isAudioMuted, isVideoMuted, isRecording, isSIP, isConferenceCall, bestName) {
height: videoCallPageMainRect.height videoCallOverlay.showOnHoldImage(isPaused)
} videoCallOverlay.updateButtonStatus(isPaused,
isAudioOnly,
isAudioMuted,
isVideoMuted,
isRecording, isSIP,
isConferenceCall)
videoCallPageRect.bestName = bestName
}
VideoCallPreviewRenderer { function onShowOnHoldLabel(isPaused) {
id: previewRenderer videoCallOverlay.showOnHoldImage(isPaused)
/*
* Property is used in the {} expression for height (extra dependency),
* it will not affect the true height expression, since expression
* at last will be taken only, but it will force the height to update
* and reevaluate getPreviewImageScalingFactor().
*/
property int previewImageScalingFactorUpdated: 0
Connections {
target: CallAdapter
function onPreviewVisibilityNeedToChange(visible) {
previewRenderer.visible = visible
}
}
width: videoCallPageMainRect.width / 4
height: {
previewImageScalingFactorUpdated
return previewRenderer.width * previewRenderer.getPreviewImageScalingFactor()
}
x: videoCallPageMainRect.width - previewRenderer.width - previewMargin
y: videoCallPageMainRect.height - previewRenderer.height - previewMargin
z: -1
states: [
State {
name: "geoChanging"
PropertyChanges {
target: previewRenderer
x: previewToX
y: previewToY
} }
} }
]
transitions: Transition { onOverlayChatButtonClicked: {
PropertyAnimation { if (inVideoCallMessageWebViewStack.visible) {
properties: "x,y" linkedWebview.resetMessagingHeaderBackButtonSource(
easing.type: Easing.OutExpo true)
duration: 250 linkedWebview.setMessagingHeaderButtonsVisible(
true)
inVideoCallMessageWebViewStack.visible = false
inVideoCallMessageWebViewStack.clear()
} else {
linkedWebview.resetMessagingHeaderBackButtonSource(
false)
linkedWebview.setMessagingHeaderButtonsVisible(
false)
inVideoCallMessageWebViewStack.visible = true
inVideoCallMessageWebViewStack.push(
linkedWebview)
}
}
}
onStopped: { DistantRenderer {
id: distantRenderer
anchors.centerIn: videoCallPageMainRect
z: -1
width: videoCallPageMainRect.width
height: videoCallPageMainRect.height
}
VideoCallPreviewRenderer {
id: previewRenderer
/*
* Property is used in the {} expression for height (extra dependency),
* it will not affect the true height expression, since expression
* at last will be taken only, but it will force the height to update
* and reevaluate getPreviewImageScalingFactor().
*/
property int previewImageScalingFactorUpdated: 0
Connections {
target: CallAdapter
onPreviewVisibilityNeedToChange: previewRenderer.visible = visible
}
width: videoCallPageMainRect.width / 4
height: {
previewImageScalingFactorUpdated
return previewRenderer.width * previewRenderer.getPreviewImageScalingFactor()
}
x: videoCallPageMainRect.width - previewRenderer.width - previewMargin
y: videoCallPageMainRect.height - previewRenderer.height - previewMargin - 56 /* Avoid overlay */
z: -1
states: [
State {
name: "geoChanging"
PropertyChanges {
target: previewRenderer
x: previewToX
y: previewToY
}
}
]
transitions: Transition {
PropertyAnimation {
properties: "x,y"
easing.type: Easing.OutExpo
duration: 250
onStopped: {
previewRenderer.state = ""
}
}
}
MouseArea {
id: dragMouseArea
anchors.fill: previewRenderer
onPressed: {
clickPos = Qt.point(mouse.x, mouse.y)
}
onReleased: {
previewRenderer.state = "" previewRenderer.state = ""
previewMagneticSnap()
}
onPositionChanged: {
/*
* Calculate mouse position relative change.
*/
var delta = Qt.point(mouse.x - clickPos.x,
mouse.y - clickPos.y)
var deltaW = previewRenderer.x + delta.x + previewRenderer.width
var deltaH = previewRenderer.y + delta.y + previewRenderer.height
/*
* Check if the previewRenderer exceeds the border of videoCallPageMainRect.
*/
if (deltaW < videoCallPageMainRect.width
&& previewRenderer.x + delta.x > 1)
previewRenderer.x += delta.x
if (deltaH < videoCallPageMainRect.height
&& previewRenderer.y + delta.y > 1)
previewRenderer.y += delta.y
} }
} }
}
MouseArea { onPreviewImageAvailable: {
id: dragMouseArea previewImageScalingFactorUpdated++
previewImageScalingFactorUpdated--
anchors.fill: previewRenderer
onPressed: {
clickPos = Qt.point(mouse.x, mouse.y)
} }
onReleased: {
previewRenderer.state = ""
previewMagneticSnap()
}
onPositionChanged: {
/*
* Calculate mouse position relative change.
*/
var delta = Qt.point(mouse.x - clickPos.x,
mouse.y - clickPos.y)
var deltaW = previewRenderer.x + delta.x + previewRenderer.width
var deltaH = previewRenderer.y + delta.y + previewRenderer.height
/*
* Check if the previewRenderer exceeds the border of videoCallPageMainRect.
*/
if (deltaW < videoCallPageMainRect.width
&& previewRenderer.x + delta.x > 1)
previewRenderer.x += delta.x
if (deltaH < videoCallPageMainRect.height
&& previewRenderer.y + delta.y > 1)
previewRenderer.y += delta.y
}
}
onPreviewImageAvailable: {
previewImageScalingFactorUpdated++
previewImageScalingFactorUpdated--
} }
} }
color: "transparent" color: "transparent"
} }
StackView { StackView {
id: inVideoCallMessageWebViewStack id: inVideoCallMessageWebViewStack
@ -343,32 +338,8 @@ Rectangle {
} }
} }
VideoCallPageContextMenu { onBestNameChanged: {
id: videoCallPageContextMenu ContactAdapter.setCalleeDisplayName(bestName)
onFullScreenNeeded: {
videoCallPageRect.needToShowInFullScreen()
}
}
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
acceptedButtons: Qt.RightButton
onClicked: {
/*
* Make menu pos at mouse.
*/
var relativeMousePos = mapToItem(videoCallPageRect,
mouse.x, mouse.y)
videoCallPageContextMenu.x = relativeMousePos.x
videoCallPageContextMenu.y = relativeMousePos.y
videoCallPageContextMenu.activate()
}
} }
color: "black" color: "black"

View file

@ -31,60 +31,26 @@ GeneralMenuItem {
property int contextMenuPreferredWidth: 250 property int contextMenuPreferredWidth: 250
itemName: qsTr("No video device")
leftBorderWidth: commonBorderWidth leftBorderWidth: commonBorderWidth
rightBorderWidth: commonBorderWidth rightBorderWidth: commonBorderWidth
TextMetrics { TextMetrics {
id: textMetrics id: textMetrics
font: deviceNameText.font
elide: Text.ElideMiddle elide: Text.ElideMiddle
elideWidth: contextMenuPreferredWidth elideWidth: contextMenuPreferredWidth
- videoCallPageContextMenuDeviceItem.implicitIndicatorWidth - videoCallPageContextMenuDeviceItem.implicitIndicatorWidth
text: videoCallPageContextMenuDeviceItem.itemName text: videoCallPageContextMenuDeviceItem.itemName
} }
contentItem: Text { itemName: textMetrics.elidedText.length !== 0 ?
id: deviceNameText textMetrics.elidedText :
qsTr("No video device")
leftPadding: 30 indicator: null
rightPadding: videoCallPageContextMenuDeviceItem.arrow.width
horizontalAlignment: Text.AlignLeft iconSource: videoCallPageContextMenuDeviceItem.checked ?
verticalAlignment: Text.AlignVCenter "qrc:/images/icons/check_box-24px.svg" :
"qrc:/images/icons/check_box_outline_blank-24px.svg"
font.pointSize: JamiTheme.textFontSize - 3
text: textMetrics.elidedText
}
indicator: Item {
id: selectItem
anchors.left: parent.left
anchors.verticalCenter: parent.verticalCenter
implicitWidth: 32
implicitHeight: 32
Rectangle {
id: selectRect
width: selectItem.width / 2
height: selectItem.height / 2
anchors.centerIn: parent
visible: videoCallPageContextMenuDeviceItem.checkable
border.color: JamiTheme.selectionGreen
radius: 3
Rectangle {
width: selectRect.width / 2
height: selectRect.height / 2
anchors.centerIn: parent
visible: videoCallPageContextMenuDeviceItem.checked
color: JamiTheme.selectionGreen
radius: 2
}
}
}
onClicked: { onClicked: {
var deviceName = videoCallPageContextMenuDeviceItem.itemName var deviceName = videoCallPageContextMenuDeviceItem.itemName

View file

@ -54,11 +54,7 @@ function createVideoDeviceContextMenuItemObjects(deviceName, setChecked, last) {
function finishCreation(deviceName, setChecked, last) { function finishCreation(deviceName, setChecked, last) {
videoDeviceContextMenuItemObject = videoDeviceContextMenuItemComponent.createObject() videoDeviceContextMenuItemObject = videoDeviceContextMenuItemComponent.createObject()
if (videoDeviceContextMenuItemObject === null) { if (videoDeviceContextMenuItemObject === null) {
// Error Handling.
/*
* Error Handling.
*/
console.log("Error creating video context menu object") console.log("Error creating video context menu object")
} }
@ -72,7 +68,7 @@ function finishCreation(deviceName, setChecked, last) {
* Push into the storage array, and insert it into context menu. * Push into the storage array, and insert it into context menu.
*/ */
itemArray.push(videoDeviceContextMenuItemObject) itemArray.push(videoDeviceContextMenuItemObject)
videoContextMenuObject.insertItem(1, videoDeviceContextMenuItemObject) videoContextMenuObject.insertItem(3 /* The button is at pos 3 in the menu */, videoDeviceContextMenuItemObject)
/* /*