todo: fix key navigation

This commit is contained in:
Gaelle Braud 2024-12-09 15:44:14 +01:00
parent 04e270e699
commit d1f1d8bfb7
7 changed files with 197 additions and 72 deletions

View file

@ -106,7 +106,7 @@ void ConferenceInfoList::setSelf(QSharedPointer<ConferenceInfoList> 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<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,6 +209,7 @@ ConferenceInfoList::build(const std::shared_ptr<linphone::ConferenceInfo> &confe
}
void ConferenceInfoList::connectItem(QSharedPointer<ConferenceInfoCore> confInfoCore) {
if (confInfoCore)
connect(confInfoCore.get(), &ConferenceInfoCore::removed, this, [this](ConferenceInfoCore *confInfo) {
remove(confInfo);
updateHaveCurrentDate();

View file

@ -46,6 +46,7 @@ public:
void updateHaveCurrentDate();
int getCurrentDateIndex();
QSharedPointer<ConferenceInfoCore> getCurrentDateConfInfo();
QSharedPointer<ConferenceInfoCore> build(const std::shared_ptr<linphone::ConferenceInfo> &conferenceInfo);
void connectItem(QSharedPointer<ConferenceInfoCore> confInfoCore);

View file

@ -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<SortFilterList *>(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<SortFilterList *>(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<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);
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<ConferenceInfoList>();
if (confInfoList) {
int listIndex = -1;
confInfoList->get(confInfo ? confInfo->getCore() : nullptr, &listIndex);
qDebug() << "list index" << listIndex;
if (listIndex != -1) {
listIndex =
dynamic_cast<SortFilterList *>(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<ConferenceInfoList, ConferenceInfoCore>(sourceLeft.row());

View file

@ -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<ConferenceInfoList> mList;
int mCurrentDateIndex = -1;
ConferenceInfoCore *mCurrentConfInfo = nullptr;
// int mCurrentDateIndex = -1;
DECLARE_ABSTRACT_OBJECT
};

View file

@ -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

View file

@ -9,35 +9,104 @@ 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
property ConferenceInfoGui selectedConference
property bool _moveToIndex: false
signal meetingSelected()
onMeetingSelected: {
updatePosition()
}
spacing: 8 * DefaultStyle.dp
highlightFollowsCurrentItem: true
highlightMoveVelocity: 1500
highlightFollowsCurrentItem: false
// highlightMoveVelocity: 1500
onCountChanged: {
selectedConference = model && currentIndex != -1 && currentIndex < model.count ? model.getAt(currentIndex) : null
onCountChanged: if(_moveToIndex && count > mainItem.currentIndex){
_moveToIndex = false
selectIndex(mainItem.currentIndex)
}
onCurrentIndexChanged: {
selectedConference = model.getAt(currentIndex) || null
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
filterText: searchBarText
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()
}
}
}

View file

@ -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