mirror of
https://git.jami.net/savoirfairelinux/jami-client-qt.git
synced 2025-04-21 21:52:03 +02:00
callview: use dynamic loading for call views
This commit replaces a StackLayout with a Loader allowing us to load initial and ongoing call views dynamically based on the current conversation's call state. This may fix several issues related to conversation loading including a possible uncaught binding loop based on observing CurrentConversation.id changes. - small header clean up Change-Id: Idfc723d8b39f19aafb026c19f26590910b5c26cd
This commit is contained in:
parent
6105f4f7ce
commit
8a149b6c4f
9 changed files with 78 additions and 81 deletions
|
@ -362,36 +362,32 @@ CallOverlayModel::clearControls()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CallOverlayModel::registerFilter(QObject* object, QQuickItem* item)
|
CallOverlayModel::setEventFilterActive(QObject* object, QQuickItem* item, bool isActive)
|
||||||
{
|
{
|
||||||
QQuickWindow* window = qobject_cast<QQuickWindow*>(object);
|
QQuickWindow* window = qobject_cast<QQuickWindow*>(object);
|
||||||
if (!window || !item) {
|
if (!window || !item) {
|
||||||
C_WARN << "Attempting to register an invalid object or item" << object << item;
|
C_WARN << "Attempting to" << (isActive ? "register" : "unregister")
|
||||||
|
<< "an invalid object or item" << window << item;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (watchedItems_.contains(item)) {
|
if (isActive) {
|
||||||
C_DBG << "Item already registered" << item;
|
if (watchedItems_.contains(item)) {
|
||||||
}
|
C_DBG << "Item already registered" << item;
|
||||||
watchedItems_.push_back(item);
|
} else {
|
||||||
if (watchedItems_.size() == 1) {
|
watchedItems_.push_back(item);
|
||||||
window->installEventFilter(this);
|
if (watchedItems_.size() == 1) {
|
||||||
}
|
window->installEventFilter(this);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
void
|
} else {
|
||||||
CallOverlayModel::unregisterFilter(QObject* object, QQuickItem* item)
|
if (!watchedItems_.contains(item)) {
|
||||||
{
|
C_DBG << "Item not registered" << item;
|
||||||
QQuickWindow* window = qobject_cast<QQuickWindow*>(object);
|
} else {
|
||||||
if (!window || !item) {
|
watchedItems_.removeOne(item);
|
||||||
C_WARN << "Attempting to unregister an invalid object or item" << object << item;
|
if (watchedItems_.size() == 0) {
|
||||||
return;
|
window->removeEventFilter(this);
|
||||||
}
|
}
|
||||||
if (!watchedItems_.contains(item)) {
|
}
|
||||||
C_DBG << "Item not registered" << item;
|
|
||||||
}
|
|
||||||
watchedItems_.removeOne(item);
|
|
||||||
if (watchedItems_.size() == 0) {
|
|
||||||
window->removeEventFilter(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -137,8 +137,7 @@ public:
|
||||||
Q_INVOKABLE QVariant overflowHiddenModel();
|
Q_INVOKABLE QVariant overflowHiddenModel();
|
||||||
Q_INVOKABLE QVariant pendingConferenceesModel();
|
Q_INVOKABLE QVariant pendingConferenceesModel();
|
||||||
|
|
||||||
Q_INVOKABLE void registerFilter(QObject* object, QQuickItem* item);
|
Q_INVOKABLE void setEventFilterActive(QObject* object, QQuickItem* item, bool isActive);
|
||||||
Q_INVOKABLE void unregisterFilter(QObject* object, QQuickItem* item);
|
|
||||||
bool eventFilter(QObject* object, QEvent* event) override;
|
bool eventFilter(QObject* object, QEvent* event) override;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
|
|
|
@ -28,6 +28,8 @@ VideoView {
|
||||||
crop: true
|
crop: true
|
||||||
visible: isRendering && visibilityCondition
|
visible: isRendering && visibilityCondition
|
||||||
|
|
||||||
|
Component.onDestruction: VideoDevices.stopDevice(rendererId);
|
||||||
|
|
||||||
function startWithId(id, force = false) {
|
function startWithId(id, force = false) {
|
||||||
if (id !== undefined && id.length === 0) {
|
if (id !== undefined && id.length === 0) {
|
||||||
stop();
|
stop();
|
||||||
|
|
|
@ -48,10 +48,10 @@ ListSelectionView {
|
||||||
leftPaneItem: viewCoordinator.getView("SidePanel", true)
|
leftPaneItem: viewCoordinator.getView("SidePanel", true)
|
||||||
|
|
||||||
rightPaneItem: StackLayout {
|
rightPaneItem: StackLayout {
|
||||||
|
id: conversationStackLayout
|
||||||
objectName: "ConversationLayout"
|
objectName: "ConversationLayout"
|
||||||
|
|
||||||
currentIndex: !CurrentConversation.hasCall ? 0 : 1
|
currentIndex: CurrentConversation.hasCall ? 1 : 0
|
||||||
onCurrentIndexChanged: chatView.parent = currentIndex === 1 ? callStackView.chatViewContainer : chatViewContainer
|
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
|
@ -64,24 +64,28 @@ ListSelectionView {
|
||||||
ChatView {
|
ChatView {
|
||||||
id: chatView
|
id: chatView
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
inCallView: parent == callStackView.chatViewContainer
|
|
||||||
|
// Parent the chat view to the call stack view when in call.
|
||||||
|
parent: callStackView.chatViewContainer ? callStackView.chatViewContainer : chatViewContainer
|
||||||
|
inCallView: parent === callStackView.chatViewContainer
|
||||||
|
|
||||||
readonly property string currentConvId: CurrentConversation.id
|
readonly property string currentConvId: CurrentConversation.id
|
||||||
onCurrentConvIdChanged: {
|
onCurrentConvIdChanged: {
|
||||||
if (!CurrentConversation.hasCall) {
|
Qt.callLater(function() {
|
||||||
Qt.callLater(focusChatView);
|
if (CurrentConversation.hasCall) {
|
||||||
} else {
|
callStackView.contentView.forceActiveFocus();
|
||||||
dismiss();
|
} else {
|
||||||
callStackView.contentView.forceActiveFocus();
|
focusChatView();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onDismiss: {
|
onDismiss: {
|
||||||
if (!inCallView) {
|
if (inCallView) {
|
||||||
viewNode.dismiss();
|
|
||||||
} else {
|
|
||||||
callStackView.chatViewContainer.visible = false;
|
callStackView.chatViewContainer.visible = false;
|
||||||
callStackView.contentView.forceActiveFocus();
|
callStackView.contentView.forceActiveFocus();
|
||||||
|
} else {
|
||||||
|
viewNode.dismiss();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,11 @@ import "../../commoncomponents"
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
property alias chatViewContainer: ongoingCallPage.chatViewContainer
|
property var chatViewContainer: {
|
||||||
|
if (callStackMainView.item instanceof OngoingCallPage)
|
||||||
|
return callStackMainView.item.chatViewContainer;
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
property alias contentView: callStackMainView
|
property alias contentView: callStackMainView
|
||||||
|
|
||||||
property var sipKeys: ["1", "2", "3", "A", "4", "5", "6", "B", "7", "8", "9", "C", "*", "0", "#", "D"]
|
property var sipKeys: ["1", "2", "3", "A", "4", "5", "6", "B", "7", "8", "9", "C", "*", "0", "#", "D"]
|
||||||
|
@ -61,44 +65,49 @@ Item {
|
||||||
// TODO: this should all be done by listening to
|
// TODO: this should all be done by listening to
|
||||||
// parent visibility change or parent `Component.onDestruction`
|
// parent visibility change or parent `Component.onDestruction`
|
||||||
function needToCloseInCallConversationAndPotentialWindow() {
|
function needToCloseInCallConversationAndPotentialWindow() {
|
||||||
ongoingCallPage.closeInCallConversation();
|
if (callStackMainView.item instanceof OngoingCallPage) {
|
||||||
ongoingCallPage.closeContextMenuAndRelatedWindows();
|
callStackMainView.item.closeInCallConversation();
|
||||||
|
callStackMainView.item.closeContextMenuAndRelatedWindows();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function toggleFullScreen() {
|
function toggleFullScreen() {
|
||||||
if (!layoutManager.isCallFullscreen) {
|
if (!layoutManager.isCallFullscreen) {
|
||||||
layoutManager.pushFullScreenItem(callStackMainView.currentItem, callStackMainView, null, null);
|
layoutManager.pushFullScreenItem(callStackMainView.item, callStackMainView, null, null);
|
||||||
} else {
|
} else {
|
||||||
layoutManager.removeFullScreenItem(callStackMainView.currentItem);
|
layoutManager.removeFullScreenItem(callStackMainView.item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StackLayout {
|
Loader {
|
||||||
id: callStackMainView
|
id: callStackMainView
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
property Item currentItem: itemAt(currentIndex)
|
sourceComponent: {
|
||||||
|
|
||||||
currentIndex: {
|
|
||||||
switch (CurrentCall.status) {
|
switch (CurrentCall.status) {
|
||||||
case Call.Status.IN_PROGRESS:
|
case Call.Status.IN_PROGRESS:
|
||||||
case Call.Status.CONNECTED:
|
case Call.Status.CONNECTED:
|
||||||
case Call.Status.PAUSED:
|
case Call.Status.PAUSED:
|
||||||
return 1;
|
return ongoingCallPageComponent;
|
||||||
case Call.Status.SEARCHING:
|
case Call.Status.SEARCHING:
|
||||||
case Call.Status.CONNECTING:
|
case Call.Status.CONNECTING:
|
||||||
case Call.Status.INCOMING_RINGING:
|
case Call.Status.INCOMING_RINGING:
|
||||||
case Call.Status.OUTGOING_RINGING:
|
case Call.Status.OUTGOING_RINGING:
|
||||||
|
return initialCallPageComponent;
|
||||||
default:
|
default:
|
||||||
return 0;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
InitialCallPage {
|
Component {
|
||||||
|
id: initialCallPageComponent
|
||||||
|
InitialCallPage {}
|
||||||
}
|
}
|
||||||
OngoingCallPage {
|
|
||||||
id: ongoingCallPage
|
Component {
|
||||||
|
id: ongoingCallPageComponent
|
||||||
|
OngoingCallPage {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,17 +61,9 @@ Item {
|
||||||
|
|
||||||
opacity: 0
|
opacity: 0
|
||||||
|
|
||||||
// (un)subscribe to an app-wide mouse move event trap filtered
|
Component.onCompleted: CallOverlayModel.setEventFilterActive(appWindow, this, true)
|
||||||
// for the overlay's geometry
|
Component.onDestruction: CallOverlayModel.setEventFilterActive(appWindow, this, false)
|
||||||
function setupFilter() {
|
onVisibleChanged: CallOverlayModel.setEventFilterActive(appWindow, this, visible)
|
||||||
if (visible) {
|
|
||||||
CallOverlayModel.registerFilter(appWindow, this);
|
|
||||||
} else {
|
|
||||||
CallOverlayModel.unregisterFilter(appWindow, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Component.onCompleted: setupFilter()
|
|
||||||
onVisibleChanged: setupFilter()
|
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
target: CallOverlayModel
|
target: CallOverlayModel
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
|
|
||||||
#include "videodevices.h"
|
#include "videodevices.h"
|
||||||
|
|
||||||
#include "api/devicemodel.h"
|
#include "global.h"
|
||||||
|
|
||||||
VideoInputDeviceModel::VideoInputDeviceModel(LRCInstance* lrcInstance,
|
VideoInputDeviceModel::VideoInputDeviceModel(LRCInstance* lrcInstance,
|
||||||
VideoDevices* videoDeviceInstance)
|
VideoDevices* videoDeviceInstance)
|
||||||
|
@ -260,11 +260,10 @@ VideoDevices::stopDevice(const QString& id)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qInfo() << "Stopping device" << id;
|
|
||||||
if (lrcInstance_->avModel().stopPreview(id)) {
|
if (lrcInstance_->avModel().stopPreview(id)) {
|
||||||
deviceOpen_ = false;
|
deviceOpen_ = false;
|
||||||
} else {
|
} else {
|
||||||
qWarning() << "Failed to stop device" << id;
|
C_DBG << "Failed to stop device" << id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
#include "directrenderer.h"
|
#include "directrenderer.h"
|
||||||
#else
|
#else
|
||||||
#include "shmrenderer.h"
|
#include "shmrenderer.h"
|
||||||
|
#include <csignal>
|
||||||
|
#include <thread>
|
||||||
#endif
|
#endif
|
||||||
#include "callbackshandler.h"
|
#include "callbackshandler.h"
|
||||||
#include "dbus/callmanager.h"
|
#include "dbus/callmanager.h"
|
||||||
|
@ -42,11 +44,7 @@
|
||||||
|
|
||||||
#include <algorithm> // std::sort
|
#include <algorithm> // std::sort
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <csignal>
|
|
||||||
#include <iomanip> // for std::put_time
|
#include <iomanip> // for std::put_time
|
||||||
#include <fstream>
|
|
||||||
#include <mutex>
|
|
||||||
#include <thread>
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
|
@ -328,7 +326,7 @@ void
|
||||||
AVModel::setDeviceSettings(video::Settings& settings)
|
AVModel::setDeviceSettings(video::Settings& settings)
|
||||||
{
|
{
|
||||||
MapStringString newSettings;
|
MapStringString newSettings;
|
||||||
auto rate = QString::number(settings.rate, 'f', 7);
|
auto rate = QString::number(static_cast<double>(settings.rate), 'f', 7);
|
||||||
rate = rate.left(rate.length() - 1);
|
rate = rate.left(rate.length() - 1);
|
||||||
newSettings["channel"] = settings.channel;
|
newSettings["channel"] = settings.channel;
|
||||||
newSettings["name"] = settings.name;
|
newSettings["name"] = settings.name;
|
||||||
|
@ -357,7 +355,7 @@ AVModel::getDeviceIdFromName(const QString& deviceName) const
|
||||||
return settings.name == deviceName;
|
return settings.name == deviceName;
|
||||||
});
|
});
|
||||||
if (iter == devices.end()) {
|
if (iter == devices.end()) {
|
||||||
qWarning() << "Couldn't find device: " << deviceName;
|
LC_WARN << "Couldn't find device: " << deviceName;
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
return *iter;
|
return *iter;
|
||||||
|
@ -491,7 +489,7 @@ void
|
||||||
AVModel::stopLocalRecorder(const QString& path) const
|
AVModel::stopLocalRecorder(const QString& path) const
|
||||||
{
|
{
|
||||||
if (path.isEmpty()) {
|
if (path.isEmpty()) {
|
||||||
qWarning("stopLocalRecorder: can't stop non existing recording");
|
LC_WARN << "stopLocalRecorder: can't stop non existing recording";
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -664,7 +662,7 @@ AVModel::getListWindows() const
|
||||||
});
|
});
|
||||||
|
|
||||||
if (xcb_connection_has_error(c.get())) {
|
if (xcb_connection_has_error(c.get())) {
|
||||||
qDebug() << "xcb connection has error";
|
LC_DBG << "xcb connection has error";
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -690,7 +688,7 @@ AVModel::getListWindows() const
|
||||||
propertyPtr replyPropList(xcb_get_property_reply(c.get(), propCookieList, &e),
|
propertyPtr replyPropList(xcb_get_property_reply(c.get(), propCookieList, &e),
|
||||||
[](auto* ptr) { free(ptr); });
|
[](auto* ptr) { free(ptr); });
|
||||||
if (e) {
|
if (e) {
|
||||||
qDebug() << "Error: " << e->error_code;
|
LC_DBG << "Error: " << e->error_code;
|
||||||
free(e);
|
free(e);
|
||||||
}
|
}
|
||||||
if (replyPropList.get()) {
|
if (replyPropList.get()) {
|
||||||
|
@ -710,7 +708,7 @@ AVModel::getListWindows() const
|
||||||
free(ptr);
|
free(ptr);
|
||||||
}};
|
}};
|
||||||
if (e) {
|
if (e) {
|
||||||
qDebug() << "Error: " << e->error_code;
|
LC_DBG << "Error: " << e->error_code;
|
||||||
free(e);
|
free(e);
|
||||||
}
|
}
|
||||||
if (replyProp.get()) {
|
if (replyProp.get()) {
|
||||||
|
@ -987,7 +985,7 @@ AVModelPimpl::getDevice(int type) const
|
||||||
if (deviceIdx < devices.size())
|
if (deviceIdx < devices.size())
|
||||||
result = devices.at(deviceIdx);
|
result = devices.at(deviceIdx);
|
||||||
} catch (std::bad_alloc& ba) {
|
} catch (std::bad_alloc& ba) {
|
||||||
qWarning() << "bad_alloc caught: " << ba.what();
|
LC_WARN << "bad_alloc caught: " << ba.what();
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
|
@ -1060,7 +1058,7 @@ AVModelPimpl::removeRenderer(const QString& id)
|
||||||
QWriteLocker lk(&renderersMutex_);
|
QWriteLocker lk(&renderersMutex_);
|
||||||
auto it = renderers_.find(id);
|
auto it = renderers_.find(id);
|
||||||
if (it == renderers_.end()) {
|
if (it == renderers_.end()) {
|
||||||
qWarning() << "Cannot remove renderer. " << id << "not found";
|
LC_DBG << "Cannot remove renderer. " << id << " not found";
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
auto removed = std::move(it->second);
|
auto removed = std::move(it->second);
|
||||||
|
|
|
@ -19,8 +19,6 @@
|
||||||
***************************************************************************/
|
***************************************************************************/
|
||||||
#include "api/lrc.h"
|
#include "api/lrc.h"
|
||||||
|
|
||||||
#include <locale>
|
|
||||||
|
|
||||||
#if !defined(_MSC_VER)
|
#if !defined(_MSC_VER)
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
Loading…
Add table
Reference in a new issue