mirror of
https://gitlab.linphone.org/BC/public/linphone-desktop.git
synced 2026-04-17 20:08:28 +00:00
Accessibility fixs :
* Fix focus on first relevant element after changing page with navbar #LINQT-2202 * Improve focus navigation on call history list #LINQT-2201 * Fix missing accessible button name in dialer #LINQT-2221 * Switch from ScrollView to Flickable in parameters * Add auto scroll on keyboard navigation in settings #LINQT-2219 * Correct back button in settings #LINQT-2209 * Fix focus when open settings page #LINQT-2208 * Arrow in vertical tab bar now change button focus instead of changing page #LINQT-2194 * Fix focus and accessibility label in magic search bar #LINQT-2205
This commit is contained in:
parent
ca452efe80
commit
d2413f33a9
25 changed files with 1269 additions and 712 deletions
|
|
@ -114,6 +114,7 @@
|
||||||
#include "tool/request/RequestDialog.hpp"
|
#include "tool/request/RequestDialog.hpp"
|
||||||
#include "tool/thread/Thread.hpp"
|
#include "tool/thread/Thread.hpp"
|
||||||
#include "tool/ui/DashRectangle.hpp"
|
#include "tool/ui/DashRectangle.hpp"
|
||||||
|
#include "tool/ui/FocusNavigator.hpp"
|
||||||
|
|
||||||
#if defined(Q_OS_MACOS)
|
#if defined(Q_OS_MACOS)
|
||||||
#include "core/event-count-notifier/EventCountNotifierMacOs.hpp"
|
#include "core/event-count-notifier/EventCountNotifierMacOs.hpp"
|
||||||
|
|
@ -714,6 +715,7 @@ void App::initCore() {
|
||||||
#endif
|
#endif
|
||||||
mEngine->rootContext()->setContextProperty("applicationName", APPLICATION_NAME);
|
mEngine->rootContext()->setContextProperty("applicationName", APPLICATION_NAME);
|
||||||
mEngine->rootContext()->setContextProperty("executableName", EXECUTABLE_NAME);
|
mEngine->rootContext()->setContextProperty("executableName", EXECUTABLE_NAME);
|
||||||
|
mEngine->rootContext()->setContextProperty("FocusNavigator", new FocusNavigator(mEngine));
|
||||||
|
|
||||||
initCppInterfaces();
|
initCppInterfaces();
|
||||||
mEngine->addImageProvider(ImageProvider::ProviderId, new ImageProvider());
|
mEngine->addImageProvider(ImageProvider::ProviderId, new ImageProvider());
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -27,6 +27,7 @@ list(APPEND _LINPHONEAPP_SOURCES
|
||||||
tool/file/TemporaryFile.cpp
|
tool/file/TemporaryFile.cpp
|
||||||
|
|
||||||
tool/ui/DashRectangle.cpp
|
tool/ui/DashRectangle.cpp
|
||||||
|
tool/ui/FocusNavigator.cpp
|
||||||
|
|
||||||
tool/accessibility/AccessibilityHelper.cpp
|
tool/accessibility/AccessibilityHelper.cpp
|
||||||
tool/accessibility/KeyboardShortcuts.cpp
|
tool/accessibility/KeyboardShortcuts.cpp
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ bool FocusHelperAttached::eventFilter(QObject *watched, QEvent *event) {
|
||||||
auto fe = static_cast<QFocusEvent *>(event);
|
auto fe = static_cast<QFocusEvent *>(event);
|
||||||
if (fe) {
|
if (fe) {
|
||||||
int focusReason = fe->reason();
|
int focusReason = fe->reason();
|
||||||
|
// qDebug() << "FocusReason" << focusReason; // Usefull to debug focus problems
|
||||||
m_keyboardFocus = (focusReason == Qt::TabFocusReason || focusReason == Qt::BacktabFocusReason);
|
m_keyboardFocus = (focusReason == Qt::TabFocusReason || focusReason == Qt::BacktabFocusReason);
|
||||||
m_otherFocus = focusReason == Qt::OtherFocusReason;
|
m_otherFocus = focusReason == Qt::OtherFocusReason;
|
||||||
emit keyboardFocusChanged();
|
emit keyboardFocusChanged();
|
||||||
|
|
|
||||||
56
Linphone/tool/ui/FocusNavigator.cpp
Normal file
56
Linphone/tool/ui/FocusNavigator.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2025 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-desktop
|
||||||
|
* (see https://www.linphone.org).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "FocusNavigator.hpp"
|
||||||
|
|
||||||
|
#include <QGuiApplication>
|
||||||
|
#include <QQuickItem>
|
||||||
|
|
||||||
|
FocusNavigator::FocusNavigator(QObject *parent) : QObject(parent) {
|
||||||
|
connect(qApp, &QGuiApplication::focusObjectChanged, this, &FocusNavigator::onFocusObjectChanged);
|
||||||
|
qApp->installEventFilter(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FocusNavigator::doesLastFocusWasKeyboard() {
|
||||||
|
return mLastFocusWasKeyboard;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FocusNavigator::eventFilter(QObject *, QEvent *event) {
|
||||||
|
switch (event->type()) {
|
||||||
|
case QEvent::FocusIn: {
|
||||||
|
auto fe = static_cast<QFocusEvent *>(event);
|
||||||
|
if (fe) {
|
||||||
|
int focusReason = fe->reason();
|
||||||
|
mLastFocusWasKeyboard = (focusReason == Qt::TabFocusReason || focusReason == Qt::BacktabFocusReason);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FocusNavigator::onFocusObjectChanged(QObject *obj) {
|
||||||
|
// qDebug() << "New focus object" << obj; // Usefull to debug focus problems
|
||||||
|
auto item = qobject_cast<QQuickItem *>(obj);
|
||||||
|
if (!item) return;
|
||||||
|
emit focusChanged(item, mLastFocusWasKeyboard);
|
||||||
|
}
|
||||||
42
Linphone/tool/ui/FocusNavigator.hpp
Normal file
42
Linphone/tool/ui/FocusNavigator.hpp
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2010-2025 Belledonne Communications SARL.
|
||||||
|
*
|
||||||
|
* This file is part of linphone-desktop
|
||||||
|
* (see https://www.linphone.org).
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <QObject>
|
||||||
|
#include <QQuickItem>
|
||||||
|
|
||||||
|
class FocusNavigator : public QObject {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit FocusNavigator(QObject *parent = nullptr);
|
||||||
|
Q_INVOKABLE bool doesLastFocusWasKeyboard();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
bool eventFilter(QObject *obj, QEvent *event) override;
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void focusChanged(QQuickItem *item, bool keyboardFocus);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool mLastFocusWasKeyboard = false;
|
||||||
|
void onFocusObjectChanged(QObject *obj);
|
||||||
|
};
|
||||||
|
|
@ -23,7 +23,8 @@ Button {
|
||||||
: mainItem.hovered || mainItem.hasNavigationFocus
|
: mainItem.hovered || mainItem.hasNavigationFocus
|
||||||
? mainItem.hoveredColor
|
? mainItem.hoveredColor
|
||||||
: mainItem.color
|
: mainItem.color
|
||||||
border.color: mainItem.borderColor
|
border.color: mainItem.keyboardFocus ? mainItem.keyboardFocusedBorderColor : mainItem.borderColor
|
||||||
|
border.width: mainItem.keyboardFocus ? mainItem.keyboardFocusedBorderWidth : mainItem.borderWidth
|
||||||
}
|
}
|
||||||
|
|
||||||
contentItem: EffectImage {
|
contentItem: EffectImage {
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,9 @@ Control.TabBar {
|
||||||
|
|
||||||
property int visibleCount: 0
|
property int visibleCount: 0
|
||||||
|
|
||||||
|
signal enterPressed()
|
||||||
|
signal spacePressed()
|
||||||
|
|
||||||
// Call it after model is ready. If done before, Repeater will not be updated
|
// Call it after model is ready. If done before, Repeater will not be updated
|
||||||
function initButtons(){
|
function initButtons(){
|
||||||
actionsRepeater.model = mainItem.model
|
actionsRepeater.model = mainItem.model
|
||||||
|
|
@ -96,6 +99,8 @@ Control.TabBar {
|
||||||
onVisibleChanged: mainItem.updateVisibleCount()
|
onVisibleChanged: mainItem.updateVisibleCount()
|
||||||
text: modelData.accessibilityLabel
|
text: modelData.accessibilityLabel
|
||||||
property bool keyboardFocus: FocusHelper.keyboardFocus
|
property bool keyboardFocus: FocusHelper.keyboardFocus
|
||||||
|
focusPolicy: Qt.StrongFocus
|
||||||
|
activeFocusOnTab: true
|
||||||
UnreadNotification {
|
UnreadNotification {
|
||||||
unread: !defaultAccount
|
unread: !defaultAccount
|
||||||
? -1
|
? -1
|
||||||
|
|
@ -165,6 +170,23 @@ Control.TabBar {
|
||||||
mainItem.implicitWidth = Math.max(mainItem.implicitWidth, advanceWidth + buttonIcon.buttonSize)
|
mainItem.implicitWidth = Math.max(mainItem.implicitWidth, advanceWidth + buttonIcon.buttonSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if (event.key === Qt.Key_Enter || event.key === Qt.Key_Return) {
|
||||||
|
mainItem.enterPressed()
|
||||||
|
} else if(event.key === Qt.Key_Space){
|
||||||
|
mainItem.spacePressed()
|
||||||
|
} else if(event.key === Qt.Key_Down){
|
||||||
|
event.accepted = true;
|
||||||
|
if(TabBar.index >= mainItem.visibleCount - 1)
|
||||||
|
return;
|
||||||
|
tabButton.nextItemInFocusChain(true).forceActiveFocus(Qt.TabFocusReason)
|
||||||
|
} else if(event.key === Qt.Key_Up){
|
||||||
|
event.accepted = true;
|
||||||
|
if(TabBar.index <= 0)
|
||||||
|
return;
|
||||||
|
tabButton.nextItemInFocusChain(false).forceActiveFocus(Qt.BacktabFocusReason)
|
||||||
|
}
|
||||||
|
}
|
||||||
onClicked: {
|
onClicked: {
|
||||||
mainItem.setCurrentIndex(TabBar.index)
|
mainItem.setCurrentIndex(TabBar.index)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,22 @@ import QtQuick.Controls.Basic as Control
|
||||||
import Linphone
|
import Linphone
|
||||||
import UtilsCpp
|
import UtilsCpp
|
||||||
import SettingsCpp
|
import SettingsCpp
|
||||||
|
import CustomControls 1.0
|
||||||
import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle
|
import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle
|
||||||
import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils
|
import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils
|
||||||
|
|
||||||
ListView {
|
ListView {
|
||||||
id: mainItem
|
id: mainItem
|
||||||
clip: true
|
clip: true
|
||||||
|
keyNavigationEnabled: false // We will reimplement the keyNavigation
|
||||||
|
activeFocusOnTab: true
|
||||||
|
|
||||||
property SearchBar searchBar
|
property SearchBar searchBar
|
||||||
property bool loading: false
|
property bool loading: false
|
||||||
property string searchText: searchBar?.text
|
property string searchText: searchBar?.text
|
||||||
property real busyIndicatorSize: Utils.getSizeWithScreenRatio(60)
|
property real busyIndicatorSize: Utils.getSizeWithScreenRatio(60)
|
||||||
|
property bool keyboardFocus: FocusHelper.keyboardFocus
|
||||||
|
property bool lastFocusByNavigationKeyboard: false // Workaround to get the correct focusReason
|
||||||
|
|
||||||
signal resultsReceived
|
signal resultsReceived
|
||||||
|
|
||||||
|
|
@ -41,7 +46,26 @@ ListView {
|
||||||
Keys.onPressed: event => {
|
Keys.onPressed: event => {
|
||||||
if (event.key == Qt.Key_Escape) {
|
if (event.key == Qt.Key_Escape) {
|
||||||
console.log("Back")
|
console.log("Back")
|
||||||
searchBar.forceActiveFocus()
|
searchBar.forceActiveFocus(Qt.BacktabFocusReason)
|
||||||
|
event.accepted = true
|
||||||
|
}
|
||||||
|
|
||||||
|
// Re-implement key navigation to have Qt.TabFocusReason and Qt.BacktabFocusReason instead of Qt.OtherFocusReason when using arrows to navigate in listView
|
||||||
|
else if (event.key === Qt.Key_Up) {
|
||||||
|
if(currentIndex === 0){
|
||||||
|
searchBar.forceActiveFocus(Qt.BacktabFocusReason)
|
||||||
|
lastFocusByNavigationKeyboard = false
|
||||||
|
}else{
|
||||||
|
decrementCurrentIndex()
|
||||||
|
currentItem.forceActiveFocus(Qt.BacktabFocusReason) // The focusReason is created by QT later, need to create a workaround
|
||||||
|
lastFocusByNavigationKeyboard = true
|
||||||
|
}
|
||||||
|
event.accepted = true
|
||||||
|
}
|
||||||
|
else if(event.key === Qt.Key_Down){
|
||||||
|
incrementCurrentIndex()
|
||||||
|
currentItem.forceActiveFocus(Qt.TabFocusReason) // The focusReason is created by QT later, need to create a workaround
|
||||||
|
lastFocusByNavigationKeyboard = true
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -113,6 +137,8 @@ ListView {
|
||||||
delegate: FocusScope {
|
delegate: FocusScope {
|
||||||
width: mainItem.width
|
width: mainItem.width
|
||||||
height: Utils.getSizeWithScreenRatio(56)
|
height: Utils.getSizeWithScreenRatio(56)
|
||||||
|
Accessible.role: Accessible.ListItem
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
z: 1
|
z: 1
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
@ -188,12 +214,14 @@ ListView {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
BigButton {
|
BigButton {
|
||||||
|
id: callButton
|
||||||
visible: !modelData.core.isConference || !SettingsCpp.disableMeetingsFeature
|
visible: !modelData.core.isConference || !SettingsCpp.disableMeetingsFeature
|
||||||
style: ButtonStyle.noBackground
|
style: ButtonStyle.noBackground
|
||||||
icon.source: AppIcons.phone
|
icon.source: AppIcons.phone
|
||||||
focus: true
|
focus: false
|
||||||
activeFocusOnTab: false
|
activeFocusOnTab: false
|
||||||
asynchronous: false
|
asynchronous: false
|
||||||
|
|
||||||
//: Call %1
|
//: Call %1
|
||||||
Accessible.name: qsTr("call_name_accessible_button").arg(historyAvatar.displayNameVal)
|
Accessible.name: qsTr("call_name_accessible_button").arg(historyAvatar.displayNameVal)
|
||||||
onClicked: {
|
onClicked: {
|
||||||
|
|
@ -206,12 +234,38 @@ ListView {
|
||||||
UtilsCpp.createCall(modelData.core.remoteAddress)
|
UtilsCpp.createCall(modelData.core.remoteAddress)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if (event.key === Qt.Key_Left){
|
||||||
|
backgroundMouseArea.forceActiveFocus(Qt.BacktabFocusReason)
|
||||||
|
lastFocusByNavigationKeyboard = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onActiveFocusChanged: {
|
||||||
|
if (!activeFocus) {
|
||||||
|
console.log("Unfocus button");
|
||||||
|
callButton.focus = false // Make sure to be unfocusable (could be when called by forceActiveFocus)
|
||||||
|
backgroundMouseArea.focus = true
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MouseArea {
|
MouseArea {
|
||||||
|
id: backgroundMouseArea
|
||||||
hoverEnabled: true
|
hoverEnabled: true
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
focus: true
|
focus: true
|
||||||
|
property bool keyboardFocus: FocusHelper.keyboardFocus || activeFocus && lastFocusByNavigationKeyboard
|
||||||
|
|
||||||
|
//: %1 - %2 - %3 - right arrow for call-back button
|
||||||
|
Accessible.name: qsTr("call_history_entry_accessible_name").arg(
|
||||||
|
//: "Appel manqué"
|
||||||
|
modelData.core.status === LinphoneEnums.CallStatus.Missed ? qsTr("notification_missed_call_title")
|
||||||
|
//: "Appel sortant"
|
||||||
|
: modelData.core.isOutgoing ? qsTr("call_outgoing")
|
||||||
|
//: "Appel entrant"
|
||||||
|
: qsTr("call_audio_incoming")
|
||||||
|
).arg(historyAvatar.displayNameVal).arg(UtilsCpp.formatDate(modelData.core.date))
|
||||||
|
|
||||||
onContainsMouseChanged: {
|
onContainsMouseChanged: {
|
||||||
if (containsMouse)
|
if (containsMouse)
|
||||||
mainItem.lastMouseContainsIndex = index
|
mainItem.lastMouseContainsIndex = index
|
||||||
|
|
@ -224,12 +278,20 @@ ListView {
|
||||||
radius: Utils.getSizeWithScreenRatio(8)
|
radius: Utils.getSizeWithScreenRatio(8)
|
||||||
color: mainItem.currentIndex
|
color: mainItem.currentIndex
|
||||||
=== index ? DefaultStyle.main2_200 : DefaultStyle.main2_100
|
=== index ? DefaultStyle.main2_200 : DefaultStyle.main2_100
|
||||||
|
border.color: backgroundMouseArea.keyboardFocus ? DefaultStyle.main2_900 : "transparent"
|
||||||
|
border.width: backgroundMouseArea.keyboardFocus ? Utils.getSizeWithScreenRatio(3) : 0
|
||||||
visible: mainItem.lastMouseContainsIndex === index
|
visible: mainItem.lastMouseContainsIndex === index
|
||||||
|| mainItem.currentIndex === index
|
|| mainItem.currentIndex === index
|
||||||
}
|
}
|
||||||
onPressed: {
|
onPressed: {
|
||||||
mainItem.currentIndex = model.index
|
mainItem.currentIndex = model.index
|
||||||
mainItem.forceActiveFocus()
|
mainItem.forceActiveFocus()
|
||||||
|
mainItem.lastFocusByNavigationKeyboard = false
|
||||||
|
}
|
||||||
|
Keys.onPressed: event => {
|
||||||
|
if(event.key === Qt.Key_Right){
|
||||||
|
callButton.forceActiveFocus(Qt.TabFocusReason)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@ Flickable {
|
||||||
direction)
|
direction)
|
||||||
if (newItem) {
|
if (newItem) {
|
||||||
newItem.selectIndex(
|
newItem.selectIndex(
|
||||||
direction > 0 ? -1 : newItem.model.count - 1)
|
direction > 0 ? -1 : newItem.model.count - 1, direction > 0 ? Qt.BacktabFocusReason : Qt.TabFocusReason)
|
||||||
event.accepted = true
|
event.accepted = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import Linphone
|
||||||
import UtilsCpp
|
import UtilsCpp
|
||||||
import ConstantsCpp
|
import ConstantsCpp
|
||||||
import SettingsCpp
|
import SettingsCpp
|
||||||
|
import CustomControls 1.0
|
||||||
import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle
|
import "qrc:/qt/qml/Linphone/view/Style/buttonStyle.js" as ButtonStyle
|
||||||
import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils
|
import "qrc:/qt/qml/Linphone/view/Control/Tool/Helper/utils.js" as Utils
|
||||||
|
|
||||||
|
|
@ -149,6 +150,9 @@ FocusScope {
|
||||||
onClicked: UtilsCpp.createCall(mainItem.addressFromFilter)
|
onClicked: UtilsCpp.createCall(mainItem.addressFromFilter)
|
||||||
KeyNavigation.left: chatButton
|
KeyNavigation.left: chatButton
|
||||||
KeyNavigation.right: videoCallButton
|
KeyNavigation.right: videoCallButton
|
||||||
|
//: "Call %1"
|
||||||
|
Accessible.name: qsTr("call_with_contact_name_accessible_button").arg(mainItem.displayName)
|
||||||
|
keyboardFocus: FocusHelper.keyboardFocus || FocusHelper.otherFocus
|
||||||
}
|
}
|
||||||
IconButton {
|
IconButton {
|
||||||
id: videoCallButton
|
id: videoCallButton
|
||||||
|
|
@ -164,6 +168,9 @@ FocusScope {
|
||||||
onClicked: UtilsCpp.createCall(mainItem.addressFromFilter, {"localVideoEnabled": true})
|
onClicked: UtilsCpp.createCall(mainItem.addressFromFilter, {"localVideoEnabled": true})
|
||||||
KeyNavigation.left: callButton
|
KeyNavigation.left: callButton
|
||||||
KeyNavigation.right: chatButton
|
KeyNavigation.right: chatButton
|
||||||
|
//: "Video call %1"
|
||||||
|
Accessible.name: qsTr("video_call_with_contact_name_accessible_button").arg(mainItem.displayName)
|
||||||
|
keyboardFocus: FocusHelper.keyboardFocus || FocusHelper.otherFocus
|
||||||
}
|
}
|
||||||
IconButton {
|
IconButton {
|
||||||
id: chatButton
|
id: chatButton
|
||||||
|
|
@ -184,6 +191,9 @@ FocusScope {
|
||||||
console.debug("[ContactListItem.qml] Open conversation")
|
console.debug("[ContactListItem.qml] Open conversation")
|
||||||
mainWindow.displayChatPage(mainItem.addressFromFilter)
|
mainWindow.displayChatPage(mainItem.addressFromFilter)
|
||||||
}
|
}
|
||||||
|
//: "Message %1"
|
||||||
|
Accessible.name: qsTr("message_with_contact_name_accessible_button").arg(mainItem.displayName)
|
||||||
|
keyboardFocus: FocusHelper.keyboardFocus || FocusHelper.otherFocus
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
PopupButton {
|
PopupButton {
|
||||||
|
|
|
||||||
|
|
@ -68,13 +68,13 @@ ListView {
|
||||||
|
|
||||||
property bool _moveToIndex: false
|
property bool _moveToIndex: false
|
||||||
|
|
||||||
function selectIndex(index){
|
function selectIndex(index, focusReason = Qt.OtherFocusReason){
|
||||||
if(mainItem.expanded && index >= 0){
|
if(mainItem.expanded && index >= 0){
|
||||||
mainItem.currentIndex = index
|
mainItem.currentIndex = index
|
||||||
var item = itemAtIndex(mainItem.currentIndex)
|
var item = itemAtIndex(mainItem.currentIndex)
|
||||||
if(item){// Item is ready and available
|
if(item){// Item is ready and available
|
||||||
mainItem.highlightedContact = item.searchResultItem
|
mainItem.highlightedContact = item.searchResultItem
|
||||||
item.forceActiveFocus()
|
item.forceActiveFocus(focusReason)
|
||||||
updatePosition()
|
updatePosition()
|
||||||
_moveToIndex = false
|
_moveToIndex = false
|
||||||
}else{// Move on the next items load.
|
}else{// Move on the next items load.
|
||||||
|
|
@ -85,7 +85,7 @@ ListView {
|
||||||
mainItem.currentIndex = -1
|
mainItem.currentIndex = -1
|
||||||
mainItem.highlightedContact = null
|
mainItem.highlightedContact = null
|
||||||
if(headerItem) {
|
if(headerItem) {
|
||||||
headerItem.forceActiveFocus()
|
headerItem.forceActiveFocus(focusReason)
|
||||||
}
|
}
|
||||||
_moveToIndex = false
|
_moveToIndex = false
|
||||||
}
|
}
|
||||||
|
|
@ -97,12 +97,12 @@ ListView {
|
||||||
if(event.key == Qt.Key_Up || event.key == Qt.Key_Down){
|
if(event.key == Qt.Key_Up || event.key == Qt.Key_Down){
|
||||||
if(event.key == Qt.Key_Up && !headerItem.activeFocus) {
|
if(event.key == Qt.Key_Up && !headerItem.activeFocus) {
|
||||||
if(currentIndex >= 0 ) {
|
if(currentIndex >= 0 ) {
|
||||||
selectIndex(mainItem.currentIndex-1)
|
selectIndex(mainItem.currentIndex-1, Qt.BacktabFocusReason)
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
}else if(event.key == Qt.Key_Down && mainItem.expanded){
|
}else if(event.key == Qt.Key_Down && mainItem.expanded){
|
||||||
if(currentIndex < model.count - 1) {
|
if(currentIndex < model.count - 1) {
|
||||||
selectIndex(mainItem.currentIndex+1)
|
selectIndex(mainItem.currentIndex+1, Qt.TabFocusReason)
|
||||||
event.accepted = true;
|
event.accepted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ Item {
|
||||||
|
|
||||||
//: %1 settings
|
//: %1 settings
|
||||||
Accessible.name: qsTr("setting_tab_accessible_name").arg(titleText)
|
Accessible.name: qsTr("setting_tab_accessible_name").arg(titleText)
|
||||||
|
Accessible.role: Accessible.ListItem
|
||||||
|
|
||||||
Keys.onPressed: (event)=>{
|
Keys.onPressed: (event)=>{
|
||||||
if(event.key == Qt.Key_Space || event.key == Qt.Key_Return || event.key == Qt.Key_Enter){
|
if(event.key == Qt.Key_Space || event.key == Qt.Key_Return || event.key == Qt.Key_Enter){
|
||||||
|
|
|
||||||
|
|
@ -172,6 +172,9 @@ FocusScope {
|
||||||
radius: Utils.getSizeWithScreenRatio(71)
|
radius: Utils.getSizeWithScreenRatio(71)
|
||||||
style: ButtonStyle.numericPad
|
style: ButtonStyle.numericPad
|
||||||
|
|
||||||
|
//: %1 longpress %2
|
||||||
|
Accessible.name: longPressText.text ? qsTr("numpad_longpress_accessible_name").arg(pressText.text).arg(longPressText.text) : pressText.text
|
||||||
|
|
||||||
contentItem: Item {
|
contentItem: Item {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
Text {
|
Text {
|
||||||
|
|
@ -215,6 +218,9 @@ FocusScope {
|
||||||
radius: Utils.getSizeWithScreenRatio(71)
|
radius: Utils.getSizeWithScreenRatio(71)
|
||||||
style: ButtonStyle.phoneGreen
|
style: ButtonStyle.phoneGreen
|
||||||
|
|
||||||
|
//: Call
|
||||||
|
Accessible.name: qsTr("call_accessible_name")
|
||||||
|
|
||||||
onClicked: mainItem.launchCall()
|
onClicked: mainItem.launchCall()
|
||||||
|
|
||||||
KeyNavigation.left: eraseButton
|
KeyNavigation.left: eraseButton
|
||||||
|
|
@ -237,6 +243,9 @@ FocusScope {
|
||||||
Layout.Layout.preferredWidth: Utils.getSizeWithScreenRatio(38)
|
Layout.Layout.preferredWidth: Utils.getSizeWithScreenRatio(38)
|
||||||
Layout.Layout.preferredHeight: Utils.getSizeWithScreenRatio(38)
|
Layout.Layout.preferredHeight: Utils.getSizeWithScreenRatio(38)
|
||||||
|
|
||||||
|
//: Erase
|
||||||
|
Accessible.name: qsTr("erase_accessible_name")
|
||||||
|
|
||||||
onClicked: mainItem.wipe()
|
onClicked: mainItem.wipe()
|
||||||
|
|
||||||
KeyNavigation.left: launchCallButton
|
KeyNavigation.left: launchCallButton
|
||||||
|
|
@ -244,8 +253,13 @@ FocusScope {
|
||||||
KeyNavigation.up: numPadGrid.getButtonAt(11)
|
KeyNavigation.up: numPadGrid.getButtonAt(11)
|
||||||
KeyNavigation.down: numPadGrid.getButtonAt(1)
|
KeyNavigation.down: numPadGrid.getButtonAt(1)
|
||||||
|
|
||||||
background: Item {
|
background: Rectangle {
|
||||||
visible: false
|
width: eraseButton.width
|
||||||
|
height: eraseButton.height
|
||||||
|
color: "transparent"
|
||||||
|
|
||||||
|
border.color: eraseButton.keyboardFocus ? eraseButton.keyboardFocusedBorderColor : "transparent"
|
||||||
|
border.width: eraseButton.keyboardFocus ? eraseButton.keyboardFocusedBorderWidth : eraseButton.borderWidth
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -69,6 +69,8 @@ Control.Popup {
|
||||||
icon.height: Utils.getSizeWithScreenRatio(24)
|
icon.height: Utils.getSizeWithScreenRatio(24)
|
||||||
style: ButtonStyle.noBackground
|
style: ButtonStyle.noBackground
|
||||||
onClicked: mainItem.close()
|
onClicked: mainItem.close()
|
||||||
|
//: Close numeric pad
|
||||||
|
Accessible.name: qsTr("close_numeric_pad_accessible_name")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
contentItem: NumericPad{
|
contentItem: NumericPad{
|
||||||
|
|
|
||||||
|
|
@ -807,6 +807,17 @@ function infoDialog(window, message) {
|
||||||
}, function (status) {})
|
}, function (status) {})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure that the item is visible in the view
|
||||||
|
function ensureVisibleY(item, view){
|
||||||
|
const itemPosition = item.mapToItem(view, 0, 0)
|
||||||
|
|
||||||
|
if (itemPosition.y < 0){
|
||||||
|
view.contentY = view.contentY + itemPosition.y
|
||||||
|
} else if (itemPosition.y + item.height > view.height){
|
||||||
|
view.contentY = itemPosition.y + view.contentY + item.height - view.height
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Set position of list.currentItem into the scrollItem
|
// Set position of list.currentItem into the scrollItem
|
||||||
function updatePosition(scrollItem, list){
|
function updatePosition(scrollItem, list){
|
||||||
if(scrollItem.height == 0) return;
|
if(scrollItem.height == 0) return;
|
||||||
|
|
|
||||||
|
|
@ -48,6 +48,8 @@ AbstractMainPage {
|
||||||
onClicked: {
|
onClicked: {
|
||||||
mainItem.goBackRequested()
|
mainItem.goBackRequested()
|
||||||
}
|
}
|
||||||
|
//: Back to previous menu
|
||||||
|
Accessible.name: qsTr("back_previous_menu_accessible_name")
|
||||||
}
|
}
|
||||||
Text {
|
Text {
|
||||||
text: titleText
|
text: titleText
|
||||||
|
|
@ -69,6 +71,9 @@ AbstractMainPage {
|
||||||
property int selectedIndex: mainItem.defaultIndex != -1 ? mainItem.defaultIndex : 0
|
property int selectedIndex: mainItem.defaultIndex != -1 ? mainItem.defaultIndex : 0
|
||||||
activeFocusOnTab: true
|
activeFocusOnTab: true
|
||||||
spacing: Utils.getSizeWithScreenRatio(5)
|
spacing: Utils.getSizeWithScreenRatio(5)
|
||||||
|
Accessible.role: Accessible.List
|
||||||
|
//: Settings page selection
|
||||||
|
Accessible.name: qsTr("settings_page_selection_accessible_name")
|
||||||
|
|
||||||
delegate: SettingsMenuItem {
|
delegate: SettingsMenuItem {
|
||||||
titleText: modelData.title
|
titleText: modelData.title
|
||||||
|
|
@ -86,7 +91,9 @@ AbstractMainPage {
|
||||||
let initialEntry = mainItem.families[familiesList.selectedIndex]
|
let initialEntry = mainItem.families[familiesList.selectedIndex]
|
||||||
rightPanelStackView.push(layoutUrl(initialEntry.layout), { titleText: initialEntry.title, model: initialEntry.model, container: rightPanelStackView})
|
rightPanelStackView.push(layoutUrl(initialEntry.layout), { titleText: initialEntry.title, model: initialEntry.model, container: rightPanelStackView})
|
||||||
familiesList.currentIndex = familiesList.selectedIndex
|
familiesList.currentIndex = familiesList.selectedIndex
|
||||||
backButton.forceActiveFocus()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Control.StackView.onActivated: {
|
||||||
|
familiesList.forceActiveFocus(FocusNavigator.doesLastFocusWasKeyboard() ? Qt.TabFocusReason : Qt.MouseFocusReason)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ Item {
|
||||||
id: mainItem
|
id: mainItem
|
||||||
property var callObj
|
property var callObj
|
||||||
property var contextualMenuOpenedComponent: undefined
|
property var contextualMenuOpenedComponent: undefined
|
||||||
|
property bool focusPageOnNextLoad: false // Focus the page on next load - usefull cause of loader
|
||||||
|
|
||||||
signal addAccountRequest
|
signal addAccountRequest
|
||||||
signal openNewCallRequest
|
signal openNewCallRequest
|
||||||
|
|
@ -184,6 +185,18 @@ Item {
|
||||||
mainStackView.currentItem.forceActiveFocus();
|
mainStackView.currentItem.forceActiveFocus();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Focus the page when user select the page with keyboard.
|
||||||
|
* Do not add this behavior on the arrows
|
||||||
|
*/
|
||||||
|
onEnterPressed: {
|
||||||
|
focusPageOnNextLoad = true
|
||||||
|
}
|
||||||
|
onSpacePressed: {
|
||||||
|
focusPageOnNextLoad = true
|
||||||
|
}
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
if (SettingsCpp.shortcutCount > 0) {
|
if (SettingsCpp.shortcutCount > 0) {
|
||||||
var shortcuts = SettingsCpp.shortcuts;
|
var shortcuts = SettingsCpp.shortcuts;
|
||||||
|
|
@ -639,6 +652,10 @@ Item {
|
||||||
openContextualMenuComponent(page);
|
openContextualMenuComponent(page);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onLoaded: {
|
||||||
|
if(focusPageOnNextLoad) item.forceActiveFocus(Qt.TabFocusReason)
|
||||||
|
focusPageOnNextLoad = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loader {
|
Loader {
|
||||||
active: mainStackLayout.currentIndex === 1
|
active: mainStackLayout.currentIndex === 1
|
||||||
|
|
@ -654,6 +671,10 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onLoaded: {
|
||||||
|
if(focusPageOnNextLoad) item.forceActiveFocus(Qt.TabFocusReason)
|
||||||
|
focusPageOnNextLoad = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Loader {
|
Loader {
|
||||||
active: mainStackLayout.currentIndex === 2
|
active: mainStackLayout.currentIndex === 2
|
||||||
|
|
@ -672,6 +693,10 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onLoaded: {
|
||||||
|
if(focusPageOnNextLoad) item.forceActiveFocus(Qt.TabFocusReason)
|
||||||
|
focusPageOnNextLoad = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
|
|
@ -688,6 +713,10 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
onLoaded: {
|
||||||
|
if(focusPageOnNextLoad) item.forceActiveFocus(Qt.TabFocusReason)
|
||||||
|
focusPageOnNextLoad = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -100,17 +100,13 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Control.ScrollView {
|
Flickable {
|
||||||
id: scrollView
|
id: scrollView
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.bottom: parent.bottom
|
anchors.bottom: parent.bottom
|
||||||
anchors.top: header.bottom
|
anchors.top: header.bottom
|
||||||
anchors.topMargin: Utils.getSizeWithScreenRatio(16)
|
anchors.topMargin: Utils.getSizeWithScreenRatio(16)
|
||||||
// Workaround while the CI is made with Qt6.5.3
|
|
||||||
// When updated to 6.8, remove this Item and
|
|
||||||
// change the ScrollView with a Flickable
|
|
||||||
Item{anchors.fill: parent}
|
|
||||||
contentHeight: contentListView.contentHeight
|
contentHeight: contentListView.contentHeight
|
||||||
Control.ScrollBar.vertical: ScrollBar {
|
Control.ScrollBar.vertical: ScrollBar {
|
||||||
active: contentListView.contentHeight > scrollView.height
|
active: contentListView.contentHeight > scrollView.height
|
||||||
|
|
@ -130,21 +126,21 @@ Rectangle {
|
||||||
model: mainItem.contentModel
|
model: mainItem.contentModel
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.leftMargin: Utils.getSizeWithScreenRatio(45)
|
anchors.leftMargin: Utils.getSizeWithScreenRatio(45)
|
||||||
anchors.rightMargin: Utils.getSizeWithScreenRatio(45)
|
anchors.rightMargin: Utils.getSizeWithScreenRatio(45)
|
||||||
height: contentHeight
|
height: contentHeight
|
||||||
spacing: Utils.getSizeWithScreenRatio(10)
|
spacing: Utils.getSizeWithScreenRatio(10)
|
||||||
delegate: ColumnLayout {
|
delegate: ColumnLayout {
|
||||||
visible: modelData.visible != undefined ? modelData.visible: true
|
visible: modelData.visible != undefined ? modelData.visible: true
|
||||||
Component.onCompleted: if (!visible) height = 0
|
Component.onCompleted: if (!visible) height = 0
|
||||||
spacing: Utils.getSizeWithScreenRatio(16)
|
spacing: Utils.getSizeWithScreenRatio(16)
|
||||||
width: contentListView.width
|
width: contentListView.width
|
||||||
Rectangle {
|
Rectangle {
|
||||||
visible: index !== 0
|
visible: index !== 0
|
||||||
Layout.topMargin: Utils.getSizeWithScreenRatio(modelData.hideTopSeparator ? 0 : 16)
|
Layout.topMargin: Utils.getSizeWithScreenRatio(modelData.hideTopSeparator ? 0 : 16)
|
||||||
Layout.bottomMargin: Utils.getSizeWithScreenRatio(16)
|
Layout.bottomMargin: Utils.getSizeWithScreenRatio(16)
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
height: Utils.getSizeWithScreenRatio(1)
|
height: Utils.getSizeWithScreenRatio(1)
|
||||||
color: modelData.hideTopSeparator ? 'transparent' : DefaultStyle.main2_500_main
|
color: modelData.hideTopSeparator ? 'transparent' : DefaultStyle.main2_500_main
|
||||||
}
|
}
|
||||||
GridLayout {
|
GridLayout {
|
||||||
|
|
@ -152,12 +148,12 @@ Rectangle {
|
||||||
columns: mainItem.useVerticalLayout ? 1 : 2
|
columns: mainItem.useVerticalLayout ? 1 : 2
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
// Layout.preferredWidth: parent.width
|
// Layout.preferredWidth: parent.width
|
||||||
rowSpacing: modelData.title.length > 0 || modelData.subTitle.length > 0 ? Utils.getSizeWithScreenRatio(20) : 0
|
rowSpacing: modelData.title.length > 0 || modelData.subTitle.length > 0 ? Utils.getSizeWithScreenRatio(20) : 0
|
||||||
columnSpacing: Utils.getSizeWithScreenRatio(47)
|
columnSpacing: Utils.getSizeWithScreenRatio(47)
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
Layout.preferredWidth: Utils.getSizeWithScreenRatio(341)
|
Layout.preferredWidth: Utils.getSizeWithScreenRatio(341)
|
||||||
Layout.maximumWidth: Utils.getSizeWithScreenRatio(341)
|
Layout.maximumWidth: Utils.getSizeWithScreenRatio(341)
|
||||||
spacing: Utils.getSizeWithScreenRatio(3)
|
spacing: Utils.getSizeWithScreenRatio(3)
|
||||||
Text {
|
Text {
|
||||||
text: modelData.title
|
text: modelData.title
|
||||||
visible: modelData.title.length > 0
|
visible: modelData.title.length > 0
|
||||||
|
|
@ -179,10 +175,10 @@ Rectangle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RowLayout {
|
RowLayout {
|
||||||
Layout.topMargin: modelData.hideTopMargin ? 0 : Utils.getSizeWithScreenRatio(mainItem.useVerticalLayout ? 10 : 21)
|
Layout.topMargin: modelData.hideTopMargin ? 0 : Utils.getSizeWithScreenRatio(mainItem.useVerticalLayout ? 10 : 21)
|
||||||
Layout.bottomMargin: Utils.getSizeWithScreenRatio(21)
|
Layout.bottomMargin: Utils.getSizeWithScreenRatio(21)
|
||||||
Layout.leftMargin: mainItem.useVerticalLayout ? 0 : Utils.getSizeWithScreenRatio(17)
|
Layout.leftMargin: mainItem.useVerticalLayout ? 0 : Utils.getSizeWithScreenRatio(17)
|
||||||
Layout.preferredWidth: Utils.getSizeWithScreenRatio(modelData.customWidth > 0 ? modelData.customWidth : 545)
|
Layout.preferredWidth: Utils.getSizeWithScreenRatio(modelData.customWidth > 0 ? modelData.customWidth : 545)
|
||||||
Layout.alignment: Qt.AlignRight
|
Layout.alignment: Qt.AlignRight
|
||||||
Loader {
|
Loader {
|
||||||
id: contentLoader
|
id: contentLoader
|
||||||
|
|
@ -190,12 +186,22 @@ Rectangle {
|
||||||
sourceComponent: modelData.contentComponent
|
sourceComponent: modelData.contentComponent
|
||||||
}
|
}
|
||||||
Item {
|
Item {
|
||||||
Layout.preferredWidth: Utils.getSizeWithScreenRatio(modelData.customRightMargin > 0 ? modelData.customRightMargin : 17)
|
Layout.preferredWidth: Utils.getSizeWithScreenRatio(modelData.customRightMargin > 0 ? modelData.customRightMargin : 17)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
target: FocusNavigator
|
||||||
|
|
||||||
|
function onFocusChanged(item, keyboardFocus) {
|
||||||
|
if(Utils.isDescendant(item,scrollView) && keyboardFocus){
|
||||||
|
Utils.ensureVisibleY(item, scrollView)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,14 @@ AbstractMainPage {
|
||||||
goToCallHistory()
|
goToCallHistory()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Focus on the first pertinent element in the page (LINQT-2202)
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
function forceActiveFocus(reason = undefined){
|
||||||
|
listStackView.currentItem?.newCallButton?.forceActiveFocus(reason)
|
||||||
|
}
|
||||||
|
|
||||||
//Group call properties
|
//Group call properties
|
||||||
property ConferenceInfoGui confInfoGui
|
property ConferenceInfoGui confInfoGui
|
||||||
property AccountProxy accounts: AccountProxy {
|
property AccountProxy accounts: AccountProxy {
|
||||||
|
|
@ -134,6 +142,8 @@ AbstractMainPage {
|
||||||
FocusScope {
|
FocusScope {
|
||||||
objectName: "historyListItem"
|
objectName: "historyListItem"
|
||||||
property alias listView: historyListView
|
property alias listView: historyListView
|
||||||
|
property alias newCallButton: newCallButton
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
@ -187,6 +197,7 @@ AbstractMainPage {
|
||||||
}
|
}
|
||||||
Button {
|
Button {
|
||||||
id: newCallButton
|
id: newCallButton
|
||||||
|
focus: true
|
||||||
style: ButtonStyle.noBackground
|
style: ButtonStyle.noBackground
|
||||||
icon.source: AppIcons.newCall
|
icon.source: AppIcons.newCall
|
||||||
Layout.preferredWidth: Utils.getSizeWithScreenRatio(34)
|
Layout.preferredWidth: Utils.getSizeWithScreenRatio(34)
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,14 @@ AbstractMainPage {
|
||||||
emptyListText: qsTr("chat_empty_title")
|
emptyListText: qsTr("chat_empty_title")
|
||||||
newItemIconSource: AppIcons.plusCircle
|
newItemIconSource: AppIcons.plusCircle
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Focus on the first pertinent element in the page (LINQT-2202)
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
function forceActiveFocus(reason = undefined){
|
||||||
|
listStackView.currentItem?.newChatButton?.forceActiveFocus(reason)
|
||||||
|
}
|
||||||
|
|
||||||
property AccountProxy accounts: AccountProxy {
|
property AccountProxy accounts: AccountProxy {
|
||||||
id: accountProxy
|
id: accountProxy
|
||||||
}
|
}
|
||||||
|
|
@ -116,6 +124,7 @@ AbstractMainPage {
|
||||||
FocusScope {
|
FocusScope {
|
||||||
objectName: "chatListItem"
|
objectName: "chatListItem"
|
||||||
property alias listView: chatListView
|
property alias listView: chatListView
|
||||||
|
property alias newChatButton: newChatButton
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
spacing: 0
|
spacing: 0
|
||||||
|
|
@ -158,6 +167,7 @@ AbstractMainPage {
|
||||||
}
|
}
|
||||||
Button {
|
Button {
|
||||||
id: newChatButton
|
id: newChatButton
|
||||||
|
focus: true
|
||||||
style: ButtonStyle.noBackground
|
style: ButtonStyle.noBackground
|
||||||
icon.source: AppIcons.plusCircle
|
icon.source: AppIcons.plusCircle
|
||||||
Layout.preferredWidth: Utils.getSizeWithScreenRatio(28)
|
Layout.preferredWidth: Utils.getSizeWithScreenRatio(28)
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,14 @@ AbstractMainPage {
|
||||||
emptyListText: qsTr("contacts_list_empty")
|
emptyListText: qsTr("contacts_list_empty")
|
||||||
newItemIconSource: AppIcons.plusCircle
|
newItemIconSource: AppIcons.plusCircle
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Focus on the first pertinent element in the page (LINQT-2202)
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
function forceActiveFocus(reason = undefined){
|
||||||
|
createContactButton.forceActiveFocus(reason)
|
||||||
|
}
|
||||||
|
|
||||||
// disable left panel contact list interaction while a contact is being edited
|
// disable left panel contact list interaction while a contact is being edited
|
||||||
property bool leftPanelEnabled: !rightPanelStackView.currentItem
|
property bool leftPanelEnabled: !rightPanelStackView.currentItem
|
||||||
|| rightPanelStackView.currentItem.objectName
|
|| rightPanelStackView.currentItem.objectName
|
||||||
|
|
@ -243,6 +251,7 @@ AbstractMainPage {
|
||||||
visible: !rightPanelStackView.currentItem
|
visible: !rightPanelStackView.currentItem
|
||||||
|| rightPanelStackView.currentItem.objectName !== "contactEdition"
|
|| rightPanelStackView.currentItem.objectName !== "contactEdition"
|
||||||
style: ButtonStyle.noBackground
|
style: ButtonStyle.noBackground
|
||||||
|
focus: true
|
||||||
icon.source: AppIcons.plusCircle
|
icon.source: AppIcons.plusCircle
|
||||||
Layout.preferredWidth: Utils.getSizeWithScreenRatio(28)
|
Layout.preferredWidth: Utils.getSizeWithScreenRatio(28)
|
||||||
Layout.preferredHeight: Utils.getSizeWithScreenRatio(28)
|
Layout.preferredHeight: Utils.getSizeWithScreenRatio(28)
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,15 @@ AbstractMainPage {
|
||||||
rightPanelStackTopMargin: Utils.getSizeWithScreenRatio(45)
|
rightPanelStackTopMargin: Utils.getSizeWithScreenRatio(45)
|
||||||
rightPanelStackBottomMargin: Utils.getSizeWithScreenRatio(30)
|
rightPanelStackBottomMargin: Utils.getSizeWithScreenRatio(30)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Focus on the first pertinent element in the page (LINQT-2202)
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
function forceActiveFocus(reason = undefined){
|
||||||
|
leftPanelStackView.currentItem?.newConfButton?.forceActiveFocus(reason)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
function createPreFilledMeeting(subject, addresses) {
|
function createPreFilledMeeting(subject, addresses) {
|
||||||
mainItem.selectedConference = Qt.createQmlObject('import Linphone
|
mainItem.selectedConference = Qt.createQmlObject('import Linphone
|
||||||
ConferenceInfoGui{
|
ConferenceInfoGui{
|
||||||
|
|
@ -137,6 +146,7 @@ AbstractMainPage {
|
||||||
id: listLayout
|
id: listLayout
|
||||||
FocusScope{
|
FocusScope{
|
||||||
property string objectName: "listLayout"
|
property string objectName: "listLayout"
|
||||||
|
property alias newConfButton: newConfButton
|
||||||
Control.StackView.onDeactivated: {
|
Control.StackView.onDeactivated: {
|
||||||
mainItem.selectedConference = null
|
mainItem.selectedConference = null
|
||||||
}
|
}
|
||||||
|
|
@ -166,6 +176,7 @@ AbstractMainPage {
|
||||||
}
|
}
|
||||||
Button {
|
Button {
|
||||||
id: newConfButton
|
id: newConfButton
|
||||||
|
focus: true
|
||||||
style: ButtonStyle.noBackground
|
style: ButtonStyle.noBackground
|
||||||
icon.source: AppIcons.plusCircle
|
icon.source: AppIcons.plusCircle
|
||||||
Layout.preferredWidth: Utils.getSizeWithScreenRatio(28)
|
Layout.preferredWidth: Utils.getSizeWithScreenRatio(28)
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue