multicall

This commit is contained in:
Gaelle Braud 2023-12-12 10:23:47 +01:00
parent f82f3cf189
commit 24c78564ef
18 changed files with 553 additions and 150 deletions

View file

@ -96,6 +96,8 @@ void App::init() {
}
setQuitOnLastWindowClosed(true); // TODO: use settings to set it
qInfo() << log().arg("Display server : %1").arg(platformName());
// QML
mEngine = new QQmlApplicationEngine(this);
// Provide `+custom` folders for custom components and `5.9` for old components.
@ -119,9 +121,13 @@ void App::init() {
QObject::connect(
mEngine, &QQmlApplicationEngine::objectCreated, this,
[this, url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl) {
qCritical() << log().arg("Main.qml couldn't be load. The app will exit");
exit(-1);
if (url == objUrl) {
if (!obj) {
qCritical() << log().arg("Main.qml couldn't be load. The app will exit");
exit(-1);
}
mMainWindow = qobject_cast<QQuickWindow *>(obj);
Q_ASSERT(mMainWindow);
}
},
Qt::QueuedConnection);
@ -149,7 +155,6 @@ void App::initCppInterfaces() {
qmlRegisterType<AccountProxy>(Constants::MainQmlUri, 1, 0, "AccountProxy");
qmlRegisterType<AccountGui>(Constants::MainQmlUri, 1, 0, "AccountGui");
qmlRegisterUncreatableType<AccountCore>(Constants::MainQmlUri, 1, 0, "AccountCore", QLatin1String("Uncreatable"));
qmlRegisterType<CallGui>(Constants::MainQmlUri, 1, 0, "CallGui");
qmlRegisterUncreatableType<CallCore>(Constants::MainQmlUri, 1, 0, "CallCore", QLatin1String("Uncreatable"));
qmlRegisterType<CallProxy>(Constants::MainQmlUri, 1, 0, "CallProxy");
qmlRegisterType<CallGui>(Constants::MainQmlUri, 1, 0, "CallGui");
@ -240,14 +245,9 @@ QQuickWindow *App::getCallsWindow(QVariant callGui) {
qCritical() << log().arg("Calls window could not be created.");
return nullptr;
}
// window->setParent(mMainWindow);
mCallsWindow = window;
}
postModelAsync([this]() {
auto core = CoreModel::getInstance()->getCore();
auto callsNb = core->getCallsNb();
postCoreAsync([this, callsNb] { mCallsWindow->setProperty("callsCount", callsNb); });
});
mCallsWindow->setProperty("call", callGui);
return mCallsWindow;
}
@ -260,13 +260,6 @@ void App::closeCallsWindow() {
}
}
void App::smartShowWindow(QQuickWindow *window) {
if (!window) return;
window->setVisible(true);
// Force show, maybe redundant with setVisible
if (window->visibility() == QWindow::Maximized) // Avoid to change visibility mode
window->showMaximized();
else window->show();
window->raise(); // Raise ensure to get focus on Mac
window->requestActivate();
}
QQuickWindow *App::getMainWindow() {
return mMainWindow;
}

View file

@ -93,7 +93,7 @@ public:
QQuickWindow *getCallsWindow(QVariant callGui);
void closeCallsWindow();
Q_INVOKABLE static void smartShowWindow(QQuickWindow *window);
QQuickWindow *getMainWindow();
QQmlApplicationEngine *mEngine = nullptr;
bool notify(QObject *receiver, QEvent *event) override;
@ -106,6 +106,7 @@ private:
QCommandLineParser *mParser = nullptr;
Thread *mLinphoneThread = nullptr;
Notifier *mNotifier = nullptr;
QQuickWindow *mMainWindow = nullptr;
QQuickWindow *mCallsWindow = nullptr;
// TODO : changer ce count lorsqu'on aura liste d'appels
int callsCount = 0;

View file

@ -143,6 +143,9 @@ void CallCore::setSelf(QSharedPointer<CallCore> me) {
mAccountModelConnection->makeConnectToCore(&CallCore::lTerminate, [this]() {
mAccountModelConnection->invokeToModel([this]() { mCallModel->terminate(); });
});
mAccountModelConnection->makeConnectToCore(&CallCore::lTerminateAllCalls, [this]() {
mAccountModelConnection->invokeToModel([this]() { mCallModel->terminateAllCalls(); });
});
}
QString CallCore::getPeerAddress() const {

View file

@ -113,6 +113,7 @@ signals:
void lAccept(bool withVideo); // Accept an incoming call
void lDecline(); // Decline an incoming call
void lTerminate(); // Hangup a call
void lTerminateAllCalls(); // Hangup all calls
void lSetSpeakerMuted(bool muted);
void lSetMicrophoneMuted(bool isMuted);
void lSetCameraEnabled(bool enabled);

View file

@ -25,6 +25,7 @@ list(APPEND _LINPHONEAPP_RC_FILES data/assistant/use-app-sip-account.rc
"data/image/phone-selected.svg"
"data/image/phone-plus.svg"
"data/image/phone-disconnect.svg"
"data/image/phone-list.svg"
"data/image/phone-transfer.svg"
"data/image/address-book.svg"
"data/image/address-book-selected.svg"

View file

@ -0,0 +1,6 @@
<svg width="32" height="32" viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M26.8446 20.1351L21.1913 17.6019L21.1757 17.5947C20.8822 17.4691 20.5621 17.4188 20.2442 17.4481C19.9264 17.4774 19.6209 17.5855 19.3553 17.7627C19.3241 17.7833 19.294 17.8057 19.2653 17.8299L16.3445 20.3199C14.4941 19.4211 12.5837 17.5251 11.6849 15.6986L14.1785 12.7334C14.2025 12.7034 14.2253 12.6734 14.2469 12.641C14.4202 12.3762 14.5254 12.0726 14.553 11.7573C14.5806 11.442 14.5299 11.1248 14.4053 10.8338V10.8194L11.8649 5.15657C11.7002 4.77648 11.4169 4.45986 11.0575 4.25397C10.698 4.04807 10.2816 3.96395 9.87045 4.01416C8.2444 4.22813 6.75185 5.02669 5.67154 6.26069C4.59124 7.49469 3.99707 9.07974 4.00001 10.7198C4.00001 20.2479 11.7521 27.9999 21.2801 27.9999C22.9202 28.0029 24.5052 27.4087 25.7393 26.3284C26.9733 25.2481 27.7718 23.7555 27.9858 22.1295C28.0361 21.7184 27.9521 21.3021 27.7465 20.9427C27.5408 20.5833 27.2244 20.3 26.8446 20.1351ZM21.2801 26.0799C17.2077 26.0755 13.3034 24.4557 10.4238 21.5761C7.54419 18.6965 5.92447 14.7922 5.92002 10.7198C5.91551 9.54798 6.33769 8.41458 7.10772 7.53127C7.87774 6.64796 8.94297 6.07513 10.1045 5.91977C10.104 5.92456 10.104 5.92938 10.1045 5.93417L12.6245 11.5742L10.1441 14.543C10.1189 14.572 10.096 14.6029 10.0757 14.6354C9.89507 14.9125 9.78913 15.2316 9.76811 15.5617C9.74709 15.8918 9.81169 16.2217 9.95565 16.5194C11.0429 18.7431 13.2833 20.9667 15.5309 22.0527C15.8309 22.1953 16.1627 22.2577 16.494 22.2337C16.8252 22.2097 17.1446 22.1002 17.4209 21.9159C17.4517 21.8951 17.4814 21.8727 17.5097 21.8487L20.4269 19.3599L26.067 21.8859C26.067 21.8859 26.0766 21.8859 26.0802 21.8859C25.9267 23.049 25.3547 24.1164 24.4713 24.8883C23.5878 25.6602 22.4533 26.0839 21.2801 26.0799Z" fill="#6C7A87"/>
<path d="M16.9336 11.8652H27.3336" stroke="#343330" stroke-linecap="round"/>
<path d="M16.9336 8.26562H27.3336" stroke="#343330" stroke-linecap="round"/>
<path d="M16.9336 4.66602H27.3336" stroke="#343330" stroke-linecap="round"/>
</svg>

After

Width:  |  Height:  |  Size: 2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.3 KiB

View file

@ -34,6 +34,10 @@ CallModel::CallModel(const std::shared_ptr<linphone::Call> &call, QObject *paren
mDurationTimer.setSingleShot(false);
connect(&mDurationTimer, &QTimer::timeout, this, [this]() { this->durationChanged(mMonitor->getDuration()); });
mDurationTimer.start();
connect(this, &CallModel::stateChanged, this, [this] {
auto state = mMonitor->getState();
if (state == linphone::Call::State::Paused) setPaused(true);
});
}
CallModel::~CallModel() {
@ -86,6 +90,10 @@ void CallModel::transferTo(const std::shared_ptr<linphone::Address> &address) {
<< log().arg(QStringLiteral("Unable to transfer: `%1`.")).arg(QString::fromStdString(address->asString()));
}
void CallModel::terminateAllCalls() {
auto status = mMonitor->getCore()->terminateAllCalls();
}
void CallModel::setMicrophoneMuted(bool isMuted) {
mustBeInLinphoneThread(log().arg(Q_FUNC_INFO));
mMonitor->setMicrophoneMuted(isMuted);

View file

@ -45,6 +45,7 @@ public:
void setCameraEnabled(bool enabled);
void setPaused(bool paused);
void transferTo(const std::shared_ptr<linphone::Address> &address);
void terminateAllCalls();
std::shared_ptr<const linphone::Address> getRemoteAddress();
bool getAuthenticationTokenVerified();

View file

@ -88,7 +88,7 @@ VariantObject *Utils::createCall(const QString &sipAddress,
App::postCoreSync([callGui]() {
auto app = App::getInstance();
auto window = app->getCallsWindow(callGui);
window->show();
smartShowWindow(window);
});
return callGui;
} else return QVariant();
@ -104,7 +104,7 @@ void Utils::openCallsWindow(CallGui *call) {
QQuickWindow *Utils::getCallsWindow(CallGui *callGui) {
auto app = App::getInstance();
auto window = app->getCallsWindow(QVariant::fromValue(callGui));
window->show();
smartShowWindow(window);
return window;
}
@ -112,6 +112,12 @@ void Utils::closeCallsWindow() {
App::getInstance()->closeCallsWindow();
}
QQuickWindow *Utils::getMainWindow() {
auto win = App::getInstance()->getMainWindow();
smartShowWindow(win);
return win;
}
VariantObject *Utils::haveAccount() {
VariantObject *result = new VariantObject();
@ -124,6 +130,16 @@ VariantObject *Utils::haveAccount() {
result->requestValue();
return result;
}
void Utils::smartShowWindow(QQuickWindow *window) {
if (!window) return;
if (window->visibility() == QWindow::Maximized) // Avoid to change visibility mode
window->showNormal();
else window->show();
window->raise(); // Raise ensure to get focus on Mac
window->requestActivate();
}
QString Utils::createAvatar(const QUrl &fileUrl) {
QString filePath = fileUrl.toLocalFile();
QString fileId; // uuid.ext

View file

@ -58,9 +58,11 @@ public:
const QString &prepareTransfertAddress = "",
const QHash<QString, QString> &headers = {});
Q_INVOKABLE static void openCallsWindow(CallGui *call);
Q_INVOKABLE static QQuickWindow *getMainWindow();
Q_INVOKABLE static QQuickWindow *getCallsWindow(CallGui *callGui);
Q_INVOKABLE static void closeCallsWindow();
Q_INVOKABLE static VariantObject *haveAccount();
Q_INVOKABLE static void smartShowWindow(QQuickWindow *window);
Q_INVOKABLE static QString createAvatar(const QUrl &fileUrl); // Return the avatar path
Q_INVOKABLE static QString formatElapsedTime(int seconds); // Return the elapsed time formated

View file

@ -10,25 +10,43 @@ Window {
id: mainWindow
width: 1512 * DefaultStyle.dp
height: 982 * DefaultStyle.dp
flags: Qt.Window
// modality: Qt.WindowModal
property CallGui call
property int callsCount: 0
onCallsCountChanged: console.log("calls count", callsCount)
onCallChanged: {
waitingTime.seconds = 0
waitingTimer.restart()
console.log("call changed", call, waitingTime.seconds)
}
property var peerName: UtilsCpp.getDisplayName(call.core.peerAddress)
property string peerNameText: peerName ? peerName.value : ""
// TODO : remove this, for debug only
property var callState: call && call.core.state
property var callState: call.core.state
onCallStateChanged: {
console.log("State:", callState)
if (callState === LinphoneEnums.CallState.Error || callState === LinphoneEnums.CallState.End) {
endCall()
endCall(call)
}
}
onClosing: {
endCall()
property var transferState: call.core.transferState
onTransferStateChanged: {
console.log("Transfer state:", transferState)
if (call.core.transferState === LinphoneEnums.CallState.Error) {
transferErrorPopup.visible = true
}
else if (call.core.transferState === LinphoneEnums.CallState.Connected){
var mainWin = UtilsCpp.getMainWindow()
UtilsCpp.smartShowWindow(mainWin)
mainWin.transferCallSucceed()
}
}
onClosing: (close) => {
close.accepted = false
terminateAllCallsDialog.open()
}
Timer {
@ -39,24 +57,69 @@ Window {
}
}
function endCall() {
console.log("remaining calls before ending", mainWindow.callsCount)
callStatusText.text = qsTr("End of the call")
if (call) call.core.lTerminate()
if (callsCount === 1) {
function endCall(callToFinish) {
if (callToFinish) callToFinish.core.lTerminate()
if (!callsModel.haveCall) {
bottomButtonsLayout.setButtonsEnabled(false)
autoCloseWindow.restart()
} else if (callToFinish.core === mainWindow.call.core) {
mainWindow.call = callsModel.currentCall
}
}
Popup {
id: terminateAllCallsDialog
modal: true
anchors.centerIn: parent
closePolicy: Control.Popup.NoAutoClose
padding: 10 * DefaultStyle.dp
contentItem: ColumnLayout {
height: terminateAllCallsDialog.height
width: 278 * DefaultStyle.dp
spacing: 8 * DefaultStyle.dp
Text {
text: qsTr("La fenêtre est sur le point d'être fermée. Cela terminera tous les appels en cours. Souhaitez vous continuer ?")
Layout.preferredWidth: parent.width
font {
pixelSize: 14 * DefaultStyle.dp
weight: 400 * DefaultStyle.dp
}
wrapMode: Text.Wrap
horizontalAlignment: Text.AlignHCenter
}
RowLayout {
Layout.alignment: Qt.AlignHCenter
Button {
text: qsTr("Oui")
onClicked: {
call.core.lTerminateAllCalls()
terminateAllCallsDialog.close()
}
}
Button {
text: qsTr("Non")
onClicked: terminateAllCallsDialog.close()
}
}
}
}
CallProxy{
id: callList
id: callsModel
onCurrentCallChanged: {
console.log("Current call changed:"+currentCall)
if(currentCall) mainWindow.call = currentCall
if(currentCall) {
mainWindow.call = currentCall
}
}
onHaveCallChanged: {
if (!haveCall) {
mainWindow.endCall()
}
}
}
component BottomButton : Button {
required property string enabledIcon
property string disabledIcon
@ -84,7 +147,7 @@ Window {
colorizationColor: disabledIcon && bottomButton.checked ? DefaultStyle.main2_0 : DefaultStyle.grey_0
}
}
Control.Popup {
Popup {
id: waitingPopup
visible: mainWindow.call.core.transferState === LinphoneEnums.CallState.OutgoingInit
|| mainWindow.call.core.transferState === LinphoneEnums.CallState.OutgoingProgress
@ -93,23 +156,8 @@ Window {
closePolicy: Control.Popup.NoAutoClose
anchors.centerIn: parent
padding: 20 * DefaultStyle.dp
background: Item {
anchors.fill: parent
Rectangle {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
height: parent.height + 2
color: DefaultStyle.main1_500_main
radius: 15 * DefaultStyle.dp
}
Rectangle {
id: mainBackground
anchors.fill: parent
radius: 15 * DefaultStyle.dp
}
}
underlineColor: DefaultStyle.main1_500_main
radius: 15 * DefaultStyle.dp
contentItem: ColumnLayout {
BusyIndicator{
Layout.alignment: Qt.AlignHCenter
@ -127,9 +175,8 @@ Window {
transferErrorPopup.close()
}
}
Control.Popup {
Popup {
id: transferErrorPopup
visible: mainWindow.call.core.transferState === LinphoneEnums.CallState.Error
onVisibleChanged: if (visible) autoClosePopup.restart()
closePolicy: Control.Popup.NoAutoClose
x : parent.x + parent.width - width
@ -137,26 +184,8 @@ Window {
rightMargin: 20 * DefaultStyle.dp
bottomMargin: 20 * DefaultStyle.dp
padding: 20 * DefaultStyle.dp
background: Item {
anchors.fill: parent
Rectangle {
anchors.left: parent.left
anchors.right: parent.right
height: parent.height + 2 * DefaultStyle.dp
color: DefaultStyle.danger_500main
}
Rectangle {
id: transferErrorBackground
anchors.fill: parent
}
MultiEffect {
anchors.fill: transferErrorBackground
shadowEnabled: true
shadowColor: DefaultStyle.grey_900
shadowBlur: 1
// shadowOpacity: 0.1
}
}
underlineColor: DefaultStyle.danger_500main
radius: 0
contentItem: ColumnLayout {
Text {
text: qsTr("Erreur de transfert")
@ -189,24 +218,23 @@ Window {
image.height: 15 * DefaultStyle.dp
image.sourceSize.width: 15 * DefaultStyle.dp
image.sourceSize.height: 15 * DefaultStyle.dp
image.source: (mainWindow.call.core.state === LinphoneEnums.CallState.Paused
|| mainWindow.callState === LinphoneEnums.CallState.PausedByRemote)
image.source: mainWindow.call.core.paused
? AppIcons.pause
: (mainWindow.callState === LinphoneEnums.CallState.End
|| mainWindow.callState === LinphoneEnums.CallState.Released)
: (mainWindow.call.core.state === LinphoneEnums.CallState.End
|| mainWindow.call.core.state === LinphoneEnums.CallState.Released)
? AppIcons.endCall
: mainWindow.call.core.dir === LinphoneEnums.CallDir.Outgoing
? AppIcons.outgoingCall
: AppIcons.incomingCall
colorizationColor: mainWindow.callState === LinphoneEnums.CallState.Paused
|| mainWindow.callState === LinphoneEnums.CallState.PausedByRemote || mainWindow.callState === LinphoneEnums.CallState.End
|| mainWindow.callState === LinphoneEnums.CallState.Released ? DefaultStyle.danger_500main : undefined
colorizationColor: mainWindow.call.core.state === LinphoneEnums.CallState.Paused
|| mainWindow.call.core.state === LinphoneEnums.CallState.PausedByRemote || mainWindow.call.core.state === LinphoneEnums.CallState.End
|| mainWindow.call.core.state === LinphoneEnums.CallState.Released ? DefaultStyle.danger_500main : undefined
}
Text {
id: callStatusText
text: (mainWindow.callState === LinphoneEnums.CallState.End || mainWindow.callState === LinphoneEnums.CallState.Released)
text: (mainWindow.call.core.state === LinphoneEnums.CallState.End || mainWindow.call.core.state === LinphoneEnums.CallState.Released)
? qsTr("End of the call")
: (mainWindow.callState === LinphoneEnums.CallState.Paused || mainWindow.callState === LinphoneEnums.CallState.PausedByRemote)
: (mainWindow.call.core.paused)
? qsTr("Appel mis en pause")
: EnumsToStringCpp.dirToString(mainWindow.call.core.dir) + qsTr(" call")
color: DefaultStyle.grey_0
@ -216,8 +244,8 @@ Window {
}
}
Rectangle {
visible: mainWindow.callState === LinphoneEnums.CallState.Connected
|| mainWindow.callState === LinphoneEnums.CallState.StreamsRunning
visible: mainWindow.call.core.state === LinphoneEnums.CallState.Connected
|| mainWindow.call.core.state === LinphoneEnums.CallState.StreamsRunning
Layout.preferredHeight: parent.height
Layout.preferredWidth: 2 * DefaultStyle.dp
}
@ -228,8 +256,8 @@ Window {
pixelSize: 22 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp
}
visible: mainWindow.callState === LinphoneEnums.CallState.Connected
|| mainWindow.callState === LinphoneEnums.CallState.StreamsRunning
visible: mainWindow.call.core.state === LinphoneEnums.CallState.Connected
|| mainWindow.call.core.state === LinphoneEnums.CallState.StreamsRunning
}
}
@ -277,7 +305,7 @@ Window {
Layout.alignment: Qt.AlignCenter
background: Rectangle {
anchors.fill: parent
color: DefaultStyle.grey_600 * DefaultStyle.dp
color: DefaultStyle.grey_600
radius: 15 * DefaultStyle.dp
}
contentItem: Item {
@ -288,7 +316,7 @@ Window {
Connections {
target: mainWindow
onCallStateChanged: {
if (mainWindow.callState === LinphoneEnums.CallState.Error) {
if (mainWindow.call.core.state === LinphoneEnums.CallState.Error) {
centerLayout.currentIndex = 2
}
}
@ -299,7 +327,7 @@ Window {
Layout.preferredWidth: parent.width
Layout.preferredHeight: parent.height
Timer {
id: secondsTimer
id: waitingTimer
interval: 1000
repeat: true
onTriggered: waitingTime.seconds += 1
@ -308,11 +336,11 @@ Window {
anchors.horizontalCenter: parent.horizontalCenter
anchors.top: parent.top
anchors.topMargin: 30 * DefaultStyle.dp
visible: mainWindow.callState == LinphoneEnums.CallState.OutgoingInit
|| mainWindow.callState == LinphoneEnums.CallState.OutgoingProgress
|| mainWindow.callState == LinphoneEnums.CallState.OutgoingRinging
|| mainWindow.callState == LinphoneEnums.CallState.OutgoingEarlyMedia
|| mainWindow.callState == LinphoneEnums.CallState.IncomingReceived
visible: mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingInit
|| mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingProgress
|| mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingRinging
|| mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingEarlyMedia
|| mainWindow.call.core.state == LinphoneEnums.CallState.IncomingReceived
BusyIndicator {
indicatorColor: DefaultStyle.main2_100
Layout.alignment: Qt.AlignHCenter
@ -324,9 +352,12 @@ Window {
color: DefaultStyle.grey_0
Layout.alignment: Qt.AlignHCenter
horizontalAlignment: Text.AlignHCenter
font.pointSize: 30 * DefaultStyle.dp
font {
pixelSize: 30 * DefaultStyle.dp
weight: 300 * DefaultStyle.dp
}
Component.onCompleted: {
secondsTimer.restart()
waitingTimer.restart()
}
}
}
@ -402,25 +433,26 @@ Window {
property int currentIndex: 0
Layout.rightMargin: 10 * DefaultStyle.dp
visible: false
headerContent: StackLayout {
currentIndex: rightPanel.currentIndex
function replace(id) {
rightPanelStack.replace(id, Control.StackView.Immediate)
}
headerContent: Text {
id: rightPanelTitle
anchors.verticalCenter: parent.verticalCenter
Text {
color: DefaultStyle.main2_700
text: qsTr("Transfert d'appel")
font.bold: true
}
Text {
color: DefaultStyle.main2_700
text: qsTr("Dialer")
font.bold: true
width: rightPanel.width
color: DefaultStyle.main2_700
// text: qsTr("Transfert d'appel")
font {
pixelSize: 16 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp
}
}
contentItem: StackLayout {
currentIndex: rightPanel.currentIndex
contentItem: Control.StackView {
id: rightPanelStack
}
Component {
id: contactsListPanel
ContactsList {
Layout.fillWidth: true
Layout.fillHeight: true
sideMargin: 10 * DefaultStyle.dp
topMargin: 15 * DefaultStyle.dp
groupCallVisible: false
@ -429,10 +461,13 @@ Window {
onCallButtonPressed: (address) => {
mainWindow.call.core.lTransferCall(address)
}
Control.StackView.onActivated: rightPanelTitle.text = qsTr("Transfert d'appel")
}
}
Component {
id: dialerPanel
ColumnLayout {
Layout.fillWidth: true
Layout.fillHeight: true
Control.StackView.onActivated: rightPanelTitle.text = qsTr("Dialer")
Item {
Layout.fillWidth: true
Layout.fillHeight: true
@ -465,6 +500,200 @@ Window {
}
}
}
Component {
id: callsListPanel
Control.Control {
Control.StackView.onActivated: rightPanelTitle.text = qsTr("Liste d'appel")
// width: callList.width
// height: callList.height
onHeightChanged: console.log("control height changed", height)
// padding: 15 * DefaultStyle.dp
topPadding: 15 * DefaultStyle.dp
bottomPadding: 15 * DefaultStyle.dp
leftPadding: 15 * DefaultStyle.dp
rightPadding: 15 * DefaultStyle.dp
background: Rectangle {
anchors.fill: parent
anchors.leftMargin: 10 * DefaultStyle.dp
anchors.rightMargin: 10 * DefaultStyle.dp
anchors.topMargin: 10 * DefaultStyle.dp
anchors.bottomMargin: 10 * DefaultStyle.dp
color: DefaultStyle.main2_0
radius: 15 * DefaultStyle.dp
}
contentItem: ListView {
id: callList
model: callsModel
height: contentHeight
onHeightChanged: console.log("height changzed lustviexw", height, contentHeight)
spacing: 15 * DefaultStyle.dp
onCountChanged: forceLayout()
delegate: Item {
anchors.left: parent.left
anchors.right: parent.right
id: callDelegate
height: 45 * DefaultStyle.dp
RowLayout {
id: delegateContent
anchors.fill: parent
anchors.leftMargin: 10 * DefaultStyle.dp
anchors.rightMargin: 10 * DefaultStyle.dp
Avatar {
id: delegateAvatar
address: modelData.core.peerAddress
Layout.preferredWidth: 45 * DefaultStyle.dp
Layout.preferredHeight: 45 * DefaultStyle.dp
}
Text {
id: delegateName
text: UtilsCpp.getDisplayName(modelData.core.peerAddress).value
Connections {
target: modelData.core
}
}
Item {
Layout.fillHeight: true
Layout.fillWidth: true
}
Text {
id: callStateText
text: modelData.core.state === LinphoneEnums.CallState.Paused
|| modelData.core.state === LinphoneEnums.CallState.PausedByRemote
? qsTr("Appel en pause") : qsTr("Appel en cours")
}
Button {
id: listCallOptionsButton
checked: listCallOptionsMenu.visible
Layout.preferredWidth: 24 * DefaultStyle.dp
Layout.preferredHeight: 24 * DefaultStyle.dp
Layout.alignment: Qt.AlignRight
leftPadding: 0
rightPadding: 0
topPadding: 0
bottomPadding: 0
background: Rectangle {
anchors.fill: listCallOptionsButton
opacity: listCallOptionsButton.checked ? 1 : 0
color: DefaultStyle.main2_300
radius: 40 * DefaultStyle.dp
}
contentItem: Image {
source: AppIcons.verticalDots
sourceSize.width: 24 * DefaultStyle.dp
sourceSize.height: 24 * DefaultStyle.dp
width: 24 * DefaultStyle.dp
height: 24 * DefaultStyle.dp
}
onPressed: {
console.log("listCallOptionsMenu visible", listCallOptionsMenu.visible, "opened", listCallOptionsMenu.opened)
if (listCallOptionsMenu.visible){
console.log("close popup")
listCallOptionsMenu.close()
}
else {
console.log("open popup")
listCallOptionsMenu.open()
}
}
Control.Popup {
id: listCallOptionsMenu
x: - width
y: listCallOptionsButton.height
onVisibleChanged: console.log("popup visible", visible)
closePolicy: Popup.CloseOnPressOutsideParent | Popup.CloseOnEscape
padding: 20 * DefaultStyle.dp
background: Item {
anchors.fill: parent
Rectangle {
id: callOptionsMenuPopup
anchors.fill: parent
color: DefaultStyle.grey_0
radius: 16 * DefaultStyle.dp
}
MultiEffect {
source: callOptionsMenuPopup
anchors.fill: callOptionsMenuPopup
shadowEnabled: true
shadowBlur: 1
shadowColor: DefaultStyle.grey_900
shadowOpacity: 0.4
}
}
contentItem: ColumnLayout {
spacing: 0
Control.Button {
background: Item {}
contentItem: RowLayout {
Image {
source: modelData.core.state === LinphoneEnums.CallState.Paused
|| modelData.core.state === LinphoneEnums.CallState.PausedByRemote
? AppIcons.phone : AppIcons.pause
sourceSize.width: 32 * DefaultStyle.dp
sourceSize.height: 32 * DefaultStyle.dp
Layout.preferredWidth: 32 * DefaultStyle.dp
Layout.preferredHeight: 32 * DefaultStyle.dp
fillMode: Image.PreserveAspectFit
}
Text {
text: modelData.core.state === LinphoneEnums.CallState.Paused
|| modelData.core.state === LinphoneEnums.CallState.PausedByRemote
? qsTr("Reprendre l'appel") : qsTr("Mettre en pause")
color: DefaultStyle.main2_500main
Layout.preferredWidth: metrics.width
}
TextMetrics {
id: metrics
text: qsTr("Reprendre l'appel")
}
Item {
Layout.fillWidth: true
}
}
onClicked: modelData.core.lSetPaused(!modelData.core.paused)
}
Control.Button {
background: Item {}
contentItem: RowLayout {
EffectImage {
image.source: AppIcons.endCall
colorizationColor: DefaultStyle.danger_500main
width: 32 * DefaultStyle.dp
height: 32 * DefaultStyle.dp
}
Text {
color: DefaultStyle.danger_500main
text: qsTr("Terminer l'appel")
}
Item {
Layout.fillWidth: true
}
}
onClicked: mainWindow.endCall(modelData)
}
}
}
}
}
// MouseArea{
// anchors.fill: delegateLayout
// onClicked: {
// callsModel.currentCall = modelData
// }
// }
}
}
}
}
}
}
GridLayout {
@ -474,13 +703,22 @@ Window {
Layout.alignment: Qt.AlignHCenter
layoutDirection: Qt.LeftToRight
columnSpacing: 20 * DefaultStyle.dp
Connections {
target: mainWindow
onCallStateChanged: if (mainWindow.callState === LinphoneEnums.CallState.Connected || mainWindow.callState === LinphoneEnums.CallState.StreamsRunning) {
function refreshLayout() {
if (mainWindow.call.core.state === LinphoneEnums.CallState.Connected || mainWindow.call.core.state === LinphoneEnums.CallState.StreamsRunning) {
bottomButtonsLayout.layoutDirection = Qt.RightToLeft
connectedCallButtons.visible = true
} else if (mainWindow.callState === LinphoneEnums.CallState.OutgoingInit || mainWindow.callState === LinphoneEnums.CallState.End) {
connectedCallButtons.visible = false
bottomButtonsLayout.layoutDirection = Qt.LeftToRight
}
}
Connections {
target: mainWindow
onCallStateChanged: bottomButtonsLayout.refreshLayout()
onCallChanged: bottomButtonsLayout.refreshLayout()
}
function setButtonsEnabled(enabled) {
for(var i=0; i < children.length; ++i) {
children[i].enabled = false
@ -490,11 +728,11 @@ Window {
Layout.row: 0
enabledIcon: AppIcons.endCall
checkable: false
Layout.column: mainWindow.callState == LinphoneEnums.CallState.OutgoingInit
|| mainWindow.callState == LinphoneEnums.CallState.OutgoingProgress
|| mainWindow.callState == LinphoneEnums.CallState.OutgoingRinging
|| mainWindow.callState == LinphoneEnums.CallState.OutgoingEarlyMedia
|| mainWindow.callState == LinphoneEnums.CallState.IncomingReceived
Layout.column: mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingInit
|| mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingProgress
|| mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingRinging
|| mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingEarlyMedia
|| mainWindow.call.core.state == LinphoneEnums.CallState.IncomingReceived
? 0 : bottomButtonsLayout.columns - 1
Layout.preferredWidth: 75 * DefaultStyle.dp
Layout.preferredHeight: 55 * DefaultStyle.dp
@ -503,7 +741,7 @@ Window {
color: DefaultStyle.danger_500main
radius: 71 * DefaultStyle.dp
}
onClicked: mainWindow.endCall()
onClicked: mainWindow.endCall(mainWindow.call)
}
RowLayout {
id: connectedCallButtons
@ -524,30 +762,51 @@ Window {
: DefaultStyle.grey_500
: DefaultStyle.grey_600
}
enabled: mainWindow.callState != LinphoneEnums.CallState.PausedByRemote
enabled: mainWindow.call.core.state != LinphoneEnums.CallState.PausedByRemote
enabledIcon: enabled && checked ? AppIcons.play : AppIcons.pause
checked: mainWindow.call && (mainWindow.call.callState === LinphoneEnums.CallState.Paused
|| mainWindow.call.callState === LinphoneEnums.CallState.PausedByRemote) || false
onClicked: mainWindow.call.core.lSetPaused(!mainWindow.call.core.paused)
checked: mainWindow.call.core.paused
onClicked: {
mainWindow.call.core.lSetPaused(!callsModel.currentCall.core.paused)
}
}
BottomButton {
id: newCallButton
checkable: false
enabledIcon: AppIcons.newCall
Layout.preferredWidth: 55 * DefaultStyle.dp
Layout.preferredHeight: 55 * DefaultStyle.dp
onClicked: {
var mainWin = UtilsCpp.getMainWindow()
UtilsCpp.smartShowWindow(mainWin)
mainWin.goToNewCall()
}
}
BottomButton {
id: transferCallButton
enabledIcon: AppIcons.transferCall
Layout.preferredWidth: 55 * DefaultStyle.dp
Layout.preferredHeight: 55 * DefaultStyle.dp
onClicked: {
rightPanel.visible = true
rightPanel.currentIndex = 0
onCheckedChanged: {
if (checked) {
rightPanel.visible = true
rightPanel.replace(contactsListPanel)
} else {
rightPanel.visible = false
}
}
Connections {
target: rightPanel
onVisibleChanged: if(!rightPanel.visible) transferCallButton.checked = false
}
}
}
RowLayout {
Layout.row: 0
Layout.column: mainWindow.callState == LinphoneEnums.CallState.OutgoingInit
|| mainWindow.callState == LinphoneEnums.CallState.OutgoingProgress
|| mainWindow.callState == LinphoneEnums.CallState.OutgoingRinging
|| mainWindow.callState == LinphoneEnums.CallState.OutgoingEarlyMedia
|| mainWindow.callState == LinphoneEnums.CallState.IncomingReceived
Layout.column: mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingInit
|| mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingProgress
|| mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingRinging
|| mainWindow.call.core.state == LinphoneEnums.CallState.OutgoingEarlyMedia
|| mainWindow.call.core.state == LinphoneEnums.CallState.IncomingReceived
? bottomButtonsLayout.columns - 1 : 0
BottomButton {
enabledIcon: AppIcons.videoCamera
@ -589,10 +848,30 @@ Window {
spacing: 10 * DefaultStyle.dp
Control.Button {
id: dialerButton
// width: 150
id: callListButton
Layout.fillWidth: true
background: Item {
visible: false
}
contentItem: RowLayout {
Image {
width: 24 * DefaultStyle.dp
height: 24 * DefaultStyle.dp
source: AppIcons.callList
}
Text {
text: qsTr("Liste d'appel")
}
}
onClicked: {
rightPanel.visible = true
rightPanel.replace(callsListPanel)
moreOptionsMenu.close()
}
}
Control.Button {
id: dialerButton
Layout.fillWidth: true
// height: 32 * DefaultStyle.dp
background: Item {
visible: false
}
@ -608,14 +887,13 @@ Window {
}
onClicked: {
rightPanel.visible = true
rightPanel.currentIndex = 1
rightPanel.replace(dialerPanel)
moreOptionsMenu.close()
}
}
Control.Button {
id: speakerButton
Layout.fillWidth: true
// height: 32 * DefaultStyle.dp
checkable: true
background: Item {
visible: false

View file

@ -16,6 +16,71 @@ Item {
signal addAccountRequest()
function goToNewCall() {
tabbar.currentIndex = 0
callPage.goToNewCall()
}
function transferCallSucceed() {
transferSucceedPopup.open()
}
Timer {
id: autoClosePopup
interval: 5000
onTriggered: {
transferSucceedPopup.close()
}
}
Popup {
id: transferSucceedPopup
onVisibleChanged: if (visible) autoClosePopup.restart()
closePolicy: Control.Popup.NoAutoClose
x : parent.x + parent.width - width
y : parent.y + parent.height - height
rightMargin: 20 * DefaultStyle.dp
bottomMargin: 20 * DefaultStyle.dp
padding: 20 * DefaultStyle.dp
underlineColor: DefaultStyle.success_500main
radius: 0
contentItem: RowLayout {
spacing: 15 * DefaultStyle.dp
EffectImage {
image.source: AppIcons.smiley
colorizationColor: DefaultStyle.success_500main
Layout.preferredWidth: 32 * DefaultStyle.dp
Layout.preferredHeight: 32 * DefaultStyle.dp
width: 32 * DefaultStyle.dp
height: 32 * DefaultStyle.dp
}
Rectangle {
Layout.preferredWidth: 1 * DefaultStyle.dp
Layout.preferredHeight: parent.height
color: DefaultStyle.main2_200
}
ColumnLayout {
Text {
text: qsTr("Appel transféré")
color: DefaultStyle.success_500main
font {
pixelSize: 16 * DefaultStyle.dp
weight: 800 * DefaultStyle.dp
}
}
Text {
Layout.alignment: Qt.AlignHCenter
Layout.fillWidth: true
text: qsTr("Votre correspondant a été transféré au contact sélectionné")
color: DefaultStyle.main2_500main
font {
pixelSize: 12 * DefaultStyle.dp
weight: 300 * DefaultStyle.dp
}
}
}
}
}
RowLayout {
anchors.fill: parent
// spacing: 30
@ -93,6 +158,7 @@ Item {
currentIndex: tabbar.currentIndex
CallPage {
id: callPage
}
//ContactPage{}
//ConversationPage{}

View file

@ -11,6 +11,16 @@ Window {
visible: true
title: qsTr("Linphone")
property bool firstConnection: true
function goToNewCall() {
mainWindowStackView.replace(mainPage, StackView.Immediate)
mainWindowStackView.currentItem.goToNewCall()
}
function transferCallSucceed() {
mainWindowStackView.replace(mainPage, StackView.Immediate)
mainWindowStackView.currentItem.transferCallSucceed()
}
AccountProxy{
id: accountProxy
onHaveAccountChanged: {

View file

@ -31,7 +31,6 @@ Control.Popup {
shadowEnabled: true
shadowColor: DefaultStyle.grey_1000
shadowOpacity: 0.8
shadowHorizontalOffset: 10 * DefaultStyle.dp
shadowBlur: 1
}
Rectangle {

View file

@ -6,20 +6,29 @@ import Linphone
Control.Popup{
id: mainItem
padding: 0
property color underlineColor
property int radius: 16 * DefaultStyle.dp
background: Item{
Rectangle {
visible: mainItem.underlineColor != undefined
width: mainItem.width
height: mainItem.height + 2 * DefaultStyle.dp
color: mainItem.underlineColor
radius: mainItem.radius
}
Rectangle{
id: backgroundItem
width: mainItem.width
height: mainItem.height
radius: 16 * DefaultStyle.dp
radius: mainItem.radius
border.color: DefaultStyle.grey_0
border.width: 1
// border.width: 1
}
MultiEffect {
anchors.fill: backgroundItem
source: backgroundItem
maskSource: backgroundItem
shadowEnabled: true
shadowColor: DefaultStyle.grey_900
shadowBlur: 1.0
shadowOpacity: 0.1
}

View file

@ -10,7 +10,11 @@ AbstractMainPage {
emptyListText: qsTr("Historique d'appel vide")
newItemIconSource: AppIcons.newCall
onNoItemButtonPressed: listStackView.push(newCallItem)
onNoItemButtonPressed: goToNewCall()
function goToNewCall() {
listStackView.push(newCallItem)
}
leftPanelContent: Item {
Layout.fillWidth: true
@ -212,6 +216,7 @@ AbstractMainPage {
var addressEnd = "@sip.linphone.org"
if (!address.endsWith(addressEnd)) address += addressEnd
var callVarObject = UtilsCpp.createCall(address)
// var window = UtilsCpp.getCallsWindow()
}
}
}

View file

@ -25,6 +25,7 @@ QtObject {
property string phoneSelected: "image://internal/phone-selected.svg"
property string newCall: "image://internal/phone-plus.svg"
property string endCall: "image://internal/phone-disconnect.svg"
property string callList: "image://internal/phone-list.svg"
property string transferCall: "image://internal/phone-transfer.svg"
property string adressBook: "image://internal/address-book.svg"
property string adressBookSelected: "image://internal/address-book-selected.svg"