Do not focus on the first element after opening the settings menu.

Fix settings menu navigation.
Update SDK for screensharing.
Fix account list object selection.
This commit is contained in:
Gaelle Braud 2024-12-11 10:39:31 +01:00
parent c908f0d42c
commit 017971c886
8 changed files with 82 additions and 65 deletions

View file

@ -60,7 +60,7 @@ void AccountList::setSelf(QSharedPointer<AccountList> me) {
QSharedPointer<AccountCore> defaultAccountCore; QSharedPointer<AccountCore> defaultAccountCore;
for (auto it : linphoneAccounts) { for (auto it : linphoneAccounts) {
auto model = AccountCore::create(it); auto model = AccountCore::create(it);
if (it == defaultAccount) defaultAccountCore = AccountCore::create(defaultAccount); if (it == defaultAccount) defaultAccountCore = model;
accounts->push_back(model); accounts->push_back(model);
} }
mModelConnection->invokeToCore([this, accounts, defaultAccountCore, isInitialization]() { mModelConnection->invokeToCore([this, accounts, defaultAccountCore, isInitialization]() {
@ -76,8 +76,10 @@ void AccountList::setSelf(QSharedPointer<AccountList> me) {
mModelConnection->makeConnectToModel( mModelConnection->makeConnectToModel(
&CoreModel::defaultAccountChanged, &CoreModel::defaultAccountChanged,
[this](const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Account> &account) { [this](const std::shared_ptr<linphone::Core> &core, const std::shared_ptr<linphone::Account> &account) {
if (account) { if (account && account->getParams()->getIdentityAddress()) {
auto model = AccountCore::create(account); auto address =
Utils::coreStringToAppString(account->getParams()->getIdentityAddress()->asStringUriOnly());
auto model = findAccountByAddress(address);
mModelConnection->invokeToCore([this, model]() { setDefaultAccount(model); }); mModelConnection->invokeToCore([this, model]() { setDefaultAccount(model); });
} else mModelConnection->invokeToCore([this]() { setDefaultAccount(nullptr); }); } else mModelConnection->invokeToCore([this]() { setDefaultAccount(nullptr); });
}); });
@ -104,12 +106,10 @@ void AccountList::setDefaultAccount(QSharedPointer<AccountCore> account) {
} }
} }
AccountGui *AccountList::findAccountByAddress(const QString &address) { QSharedPointer<AccountCore> AccountList::findAccountByAddress(const QString &address) {
for (auto &item : mList) { for (auto &item : getSharedList<AccountCore>()) {
if (auto isAccount = item.objectCast<AccountCore>()) { if (item->getIdentityAddress() == address) {
if (isAccount->getIdentityAddress() == address) { return item;
return new AccountGui(isAccount);
}
} }
} }
return nullptr; return nullptr;

View file

@ -43,7 +43,7 @@ public:
AccountGui *getDefaultAccount() const; AccountGui *getDefaultAccount() const;
QSharedPointer<AccountCore> getDefaultAccountCore() const; QSharedPointer<AccountCore> getDefaultAccountCore() const;
void setDefaultAccount(QSharedPointer<AccountCore> account); void setDefaultAccount(QSharedPointer<AccountCore> account);
AccountGui *findAccountByAddress(const QString &address); QSharedPointer<AccountCore> findAccountByAddress(const QString &address);
AccountGui *firstAccount(); AccountGui *firstAccount();
bool getHaveAccount() const; bool getHaveAccount() const;

View file

@ -39,9 +39,6 @@ AccountGui *AccountProxy::getDefaultAccount() {
return new AccountGui(mDefaultAccount); return new AccountGui(mDefaultAccount);
} }
void AccountProxy::setDefaultAccount(AccountGui *account) {
}
// Reset the default account to let UI build its new object if needed. // Reset the default account to let UI build its new object if needed.
void AccountProxy::resetDefaultAccount() { void AccountProxy::resetDefaultAccount() {
mDefaultAccount = nullptr; mDefaultAccount = nullptr;
@ -50,7 +47,7 @@ void AccountProxy::resetDefaultAccount() {
AccountGui *AccountProxy::findAccountByAddress(const QString &address) { AccountGui *AccountProxy::findAccountByAddress(const QString &address) {
auto model = getListModel<AccountList>(); auto model = getListModel<AccountList>();
if (model) return model->findAccountByAddress(address); if (model) return new AccountGui(model->findAccountByAddress(address));
else return nullptr; else return nullptr;
} }

View file

@ -31,7 +31,7 @@
class AccountProxy : public LimitProxy { class AccountProxy : public LimitProxy {
Q_OBJECT Q_OBJECT
Q_PROPERTY(AccountGui *defaultAccount READ getDefaultAccount WRITE setDefaultAccount NOTIFY defaultAccountChanged) Q_PROPERTY(AccountGui *defaultAccount READ getDefaultAccount NOTIFY defaultAccountChanged)
Q_PROPERTY(bool haveAccount READ getHaveAccount NOTIFY haveAccountChanged) Q_PROPERTY(bool haveAccount READ getHaveAccount NOTIFY haveAccountChanged)
Q_PROPERTY(bool isInitialized READ isInitialized NOTIFY initializedChanged) Q_PROPERTY(bool isInitialized READ isInitialized NOTIFY initializedChanged)
@ -42,7 +42,6 @@ public:
~AccountProxy(); ~AccountProxy();
AccountGui *getDefaultAccount(); // Get a new object from List or give the stored one. AccountGui *getDefaultAccount(); // Get a new object from List or give the stored one.
void setDefaultAccount(AccountGui *account); // TODO
void resetDefaultAccount(); // Reset the default account to let UI build its new object if needed. void resetDefaultAccount(); // Reset the default account to let UI build its new object if needed.
Q_INVOKABLE AccountGui *findAccountByAddress(const QString &address); Q_INVOKABLE AccountGui *findAccountByAddress(const QString &address);
Q_INVOKABLE AccountGui *firstAccount(); Q_INVOKABLE AccountGui *firstAccount();

View file

@ -28,12 +28,53 @@ Button {
popup.open() popup.open()
} }
function isFocusable(item){
return item.activeFocusOnTab
}
function getPreviousItem(index){
return _getPreviousItem(popup.contentItem instanceof FocusScope ? popup.contentItem.children[0] : popup.contentItem, index)
}
function getNextItem(index){
return _getNextItem(popup.contentItem instanceof FocusScope ? popup.contentItem.children[0] : popup.contentItem, index)
}
function _getPreviousItem(content, index){
if(content.visibleChildren.length == 0) return null
--index
while(index >= 0){
if( isFocusable(content.children[index]) && content.children[index].visible) return content.children[index]
--index
}
return _getPreviousItem(content, content.children.length)
}
function _getNextItem(content, index){
++index
while(index < content.children.length){
if( isFocusable(content.children[index]) && content.children[index].visible) return content.children[index]
++index
}
return _getNextItem(content, -1)
}
Keys.onPressed: (event) => { Keys.onPressed: (event) => {
if(popup.checked && event.key == Qt.Key_Escape){ if(mainItem.checked){
if( event.key == Qt.Key_Escape || event.key == Qt.Key_Left || event.key == Qt.Key_Space){
mainItem.close() mainItem.close()
mainItem.forceActiveFocus()
event.accepted = true
}else if(event.key == Qt.Key_Up){
getPreviousItem(0).forceActiveFocus()
event.accepted = true
}else if(event.key == Qt.Key_Tab || event.key == Qt.Key_Down){
getNextItem(-1).forceActiveFocus()
event.accepted = true
}
}else if(event.key == Qt.Key_Space){
mainItem.open()
event.accepted = true event.accepted = true
} }
} }
background: Item { background: Item {
anchors.fill: mainItem anchors.fill: mainItem
Rectangle { Rectangle {
@ -84,16 +125,17 @@ Button {
if( y < mainItem.height && y + popupHeight > 0){ if( y < mainItem.height && y + popupHeight > 0){
x += mainItem.width x += mainItem.width
} }
popup.contentItem.forceActiveFocus()
} }
onHeightChanged: Qt.callLater(updatePosition) onHeightChanged: Qt.callLater(updatePosition)
onWidthChanged: Qt.callLater(updatePosition) onWidthChanged: Qt.callLater(updatePosition)
onVisibleChanged: Qt.callLater(updatePosition)
Connections{ Connections{
target: mainItem.Window target: mainItem.Window
function onHeightChanged(){ Qt.callLater(popup.updatePosition)} function onHeightChanged(){ Qt.callLater(popup.updatePosition)}
function onWidthChanged(){ Qt.callLater(popup.updatePosition)} function onWidthChanged(){ Qt.callLater(popup.updatePosition)}
} }
onVisibleChanged: Qt.callLater(updatePosition)
background: Item { background: Item {
anchors.fill: parent anchors.fill: parent

View file

@ -376,41 +376,23 @@ Item {
event.accepted = true; event.accepted = true;
} }
} }
ColumnLayout { ColumnLayout {
id: settingsButtons id: settingsButtons
anchors.fill: parent
spacing: 16 * DefaultStyle.dp spacing: 16 * DefaultStyle.dp
anchors.fill: parent
function getPreviousItem(index){
if(visibleChildren.length == 0) return null
--index
while(index >= 0){
if( index!= 4 && children[index].visible) return children[index]
--index
}
return getPreviousItem(children.length)
}
function getNextItem(index){
++index
while(index < children.length){
if( index!= 4 && children[index].visible) return children[index]
++index
}
return getNextItem(-1)
}
IconLabelButton { IconLabelButton {
id: accountButton id: accountButton
Layout.preferredHeight: 32 * DefaultStyle.dp Layout.preferredHeight: 32 * DefaultStyle.dp
Layout.fillWidth: true Layout.fillWidth: true
visible: !SettingsCpp.hideAccountSettings visible: !SettingsCpp.hideAccountSettings
focus: visible
iconSize: 32 * DefaultStyle.dp iconSize: 32 * DefaultStyle.dp
text: qsTr("Mon compte") text: qsTr("Mon compte")
iconSource: AppIcons.manageProfile iconSource: AppIcons.manageProfile
onClicked: openAccountSettings(accountProxy.defaultAccount ? accountProxy.defaultAccount : accountProxy.firstAccount()) onClicked: openAccountSettings(accountProxy.defaultAccount ? accountProxy.defaultAccount : accountProxy.firstAccount())
KeyNavigation.up: visibleChildren.length != 0 ? settingsButtons.getPreviousItem(0) : null KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(0) : null
KeyNavigation.down: visibleChildren.length != 0 ? settingsButtons.getNextItem(0) : null KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(0) : null
} }
IconLabelButton { IconLabelButton {
id: dndButton id: dndButton
@ -423,51 +405,47 @@ Item {
settingsMenuButton.popup.close() settingsMenuButton.popup.close()
SettingsCpp.dnd = !SettingsCpp.dnd SettingsCpp.dnd = !SettingsCpp.dnd
} }
KeyNavigation.up: visibleChildren.length != 0 ? settingsButtons.getPreviousItem(0) : null KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(1) : null
KeyNavigation.down: visibleChildren.length != 0 ? settingsButtons.getNextItem(0) : null KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(1) : null
} }
IconLabelButton { IconLabelButton {
id: settingsButton id: settingsButton
Layout.preferredHeight: 32 * DefaultStyle.dp Layout.preferredHeight: 32 * DefaultStyle.dp
Layout.fillWidth: true Layout.fillWidth: true
visible: !SettingsCpp.hideSettings visible: !SettingsCpp.hideSettings
focus: !accountButton.visible && visible
iconSize: 32 * DefaultStyle.dp iconSize: 32 * DefaultStyle.dp
text: qsTr("Paramètres") text: qsTr("Paramètres")
iconSource: AppIcons.settings iconSource: AppIcons.settings
onClicked: openContextualMenuComponent(settingsPageComponent) onClicked: openContextualMenuComponent(settingsPageComponent)
KeyNavigation.up: visibleChildren.length != 0 ? settingsButtons.getPreviousItem(1) : null KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(2) : null
KeyNavigation.down: visibleChildren.length != 0 ? settingsButtons.getNextItem(1) : null KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(2) : null
} }
IconLabelButton { IconLabelButton {
id: recordsButton id: recordsButton
Layout.preferredHeight: 32 * DefaultStyle.dp Layout.preferredHeight: 32 * DefaultStyle.dp
Layout.fillWidth: true Layout.fillWidth: true
visible: !SettingsCpp.disableCallRecordings visible: !SettingsCpp.disableCallRecordings
focus: !accountButton.visible && !settingsButton.visible && visible
iconSize: 32 * DefaultStyle.dp iconSize: 32 * DefaultStyle.dp
text: qsTr("Enregistrements") text: qsTr("Enregistrements")
iconSource: AppIcons.micro iconSource: AppIcons.micro
KeyNavigation.up: visibleChildren.length != 0 ? settingsButtons.getPreviousItem(2) : null KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(3) : null
KeyNavigation.down: visibleChildren.length != 0 ? settingsButtons.getNextItem(2) : null KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(3) : null
} }
IconLabelButton { IconLabelButton {
id: helpButton id: helpButton
Layout.preferredHeight: 32 * DefaultStyle.dp Layout.preferredHeight: 32 * DefaultStyle.dp
Layout.fillWidth: true Layout.fillWidth: true
iconSize: 32 * DefaultStyle.dp iconSize: 32 * DefaultStyle.dp
focus: !accountButton.visible && !settingsButton.visible && !recordsButton.visible
text: qsTr("Aide") text: qsTr("Aide")
iconSource: AppIcons.question iconSource: AppIcons.question
onClicked: openContextualMenuComponent(helpPageComponent) onClicked: openContextualMenuComponent(helpPageComponent)
KeyNavigation.up: visibleChildren.length != 0 ? settingsButtons.getPreviousItem(3) : null KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(4) : null
KeyNavigation.down: visibleChildren.length != 0 ? settingsButtons.getNextItem(3) : null KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(4) : null
} }
IconLabelButton { IconLabelButton {
id: quitButton id: quitButton
Layout.preferredHeight: 32 * DefaultStyle.dp Layout.preferredHeight: 32 * DefaultStyle.dp
Layout.fillWidth: true Layout.fillWidth: true
focus: !accountButton.visible && !settingsButton.visible && visible
iconSize: 32 * DefaultStyle.dp iconSize: 32 * DefaultStyle.dp
text: qsTr("Quitter Linphone") text: qsTr("Quitter Linphone")
iconSource: AppIcons.power iconSource: AppIcons.power
@ -484,8 +462,8 @@ Item {
} }
) )
} }
KeyNavigation.up: visibleChildren.length != 0 ? settingsButtons.getPreviousItem(4) : null KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(5) : null
KeyNavigation.down: visibleChildren.length != 0 ? settingsButtons.getNextItem(4) : null KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(5) : null
} }
Rectangle { Rectangle {
Layout.fillWidth: true Layout.fillWidth: true
@ -502,8 +480,8 @@ Item {
text: qsTr("Ajouter un compte") text: qsTr("Ajouter un compte")
iconSource: AppIcons.plusCircle iconSource: AppIcons.plusCircle
onClicked: mainItem.addAccountRequest() onClicked: mainItem.addAccountRequest()
KeyNavigation.up: visibleChildren.length != 0 ? settingsButtons.getPreviousItem(5) : null KeyNavigation.up: visibleChildren.length != 0 ? settingsMenuButton.getPreviousItem(7) : null
KeyNavigation.down: visibleChildren.length != 0 ? settingsButtons.getNextItem(5) : null KeyNavigation.down: visibleChildren.length != 0 ? settingsMenuButton.getNextItem(7) : null
} }
} }
} }

View file

@ -38,20 +38,21 @@ Item {
Layout.fillWidth: true Layout.fillWidth: true
spacing: mainItem.spacing spacing: mainItem.spacing
model: AccountProxy { model: AccountProxy {
id: accountProxy
sourceModel: AppCpp.accounts sourceModel: AppCpp.accounts
} }
delegate: Contact{ delegate: Contact{
id: contactItem id: contactItem
width: list.width width: list.width
account: modelData account: modelData
property bool isSelected: modelData && accountProxy.defaultAccount && modelData.core === accountProxy.defaultAccount.core
onAvatarClicked: fileDialog.open() onAvatarClicked: fileDialog.open()
onBackgroundClicked: { onBackgroundClicked: {
list.currentIndex = index
modelData.core.lSetDefaultAccount() modelData.core.lSetDefaultAccount()
} }
onEdit: editAccount(modelData) onEdit: editAccount(modelData)
hoverEnabled: true hoverEnabled: true
backgroundColor: list.currentIndex === index backgroundColor: contactItem.isSelected
? DefaultStyle.grey_200 ? DefaultStyle.grey_200
: hovered : hovered
? DefaultStyle.main2_100 ? DefaultStyle.main2_100

@ -1 +1 @@
Subproject commit 3e3edec2889317585d5267d764885b2c25806aeb Subproject commit 0383755cb03b44baebadb523ff7e44c51d4bd404