mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-01-17 11:28:07 +00:00
Fix moving current date.
Set dummy conference info as a null core. Load new items in case of chaning dates. Allow gui to load until current date. Fix video direction on screensharing. Update SDK for tone indication on meetings. Clean
This commit is contained in:
parent
656fdc8093
commit
bdbab66c94
13 changed files with 326 additions and 202 deletions
|
|
@ -29,6 +29,7 @@ ConferenceInfoGui::ConferenceInfoGui() {
|
|||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
|
||||
if (isInLinphoneThread()) moveToThread(App::getInstance()->thread());
|
||||
}
|
||||
|
||||
ConferenceInfoGui::ConferenceInfoGui(QSharedPointer<ConferenceInfoCore> core) {
|
||||
App::getInstance()->mEngine->setObjectOwnership(this, QQmlEngine::JavaScriptOwnership);
|
||||
mCore = core;
|
||||
|
|
|
|||
|
|
@ -86,8 +86,7 @@ void ConferenceInfoList::setSelf(QSharedPointer<ConferenceInfoList> me) {
|
|||
for (auto &item : *items) {
|
||||
connectItem(item);
|
||||
}
|
||||
resetData<ConferenceInfoCore>(*items);
|
||||
updateHaveCurrentDate();
|
||||
resetData(*items);
|
||||
delete items;
|
||||
if (isInitialization) {
|
||||
emit initialized();
|
||||
|
|
@ -99,52 +98,62 @@ void ConferenceInfoList::setSelf(QSharedPointer<ConferenceInfoList> me) {
|
|||
// This is needed because account does not have a contact address until
|
||||
// it is connected, so we can't verify if it is the organizer of a deleted
|
||||
// conference (which must hidden)
|
||||
auto connectModel = [this] {
|
||||
mCoreModelConnection->invokeToModel([this]() {
|
||||
if (mCurrentAccountCore) disconnect(mCurrentAccountCore.get());
|
||||
auto defaultAccount = CoreModel::getInstance()->getCore()->getDefaultAccount();
|
||||
if (defaultAccount) {
|
||||
mCurrentAccountCore = AccountCore::create(defaultAccount);
|
||||
connect(mCurrentAccountCore.get(), &AccountCore::registrationStateChanged, this,
|
||||
[this] { emit lUpdate(); });
|
||||
}
|
||||
});
|
||||
};
|
||||
mCoreModelConnection->makeConnectToModel(&CoreModel::defaultAccountChanged, connectModel);
|
||||
connectModel();
|
||||
|
||||
auto addConference = [this](const std::shared_ptr<linphone::ConferenceInfo> &confInfo) {
|
||||
auto list = getSharedList<ConferenceInfoCore>();
|
||||
auto haveConf =
|
||||
std::find_if(list.begin(), list.end(), [confInfo](const QSharedPointer<ConferenceInfoCore> &item) {
|
||||
std::shared_ptr<linphone::Address> confAddr = nullptr;
|
||||
if (item) ToolModel::interpretUrl(item->getUri());
|
||||
return confInfo->getUri()->weakEqual(confAddr);
|
||||
});
|
||||
if (haveConf == list.end()) {
|
||||
auto confInfoCore = build(confInfo);
|
||||
mCoreModelConnection->invokeToCore([this, confInfoCore] {
|
||||
add(confInfoCore);
|
||||
connectItem(confInfoCore);
|
||||
updateHaveCurrentDate();
|
||||
emit confInfoInserted(getCount() - 1, new ConferenceInfoGui(confInfoCore));
|
||||
});
|
||||
}
|
||||
};
|
||||
mCoreModelConnection->makeConnectToModel(&CoreModel::defaultAccountChanged,
|
||||
&ConferenceInfoList::updateCurrentAccount);
|
||||
updateCurrentAccount();
|
||||
|
||||
mCoreModelConnection->makeConnectToModel(
|
||||
&CoreModel::conferenceInfoCreated,
|
||||
[addConference](const std::shared_ptr<linphone::ConferenceInfo> &confInfo) { addConference(confInfo); });
|
||||
[this](const std::shared_ptr<linphone::ConferenceInfo> &confInfo) { addConference(confInfo); });
|
||||
mCoreModelConnection->makeConnectToModel(
|
||||
&CoreModel::conferenceInfoReceived,
|
||||
[this, addConference](const std::shared_ptr<linphone::Core> &core,
|
||||
const std::shared_ptr<const linphone::ConferenceInfo> &conferenceInfo) {
|
||||
[this](const std::shared_ptr<linphone::Core> &core,
|
||||
const std::shared_ptr<const linphone::ConferenceInfo> &conferenceInfo) {
|
||||
lDebug() << log().arg("conference info received") << conferenceInfo->getSubject();
|
||||
addConference(conferenceInfo->clone());
|
||||
});
|
||||
emit lUpdate(true);
|
||||
}
|
||||
|
||||
void ConferenceInfoList::resetData(QList<QSharedPointer<ConferenceInfoCore>> data) {
|
||||
beginResetModel();
|
||||
mList.clear();
|
||||
for (auto i : data)
|
||||
mList << i.template objectCast<QObject>();
|
||||
updateHaveCurrentDate(); // Set have current date before resetting models to let proxy having this info.
|
||||
endResetModel();
|
||||
}
|
||||
|
||||
void ConferenceInfoList::addConference(const std::shared_ptr<linphone::ConferenceInfo> &confInfo) {
|
||||
auto list = getSharedList<ConferenceInfoCore>();
|
||||
auto haveConf = std::find_if(list.begin(), list.end(), [confInfo](const QSharedPointer<ConferenceInfoCore> &item) {
|
||||
std::shared_ptr<linphone::Address> confAddr = nullptr;
|
||||
if (item) ToolModel::interpretUrl(item->getUri());
|
||||
return confInfo->getUri()->weakEqual(confAddr);
|
||||
});
|
||||
if (haveConf == list.end()) {
|
||||
auto confInfoCore = build(confInfo);
|
||||
mCoreModelConnection->invokeToCore([this, confInfoCore] {
|
||||
connectItem(confInfoCore);
|
||||
add(confInfoCore);
|
||||
updateHaveCurrentDate();
|
||||
emit confInfoInserted(confInfoCore);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void ConferenceInfoList::updateCurrentAccount() {
|
||||
mCoreModelConnection->invokeToModel([this]() {
|
||||
if (mCurrentAccountCore) disconnect(mCurrentAccountCore.get());
|
||||
auto defaultAccount = CoreModel::getInstance()->getCore()->getDefaultAccount();
|
||||
if (defaultAccount) {
|
||||
mCurrentAccountCore = AccountCore::create(defaultAccount);
|
||||
connect(mCurrentAccountCore.get(), &AccountCore::registrationStateChanged, this,
|
||||
[this] { emit lUpdate(true); });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool ConferenceInfoList::haveCurrentDate() const {
|
||||
return mHaveCurrentDate;
|
||||
}
|
||||
|
|
@ -179,6 +188,19 @@ int ConferenceInfoList::getCurrentDateIndex() {
|
|||
return it == confInfoList.end() ? -1 : std::distance(confInfoList.begin(), it);
|
||||
}
|
||||
|
||||
QSharedPointer<ConferenceInfoCore> ConferenceInfoList::getCurrentDateConfInfo() {
|
||||
auto today = QDate::currentDate();
|
||||
auto confInfoList = getSharedList<ConferenceInfoCore>();
|
||||
QList<QSharedPointer<ConferenceInfoCore>>::iterator it;
|
||||
if (mHaveCurrentDate) {
|
||||
it = std::find_if(confInfoList.begin(), confInfoList.end(),
|
||||
[today](const QSharedPointer<ConferenceInfoCore> &item) {
|
||||
return item && item->getDateTimeUtc().date() == today;
|
||||
});
|
||||
} else it = std::find(confInfoList.begin(), confInfoList.end(), nullptr);
|
||||
return it != confInfoList.end() ? *it : nullptr;
|
||||
}
|
||||
|
||||
QSharedPointer<ConferenceInfoCore>
|
||||
ConferenceInfoList::build(const std::shared_ptr<linphone::ConferenceInfo> &conferenceInfo) {
|
||||
auto me = CoreModel::getInstance()->getCore()->getDefaultAccount()->getParams()->getIdentityAddress();
|
||||
|
|
@ -196,10 +218,11 @@ ConferenceInfoList::build(const std::shared_ptr<linphone::ConferenceInfo> &confe
|
|||
}
|
||||
|
||||
void ConferenceInfoList::connectItem(QSharedPointer<ConferenceInfoCore> confInfoCore) {
|
||||
connect(confInfoCore.get(), &ConferenceInfoCore::removed, this, [this](ConferenceInfoCore *confInfo) {
|
||||
remove(confInfo);
|
||||
updateHaveCurrentDate();
|
||||
});
|
||||
if (confInfoCore)
|
||||
connect(confInfoCore.get(), &ConferenceInfoCore::removed, this, [this](ConferenceInfoCore *confInfo) {
|
||||
remove(confInfo);
|
||||
updateHaveCurrentDate();
|
||||
});
|
||||
}
|
||||
|
||||
QHash<int, QByteArray> ConferenceInfoList::roleNames() const {
|
||||
|
|
@ -221,10 +244,10 @@ QVariant ConferenceInfoList::data(const QModelIndex &index, int role) const {
|
|||
}
|
||||
} else { // Dummy date
|
||||
if (role == Qt::DisplayRole) {
|
||||
return QVariant::fromValue(new ConferenceInfoGui());
|
||||
return QVariant::fromValue(new ConferenceInfoGui(nullptr));
|
||||
} else if (role == Qt::DisplayRole + 1) {
|
||||
return Utils::toDateMonthString(QDateTime::currentDateTimeUtc());
|
||||
}
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,13 +39,17 @@ public:
|
|||
~ConferenceInfoList();
|
||||
|
||||
void setSelf(QSharedPointer<ConferenceInfoList> me);
|
||||
void resetData(QList<QSharedPointer<ConferenceInfoCore>> data);
|
||||
|
||||
void addConference(const std::shared_ptr<linphone::ConferenceInfo> &confInfo);
|
||||
void updateCurrentAccount();
|
||||
|
||||
bool haveCurrentDate() const;
|
||||
void setHaveCurrentDate(bool have);
|
||||
|
||||
void updateHaveCurrentDate();
|
||||
|
||||
int getCurrentDateIndex();
|
||||
QSharedPointer<ConferenceInfoCore> getCurrentDateConfInfo();
|
||||
|
||||
QSharedPointer<ConferenceInfoCore> build(const std::shared_ptr<linphone::ConferenceInfo> &conferenceInfo);
|
||||
void connectItem(QSharedPointer<ConferenceInfoCore> confInfoCore);
|
||||
|
|
@ -60,7 +64,7 @@ signals:
|
|||
void addCurrentDateChanged();
|
||||
void haveCurrentDateChanged();
|
||||
void currentDateIndexChanged(int index);
|
||||
void confInfoInserted(int index, ConferenceInfoGui *data);
|
||||
void confInfoInserted(QSharedPointer<ConferenceInfoCore> data);
|
||||
|
||||
private:
|
||||
QSharedPointer<SafeConnection<ConferenceInfoList, CoreModel>> mCoreModelConnection;
|
||||
|
|
|
|||
|
|
@ -32,27 +32,20 @@ ConferenceInfoProxy::ConferenceInfoProxy(QObject *parent) : LimitProxy(parent) {
|
|||
connect(
|
||||
mList.get(), &ConferenceInfoList::haveCurrentDateChanged, this,
|
||||
[this] {
|
||||
setCurrentDateIndex(getCurrentDateIndex());
|
||||
auto sortModel = dynamic_cast<SortFilterList *>(sourceModel());
|
||||
sortModel->invalidate();
|
||||
sortModel->invalidate(); // New date => sort and filter change.
|
||||
loadUntil(nullptr);
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
connect(
|
||||
App::getInstance(), &App::currentDateChanged, this, [this] { setCurrentDateIndex(getCurrentDateIndex()); },
|
||||
Qt::QueuedConnection);
|
||||
connect(
|
||||
mList.get(), &ConferenceInfoList::confInfoInserted, this,
|
||||
[this](int index, ConferenceInfoGui *data) {
|
||||
[this](QSharedPointer<ConferenceInfoCore> data) {
|
||||
auto sortModel = dynamic_cast<SortFilterList *>(sourceModel());
|
||||
if (sortModel) {
|
||||
auto proxyIndex = sortModel->mapFromSource(mList->index(index, 0)).row();
|
||||
if (proxyIndex >= getMaxDisplayItems()) setMaxDisplayItems(proxyIndex + 1);
|
||||
emit conferenceInfoCreated(proxyIndex);
|
||||
}
|
||||
sortModel->invalidate(); // New conf => sort change. Filter can change if on current date.
|
||||
emit conferenceInfoCreated(new ConferenceInfoGui(data));
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
connect(mList.get(), &ConferenceInfoList::initialized, this,
|
||||
[this] { setCurrentDateIndex(getCurrentDateIndex()); });
|
||||
connect(mList.get(), &ConferenceInfoList::initialized, this, &ConferenceInfoProxy::initialized);
|
||||
}
|
||||
|
||||
ConferenceInfoProxy::~ConferenceInfoProxy() {
|
||||
|
|
@ -90,19 +83,35 @@ bool ConferenceInfoProxy::SortFilterList::filterAcceptsRow(int sourceRow, const
|
|||
}
|
||||
}
|
||||
|
||||
int ConferenceInfoProxy::getCurrentDateIndex() const {
|
||||
auto sortModel = dynamic_cast<SortFilterList *>(sourceModel());
|
||||
auto modelIndex = mList->getCurrentDateIndex();
|
||||
auto proxyIndex = sortModel->mapFromSource(mList->index(modelIndex, 0)).row();
|
||||
return proxyIndex;
|
||||
void ConferenceInfoProxy::clear() {
|
||||
mList->clearData();
|
||||
}
|
||||
|
||||
void ConferenceInfoProxy::setCurrentDateIndex(int index) {
|
||||
if (mCurrentDateIndex != index) {
|
||||
if (index >= mMaxDisplayItems) setMaxDisplayItems(index + 1);
|
||||
mCurrentDateIndex = index;
|
||||
emit currentDateIndexChanged(index);
|
||||
int ConferenceInfoProxy::loadUntil(ConferenceInfoGui *confInfo) {
|
||||
return loadUntil(confInfo ? confInfo->mCore : nullptr);
|
||||
}
|
||||
|
||||
int ConferenceInfoProxy::loadUntil(QSharedPointer<ConferenceInfoCore> data) {
|
||||
auto confInfoList = getListModel<ConferenceInfoList>();
|
||||
if (confInfoList) {
|
||||
int listIndex = -1;
|
||||
// Get list index.
|
||||
if (!data) listIndex = confInfoList->getCurrentDateIndex();
|
||||
else confInfoList->get(data.get(), &listIndex);
|
||||
if (listIndex == -1) return -1;
|
||||
// Get the index inside sorted/filtered list.
|
||||
auto listModelIndex =
|
||||
dynamic_cast<SortFilterList *>(sourceModel())->mapFromSource(confInfoList->index(listIndex, 0));
|
||||
// Load enough items into LimitProxy.
|
||||
if (mMaxDisplayItems < listModelIndex.row()) setMaxDisplayItems(listModelIndex.row() + mDisplayItemsStep);
|
||||
// Get the new index inside sorted/filtered list.
|
||||
listModelIndex =
|
||||
dynamic_cast<SortFilterList *>(sourceModel())->mapFromSource(confInfoList->index(listIndex, 0));
|
||||
// Get the index inside LimitProxy.
|
||||
listIndex = mapFromSource(listModelIndex).row();
|
||||
return listIndex;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool ConferenceInfoProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft,
|
||||
|
|
|
|||
|
|
@ -25,12 +25,13 @@
|
|||
#include "tool/AbstractObject.hpp"
|
||||
|
||||
class ConferenceInfoList;
|
||||
class ConferenceInfoGui;
|
||||
class ConferenceInfoCore;
|
||||
|
||||
class ConferenceInfoProxy : public LimitProxy, public AbstractObject {
|
||||
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(bool haveCurrentDate READ haveCurrentDate NOTIFY haveCurrentDateChanged)
|
||||
// Q_PROPERTY(int currentDateIndex READ getCurrentDateIndex NOTIFY currentDateIndexChanged)
|
||||
|
||||
public:
|
||||
enum ConferenceInfoFiltering { None = 0, Future = 1 };
|
||||
|
|
@ -43,17 +44,18 @@ public:
|
|||
|
||||
bool haveCurrentDate() const;
|
||||
|
||||
Q_INVOKABLE int getCurrentDateIndex() const;
|
||||
Q_INVOKABLE void setCurrentDateIndex(int index);
|
||||
|
||||
Q_INVOKABLE void clear();
|
||||
Q_INVOKABLE int loadUntil(ConferenceInfoGui *confInfo);
|
||||
int loadUntil(QSharedPointer<ConferenceInfoCore> data);
|
||||
signals:
|
||||
void initialized();
|
||||
void haveCurrentDateChanged();
|
||||
void conferenceInfoCreated(int index);
|
||||
void currentDateIndexChanged(int index);
|
||||
void conferenceInfoCreated(ConferenceInfoGui *confInfo);
|
||||
|
||||
private:
|
||||
QSharedPointer<ConferenceInfoList> mList;
|
||||
int mCurrentDateIndex = -1;
|
||||
ConferenceInfoCore *mCurrentConfInfo = nullptr;
|
||||
// int mCurrentDateIndex = -1;
|
||||
|
||||
DECLARE_ABSTRACT_OBJECT
|
||||
};
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ int MagicSearchProxy::loadUntil(const QString &address) {
|
|||
if (listIndex == -1) return -1;
|
||||
listIndex =
|
||||
dynamic_cast<SortFilterList *>(sourceModel())->mapFromSource(magicSearchList->index(listIndex, 0)).row();
|
||||
if (mMaxDisplayItems < listIndex) setMaxDisplayItems(listIndex + 1);
|
||||
if (mMaxDisplayItems < listIndex) setMaxDisplayItems(listIndex + mDisplayItemsStep);
|
||||
return listIndex;
|
||||
}
|
||||
return -1;
|
||||
|
|
|
|||
|
|
@ -143,11 +143,11 @@ void ConferenceModel::toggleScreenSharing() {
|
|||
if (enable) {
|
||||
params->setConferenceVideoLayout(linphone::Conference::Layout::ActiveSpeaker);
|
||||
params->enableVideo(true);
|
||||
params->enableCamera(false);
|
||||
auto videoDirection = params->getVideoDirection();
|
||||
if (videoDirection != linphone::MediaDirection::SendOnly &&
|
||||
videoDirection != linphone::MediaDirection::SendRecv)
|
||||
params->setVideoDirection(linphone::MediaDirection::SendOnly);
|
||||
params->setVideoDirection(videoDirection == linphone::MediaDirection::RecvOnly ||
|
||||
videoDirection == linphone::MediaDirection::SendRecv
|
||||
? linphone::MediaDirection::SendRecv
|
||||
: linphone::MediaDirection::SendOnly);
|
||||
}
|
||||
if (params->isValid()) mMonitor->getCall()->update(params);
|
||||
else lCritical() << log().arg("Cannot toggle screen sharing because parameters are invalid");
|
||||
|
|
|
|||
|
|
@ -26,7 +26,6 @@ ColumnLayout {
|
|||
Layout.fillWidth: true
|
||||
columns: mainItem.useVerticalLayout ? 1 : children.length
|
||||
rows: 1
|
||||
onColumnsChanged: console.log("columns changed", columns, rows)
|
||||
columnSpacing: 49 * DefaultStyle.dp
|
||||
rowSpacing: 27 * DefaultStyle.dp
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,41 @@ Flickable{
|
|||
contactsList.currentIndex = -1
|
||||
suggestionsList.currentIndex = -1
|
||||
}
|
||||
|
||||
function findNextList(item, count, direction){
|
||||
if(count == 3) return null
|
||||
var nextItem
|
||||
switch(item){
|
||||
case suggestionsList:nextItem=(direction > 0 ? favoritesList : contactsList);break;
|
||||
case contactsList:nextItem=(direction > 0 ? suggestionsList : favoritesList);break;
|
||||
case favoritesList:nextItem=(direction > 0 ? contactsList : suggestionsList);break;
|
||||
default: return null
|
||||
}
|
||||
if( nextItem.model.count > 0) return nextItem
|
||||
else return findNextList(nextItem, count+1, direction)
|
||||
}
|
||||
|
||||
function updatePosition(list){
|
||||
var item = list.itemAtIndex(list.currentIndex)
|
||||
var centerItemPos = 0
|
||||
if( item && list.expanded){
|
||||
// For debugging just in case
|
||||
//var listPosition = item.mapToItem(favoriteList, item.x, item.y)
|
||||
//var newPosition = favoriteList.mapToItem(mainItem, listPosition.x, listPosition.y)
|
||||
//console.log("item pos: " +item.x + " / " +item.y)
|
||||
//console.log("fav pos: " +favoriteList.x + " / " +favoriteList.y)
|
||||
//console.log("fav content: " +favoriteList.contentX + " / " +favoriteList.contentY)
|
||||
//console.log("main pos: " +mainItem.x + " / " +mainItem.y)
|
||||
//console.log("main content: " +mainItem.contentX + " / " +mainItem.contentY)
|
||||
//console.log("list pos: " +listPosition.x + " / " +listPosition.y)
|
||||
//console.log("new pos: " +newPosition.x + " / " +newPosition.y)
|
||||
//console.log("header pos: " +headerItem.x + " / " +headerItem.y)
|
||||
//console.log("Moving to " + (headerItem.y+item.y))
|
||||
centerItemPos = item.y + list.y + list.headerHeight +item.height/2
|
||||
}
|
||||
var centerPos = centerItemPos - height/2
|
||||
mainItem.contentY = Math.max(0, Math.min(centerPos, height, contentHeight-height))
|
||||
}
|
||||
|
||||
onHighlightedContactChanged:{
|
||||
favoritesList.highlightedContact = highlightedContact
|
||||
|
|
@ -126,39 +161,6 @@ Flickable{
|
|||
if( (contactsProxy.haveMore && contactList.expanded ) || mainItem.hideSuggestions) contactsProxy.displayMore()
|
||||
else suggestionsProxy.displayMore()
|
||||
}
|
||||
function findNextList(item, count, direction){
|
||||
if(count == 3) return null
|
||||
var nextItem
|
||||
switch(item){
|
||||
case suggestionsList:nextItem=(direction > 0 ? favoritesList : contactsList);break;
|
||||
case contactsList:nextItem=(direction > 0 ? suggestionsList : favoritesList);break;
|
||||
case favoritesList:nextItem=(direction > 0 ? contactsList : suggestionsList);break;
|
||||
default: return null
|
||||
}
|
||||
if( nextItem.model.count > 0) return nextItem
|
||||
else return findNextList(nextItem, count+1, direction)
|
||||
}
|
||||
function updatePosition(list){
|
||||
var item = list.itemAtIndex(list.currentIndex)
|
||||
var centerItemPos = 0
|
||||
if( item && list.expanded){
|
||||
// For debugging just in case
|
||||
//var listPosition = item.mapToItem(favoriteList, item.x, item.y)
|
||||
//var newPosition = favoriteList.mapToItem(mainItem, listPosition.x, listPosition.y)
|
||||
//console.log("item pos: " +item.x + " / " +item.y)
|
||||
//console.log("fav pos: " +favoriteList.x + " / " +favoriteList.y)
|
||||
//console.log("fav content: " +favoriteList.contentX + " / " +favoriteList.contentY)
|
||||
//console.log("main pos: " +mainItem.x + " / " +mainItem.y)
|
||||
//console.log("main content: " +mainItem.contentX + " / " +mainItem.contentY)
|
||||
//console.log("list pos: " +listPosition.x + " / " +listPosition.y)
|
||||
//console.log("new pos: " +newPosition.x + " / " +newPosition.y)
|
||||
//console.log("header pos: " +headerItem.x + " / " +headerItem.y)
|
||||
//console.log("Moving to " + (headerItem.y+item.y))
|
||||
centerItemPos = item.y + list.y + list.headerHeight +item.height/2
|
||||
}
|
||||
var centerPos = centerItemPos - height/2
|
||||
mainItem.contentY = Math.max(0, Math.min(centerPos, height, contentHeight-height))
|
||||
}
|
||||
Behavior on contentY{
|
||||
NumberAnimation {
|
||||
duration: 500
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import QtQuick
|
||||
import QtQuick.Layouts
|
||||
import QtQuick.Effects
|
||||
import QtQuick.Controls.Basic
|
||||
|
||||
import Linphone
|
||||
import QtQml
|
||||
|
|
@ -8,36 +9,121 @@ import UtilsCpp
|
|||
|
||||
ListView {
|
||||
id: mainItem
|
||||
visible: count > 0
|
||||
clip: true
|
||||
|
||||
property string searchBarText
|
||||
property bool hoverEnabled: true
|
||||
property var delegateButtons
|
||||
property ConferenceInfoGui selectedConference: model && currentIndex != -1 ? model.getAt(currentIndex) : null
|
||||
property ConferenceInfoGui selectedConference
|
||||
property bool _moveToIndex: false
|
||||
|
||||
visible: count > 0
|
||||
clip: true
|
||||
cacheBuffer: height/2
|
||||
|
||||
spacing: 8 * DefaultStyle.dp
|
||||
highlightFollowsCurrentItem: true
|
||||
highlightMoveVelocity: 1500
|
||||
|
||||
onCountChanged: {
|
||||
selectedConference = model && currentIndex != -1 && currentIndex < model.count ? model.getAt(currentIndex) : null
|
||||
highlightFollowsCurrentItem: false
|
||||
|
||||
function selectIndex(index){
|
||||
mainItem.currentIndex = index
|
||||
}
|
||||
onCurrentIndexChanged: {
|
||||
selectedConference = model.getAt(currentIndex) || null
|
||||
|
||||
function resetSelections(){
|
||||
mainItem.selectedConference = null
|
||||
mainItem.currentIndex = -1
|
||||
}
|
||||
// Issues Notes:
|
||||
// positionViewAtIndex:
|
||||
// - if currentItem was in cache, it will not go to it (ex: contentY=63, currentItem.y=3143)
|
||||
// - Animation don't work
|
||||
function moveToCurrentItem(){
|
||||
var centerItemPos = 0
|
||||
if( currentItem){
|
||||
centerItemPos = currentItem.y + currentItem.height/2
|
||||
}
|
||||
var centerPos = centerItemPos - height/2
|
||||
moveBehaviorTimer.startAnimation()
|
||||
mainItem.contentY = Math.max(0, Math.min(centerPos, contentHeight-height))
|
||||
}
|
||||
onCurrentItemChanged: {
|
||||
moveToCurrentItem()
|
||||
if(currentItem) {
|
||||
mainItem.selectedConference = currentItem.itemGui
|
||||
currentItem.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
// When cache is updating, contentHeight changes. Update position if we are moving the view.
|
||||
onContentHeightChanged:{
|
||||
if(moveBehavior.enabled){
|
||||
moveToCurrentItem()
|
||||
}
|
||||
}
|
||||
onAtYEndChanged: if(atYEnd) confInfoProxy.displayMore()
|
||||
|
||||
Timer{
|
||||
id: moveBehaviorTimer
|
||||
interval: 501
|
||||
onTriggered: moveBehavior.enabled = false
|
||||
function startAnimation(){
|
||||
moveBehavior.enabled = true
|
||||
moveBehaviorTimer.restart()
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on contentY{
|
||||
id: moveBehavior
|
||||
enabled: false
|
||||
NumberAnimation {
|
||||
duration: 500
|
||||
easing.type: Easing.OutExpo
|
||||
onFinished: {// Not call if on Behavior. Callback just in case.
|
||||
moveBehavior.enabled = false
|
||||
}
|
||||
}
|
||||
}
|
||||
Keys.onPressed: (event)=> {
|
||||
if(event.key == Qt.Key_Up) {
|
||||
if(currentIndex > 0 ) {
|
||||
selectIndex(mainItem.currentIndex-1)
|
||||
event.accepted = true
|
||||
} else {
|
||||
selectIndex(model.count - 1)
|
||||
event.accepted = true
|
||||
}
|
||||
}else if(event.key == Qt.Key_Down){
|
||||
if(currentIndex < model.count - 1) {
|
||||
selectIndex(currentIndex+1)
|
||||
event.accepted = true
|
||||
} else {
|
||||
selectIndex(0)
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
model: ConferenceInfoProxy {
|
||||
id: confInfoProxy
|
||||
filterText: searchBarText
|
||||
filterType: ConferenceInfoProxy.None
|
||||
initialDisplayItems: mainItem.height / (63 * DefaultStyle.dp) + 5
|
||||
displayItemsStep: initialDisplayItems/2
|
||||
onConferenceInfoCreated: (index) => {
|
||||
mainItem.currentIndex = index
|
||||
function selectData(confInfoGui){
|
||||
mainItem.currentIndex = loadUntil(confInfoGui)
|
||||
}
|
||||
onCurrentDateIndexChanged: (index) => mainItem.currentIndex = index
|
||||
onConferenceInfoCreated: (confInfoGui) => {
|
||||
selectData(confInfoGui)
|
||||
}
|
||||
onInitialized: {
|
||||
// Move to currentDate
|
||||
selectData(null)
|
||||
}
|
||||
}
|
||||
|
||||
ScrollBar.vertical: ScrollBar {
|
||||
id: scrollbar
|
||||
rightPadding: 8 * DefaultStyle.dp
|
||||
|
||||
active: true
|
||||
interactive: true
|
||||
policy: mainItem.contentHeight > mainItem.height ? ScrollBar.AlwaysOn : ScrollBar.AlwaysOff
|
||||
}
|
||||
|
||||
section {
|
||||
|
|
@ -56,30 +142,31 @@ ListView {
|
|||
}
|
||||
property: '$sectionMonth'
|
||||
}
|
||||
|
||||
|
||||
delegate: FocusScope {
|
||||
id: itemDelegate
|
||||
height: 63 * DefaultStyle.dp
|
||||
height: 63 * DefaultStyle.dp + (!isFirst && dateDay.visible ? topOffset : 0)
|
||||
width: mainItem.width
|
||||
enabled: !isCanceled && haveModel
|
||||
property var previousItem : mainItem.model.count > 0 && index > 0 ? mainItem.model.getAt(index-1) : null
|
||||
property var dateTime: !!$modelData && $modelData.core.haveModel ? $modelData.core.dateTime : UtilsCpp.getCurrentDateTime()
|
||||
|
||||
property var itemGui: $modelData
|
||||
// Do not use itemAtIndex because of caching items. Using getAt ensure to have a GUI
|
||||
property var previousConfInfoGui : mainItem.model.getAt(index-1)
|
||||
property var dateTime: itemGui.core ? itemGui.core.dateTimeUtc : UtilsCpp.getCurrentDateTime()
|
||||
property string day : UtilsCpp.toDateDayNameString(dateTime)
|
||||
property string dateString: UtilsCpp.toDateString(dateTime)
|
||||
property string previousDateString: previousItem ? UtilsCpp.toDateString(previousItem.core ? previousItem.core.dateTimeUtc : UtilsCpp.getCurrentDateTimeUtc()) : ''
|
||||
property string previousDateString: previousConfInfoGui ? UtilsCpp.toDateString(previousConfInfoGui.core ? previousConfInfoGui.core.dateTimeUtc : UtilsCpp.getCurrentDateTimeUtc()) : ''
|
||||
property bool isFirst : ListView.previousSection !== ListView.section
|
||||
property int topOffset: (dateDay.visible && !isFirst? 8 * DefaultStyle.dp : 0)
|
||||
property var endDateTime: $modelData ? $modelData.core.endDateTime : UtilsCpp.getCurrentDateTime()
|
||||
property var haveModel: !!$modelData && $modelData != undefined && $modelData.core.haveModel || false
|
||||
property bool isCanceled: $modelData?.core.state === LinphoneEnums.ConferenceInfoState.Cancelled || false
|
||||
Component.onCompleted: if (!isFirst && dateDay.visible) {
|
||||
height = (63+topOffset)*DefaultStyle.dp
|
||||
delegateIn.anchors.topMargin = topOffset
|
||||
}
|
||||
property var endDateTime: itemGui.core ? itemGui.core.endDateTime : UtilsCpp.getCurrentDateTime()
|
||||
property bool haveModel: itemGui.core ? itemGui.core.haveModel : false
|
||||
property bool isCanceled: itemGui.core ? itemGui.core.state === LinphoneEnums.ConferenceInfoState.Cancelled : false
|
||||
property bool isSelected: itemGui.core == mainItem.selectedConference?.core
|
||||
|
||||
RowLayout{
|
||||
id: delegateIn
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: !itemDelegate.isFirst && dateDay.visible ? itemDelegate.topOffset : 0
|
||||
spacing: 0
|
||||
Item{
|
||||
Layout.preferredWidth: 32 * DefaultStyle.dp
|
||||
|
|
@ -141,7 +228,7 @@ ListView {
|
|||
anchors.rightMargin: 5 // margin to avoid clipping shadows at right
|
||||
radius: 10 * DefaultStyle.dp
|
||||
visible: itemDelegate.haveModel || itemDelegate.activeFocus
|
||||
color: mainItem.currentIndex === index ? DefaultStyle.main2_200 : DefaultStyle.grey_0
|
||||
color: itemDelegate.isSelected ? DefaultStyle.main2_200 : DefaultStyle.grey_0 // mainItem.currentIndex === index
|
||||
ColumnLayout {
|
||||
anchors.fill: parent
|
||||
anchors.left: parent.left
|
||||
|
|
@ -156,7 +243,7 @@ ListView {
|
|||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
}
|
||||
Text {
|
||||
text: $modelData? $modelData.core.subject : ""
|
||||
text: itemGui.core? itemGui.core.subject : ""
|
||||
Layout.fillWidth: true
|
||||
maximumLineCount: 1
|
||||
font {
|
||||
|
|
@ -203,8 +290,7 @@ ListView {
|
|||
cursorShape: Qt.PointingHandCursor
|
||||
visible: itemDelegate.haveModel
|
||||
onClicked: {
|
||||
mainItem.currentIndex = index
|
||||
itemDelegate.forceActiveFocus()
|
||||
mainItem.selectIndex(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,7 +31,6 @@ AbstractMainPage {
|
|||
if (rightPanelStackView.currentItem && rightPanelStackView.currentItem.objectName === "contactDetail") rightPanelStackView.clear()
|
||||
}
|
||||
}
|
||||
signal forceListsUpdate()
|
||||
|
||||
onNoItemButtonPressed: createContact("", "")
|
||||
|
||||
|
|
|
|||
|
|
@ -8,30 +8,18 @@ import UtilsCpp
|
|||
// TODO : spacing
|
||||
AbstractMainPage {
|
||||
id: mainItem
|
||||
noItemButtonText: qsTr("Créer une réunion")
|
||||
emptyListText: qsTr("Aucune réunion")
|
||||
newItemIconSource: AppIcons.plusCircle
|
||||
rightPanelColor: selectedConference ? DefaultStyle.grey_0 : DefaultStyle.grey_100
|
||||
|
||||
property ConferenceInfoGui selectedConference
|
||||
property int meetingListCount
|
||||
signal returnRequested()
|
||||
signal addParticipantsValidated(list<string> selectedParticipants)
|
||||
Component.onCompleted: rightPanelStackView.push(overridenRightPanel, Control.StackView.Immediate)
|
||||
|
||||
noItemButtonText: qsTr("Créer une réunion")
|
||||
emptyListText: qsTr("Aucune réunion")
|
||||
newItemIconSource: AppIcons.plusCircle
|
||||
rightPanelColor: selectedConference ? DefaultStyle.grey_0 : DefaultStyle.grey_100
|
||||
showDefaultItem: leftPanelStackView.currentItem?.objectName === "listLayout" && meetingListCount === 0
|
||||
|
||||
onVisibleChanged: if (!visible) {
|
||||
leftPanelStackView.clear()
|
||||
leftPanelStackView.push(leftPanelStackView.initialItem)
|
||||
}
|
||||
|
||||
onSelectedConferenceChanged: {
|
||||
overridenRightPanelStackView.clear()
|
||||
if (selectedConference && selectedConference.core.haveModel) {
|
||||
if (!overridenRightPanelStackView.currentItem || overridenRightPanelStackView.currentItem != meetingDetail) overridenRightPanelStackView.replace(meetingDetail, Control.StackView.Immediate)
|
||||
}
|
||||
}
|
||||
|
||||
onNoItemButtonPressed: editConference()
|
||||
|
||||
function editConference(confInfoGui = null) {
|
||||
var isCreation = !confInfoGui
|
||||
|
|
@ -49,6 +37,33 @@ AbstractMainPage {
|
|||
item.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
onVisibleChanged: if (!visible) {
|
||||
leftPanelStackView.clear()
|
||||
leftPanelStackView.push(leftPanelStackView.initialItem)
|
||||
|
||||
}
|
||||
|
||||
onSelectedConferenceChanged: {
|
||||
overridenRightPanelStackView.clear()
|
||||
if (selectedConference && selectedConference.core && selectedConference.core.haveModel) {
|
||||
if (!overridenRightPanelStackView.currentItem || overridenRightPanelStackView.currentItem != meetingDetail) overridenRightPanelStackView.replace(meetingDetail, Control.StackView.Immediate)
|
||||
}
|
||||
}
|
||||
|
||||
onNoItemButtonPressed: editConference()
|
||||
|
||||
Component.onCompleted: rightPanelStackView.push(overridenRightPanel, Control.StackView.Immediate)
|
||||
|
||||
leftPanelContent: Control.StackView {
|
||||
id: leftPanelStackView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.leftMargin: 45 * DefaultStyle.dp
|
||||
initialItem: listLayout
|
||||
clip: true
|
||||
}
|
||||
|
||||
Dialog {
|
||||
id: cancelAndDeleteConfDialog
|
||||
|
|
@ -96,15 +111,6 @@ AbstractMainPage {
|
|||
]
|
||||
}
|
||||
|
||||
leftPanelContent: Control.StackView {
|
||||
id: leftPanelStackView
|
||||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
Layout.leftMargin: 45 * DefaultStyle.dp
|
||||
initialItem: listLayout
|
||||
clip: true
|
||||
}
|
||||
|
||||
Item {
|
||||
id: overridenRightPanel
|
||||
Control.StackView {
|
||||
|
|
@ -188,8 +194,13 @@ AbstractMainPage {
|
|||
Layout.fillWidth: true
|
||||
Layout.fillHeight: true
|
||||
|
||||
onCountChanged: mainItem.meetingListCount = count
|
||||
searchBarText: searchBar.text
|
||||
|
||||
onCountChanged: mainItem.meetingListCount = count
|
||||
onSelectedConferenceChanged: {
|
||||
mainItem.selectedConference = selectedConference
|
||||
}
|
||||
|
||||
Keys.onPressed: (event) => {
|
||||
if(event.key == Qt.Key_Escape){
|
||||
searchBar.forceActiveFocus()
|
||||
|
|
@ -199,18 +210,6 @@ AbstractMainPage {
|
|||
event.accepted = true
|
||||
}
|
||||
}
|
||||
onSelectedConferenceChanged: {
|
||||
mainItem.selectedConference = selectedConference
|
||||
}
|
||||
Control.ScrollBar.vertical: ScrollBar {
|
||||
id: meetingsScrollbar
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 8 * DefaultStyle.dp
|
||||
active: true
|
||||
interactive: true
|
||||
policy: Control.ScrollBar.AsNeeded
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -579,7 +578,7 @@ AbstractMainPage {
|
|||
}
|
||||
Text {
|
||||
Layout.fillWidth: true
|
||||
text: mainItem.selectedConference ? mainItem.selectedConference.core.subject : ""
|
||||
text: mainItem.selectedConference ? mainItem.selectedConference.core?.subject : ""
|
||||
maximumLineCount: 1
|
||||
font {
|
||||
pixelSize: 20 * DefaultStyle.dp
|
||||
|
|
@ -591,7 +590,7 @@ AbstractMainPage {
|
|||
}
|
||||
Button {
|
||||
id: editButton
|
||||
property var isMeObj: UtilsCpp.isMe(mainItem.selectedConference?.core.organizerAddress)
|
||||
property var isMeObj: UtilsCpp.isMe(mainItem.selectedConference?.core?.organizerAddress)
|
||||
visible: mainItem.selectedConference && isMeObj && isMeObj.value || false
|
||||
Layout.preferredWidth: 24 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 24 * DefaultStyle.dp
|
||||
|
|
@ -622,8 +621,8 @@ AbstractMainPage {
|
|||
textColor: DefaultStyle.danger_500main
|
||||
contentImageColor: DefaultStyle.danger_500main
|
||||
inversedColors: true
|
||||
property var isMeObj: UtilsCpp.isMe(mainItem.selectedConference?.core.organizerAddress)
|
||||
property bool canCancel: isMeObj && isMeObj.value && mainItem.selectedConference.core.state !== LinphoneEnums.ConferenceInfoState.Cancelled
|
||||
property var isMeObj: UtilsCpp.isMe(mainItem.selectedConference?.core?.organizerAddress)
|
||||
property bool canCancel: isMeObj && isMeObj.value && mainItem.selectedConference?.core?.state !== LinphoneEnums.ConferenceInfoState.Cancelled
|
||||
icon.source: AppIcons.trashCan
|
||||
icon.width: 24 * DefaultStyle.dp
|
||||
icon.height: 24 * DefaultStyle.dp
|
||||
|
|
@ -670,7 +669,7 @@ AbstractMainPage {
|
|||
id: linkButton
|
||||
Layout.fillWidth: true
|
||||
font.bold: shadowEnabled
|
||||
text: mainItem.selectedConference ? mainItem.selectedConference.core.uri : ""
|
||||
text: mainItem.selectedConference ? mainItem.selectedConference.core?.uri : ""
|
||||
textSize: 14 * DefaultStyle.dp
|
||||
textWeight: 400 * DefaultStyle.dp
|
||||
underline: true
|
||||
|
|
@ -719,10 +718,10 @@ AbstractMainPage {
|
|||
}
|
||||
Text {
|
||||
text: mainItem.selectedConference
|
||||
? UtilsCpp.toDateString(mainItem.selectedConference.core.dateTimeUtc)
|
||||
+ " | " + UtilsCpp.toDateHourString(mainItem.selectedConference.core.dateTimeUtc)
|
||||
? UtilsCpp.toDateString(mainItem.selectedConference.core?.dateTimeUtc)
|
||||
+ " | " + UtilsCpp.toDateHourString(mainItem.selectedConference.core?.dateTimeUtc)
|
||||
+ " - "
|
||||
+ UtilsCpp.toDateHourString(mainItem.selectedConference.core.endDateTime)
|
||||
+ UtilsCpp.toDateHourString(mainItem.selectedConference.core?.endDateTime)
|
||||
: ''
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
|
|
@ -738,7 +737,7 @@ AbstractMainPage {
|
|||
source: AppIcons.globe
|
||||
}
|
||||
Text {
|
||||
text: qsTr("Time zone: ") + (mainItem.selectedConference ? (mainItem.selectedConference.core.timeZoneModel.displayName + ", " + mainItem.selectedConference.core.timeZoneModel.countryName) : "")
|
||||
text: qsTr("Time zone: ") + (mainItem.selectedConference ? (mainItem.selectedConference.core?.timeZoneModel.displayName + ", " + mainItem.selectedConference.core.timeZoneModel.countryName) : "")
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
capitalization: Font.Capitalize
|
||||
|
|
@ -748,7 +747,7 @@ AbstractMainPage {
|
|||
}
|
||||
}
|
||||
Section {
|
||||
visible: mainItem.selectedConference && mainItem.selectedConference.core.description.length != 0
|
||||
visible: mainItem.selectedConference && mainItem.selectedConference.core?.description.length != 0
|
||||
content: RowLayout {
|
||||
spacing: 8 * DefaultStyle.dp
|
||||
EffectImage {
|
||||
|
|
@ -758,7 +757,7 @@ AbstractMainPage {
|
|||
colorizationColor: DefaultStyle.main2_600
|
||||
}
|
||||
Text {
|
||||
text: mainItem.selectedConference ? mainItem.selectedConference.core.description : ""
|
||||
text: mainItem.selectedConference ? mainItem.selectedConference.core?.description : ""
|
||||
Layout.fillWidth: true
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
|
|
@ -779,10 +778,10 @@ AbstractMainPage {
|
|||
Avatar {
|
||||
Layout.preferredWidth: 45 * DefaultStyle.dp
|
||||
Layout.preferredHeight: 45 * DefaultStyle.dp
|
||||
_address: mainItem.selectedConference ? mainItem.selectedConference.core.organizerAddress : ""
|
||||
_address: mainItem.selectedConference ? mainItem.selectedConference.core?.organizerAddress : ""
|
||||
}
|
||||
Text {
|
||||
text: mainItem.selectedConference ? mainItem.selectedConference.core.organizerName : ""
|
||||
text: mainItem.selectedConference ? mainItem.selectedConference.core?.organizerName : ""
|
||||
font {
|
||||
pixelSize: 14 * DefaultStyle.dp
|
||||
capitalization: Font.Capitalize
|
||||
|
|
@ -807,7 +806,7 @@ AbstractMainPage {
|
|||
id: participantList
|
||||
Layout.preferredHeight: Math.min(184 * DefaultStyle.dp, contentHeight)
|
||||
Layout.fillWidth: true
|
||||
model: mainItem.selectedConference ? mainItem.selectedConference.core.participants : []
|
||||
model: mainItem.selectedConference ? mainItem.selectedConference.core?.participants : []
|
||||
clip: true
|
||||
delegate: RowLayout {
|
||||
height: 56 * DefaultStyle.dp
|
||||
|
|
@ -828,7 +827,7 @@ AbstractMainPage {
|
|||
}
|
||||
Text {
|
||||
text: qsTr("Organizer")
|
||||
visible: mainItem.selectedConference && mainItem.selectedConference.core.organizerAddress === modelData.address
|
||||
visible: mainItem.selectedConference && mainItem.selectedConference.core?.organizerAddress === modelData.address
|
||||
color: DefaultStyle.main2_400
|
||||
font {
|
||||
pixelSize: 12 * DefaultStyle.dp
|
||||
|
|
@ -841,7 +840,7 @@ AbstractMainPage {
|
|||
}
|
||||
Button {
|
||||
id: joinButton
|
||||
visible: mainItem.selectedConference && mainItem.selectedConference.core.state !== LinphoneEnums.ConferenceInfoState.Cancelled
|
||||
visible: mainItem.selectedConference && mainItem.selectedConference.core?.state !== LinphoneEnums.ConferenceInfoState.Cancelled
|
||||
Layout.fillWidth: true
|
||||
text: qsTr("Rejoindre la réunion")
|
||||
topPadding: 11 * DefaultStyle.dp
|
||||
|
|
|
|||
2
external/linphone-sdk
vendored
2
external/linphone-sdk
vendored
|
|
@ -1 +1 @@
|
|||
Subproject commit c8d895cb162e0d6782d339e2ea3950ba2b8ca3da
|
||||
Subproject commit 3e3edec2889317585d5267d764885b2c25806aeb
|
||||
Loading…
Add table
Reference in a new issue