diff --git a/Linphone/core/conference/ConferenceInfoList.cpp b/Linphone/core/conference/ConferenceInfoList.cpp index fb26a2d22..90ea07167 100644 --- a/Linphone/core/conference/ConferenceInfoList.cpp +++ b/Linphone/core/conference/ConferenceInfoList.cpp @@ -106,7 +106,7 @@ void ConferenceInfoList::setSelf(QSharedPointer me) { if (defaultAccount) { mCurrentAccountCore = AccountCore::create(defaultAccount); connect(mCurrentAccountCore.get(), &AccountCore::registrationStateChanged, this, - [this] { emit lUpdate(); }); + [this] { emit lUpdate(true); }); } }); }; @@ -179,6 +179,19 @@ int ConferenceInfoList::getCurrentDateIndex() { return it == confInfoList.end() ? -1 : std::distance(confInfoList.begin(), it); } +QSharedPointer ConferenceInfoList::getCurrentDateConfInfo() { + auto today = QDate::currentDate(); + auto confInfoList = getSharedList(); + QList>::iterator it; + if (mHaveCurrentDate) { + it = std::find_if(confInfoList.begin(), confInfoList.end(), + [today](const QSharedPointer &item) { + return item && item->getDateTimeUtc().date() == today; + }); + } else it = std::find(confInfoList.begin(), confInfoList.end(), nullptr); + return it != confInfoList.end() ? *it : nullptr; +} + QSharedPointer ConferenceInfoList::build(const std::shared_ptr &conferenceInfo) { auto me = CoreModel::getInstance()->getCore()->getDefaultAccount()->getParams()->getIdentityAddress(); @@ -196,10 +209,11 @@ ConferenceInfoList::build(const std::shared_ptr &confe } void ConferenceInfoList::connectItem(QSharedPointer 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 ConferenceInfoList::roleNames() const { diff --git a/Linphone/core/conference/ConferenceInfoList.hpp b/Linphone/core/conference/ConferenceInfoList.hpp index 723fc4474..90ae11608 100644 --- a/Linphone/core/conference/ConferenceInfoList.hpp +++ b/Linphone/core/conference/ConferenceInfoList.hpp @@ -46,6 +46,7 @@ public: void updateHaveCurrentDate(); int getCurrentDateIndex(); + QSharedPointer getCurrentDateConfInfo(); QSharedPointer build(const std::shared_ptr &conferenceInfo); void connectItem(QSharedPointer confInfoCore); diff --git a/Linphone/core/conference/ConferenceInfoProxy.cpp b/Linphone/core/conference/ConferenceInfoProxy.cpp index 940023506..5a801fed2 100644 --- a/Linphone/core/conference/ConferenceInfoProxy.cpp +++ b/Linphone/core/conference/ConferenceInfoProxy.cpp @@ -32,27 +32,27 @@ ConferenceInfoProxy::ConferenceInfoProxy(QObject *parent) : LimitProxy(parent) { connect( mList.get(), &ConferenceInfoList::haveCurrentDateChanged, this, [this] { - setCurrentDateIndex(getCurrentDateIndex()); + qDebug() << "have current date changed ========================="; + auto currentConfInfo = getCurrentDateConfInfo(); + setCurrentConfInfo(currentConfInfo); auto sortModel = dynamic_cast(sourceModel()); sortModel->invalidate(); }, Qt::QueuedConnection); connect( - App::getInstance(), &App::currentDateChanged, this, [this] { setCurrentDateIndex(getCurrentDateIndex()); }, + App::getInstance(), &App::currentDateChanged, this, [this] { setCurrentConfInfo(getCurrentDateConfInfo()); }, Qt::QueuedConnection); connect( mList.get(), &ConferenceInfoList::confInfoInserted, this, - [this](int index, ConferenceInfoGui *data) { - auto sortModel = dynamic_cast(sourceModel()); - if (sortModel) { - auto proxyIndex = sortModel->mapFromSource(mList->index(index, 0)).row(); - if (proxyIndex >= getMaxDisplayItems()) setMaxDisplayItems(proxyIndex + 1); - emit conferenceInfoCreated(proxyIndex); - } - }, - Qt::QueuedConnection); - connect(mList.get(), &ConferenceInfoList::initialized, this, - [this] { setCurrentDateIndex(getCurrentDateIndex()); }); + [this](int index, ConferenceInfoGui *data) { emit conferenceInfoCreated(data); }, Qt::QueuedConnection); + connect(mList.get(), &ConferenceInfoList::initialized, this, [this] { + qDebug() << "initialized ========================="; + auto currentConfInfo = getCurrentDateConfInfo(); + // auto confIndex = loadUntil(currentConfInfo); + setCurrentConfInfo(currentConfInfo); + // force emitting on initialized to handle dummy item which is nullptr + // emit currentConfInfoChanged(currentConfInfo); + }); } ConferenceInfoProxy::~ConferenceInfoProxy() { @@ -90,21 +90,46 @@ bool ConferenceInfoProxy::SortFilterList::filterAcceptsRow(int sourceRow, const } } -int ConferenceInfoProxy::getCurrentDateIndex() const { - auto sortModel = dynamic_cast(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); +ConferenceInfoGui *ConferenceInfoProxy::getCurrentDateConfInfo() const { + auto confInfoCore = mList->getCurrentDateConfInfo(); + if (confInfoCore) qDebug() << "current is" << confInfoCore->getSubject(); + else qDebug() << "current is dummy"; + return new ConferenceInfoGui(confInfoCore); +} + +void ConferenceInfoProxy::setCurrentConfInfo(ConferenceInfoGui *confInfoGui) { + if (mCurrentConfInfo != confInfoGui->getCore()) { + mCurrentConfInfo = confInfoGui->getCore(); + emit currentConfInfoChanged(confInfoGui); } } +int ConferenceInfoProxy::loadUntil(ConferenceInfoGui *confInfo) { + auto confInfoList = getListModel(); + if (confInfoList) { + int listIndex = -1; + confInfoList->get(confInfo ? confInfo->getCore() : nullptr, &listIndex); + qDebug() << "list index" << listIndex; + if (listIndex != -1) { + listIndex = + dynamic_cast(sourceModel())->mapFromSource(confInfoList->index(listIndex, 0)).row(); + qDebug() << "proxy index" << listIndex << mMaxDisplayItems; + if (mMaxDisplayItems < listIndex) setMaxDisplayItems(mMaxDisplayItems + mDisplayItemsStep); + } + return listIndex; + } + return -1; +} + +void ConferenceInfoProxy::loadUntil(int i) { + qDebug() << "max display" << mMaxDisplayItems << "i" << i; + if (mMaxDisplayItems < i) setMaxDisplayItems(i + 1); +} + bool ConferenceInfoProxy::SortFilterList::lessThan(const QModelIndex &sourceLeft, const QModelIndex &sourceRight) const { auto l = getItemAtSource(sourceLeft.row()); diff --git a/Linphone/core/conference/ConferenceInfoProxy.hpp b/Linphone/core/conference/ConferenceInfoProxy.hpp index 6424039e0..8ede13903 100644 --- a/Linphone/core/conference/ConferenceInfoProxy.hpp +++ b/Linphone/core/conference/ConferenceInfoProxy.hpp @@ -25,11 +25,14 @@ #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(ConferenceInfoGui *currentConfInfo READ getCurrentDateConfInfo NOTIFY currentConfInfoChanged) // Q_PROPERTY(int currentDateIndex READ getCurrentDateIndex NOTIFY currentDateIndexChanged) public: @@ -43,17 +46,21 @@ public: bool haveCurrentDate() const; - Q_INVOKABLE int getCurrentDateIndex() const; - Q_INVOKABLE void setCurrentDateIndex(int index); - + Q_INVOKABLE void clear(); + Q_INVOKABLE ConferenceInfoGui *getCurrentDateConfInfo() const; + Q_INVOKABLE void setCurrentConfInfo(ConferenceInfoGui *confInfoGui); + Q_INVOKABLE int loadUntil(ConferenceInfoGui *confInfo); + Q_INVOKABLE void loadUntil(int index); signals: void haveCurrentDateChanged(); - void conferenceInfoCreated(int index); - void currentDateIndexChanged(int index); + void conferenceInfoCreated(ConferenceInfoGui *confInfo); + // void currentDateIndexChanged(int index); + void currentConfInfoChanged(ConferenceInfoGui *confInfoGui); private: QSharedPointer mList; - int mCurrentDateIndex = -1; + ConferenceInfoCore *mCurrentConfInfo = nullptr; + // int mCurrentDateIndex = -1; DECLARE_ABSTRACT_OBJECT }; diff --git a/Linphone/view/Control/Container/Contact/ContactLayout.qml b/Linphone/view/Control/Container/Contact/ContactLayout.qml index 1451bca89..bd3ef1e05 100644 --- a/Linphone/view/Control/Container/Contact/ContactLayout.qml +++ b/Linphone/view/Control/Container/Contact/ContactLayout.qml @@ -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 diff --git a/Linphone/view/Control/Display/Meeting/MeetingListView.qml b/Linphone/view/Control/Display/Meeting/MeetingListView.qml index 9dc77391b..8327b12b7 100644 --- a/Linphone/view/Control/Display/Meeting/MeetingListView.qml +++ b/Linphone/view/Control/Display/Meeting/MeetingListView.qml @@ -9,24 +9,86 @@ import UtilsCpp ListView { id: mainItem visible: count > 0 + onVisibleChanged: if (!visible) confInfoProxy.clear() clip: true property string searchBarText property bool hoverEnabled: true property var delegateButtons - property ConferenceInfoGui selectedConference: model && currentIndex != -1 ? model.getAt(currentIndex) : null - - spacing: 8 * DefaultStyle.dp - highlightFollowsCurrentItem: true - highlightMoveVelocity: 1500 + property ConferenceInfoGui selectedConference + property bool _moveToIndex: false - onCountChanged: { - selectedConference = model && currentIndex != -1 && currentIndex < model.count ? model.getAt(currentIndex) : null + signal meetingSelected() + onMeetingSelected: { + updatePosition() } - onCurrentIndexChanged: { - selectedConference = model.getAt(currentIndex) || null + spacing: 8 * DefaultStyle.dp + highlightFollowsCurrentItem: false + // highlightMoveVelocity: 1500 + + onCountChanged: if(_moveToIndex && count > mainItem.currentIndex){ + _moveToIndex = false + selectIndex(mainItem.currentIndex) } + + function selectIndex(index){ + if (index < 0) return + // confInfoProxy.loadUntil() + mainItem.currentIndex = index + console.log("select index", currentIndex, index) + var item = itemAtIndex(index) + confInfoProxy.loadUntil(model.count - 1) + if(item){// Item is ready and available + mainItem.selectedConference = item && item.itemGui || null + item.forceActiveFocus() + updatePosition() + } else { + _moveToIndex = true + console.log("NO ITEM") + } + } + onAtYEndChanged: if(atYEnd) confInfoProxy.displayMore() + + function updatePosition(){ + var item = itemAtIndex(currentIndex) + var centerItemPos = 0 + console.log("update position for item", item, currentIndex) + if(item){ + centerItemPos = item.y + y + item.height/2 + var centerPos = centerItemPos - height/2 + mainItem.contentY = Math.max(0, Math.min(centerPos, contentHeight-height, height)) + } else { + console.log("NO ITEM") + } + } + Behavior on contentY{ + NumberAnimation { + duration: 500 + easing.type: Easing.OutExpo + } + } + + Keys.onPressed: (event)=> { + var direction = (event.key == Qt.Key_Up ? -1 : 1) + 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 @@ -34,10 +96,17 @@ ListView { filterType: ConferenceInfoProxy.None initialDisplayItems: mainItem.height / (63 * DefaultStyle.dp) + 5 displayItemsStep: initialDisplayItems/2 - onConferenceInfoCreated: (index) => { - mainItem.currentIndex = index + onConferenceInfoCreated: (data) => { + console.log("select conf created", data.core.subject) + // confInfoProxy.loadUntil(data) + mainItem.selectedConference = data + } + onCurrentConfInfoChanged: (confInfoGui) => { + console.log("selected conf changed", confInfoGui) + confInfoProxy.loadUntil(confInfoGui) + if (confInfoGui.core) console.log("with subject", confInfoGui.core.subject) + mainItem.selectedConference = confInfoGui } - onCurrentDateIndexChanged: (index) => mainItem.currentIndex = index } section { @@ -62,16 +131,25 @@ ListView { height: 63 * DefaultStyle.dp 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 ConferenceInfoGui itemGui: $modelData + property ConferenceInfoGui previousItem : mainItem.model.count > 0 && index > 0 ? mainItem.model.getAt(index-1) : null + property var dateTime: itemGui ? itemGui.core.dateTime : 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 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 + property var endDateTime: itemGui ? itemGui.core.endDateTime : UtilsCpp.getCurrentDateTime() + property bool haveModel: itemGui ? itemGui.core.haveModel : false + property bool isCanceled: itemGui ? itemGui.core.state === LinphoneEnums.ConferenceInfoState.Cancelled : false + property bool isSelected: !itemGui ? !mainItem.selectedConference : mainItem.selectedConference && itemGui.core === mainItem.selectedConference.core + onIsSelectedChanged: { + if(isSelected) { + console.log("select delegate at index", index) + // mainItem.currentIndex = index + mainItem.selectIndex(index) + } + } Component.onCompleted: if (!isFirst && dateDay.visible) { height = (63+topOffset)*DefaultStyle.dp delegateIn.anchors.topMargin = topOffset @@ -141,7 +219,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 +234,7 @@ ListView { Layout.preferredHeight: 24 * DefaultStyle.dp } Text { - text: $modelData? $modelData.core.subject : "" + text: itemGui? itemGui.core.subject : "" Layout.fillWidth: true maximumLineCount: 1 font { @@ -203,8 +281,9 @@ ListView { cursorShape: Qt.PointingHandCursor visible: itemDelegate.haveModel onClicked: { - mainItem.currentIndex = index + confInfoProxy.setCurrentConfInfo(itemGui) itemDelegate.forceActiveFocus() + mainItem.meetingSelected() } } } diff --git a/Linphone/view/Page/Main/Meeting/MeetingPage.qml b/Linphone/view/Page/Main/Meeting/MeetingPage.qml index d12058c6f..2c60217b3 100644 --- a/Linphone/view/Page/Main/Meeting/MeetingPage.qml +++ b/Linphone/view/Page/Main/Meeting/MeetingPage.qml @@ -26,7 +26,7 @@ AbstractMainPage { onSelectedConferenceChanged: { overridenRightPanelStackView.clear() - if (selectedConference && selectedConference.core.haveModel) { + if (selectedConference.core && selectedConference.core.haveModel) { if (!overridenRightPanelStackView.currentItem || overridenRightPanelStackView.currentItem != meetingDetail) overridenRightPanelStackView.replace(meetingDetail, Control.StackView.Immediate) } } @@ -579,7 +579,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 +591,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 +622,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 +670,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 +719,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 +738,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 +748,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 +758,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 +779,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 +807,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 +828,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 +841,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