mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-29 15:03:09 +00:00
homescreens/folio: Add keyboard navigation on pages
Implements the rest of https://invent.kde.org/plasma/plasma-mobile/-/issues/219
This commit is contained in:
parent
5c404c0f0d
commit
dc1fa9b187
7 changed files with 430 additions and 48 deletions
|
|
@ -20,7 +20,7 @@ import org.kde.kirigami 2.19 as Kirigami
|
|||
|
||||
MouseArea {
|
||||
id: root
|
||||
onClicked: root.requestedClose()
|
||||
onClicked: root.requestedClose(false)
|
||||
|
||||
function requestFocus() {
|
||||
queryField.forceActiveFocus();
|
||||
|
|
@ -30,11 +30,11 @@ MouseArea {
|
|||
queryField.text = "";
|
||||
}
|
||||
|
||||
signal requestedClose()
|
||||
signal requestedClose(triggeredByKeyEvent: bool)
|
||||
|
||||
Keys.onPressed: (event) => {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
root.requestedClose();
|
||||
root.requestedClose(true);
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -77,7 +77,7 @@ MouseArea {
|
|||
if (event.key === Qt.Key_Down) {
|
||||
if (listView.count === 0) {
|
||||
// Close if listview has no elements
|
||||
root.requestedClose();
|
||||
root.requestedClose(true);
|
||||
} else {
|
||||
// Focus on listview if there are elements
|
||||
listView.forceActiveFocus();
|
||||
|
|
@ -111,7 +111,7 @@ MouseArea {
|
|||
}
|
||||
|
||||
onActivated: {
|
||||
root.requestedClose();
|
||||
root.requestedClose(false);
|
||||
}
|
||||
onUpdateQueryString: {
|
||||
queryField.text = text
|
||||
|
|
@ -153,7 +153,7 @@ MouseArea {
|
|||
// Close search view if we press down with last item selected
|
||||
Keys.onPressed: (event) => {
|
||||
if (event.key === Qt.Key_Down && (model.index === listView.count - 1)) {
|
||||
root.requestedClose();
|
||||
root.requestedClose(true);
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -169,7 +169,7 @@ MouseArea {
|
|||
listView.currentIndex = model.index;
|
||||
listView.runCurrentIndex();
|
||||
|
||||
root.requestedClose();
|
||||
root.requestedClose(false);
|
||||
}
|
||||
hoverEnabled: true
|
||||
|
||||
|
|
|
|||
|
|
@ -34,6 +34,17 @@ MouseArea {
|
|||
}
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
// Focus on first delegate when favorites bar focused
|
||||
let firstDelegate = repeater.itemAt(0);
|
||||
if (!firstDelegate) {
|
||||
return;
|
||||
}
|
||||
firstDelegate.keyboardFocus();
|
||||
}
|
||||
}
|
||||
|
||||
MobileShell.HapticsEffect {
|
||||
id: haptics
|
||||
}
|
||||
|
|
@ -54,11 +65,11 @@ MouseArea {
|
|||
|
||||
readonly property var dragState: folio.HomeScreenState.dragState
|
||||
readonly property bool isDropPositionThis: dragState.candidateDropPosition.location === Folio.DelegateDragPosition.Favourites &&
|
||||
dragState.candidateDropPosition.favouritesPosition === delegate.index
|
||||
dragState.candidateDropPosition.favouritesPosition === delegate.index
|
||||
readonly property bool isAppHoveredOver: folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate &&
|
||||
dragState.dropDelegate &&
|
||||
dragState.dropDelegate.type === Folio.FolioDelegate.Application &&
|
||||
isDropPositionThis
|
||||
dragState.dropDelegate &&
|
||||
dragState.dropDelegate.type === Folio.FolioDelegate.Application &&
|
||||
isDropPositionThis
|
||||
|
||||
readonly property bool isLocationBottom: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom
|
||||
|
||||
|
|
@ -79,7 +90,56 @@ MouseArea {
|
|||
width: folio.HomeScreenState.pageCellWidth
|
||||
height: folio.HomeScreenState.pageCellHeight
|
||||
|
||||
// Keyboard navigation to other delegates
|
||||
Keys.onPressed: (event) => {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Up:
|
||||
if (!isLocationBottom) {
|
||||
let nextDelegate = repeater.itemAt(delegate.index - 1);
|
||||
if (nextDelegate) {
|
||||
nextDelegate.keyboardFocus();
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Qt.Key_Down:
|
||||
if (!isLocationBottom) {
|
||||
let nextDelegate = repeater.itemAt(delegate.index + 1);
|
||||
if (nextDelegate) {
|
||||
nextDelegate.keyboardFocus();
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Qt.Key_Left:
|
||||
if (isLocationBottom) {
|
||||
let nextDelegate = repeater.itemAt(delegate.index - 1);
|
||||
if (nextDelegate) {
|
||||
nextDelegate.keyboardFocus();
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Qt.Key_Right:
|
||||
if (isLocationBottom) {
|
||||
let nextDelegate = repeater.itemAt(delegate.index + 1);
|
||||
if (nextDelegate) {
|
||||
nextDelegate.keyboardFocus();
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
function keyboardFocus() {
|
||||
if (loader.item) {
|
||||
loader.item.keyboardFocus();
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: loader
|
||||
anchors.fill: parent
|
||||
|
||||
sourceComponent: {
|
||||
|
|
|
|||
|
|
@ -36,12 +36,36 @@ Folio.DelegateTouchArea {
|
|||
folio.HomeScreenState.closeFolder();
|
||||
}
|
||||
|
||||
Keys.onPressed: (event) => {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Escape:
|
||||
case Qt.Key_Back:
|
||||
// Close view
|
||||
root.close();
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_Up:
|
||||
case Qt.Key_Down:
|
||||
case Qt.Key_Left:
|
||||
case Qt.Key_Right:
|
||||
// Keyboard focus on first item
|
||||
if (delegateRepeater.count > 0) {
|
||||
delegateRepeater.itemAt(0).keyboardFocus();
|
||||
event.accepted = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: folio.HomeScreenState
|
||||
|
||||
function onFolderAboutToOpen(x, y) {
|
||||
root.folderPositionX = x - folio.HomeScreenState.viewLeftPadding;
|
||||
root.folderPositionY = y - folio.HomeScreenState.viewTopPadding;
|
||||
|
||||
// Focus view when opened
|
||||
root.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -73,6 +97,70 @@ Folio.DelegateTouchArea {
|
|||
folio.HomeScreenState.folderPageContentHeight = (folderBackground.height - margin * 2);
|
||||
}
|
||||
|
||||
function keyboardNavigateForDelegate(key, column, row, page) {
|
||||
let dx = 0;
|
||||
let dy = 0;
|
||||
switch (key) {
|
||||
case Qt.Key_Up: { dy = -1; break; }
|
||||
case Qt.Key_Down: { dy = 1; break; }
|
||||
case Qt.Key_Left: { dx = -1; break; }
|
||||
case Qt.Key_Right: { dx = 1; break; }
|
||||
default: return;
|
||||
}
|
||||
|
||||
let x = column + dx;
|
||||
let y = row + dy;
|
||||
|
||||
// Loop in direction to find next delegate
|
||||
while (x >= 0 && x < folio.HomeScreenState.folderGridLength
|
||||
&& y >= 0 && y < folio.HomeScreenState.folderGridLength) {
|
||||
|
||||
// Find delegate at x, y
|
||||
for (let i = 0; i < delegateRepeater.count; ++i) {
|
||||
let cDelegate = delegateRepeater.itemAt(i);
|
||||
if (cDelegate.columnValue === x && cDelegate.rowValue === y && cDelegate.pageValue === page) {
|
||||
// Delegate matches, focus on it and return
|
||||
cDelegate.keyboardFocus();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
x += dx;
|
||||
y += dy;
|
||||
}
|
||||
|
||||
// Behavior if no delegate is found to navigate to
|
||||
switch (key) {
|
||||
case Qt.Key_Up:
|
||||
case Qt.Key_Down:
|
||||
break;
|
||||
case Qt.Key_Left: {
|
||||
// Go to the left page if a delegate exists there
|
||||
let cDelegate = delegateRepeater.itemAt((page - 1)
|
||||
* folio.HomeScreenState.folderGridLength
|
||||
* folio.HomeScreenState.folderGridLength);
|
||||
if (cDelegate) {
|
||||
cDelegate.keyboardFocus();
|
||||
folio.HomeScreenState.goToFolderPage(page - 1, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case Qt.Key_Right: {
|
||||
// Go to the right page if a delegate exists there
|
||||
let cDelegate = delegateRepeater.itemAt((page + 1)
|
||||
* folio.HomeScreenState.folderGridLength
|
||||
* folio.HomeScreenState.folderGridLength);
|
||||
if (cDelegate) {
|
||||
cDelegate.keyboardFocus();
|
||||
folio.HomeScreenState.goToFolderPage(page + 1, false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: folio.HomeScreenState
|
||||
|
||||
|
|
@ -168,6 +256,7 @@ Folio.DelegateTouchArea {
|
|||
x: folio.HomeScreenState.folderViewX
|
||||
|
||||
Repeater {
|
||||
id: delegateRepeater
|
||||
model: root.folder ? root.folder.applications : []
|
||||
|
||||
delegate: Item {
|
||||
|
|
@ -187,21 +276,16 @@ Folio.DelegateTouchArea {
|
|||
|
||||
readonly property var dragState: folio.HomeScreenState.dragState
|
||||
readonly property bool isDropPositionThis: dragState.candidateDropPosition.location === Folio.DelegateDragPosition.Folder &&
|
||||
dragState.candidateDropPosition.folderPosition === index
|
||||
dragState.candidateDropPosition.folderPosition === index
|
||||
|
||||
// get the index position value so we can animate them
|
||||
property double columnValue: model.columnIndex
|
||||
property double rowValue: model.rowIndex
|
||||
property double pageValue: model.pageIndex
|
||||
Behavior on columnValue {
|
||||
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad }
|
||||
}
|
||||
Behavior on rowValue {
|
||||
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad }
|
||||
}
|
||||
Behavior on pageValue {
|
||||
NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad }
|
||||
}
|
||||
|
||||
Behavior on columnValue { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } }
|
||||
Behavior on rowValue { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } }
|
||||
Behavior on pageValue { NumberAnimation { duration: Kirigami.Units.longDuration; easing.type: Easing.InOutQuad } }
|
||||
|
||||
// multiply the index values by the cell size to get the actual position
|
||||
readonly property int positionColumn: folderCellSize * columnValue
|
||||
|
|
@ -215,6 +299,28 @@ Folio.DelegateTouchArea {
|
|||
width: cellWidth
|
||||
height: cellHeight
|
||||
|
||||
// Implement keyboard arrow navigation
|
||||
Keys.onPressed: (event) => {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Up:
|
||||
case Qt.Key_Down:
|
||||
case Qt.Key_Left:
|
||||
case Qt.Key_Right:
|
||||
event.accepted = true;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
root.keyboardNavigateForDelegate(event.key, columnValue, rowValue, pageValue);
|
||||
}
|
||||
|
||||
function keyboardFocus() {
|
||||
if (delegateLoader.item) {
|
||||
delegateLoader.item.keyboardFocus();
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: delegateLoader
|
||||
anchors.fill: parent
|
||||
|
|
|
|||
|
|
@ -43,6 +43,8 @@ Item {
|
|||
onBottomMarginChanged: folio.HomeScreenState.viewBottomPadding = root.bottomMargin
|
||||
onLeftMarginChanged: folio.HomeScreenState.viewLeftPadding = root.leftMargin
|
||||
onRightMarginChanged: folio.HomeScreenState.viewRightPadding = root.rightMargin
|
||||
onWidthChanged: folio.HomeScreenState.viewWidth = width
|
||||
onHeightChanged: folio.HomeScreenState.viewHeight = height
|
||||
|
||||
signal wallpaperSelectorTriggered()
|
||||
|
||||
|
|
@ -75,6 +77,16 @@ Item {
|
|||
Plasmoid.internalAction("configure").trigger();
|
||||
}
|
||||
|
||||
Keys.onPressed: (event) => {
|
||||
// The root is focused when we aren't in key navigation mode
|
||||
// Begin key navigation when arrow keys are pressed
|
||||
if (event.key === Qt.Key_Up || event.key === Qt.Key_Down
|
||||
|| event.key === Qt.Key_Left || event.key === Qt.Key_Right) {
|
||||
homeScreenPages.forceActiveFocus();
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
// determine how tall an app label is, for delegate measurements
|
||||
DelegateLabel {
|
||||
id: appLabelMetrics
|
||||
|
|
@ -88,20 +100,23 @@ Item {
|
|||
}
|
||||
}
|
||||
|
||||
// determine screen dimensions
|
||||
Item {
|
||||
id: screenDimensions
|
||||
anchors.fill: parent
|
||||
|
||||
onWidthChanged: folio.HomeScreenState.viewWidth = width;
|
||||
onHeightChanged: folio.HomeScreenState.viewHeight = height;
|
||||
}
|
||||
|
||||
// a way of stopping focus
|
||||
FocusScope {
|
||||
id: noFocus
|
||||
}
|
||||
|
||||
// Listen to view changes
|
||||
Connections {
|
||||
target: folio.HomeScreenState
|
||||
|
||||
function onViewStateChanged() {
|
||||
if (folio.HomeScreenState.viewState === Folio.HomeScreenState.PageView) {
|
||||
// Focus root when on page view
|
||||
root.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// area that can be swiped
|
||||
MobileShell.SwipeArea {
|
||||
id: swipeArea
|
||||
|
|
@ -211,6 +226,50 @@ Item {
|
|||
homeScreenState.pageHeight = homeScreenPages.height;
|
||||
}
|
||||
|
||||
// Keyboard navigation from pages
|
||||
Keys.onPressed: (event) => {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Up:
|
||||
// Open search widget when going up
|
||||
folio.HomeScreenState.openSearchWidget();
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_Down:
|
||||
// Focus on favorites bar or app drawer, depending on its physical location
|
||||
if (folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom) {
|
||||
favouritesBar.forceActiveFocus();
|
||||
} else {
|
||||
folio.HomeScreenState.openAppDrawer();
|
||||
}
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_Left:
|
||||
if (folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Left) {
|
||||
// If favorites bar is on the left, navigate to it
|
||||
favouritesBar.forceActiveFocus();
|
||||
} else {
|
||||
// Otherwise go to page on the left
|
||||
folio.HomeScreenState.goToPage(folio.HomeScreenState.currentPage - 1, false);
|
||||
homeScreenPages.focusCurrentPageForKeyboardNav();
|
||||
}
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_Right:
|
||||
if (folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Right) {
|
||||
// If favorites bar is on the right, navigate to it
|
||||
favouritesBar.forceActiveFocus();
|
||||
} else {
|
||||
// Otherwise go to page on the right
|
||||
folio.HomeScreenState.goToPage(folio.HomeScreenState.currentPage + 1, false);
|
||||
homeScreenPages.focusCurrentPageForKeyboardNav();
|
||||
}
|
||||
event.accepted = true;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
transform: [
|
||||
Scale {
|
||||
// animation when settings opens
|
||||
|
|
@ -298,6 +357,42 @@ Item {
|
|||
anchors.leftMargin: root.leftMargin
|
||||
anchors.rightMargin: root.rightMargin
|
||||
|
||||
// Keyboard navigation on favorites bar
|
||||
Keys.onPressed: (event) => {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Up:
|
||||
// Focus on homescreen pages or search widget depending on physical position
|
||||
if (folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom) {
|
||||
homeScreenPages.forceActiveFocus();
|
||||
} else {
|
||||
folio.HomeScreenState.openSearchWidget();
|
||||
}
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_Down:
|
||||
// Open app drawer
|
||||
folio.HomeScreenState.openAppDrawer();
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_Left:
|
||||
if (folio.HomeScreenState.favoritesBarLocation === Folio.HomeScreenState.Left) {
|
||||
// Go to left page if mounted on the left
|
||||
folio.HomeScreenState.goToPage(folio.HomeScreenState.currentPage - 1, false);
|
||||
event.accepted = true;
|
||||
}
|
||||
break;
|
||||
case Qt.Key_Right:
|
||||
if (folio.HomeScreenState.favoritesBarLocation === Folio.HomeScreenState.Right) {
|
||||
// Go to right page if mounted on the right
|
||||
folio.HomeScreenState.goToPage(folio.HomeScreenState.currentPage + 1, false);
|
||||
event.accepted = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
states: [
|
||||
State {
|
||||
name: "bottom"
|
||||
|
|
@ -499,13 +594,11 @@ Item {
|
|||
function onSearchWidgetOpenProgressChanged() {
|
||||
if (homeScreenState.searchWidgetOpenProgress === 1.0) {
|
||||
searchWidget.requestFocus();
|
||||
} else if (!root.activeFocus) {
|
||||
root.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onRequestedClose: {
|
||||
onRequestedClose: (triggeredByKeyEvent) => {
|
||||
homeScreenState.closeSearchWidget();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -25,6 +25,80 @@ Item {
|
|||
property var pageModel
|
||||
property var homeScreen
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
// Focus on first delegate when this page is focused
|
||||
let firstDelegate = findFirstDelegate();
|
||||
if (!firstDelegate) {
|
||||
return;
|
||||
}
|
||||
firstDelegate.keyboardFocus();
|
||||
}
|
||||
}
|
||||
|
||||
// Returns the first delegate on the page, or null if none exist
|
||||
function findFirstDelegate() {
|
||||
let firstDelegate = delegateRepeater.itemAt(0);
|
||||
if (!firstDelegate) {
|
||||
return null;
|
||||
}
|
||||
|
||||
for (let i = 0; i < delegateRepeater.count; ++i) {
|
||||
let delegate = delegateRepeater.itemAt(i);
|
||||
|
||||
const isAppOrFolder = delegate.pageDelegate.type === Folio.FolioDelegate.Application || delegate.pageDelegate.type === Folio.FolioDelegate.Folder;
|
||||
|
||||
// If it's on an earlier row, or on the same row but earlier column
|
||||
if (isAppOrFolder
|
||||
&& (delegate.row < firstDelegate.row
|
||||
|| (delegate.column < firstDelegate.column
|
||||
&& delegate.row === firstDelegate.row))) {
|
||||
firstDelegate = delegate;
|
||||
}
|
||||
}
|
||||
return firstDelegate;
|
||||
}
|
||||
|
||||
// Returns the next application/folder delegate on the page from the given delegate
|
||||
// in a certain direction, or null if none exist.
|
||||
function findNextAppDelegate(delegate, direction: MobileShell.Direction) {
|
||||
let dx = 0;
|
||||
let dy = 0;
|
||||
switch (direction) {
|
||||
case MobileShell.Direction.Up:
|
||||
dy = -1;
|
||||
break;
|
||||
case MobileShell.Direction.Down:
|
||||
dy = 1;
|
||||
break;
|
||||
case MobileShell.Direction.Left:
|
||||
dx = -1;
|
||||
break;
|
||||
case MobileShell.Direction.Right:
|
||||
dx = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
let x = delegate.column + dx;
|
||||
let y = delegate.row + dy;
|
||||
|
||||
// Loop in direction to find delegate
|
||||
while (x >= 0 && x < folio.HomeScreenState.pageColumns && y >= 0 && y < folio.HomeScreenState.pageRows) {
|
||||
for (let i = 0; i < delegateRepeater.count; ++i) {
|
||||
let delegate = delegateRepeater.itemAt(i);
|
||||
|
||||
if (delegate.row === y && delegate.column === x
|
||||
&& (delegate.pageDelegate.type === Folio.FolioDelegate.Application
|
||||
|| delegate.pageDelegate.type === Folio.FolioDelegate.Folder)) {
|
||||
return delegate;
|
||||
}
|
||||
}
|
||||
x += dx;
|
||||
y += dy;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
MobileShell.HapticsEffect {
|
||||
id: haptics
|
||||
}
|
||||
|
|
@ -72,10 +146,10 @@ Item {
|
|||
|
||||
// only show if the widget can be placed here
|
||||
visible: folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate &&
|
||||
dropPosition.location === Folio.DelegateDragPosition.Pages &&
|
||||
dropPosition.page === root.pageNum &&
|
||||
dropDelegateIsWidget &&
|
||||
pageModel.canAddDelegate(dropPosition.pageRow, dropPosition.pageColumn, dropDelegate)
|
||||
dropPosition.location === Folio.DelegateDragPosition.Pages &&
|
||||
dropPosition.page === root.pageNum &&
|
||||
dropDelegateIsWidget &&
|
||||
pageModel.canAddDelegate(dropPosition.pageRow, dropPosition.pageColumn, dropDelegate)
|
||||
|
||||
radius: Kirigami.Units.cornerRadius
|
||||
color: Qt.rgba(255, 255, 255, 0.3)
|
||||
|
|
@ -89,6 +163,7 @@ Item {
|
|||
|
||||
// repeater of all delegates in the page
|
||||
Repeater {
|
||||
id: delegateRepeater
|
||||
model: root.pageModel
|
||||
|
||||
delegate: Item {
|
||||
|
|
@ -101,14 +176,14 @@ Item {
|
|||
property var dragState: folio.HomeScreenState.dragState
|
||||
|
||||
property bool isDropPositionThis: dragState.candidateDropPosition.location === Folio.DelegateDragPosition.Pages &&
|
||||
dragState.candidateDropPosition.page === root.pageNum &&
|
||||
dragState.candidateDropPosition.pageRow === delegate.pageDelegate.row &&
|
||||
dragState.candidateDropPosition.pageColumn === delegate.pageDelegate.column
|
||||
dragState.candidateDropPosition.page === root.pageNum &&
|
||||
dragState.candidateDropPosition.pageRow === delegate.pageDelegate.row &&
|
||||
dragState.candidateDropPosition.pageColumn === delegate.pageDelegate.column
|
||||
|
||||
property bool isAppHoveredOver: folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate &&
|
||||
dragState.dropDelegate &&
|
||||
dragState.dropDelegate.type === Folio.FolioDelegate.Application &&
|
||||
isDropPositionThis
|
||||
dragState.dropDelegate &&
|
||||
dragState.dropDelegate.type === Folio.FolioDelegate.Application &&
|
||||
isDropPositionThis
|
||||
|
||||
implicitWidth: loader.item ? loader.item.implicitWidth : 0
|
||||
implicitHeight: loader.item ? loader.item.implicitHeight : 0
|
||||
|
|
@ -132,6 +207,39 @@ Item {
|
|||
// folio.HomeScreenState.snapPage();
|
||||
}
|
||||
|
||||
// Keyboard navigation between delegates
|
||||
Keys.onPressed: (event) => {
|
||||
let direction = MobileShell.Direction.Up;
|
||||
switch (event.key) {
|
||||
case Qt.Key_Up:
|
||||
direction = MobileShell.Direction.Up;
|
||||
break;
|
||||
case Qt.Key_Down:
|
||||
direction = MobileShell.Direction.Down;
|
||||
break;
|
||||
case Qt.Key_Left:
|
||||
direction = MobileShell.Direction.Left;
|
||||
break;
|
||||
case Qt.Key_Right:
|
||||
direction = MobileShell.Direction.Right;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
}
|
||||
|
||||
let nextDelegate = root.findNextAppDelegate(delegate, direction);
|
||||
if (nextDelegate) {
|
||||
nextDelegate.keyboardFocus();
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
function keyboardFocus() {
|
||||
if (loader.item) {
|
||||
loader.item.keyboardFocus();
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: loader
|
||||
anchors.top: parent.top
|
||||
|
|
@ -251,8 +359,8 @@ Item {
|
|||
|
||||
// do not show if the drop animation is running to this delegate, and the drop delegate is a folder
|
||||
visible: !(root.homeScreen.dropAnimationRunning &&
|
||||
delegate.isDropPositionThis &&
|
||||
delegate.dragState.dropDelegate.type === Folio.FolioDelegate.Folder)
|
||||
delegate.isDropPositionThis &&
|
||||
delegate.dragState.dropDelegate.type === Folio.FolioDelegate.Folder)
|
||||
|
||||
// don't show label in drag and drop mode
|
||||
labelOpacity: delegate.opacity
|
||||
|
|
|
|||
|
|
@ -31,6 +31,20 @@ MouseArea {
|
|||
}
|
||||
}
|
||||
|
||||
onActiveFocusChanged: {
|
||||
if (activeFocus) {
|
||||
// When this component is focused, move focus to current page (keyboard navigation)
|
||||
focusCurrentPageForKeyboardNav();
|
||||
}
|
||||
}
|
||||
|
||||
function focusCurrentPageForKeyboardNav() {
|
||||
const currentPage = pageRepeater.itemAt(folio.HomeScreenState.currentPage);
|
||||
if (currentPage) {
|
||||
currentPage.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
MobileShell.HapticsEffect {
|
||||
id: haptics
|
||||
}
|
||||
|
|
@ -40,6 +54,7 @@ MouseArea {
|
|||
}
|
||||
|
||||
Repeater {
|
||||
id: pageRepeater
|
||||
model: folio.PageListModel
|
||||
|
||||
delegate: HomeScreenPage {
|
||||
|
|
|
|||
|
|
@ -29,9 +29,6 @@ ContainmentItem {
|
|||
folio.FolioSettings.load();
|
||||
folio.FavouritesModel.load();
|
||||
folio.PageListModel.load();
|
||||
|
||||
// ensure the gestures work immediately on load
|
||||
forceActiveFocus();
|
||||
}
|
||||
|
||||
property MobileShell.MaskManager maskManager: MobileShell.MaskManager {
|
||||
|
|
@ -167,6 +164,9 @@ ContainmentItem {
|
|||
leftMargin: homeScreen.leftMargin
|
||||
rightMargin: homeScreen.rightMargin
|
||||
|
||||
// Ensure is the focused item at start
|
||||
Component.onCompleted: forceActiveFocus()
|
||||
|
||||
onWallpaperSelectorTriggered: wallpaperSelectorLoader.active = true
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue