diff --git a/containments/homescreens/folio/CMakeLists.txt b/containments/homescreens/folio/CMakeLists.txt index 8c264cfb..960203de 100644 --- a/containments/homescreens/folio/CMakeLists.txt +++ b/containments/homescreens/folio/CMakeLists.txt @@ -9,6 +9,7 @@ plasma_add_applet(org.kde.plasma.mobile.homescreen.folio qml/AppDrawerGrid.qml qml/AppDrawerHeader.qml qml/DelegateDragItem.qml + qml/DelegateDropArea.qml qml/FavouritesBar.qml qml/FolderView.qml qml/FolderViewTitle.qml @@ -65,6 +66,7 @@ ecm_target_qml_sources(org.kde.plasma.mobile.homescreen.folio SOURCES ) ecm_target_qml_sources(org.kde.plasma.mobile.homescreen.folio SOURCES + qml/settings/AppletListDelegate.qml qml/settings/AppletListViewer.qml qml/settings/SettingsButton.qml qml/settings/SettingsComponent.qml diff --git a/containments/homescreens/folio/dragstate.cpp b/containments/homescreens/folio/dragstate.cpp index 582122e7..972b2378 100644 --- a/containments/homescreens/folio/dragstate.cpp +++ b/containments/homescreens/folio/dragstate.cpp @@ -175,12 +175,9 @@ DragState::DragState(HomeScreenState *state, HomeScreen *parent) connect(m_state, &HomeScreenState::delegateDragFromFavouritesStarted, this, &DragState::onDelegateDragFromFavouritesStarted); connect(m_state, &HomeScreenState::delegateDragFromFolderStarted, this, &DragState::onDelegateDragFromFolderStarted); connect(m_state, &HomeScreenState::delegateDragFromWidgetListStarted, this, &DragState::onDelegateDragFromWidgetListStarted); - connect(m_state, &HomeScreenState::swipeStateChanged, this, [this]() { - if (m_state->swipeState() == HomeScreenState::DraggingDelegate) { - onDelegateDraggingStarted(); - } - }); - connect(m_state, &HomeScreenState::delegateDragEnded, this, &DragState::onDelegateDropped); + connect(m_state, &HomeScreenState::delegateDragStarted, this, &DragState::onDelegateDraggingStarted); + connect(m_state, &HomeScreenState::delegateDragDropped, this, &DragState::onDelegateDropped); + connect(m_state, &HomeScreenState::delegateDragCancelled, this, &DragState::onDelegateDraggingCancelled); connect(m_state, &HomeScreenState::pageNumChanged, this, [this]() { m_candidateDropPosition->setPageRow(m_state->currentPage()); @@ -546,19 +543,8 @@ void DragState::onDelegateDropped() // add dropped delegate bool success = createDropPositionDelegate(); - // delete empty pages at the end if they exist - // (it can be created if user drags app to new page, but doesn't place it there) - m_homeScreen->pageListModel()->deleteEmptyPagesAtEnd(); - - // clear ghost position if there is one - m_homeScreen->favouritesModel()->deleteGhostEntry(); - - // reset timers - m_folderInsertBetweenTimer->stop(); - m_changeFolderPageTimer->stop(); - m_leaveFolderTimer->stop(); - m_changePageTimer->stop(); - m_favouritesInsertBetweenTimer->stop(); + // Cleanup timers and state + dragStopCleanup(); // emit corresponding signal // -> if we couldn't drop a new delegate at a spot, emit newDelegateDropAbandoned() @@ -570,6 +556,41 @@ void DragState::onDelegateDropped() } } +void DragState::onDelegateDraggingCancelled() +{ + if (!m_dropDelegate) { + return; + } + + // Cleanup timers and state + dragStopCleanup(); + + if (m_startPosition->location() == DelegateDragPosition::WidgetList || m_startPosition->location() == DelegateDragPosition::AppDrawer) { + // If this is a new delegate, it's abandoned + Q_EMIT newDelegateDropAbandoned(); + } else { + // If it's an existing delegate, it simply goes back to its original position + Q_EMIT delegateDroppedAndPlaced(); + } +} + +void DragState::dragStopCleanup() +{ + // Delete empty pages at the end if they exist + // (it can be created if user drags app to new page, but doesn't place it there) + m_homeScreen->pageListModel()->deleteEmptyPagesAtEnd(); + + // Clear ghost position if there is one + m_homeScreen->favouritesModel()->deleteGhostEntry(); + + // Reset timers + m_folderInsertBetweenTimer->stop(); + m_changeFolderPageTimer->stop(); + m_leaveFolderTimer->stop(); + m_changePageTimer->stop(); + m_favouritesInsertBetweenTimer->stop(); +} + void DragState::onLeaveCurrentFolder() { if (!m_state) { @@ -589,7 +610,7 @@ void DragState::onLeaveCurrentFolder() void DragState::onChangePageTimerFinished() { - if (!m_state || (m_state->swipeState() != HomeScreenState::DraggingDelegate)) { + if (!m_state || !m_state->isDraggingDelegate()) { return; } @@ -624,7 +645,7 @@ void DragState::onChangePageTimerFinished() void DragState::onOpenFolderTimerFinished() { - if (!m_state || m_state->swipeState() != HomeScreenState::DraggingDelegate || m_state->viewState() != HomeScreenState::PageView + if (!m_state || !m_state->isDraggingDelegate() || m_state->viewState() != HomeScreenState::PageView || (m_candidateDropPosition->location() != DelegateDragPosition::Pages && m_candidateDropPosition->location() != DelegateDragPosition::Favourites)) { return; } @@ -672,7 +693,7 @@ void DragState::onOpenFolderTimerFinished() void DragState::onLeaveFolderTimerFinished() { - if (!m_state || (m_state->swipeState() != HomeScreenState::DraggingDelegate) || !m_state->currentFolder()) { + if (!m_state || !m_state->isDraggingDelegate() || !m_state->currentFolder()) { return; } @@ -684,7 +705,7 @@ void DragState::onLeaveFolderTimerFinished() void DragState::onChangeFolderPageTimerFinished() { - if (!m_state || (m_state->swipeState() != HomeScreenState::DraggingDelegate) || !m_state->currentFolder()) { + if (!m_state || !m_state->isDraggingDelegate() || !m_state->currentFolder()) { return; } @@ -720,7 +741,7 @@ void DragState::onChangeFolderPageTimerFinished() void DragState::onFolderInsertBetweenTimerFinished() { - if (!m_state || (m_state->swipeState() != HomeScreenState::DraggingDelegate) || !m_state->currentFolder()) { + if (!m_state || !m_state->isDraggingDelegate() || !m_state->currentFolder()) { return; } diff --git a/containments/homescreens/folio/dragstate.h b/containments/homescreens/folio/dragstate.h index bbf23545..e85f2f51 100644 --- a/containments/homescreens/folio/dragstate.h +++ b/containments/homescreens/folio/dragstate.h @@ -118,6 +118,7 @@ private Q_SLOTS: void onDelegateDragFromFolderStarted(FolioApplicationFolder *folder, int position); void onDelegateDragFromWidgetListStarted(QString appletPluginId); void onDelegateDropped(); + void onDelegateDraggingCancelled(); void onLeaveCurrentFolder(); @@ -129,6 +130,9 @@ private Q_SLOTS: void onFavouritesInsertBetweenTimerFinished(); private: + // Cleanup after a drag event (stop timers etc.) + void dragStopCleanup(); + // deletes the delegate at m_startPosition void deleteStartPositionDelegate(); diff --git a/containments/homescreens/folio/homescreenstate.cpp b/containments/homescreens/folio/homescreenstate.cpp index ed78538c..d7432a71 100644 --- a/containments/homescreens/folio/homescreenstate.cpp +++ b/containments/homescreens/folio/homescreenstate.cpp @@ -195,6 +195,7 @@ void HomeScreenState::setSwipeState(SwipeState swipeState) if (swipeState != m_swipeState) { m_swipeState = swipeState; Q_EMIT swipeStateChanged(); + Q_EMIT isDraggingDelegateChanged(); } } @@ -692,6 +693,11 @@ int HomeScreenState::currentFolderPage() return m_folderPageNum; } +bool HomeScreenState::isDraggingDelegate() +{ + return m_dragDropActive || m_swipeState == SwipeState::DraggingDelegate; +} + FolioDelegate *HomeScreenState::getPageDelegateAt(int page, int row, int column) { PageModel *pageModel = m_homeScreen->pageListModel()->getPage(page); @@ -905,6 +911,7 @@ void HomeScreenState::startDelegateAppDrawerDrag(qreal startX, qreal startY, qre // we start dragging the delegate immediately from the app drawer, because we don't have a context menu to deal with! // NOTE: this has to happen after delegateDragFromAppDrawerStarted, because slots for that expect SwipeState::AwaitingDraggingDelegate setSwipeState(SwipeState::DraggingDelegate); + Q_EMIT delegateDragStarted(); } void HomeScreenState::startDelegateFolderDrag(qreal startX, @@ -922,10 +929,6 @@ void HomeScreenState::startDelegateWidgetListDrag(qreal startX, qreal startY, qr { startDelegateDrag(startX, startY, pointerOffsetX, pointerOffsetY); Q_EMIT delegateDragFromWidgetListStarted(appletPluginId); - - // we start dragging the delegate immediately from the app drawer, because we don't have a context menu to deal with! - // NOTE: this has to happen after delegateDragFromAppDrawerStarted, because slots for that expect SwipeState::AwaitingDraggingDelegate - setSwipeState(SwipeState::DraggingDelegate); } void HomeScreenState::cancelDelegateDrag() @@ -991,7 +994,7 @@ void HomeScreenState::swipeEnded() break; } case SwipeState::DraggingDelegate: - Q_EMIT delegateDragEnded(); + Q_EMIT delegateDragDropped(); break; case SwipeState::AwaitingDraggingDelegate: case SwipeState::DeterminingSwipeType: @@ -1003,6 +1006,45 @@ void HomeScreenState::swipeEnded() setSwipeState(SwipeState::None); } +void HomeScreenState::dragStart() +{ + // Cancel AwaitingDraggingDelegate + swipeEnded(); + + m_dragDropActive = true; + Q_EMIT delegateDragStarted(); + Q_EMIT isDraggingDelegateChanged(); +} + +void HomeScreenState::dragMove(qreal deltaX, qreal deltaY) +{ + if (!m_dragDropActive) { + return; + } + setDelegateDragX(m_delegateDragX + deltaX); + setDelegateDragY(m_delegateDragY + deltaY); +} + +void HomeScreenState::dragDrop() +{ + if (!m_dragDropActive) { + return; + } + m_dragDropActive = false; + Q_EMIT delegateDragDropped(); + Q_EMIT isDraggingDelegateChanged(); +} + +void HomeScreenState::dragCancel() +{ + if (!m_dragDropActive) { + return; + } + m_dragDropActive = false; + Q_EMIT delegateDragCancelled(); + Q_EMIT isDraggingDelegateChanged(); +} + void HomeScreenState::swipeCancelled() { setSwipeState(SwipeState::None); @@ -1038,6 +1080,7 @@ void HomeScreenState::swipeMoved(qreal totalDeltaX, qreal totalDeltaY, qreal del break; case SwipeState::AwaitingDraggingDelegate: setSwipeState(SwipeState::DraggingDelegate); + Q_EMIT delegateDragStarted(); break; case SwipeState::DraggingDelegate: setDelegateDragX(m_delegateDragX + deltaX); diff --git a/containments/homescreens/folio/homescreenstate.h b/containments/homescreens/folio/homescreenstate.h index 058d3e25..e5d02a4b 100644 --- a/containments/homescreens/folio/homescreenstate.h +++ b/containments/homescreens/folio/homescreenstate.h @@ -80,6 +80,8 @@ class HomeScreenState : public QObject Q_PROPERTY(int currentPage READ currentPage NOTIFY pageNumChanged) Q_PROPERTY(int currentFolderPage READ currentFolderPage NOTIFY folderPageNumChanged) + Q_PROPERTY(bool isDraggingDelegate READ isDraggingDelegate NOTIFY isDraggingDelegateChanged) + public: enum SwipeState { None, @@ -258,6 +260,9 @@ public: int currentFolderPage(); + // Whether something is being dragged (either from SwipeArea or Drag & Drop) + bool isDraggingDelegate(); + // QML helpers Q_INVOKABLE FolioDelegate *getPageDelegateAt(int page, int row, int column); Q_INVOKABLE FolioDelegate *getFavouritesDelegateAt(int position); @@ -305,7 +310,9 @@ Q_SIGNALS: void searchWidgetYChanged(); void delegateDragXChanged(); void delegateDragYChanged(); - void delegateDragEnded(); + void delegateDragStarted(); + void delegateDragDropped(); + void delegateDragCancelled(); void delegateDragFromPageStarted(int page, int row, int column); void delegateDragFromFavouritesStarted(int position); void delegateDragFromAppDrawerStarted(QString storageId); @@ -313,6 +320,7 @@ Q_SIGNALS: void delegateDragFromWidgetListStarted(QString appletPluginId); void pageNumChanged(); void folderPageNumChanged(); + void isDraggingDelegateChanged(); void leftCurrentFolder(); void folderAboutToOpen(qreal x, qreal y); // the position on the screen where the delegate is at, for animations @@ -347,6 +355,12 @@ public Q_SLOTS: void swipeCancelled(); void swipeMoved(qreal totalDeltaX, qreal totalDeltaY, qreal deltaX, qreal deltaY); + // from DropArea + void dragStart(); + void dragMove(qreal deltaX, qreal deltaY); + void dragDrop(); + void dragCancel(); + private: void setViewState(ViewState viewState); void setSwipeState(SwipeState swipeState); @@ -410,6 +424,7 @@ private: qreal m_delegateDragY{0}; qreal m_delegateDragPointerOffsetX{0}; qreal m_delegateDragPointerOffsetY{0}; + bool m_dragDropActive{false}; int m_pageNum{0}; int m_folderPageNum{0}; diff --git a/containments/homescreens/folio/qml/DelegateDragItem.qml b/containments/homescreens/folio/qml/DelegateDragItem.qml index 36efd881..59e7c8b0 100644 --- a/containments/homescreens/folio/qml/DelegateDragItem.qml +++ b/containments/homescreens/folio/qml/DelegateDragItem.qml @@ -10,6 +10,8 @@ import org.kde.plasma.private.mobileshell as MobileShell import "./delegate" +// Placeholder item that the user sees as they drag app/folder delegates around. +// See WidgetDragItem for the equivalent for widgets. Item { id: root property Folio.HomeScreen folio @@ -75,15 +77,16 @@ Item { property var delegateDroppedOn: null // reset and show drag item - function onSwipeStateChanged() { - if (folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate && !isWidgetDrag) { - root.scale = 1.0; - root.visible = true; + function onDelegateDragStarted() { + if (isWidgetDrag) { + return; } + root.scale = 1.0; + root.visible = true; } // save the existing delegate at the spot (this is called before the delegate is dropped) - function onDelegateDragEnded() { + function onDelegateDragDropped() { if (root.isWidgetDrag) { return; } @@ -103,6 +106,7 @@ Item { break; } } + } Connections { @@ -142,7 +146,7 @@ Item { // scale animation if we are creating, or inserting into a folder scaleAnim.restart(); - } + } } // if the drop has been abandoned, just hide diff --git a/containments/homescreens/folio/qml/DelegateDropArea.qml b/containments/homescreens/folio/qml/DelegateDropArea.qml new file mode 100644 index 00000000..a57e3a71 --- /dev/null +++ b/containments/homescreens/folio/qml/DelegateDropArea.qml @@ -0,0 +1,57 @@ +// SPDX-FileCopyrightText: 2025 Devin Lin +// SPDX-License-Identifier: LGPL-2.0-or-later + +import QtQuick + +import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio + +DropArea { + id: root + property Folio.HomeScreen folio + property Folio.HomeScreenState homeScreenState: folio.HomeScreenState + + keys: ["text/x-plasmoidservicename"] + + property real prevX + property real prevY + + onEntered: (drag) => { + drag.accept(); + const widthOffset = folio.HomeScreenState.pageCellWidth / 2; + const heightOffset = folio.HomeScreenState.pageCellHeight / 2; + + homeScreenState.startDelegateWidgetListDrag( + drag.x - widthOffset, + drag.y - heightOffset, + widthOffset, + heightOffset, + drag.getDataAsString("text/x-plasmoidservicename") + ); + + homeScreenState.dragStart(); + prevX = drag.x; + prevY = drag.y; + } + onDropped: (drop) => { + drop.accept(); + dropWaitTimer.restart(); + } + onExited: { + homeScreenState.dragCancel(); + } + onPositionChanged: (drag) => { + drag.accept(); + homeScreenState.dragMove(drag.x - prevX, drag.y - prevY); + prevX = drag.x; + prevY = drag.y; + } + + // HACK: Seems to crash otherwise, Qt bug? + Timer { + id: dropWaitTimer + interval: 10 + onTriggered: { + homeScreenState.dragDrop(); + } + } +} diff --git a/containments/homescreens/folio/qml/FavouritesBar.qml b/containments/homescreens/folio/qml/FavouritesBar.qml index 5881c37c..2be9b087 100644 --- a/containments/homescreens/folio/qml/FavouritesBar.qml +++ b/containments/homescreens/folio/qml/FavouritesBar.qml @@ -66,7 +66,7 @@ MouseArea { readonly property var dragState: folio.HomeScreenState.dragState readonly property bool isDropPositionThis: dragState.candidateDropPosition.location === Folio.DelegateDragPosition.Favourites && dragState.candidateDropPosition.favouritesPosition === delegate.index - readonly property bool isAppHoveredOver: folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate && + readonly property bool isAppHoveredOver: folio.HomeScreenState.isDraggingDelegate && dragState.dropDelegate && dragState.dropDelegate.type === Folio.FolioDelegate.Application && isDropPositionThis @@ -178,7 +178,7 @@ MouseArea { shadow: true turnToFolder: delegate.isAppHoveredOver - turnToFolderAnimEnabled: folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate + turnToFolderAnimEnabled: folio.HomeScreenState.isDraggingDelegate // do not show if the drop animation is running to this delegate visible: !(root.homeScreen.dropAnimationRunning && delegate.isDropPositionThis) @@ -221,10 +221,8 @@ MouseArea { Connections { target: folio.HomeScreenState - function onSwipeStateChanged() { - if (folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate) { - contextMenu.close(); - } + function onDelegateDragStarted() { + contextMenu.close(); } } @@ -298,10 +296,8 @@ MouseArea { Connections { target: folio.HomeScreenState - function onSwipeStateChanged() { - if (folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate) { - contextMenu.close(); - } + function onDelegateDragStarted() { + contextMenu.close(); } } diff --git a/containments/homescreens/folio/qml/FolderView.qml b/containments/homescreens/folio/qml/FolderView.qml index af14eee4..e86fcd79 100644 --- a/containments/homescreens/folio/qml/FolderView.qml +++ b/containments/homescreens/folio/qml/FolderView.qml @@ -326,7 +326,7 @@ Folio.DelegateTouchArea { anchors.fill: parent sourceComponent: { - if (delegate.delegateModel.type === Folio.FolioDelegate.Application) { + if (delegate.delegateModel && delegate.delegateModel.type === Folio.FolioDelegate.Application) { return appComponent; } else { return noneComponent; @@ -391,10 +391,8 @@ Folio.DelegateTouchArea { Connections { target: folio.HomeScreenState - function onSwipeStateChanged() { - if (folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate) { - contextMenu.close(); - } + function onDelegateDragStarted() { + contextMenu.close(); } } diff --git a/containments/homescreens/folio/qml/FolioHomeScreen.qml b/containments/homescreens/folio/qml/FolioHomeScreen.qml index de3c6c2c..2b11977c 100644 --- a/containments/homescreens/folio/qml/FolioHomeScreen.qml +++ b/containments/homescreens/folio/qml/FolioHomeScreen.qml @@ -117,497 +117,493 @@ Item { } } - // area that can be swiped - MobileShell.SwipeArea { - id: swipeArea + // Drag and drop area + DelegateDropArea { + id: dropArea + folio: root.folio anchors.fill: parent - interactive: root.interactive && - settingsLoader.homeScreenInteractive && - (appDrawer.flickable.atYBeginning || // there are cases where contentY > 0 but atYBeginning is true - appDrawer.flickable.contentY <= 10 || - // disable the swipe area when we are swiping in the app drawer, and not in drag-and-drop - folio.HomeScreenState.swipeState === Folio.HomeScreenState.AwaitingDraggingDelegate || - folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate || - folio.HomeScreenState.swipeState === Folio.HomeScreenState.SwipingAppDrawerGrid || - folio.HomeScreenState.viewState !== Folio.HomeScreenState.AppDrawerView) + // Area that can be swiped + MobileShell.SwipeArea { + id: swipeArea + anchors.fill: parent - onSwipeStarted: (currentPos, startPos) => { - const deltaX = currentPos.x - startPos.x; - const deltaY = currentPos.y - startPos.y; - homeScreenState.swipeStarted(deltaX, deltaY); - } - onSwipeEnded: { - homeScreenState.swipeEnded(); - } - onSwipeMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => { - // cancel swipe when settings component is opening to prevent conflicts - if (folio.HomeScreenState.settingsOpenProgress && folio.HomeScreenState.viewState !== Folio.HomeScreenState.SettingsView) { - homeScreenState.swipeCancelled(); - return; + interactive: root.interactive && + settings.homeScreenInteractive && + !dropArea.containsDrag && + (appDrawer.flickable.atYBeginning || // there are cases where contentY > 0 but atYBeginning is true + appDrawer.flickable.contentY <= 10 || + // disable the swipe area when we are swiping in the app drawer, and not in drag-and-drop + folio.HomeScreenState.swipeState === Folio.HomeScreenState.AwaitingDraggingDelegate || + folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate || + folio.HomeScreenState.swipeState === Folio.HomeScreenState.SwipingAppDrawerGrid || + folio.HomeScreenState.viewState !== Folio.HomeScreenState.AppDrawerView) + + onSwipeStarted: (currentPos, startPos) => { + const deltaX = currentPos.x - startPos.x; + const deltaY = currentPos.y - startPos.y; + homeScreenState.swipeStarted(deltaX, deltaY); } - homeScreenState.swipeMoved(totalDeltaX, totalDeltaY, deltaX, deltaY); - } - - onTouchpadScrollStarted: homeScreenState.swipeStarted(0, 0); - onTouchpadScrollEnded: homeScreenState.swipeEnded(); - onTouchpadScrollMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => homeScreenState.swipeMoved(totalDeltaX, totalDeltaY, deltaX, deltaY); - - onPressedChanged: { - if (pressed) { - // ensures that components like the widget settings overlay close when swiping - noFocus.forceActiveFocus(); + onSwipeEnded: { + homeScreenState.swipeEnded(); + } + onSwipeMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => { + // cancel swipe when settings component is opening to prevent conflicts + if (folio.HomeScreenState.settingsOpenProgress && folio.HomeScreenState.viewState !== Folio.HomeScreenState.SettingsView) { + homeScreenState.swipeCancelled(); + return; + } + homeScreenState.swipeMoved(totalDeltaX, totalDeltaY, deltaX, deltaY); } - } - Loader { - id: settingsLoader - asynchronous: true - active: true + onTouchpadScrollStarted: homeScreenState.swipeStarted(0, 0); + onTouchpadScrollEnded: homeScreenState.swipeEnded(); + onTouchpadScrollMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => homeScreenState.swipeMoved(totalDeltaX, totalDeltaY, deltaX, deltaY); - // Don't anchor, since we set y - width: parent.width - height: parent.height - opacity: folio.HomeScreenState.settingsOpenProgress + onPressedChanged: { + if (pressed) { + // ensures that components like the widget settings overlay close when swiping + noFocus.forceActiveFocus(); + } + } - // move the settings out of the way if it is not visible - // NOTE: we do this instead of setting visible to false, because - // it doesn't mess with widget drag and drop - y: (opacity > 0) ? 0 : parent.height - z: 1 - - readonly property bool homeScreenInteractive: item ? item.homeScreenInteractive : true - - sourceComponent: SettingsComponent { + SettingsComponent { id: settings folio: root.folio + homeScreen: root + settingsModeHomeScreenScale: root.settingsModeHomeScreenScale + + // Don't anchor, since we set y + width: parent.width + height: parent.height + opacity: folio.HomeScreenState.settingsOpenProgress + visible: opacity > 0 + + z: 1 bottomMargin: root.bottomMargin leftMargin: root.leftMargin rightMargin: root.rightMargin - - settingsModeHomeScreenScale: root.settingsModeHomeScreenScale - homeScreen: root } - } - Item { - id: mainHomeScreen - anchors.fill: parent + Item { + id: mainHomeScreen + anchors.fill: parent - // we stop showing halfway through the animation - opacity: 1 - Math.max(homeScreenState.appDrawerOpenProgress, homeScreenState.searchWidgetOpenProgress, homeScreenState.folderOpenProgress) * 2 - visible: opacity > 0 // prevent handlers from picking up events - - transform: [ - Scale { - property real scaleFactor: Math.max(homeScreenState.appDrawerOpenProgress, homeScreenState.searchWidgetOpenProgress) - origin.x: mainHomeScreen.width / 2 - origin.y: mainHomeScreen.height / 2 - yScale: 1 - (scaleFactor * 2) * 0.1 - xScale: 1 - (scaleFactor * 2) * 0.1 - } - ] - - HomeScreenPages { - id: homeScreenPages - folio: root.folio - maskManager: root.maskManager - homeScreen: root - - anchors.topMargin: root.topMargin - anchors.leftMargin: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Left ? 0 : root.leftMargin - anchors.rightMargin: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Right ? 0 : root.rightMargin - anchors.bottomMargin: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom ? 0 : root.bottomMargin - - // update the model with page dimensions - onWidthChanged: { - homeScreenState.pageWidth = homeScreenPages.width; - } - onHeightChanged: { - 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; - } - } + // we stop showing halfway through the animation + opacity: 1 - Math.max(homeScreenState.appDrawerOpenProgress, homeScreenState.searchWidgetOpenProgress, homeScreenState.folderOpenProgress) * 2 + visible: opacity > 0 // prevent handlers from picking up events transform: [ Scale { - // animation when settings opens - property real scaleFactor: 1 - folio.HomeScreenState.settingsOpenProgress * (1 - settingsModeHomeScreenScale) - origin.x: root.leftMargin + (root.width - root.rightMargin - root.leftMargin) / 2 - origin.y: root.height * settingsModeHomeScreenScale / 2 - xScale: scaleFactor - yScale: scaleFactor + property real scaleFactor: Math.max(homeScreenState.appDrawerOpenProgress, homeScreenState.searchWidgetOpenProgress) + origin.x: mainHomeScreen.width / 2 + origin.y: mainHomeScreen.height / 2 + yScale: 1 - (scaleFactor * 2) * 0.1 + xScale: 1 - (scaleFactor * 2) * 0.1 } ] - states: [ - State { - name: "bottom" - when: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom - AnchorChanges { - target: homeScreenPages - anchors.top: parent.top - anchors.bottom: favouritesBar.top - anchors.left: parent.left - anchors.right: parent.right - } - }, State { - name: "left" - when: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Left - AnchorChanges { - target: homeScreenPages - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.left: favouritesBar.right - anchors.right: parent.right - } - }, State { - name: "right" - when: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Right - AnchorChanges { - target: homeScreenPages - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: favouritesBar.left + HomeScreenPages { + id: homeScreenPages + folio: root.folio + maskManager: root.maskManager + homeScreen: root + + anchors.topMargin: root.topMargin + anchors.leftMargin: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Left ? 0 : root.leftMargin + anchors.rightMargin: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Right ? 0 : root.rightMargin + anchors.bottomMargin: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom ? 0 : root.bottomMargin + + // update the model with page dimensions + onWidthChanged: { + homeScreenState.pageWidth = homeScreenPages.width; + } + onHeightChanged: { + 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 + property real scaleFactor: 1 - folio.HomeScreenState.settingsOpenProgress * (1 - settingsModeHomeScreenScale) + origin.x: root.leftMargin + (root.width - root.rightMargin - root.leftMargin) / 2 + origin.y: root.height * settingsModeHomeScreenScale / 2 + xScale: scaleFactor + yScale: scaleFactor + } + ] + + states: [ + State { + name: "bottom" + when: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom + AnchorChanges { + target: homeScreenPages + anchors.top: parent.top + anchors.bottom: favouritesBar.top + anchors.left: parent.left + anchors.right: parent.right + } + }, State { + name: "left" + when: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Left + AnchorChanges { + target: homeScreenPages + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: favouritesBar.right + anchors.right: parent.right + } + }, State { + name: "right" + when: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Right + AnchorChanges { + target: homeScreenPages + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: favouritesBar.left + } + } + ] + } + + Rectangle { + id: favouritesBarScrim + color: Qt.rgba(255, 255, 255, 0.2) + + Component.onCompleted: maskManager.assignToMask(this) + + // don't show in settings mode + opacity: 1 - folio.HomeScreenState.settingsOpenProgress + visible: folio.FolioSettings.showFavouritesBarBackground + + anchors.top: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom ? favouritesBar.top : parent.top + anchors.bottom: parent.bottom + anchors.left: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Right ? favouritesBar.left : parent.left + anchors.right: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Left ? favouritesBar.right : parent.right + + // because of the scale animation, we need to extend the panel out a bit + anchors.topMargin: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom ? 0 : -Kirigami.Units.gridUnit * 5 + anchors.bottomMargin: -Kirigami.Units.gridUnit * 5 + anchors.leftMargin: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Right ? 0 : -Kirigami.Units.gridUnit * 5 + anchors.rightMargin: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Left ? 0 : -Kirigami.Units.gridUnit * 5 + } + + FavouritesBar { + id: favouritesBar + folio: root.folio + maskManager: root.maskManager + homeScreen: root + + // don't show in settings mode + opacity: 1 - folio.HomeScreenState.settingsOpenProgress + visible: opacity > 0 + + // one is ignored as anchors are set + height: Kirigami.Units.gridUnit * 6 + width: Kirigami.Units.gridUnit * 6 + + anchors.topMargin: root.topMargin + anchors.bottomMargin: root.bottomMargin + 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.favouritesBarLocation === 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.favouritesBarLocation === 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" + when: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom + AnchorChanges { + target: favouritesBar + anchors.top: undefined + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: parent.right + } + PropertyChanges { + target: favouritesBar + height: Kirigami.Units.gridUnit * 6 + } + }, State { + name: "left" + when: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Left + AnchorChanges { + target: favouritesBar + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: parent.left + anchors.right: undefined + } + PropertyChanges { + target: favouritesBar + width: Kirigami.Units.gridUnit * 6 + } + }, State { + name: "right" + when: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Right + AnchorChanges { + target: favouritesBar + anchors.top: parent.top + anchors.bottom: parent.bottom + anchors.left: undefined + anchors.right: parent.right + } + PropertyChanges { + target: favouritesBar + width: Kirigami.Units.gridUnit * 6 + } + } + ] + } + + Item { + id: pageIndicatorWrapper + property bool favouritesBarAtBottom: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom + + // don't show in settings mode + opacity: 1 - folio.HomeScreenState.settingsOpenProgress + + anchors.top: parent.top + anchors.left: parent.left + anchors.right: parent.right + anchors.bottom: favouritesBarAtBottom ? favouritesBar.top : parent.bottom + + anchors.topMargin: root.topMargin + anchors.leftMargin: root.leftMargin + anchors.rightMargin: root.rightMargin + anchors.bottomMargin: favouritesBarAtBottom ? 0 : (root.bottomMargin + Kirigami.Units.largeSpacing) + + // show page indicator if there are multiple pages + QQC2.PageIndicator { + visible: count > 1 + Kirigami.Theme.inherit: false + Kirigami.Theme.colorSet: Kirigami.Theme.Complementary + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + + currentIndex: folio.HomeScreenState.currentPage + count: folio.PageListModel.length + + TapHandler { + onTapped: folio.HomeScreenState.openAppDrawer() + } + } + + // show arrow to open app drawer when there is 1 page + Kirigami.Icon { + source: 'arrow-up' + Kirigami.Theme.inherit: false + Kirigami.Theme.colorSet: Kirigami.Theme.Complementary + + implicitHeight: Kirigami.Units.iconSizes.small + implicitWidth: Kirigami.Units.iconSizes.small + + visible: folio.PageListModel.length <= 1 + + anchors.horizontalCenter: parent.horizontalCenter + anchors.bottom: parent.bottom + anchors.bottomMargin: Kirigami.Units.smallSpacing + + TapHandler { + onTapped: folio.HomeScreenState.openAppDrawer() + } + } + } } - Rectangle { - id: favouritesBarScrim - color: Qt.rgba(255, 255, 255, 0.2) - - Component.onCompleted: maskManager.assignToMask(this) - - // don't show in settings mode - opacity: 1 - folio.HomeScreenState.settingsOpenProgress - visible: folio.FolioSettings.showFavouritesBarBackground - - anchors.top: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom ? favouritesBar.top : parent.top - anchors.bottom: parent.bottom - anchors.left: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Right ? favouritesBar.left : parent.left - anchors.right: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Left ? favouritesBar.right : parent.right - - // because of the scale animation, we need to extend the panel out a bit - anchors.topMargin: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom ? 0 : -Kirigami.Units.gridUnit * 5 - anchors.bottomMargin: -Kirigami.Units.gridUnit * 5 - anchors.leftMargin: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Right ? 0 : -Kirigami.Units.gridUnit * 5 - anchors.rightMargin: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Left ? 0 : -Kirigami.Units.gridUnit * 5 - } - - FavouritesBar { - id: favouritesBar + // folder view + FolderView { + id: folderView folio: root.folio - maskManager: root.maskManager + anchors.fill: parent + anchors.topMargin: root.topMargin + anchors.leftMargin: root.leftMargin + anchors.rightMargin: root.rightMargin + anchors.bottomMargin: root.bottomMargin + + homeScreen: root + opacity: homeScreenState.folderOpenProgress + transform: Translate { y: folderView.opacity > 0 ? 0 : folderView.height } + } + + // bottom app drawer + AppDrawer { + id: appDrawer + folio: root.folio + width: parent.width + height: parent.height + homeScreen: root - // don't show in settings mode - opacity: 1 - folio.HomeScreenState.settingsOpenProgress - visible: opacity > 0 + // we only start showing it halfway through + opacity: homeScreenState.appDrawerOpenProgress < 0.5 ? 0 : (homeScreenState.appDrawerOpenProgress - 0.5) * 2 - // one is ignored as anchors are set - height: Kirigami.Units.gridUnit * 6 - width: Kirigami.Units.gridUnit * 6 + // position for animation + property real animationY: (1 - homeScreenState.appDrawerOpenProgress) * (Kirigami.Units.gridUnit * 2) + + // move the app drawer out of the way if it is not visible + // NOTE: we do this instead of setting visible to false, because + // it doesn't mess with app drag and drop from the app drawer + y: (opacity > 0) ? animationY : parent.height + + headerHeight: Math.round(Kirigami.Units.gridUnit * 4) + headerItem: AppDrawerHeader { + id: appDrawerHeader + folio: root.folio + + onReleaseFocusRequested: appDrawer.forceActiveFocus() + } + + // Account for panels + topPadding: root.topMargin + bottomPadding: root.bottomMargin + leftPadding: root.leftMargin + rightPadding: root.rightMargin + + // Forward keyboard text to the search bar + Keys.onPressed: (event) => { + if (event.text.trim().length > 0) { + appDrawerHeader.addSearchText(event.text); + appDrawerHeader.forceActiveFocus(); + event.accepted = true; + } else if (event.key === Qt.Key_Left || event.key === Qt.Key_Right || event.key === Qt.Key_Up || event.key === Qt.Key_Down) { + appDrawerHeader.forceActiveFocus(); + event.accepted = true; + } + } + + Connections { + target: folio.HomeScreenState + + function onAppDrawerOpened() { + appDrawer.forceActiveFocus(); + } + + function onAppDrawerClosed() { + // reset app drawer position when closed + appDrawer.flickable.contentY = 0; + } + } + } + + // search component + MobileShell.KRunnerScreen { + id: searchWidget + anchors.fill: parent + + opacity: homeScreenState.searchWidgetOpenProgress + visible: opacity > 0 + transform: Translate { y: (1 - homeScreenState.searchWidgetOpenProgress) * (-Kirigami.Units.gridUnit * 2) } + + onVisibleChanged: { + if (!visible) { + // clear search bar when closed + searchWidget.clearField(); + } + } + + // focus the search bar if it opens + Connections { + target: folio.HomeScreenState + + function onSearchWidgetOpenProgressChanged() { + if (homeScreenState.searchWidgetOpenProgress === 1.0) { + searchWidget.requestFocus(); + } + } + } + + onRequestedClose: (triggeredByKeyEvent) => { + homeScreenState.closeSearchWidget(); + } anchors.topMargin: root.topMargin anchors.bottomMargin: root.bottomMargin 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.favouritesBarLocation === 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.favouritesBarLocation === 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" - when: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom - AnchorChanges { - target: favouritesBar - anchors.top: undefined - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: parent.right - } - PropertyChanges { - target: favouritesBar - height: Kirigami.Units.gridUnit * 6 - } - }, State { - name: "left" - when: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Left - AnchorChanges { - target: favouritesBar - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.left: parent.left - anchors.right: undefined - } - PropertyChanges { - target: favouritesBar - width: Kirigami.Units.gridUnit * 6 - } - }, State { - name: "right" - when: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Right - AnchorChanges { - target: favouritesBar - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.left: undefined - anchors.right: parent.right - } - PropertyChanges { - target: favouritesBar - width: Kirigami.Units.gridUnit * 6 - } - } - ] } - - Item { - id: pageIndicatorWrapper - property bool favouritesBarAtBottom: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom - - // don't show in settings mode - opacity: 1 - folio.HomeScreenState.settingsOpenProgress - - anchors.top: parent.top - anchors.left: parent.left - anchors.right: parent.right - anchors.bottom: favouritesBarAtBottom ? favouritesBar.top : parent.bottom - - anchors.topMargin: root.topMargin - anchors.leftMargin: root.leftMargin - anchors.rightMargin: root.rightMargin - anchors.bottomMargin: favouritesBarAtBottom ? 0 : (root.bottomMargin + Kirigami.Units.largeSpacing) - - // show page indicator if there are multiple pages - QQC2.PageIndicator { - visible: count > 1 - Kirigami.Theme.inherit: false - Kirigami.Theme.colorSet: Kirigami.Theme.Complementary - - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - - currentIndex: folio.HomeScreenState.currentPage - count: folio.PageListModel.length - - TapHandler { - onTapped: folio.HomeScreenState.openAppDrawer() - } - } - - // show arrow to open app drawer when there is 1 page - Kirigami.Icon { - source: 'arrow-up' - Kirigami.Theme.inherit: false - Kirigami.Theme.colorSet: Kirigami.Theme.Complementary - - implicitHeight: Kirigami.Units.iconSizes.small - implicitWidth: Kirigami.Units.iconSizes.small - - visible: folio.PageListModel.length <= 1 - - anchors.horizontalCenter: parent.horizontalCenter - anchors.bottom: parent.bottom - anchors.bottomMargin: Kirigami.Units.smallSpacing - - TapHandler { - onTapped: folio.HomeScreenState.openAppDrawer() - } - } - } - } - - // folder view - FolderView { - id: folderView - folio: root.folio - anchors.fill: parent - anchors.topMargin: root.topMargin - anchors.leftMargin: root.leftMargin - anchors.rightMargin: root.rightMargin - anchors.bottomMargin: root.bottomMargin - - homeScreen: root - opacity: homeScreenState.folderOpenProgress - transform: Translate { y: folderView.opacity > 0 ? 0 : folderView.height } - } - - // bottom app drawer - AppDrawer { - id: appDrawer - folio: root.folio - width: parent.width - height: parent.height - - homeScreen: root - - // we only start showing it halfway through - opacity: homeScreenState.appDrawerOpenProgress < 0.5 ? 0 : (homeScreenState.appDrawerOpenProgress - 0.5) * 2 - - // position for animation - property real animationY: (1 - homeScreenState.appDrawerOpenProgress) * (Kirigami.Units.gridUnit * 2) - - // move the app drawer out of the way if it is not visible - // NOTE: we do this instead of setting visible to false, because - // it doesn't mess with app drag and drop from the app drawer - y: (opacity > 0) ? animationY : parent.height - - headerHeight: Math.round(Kirigami.Units.gridUnit * 4) - headerItem: AppDrawerHeader { - id: appDrawerHeader - folio: root.folio - - onReleaseFocusRequested: appDrawer.forceActiveFocus() - } - - // Account for panels - topPadding: root.topMargin - bottomPadding: root.bottomMargin - leftPadding: root.leftMargin - rightPadding: root.rightMargin - - // Forward keyboard text to the search bar - Keys.onPressed: (event) => { - if (event.text.trim().length > 0) { - appDrawerHeader.addSearchText(event.text); - appDrawerHeader.forceActiveFocus(); - event.accepted = true; - } else if (event.key === Qt.Key_Left || event.key === Qt.Key_Right || event.key === Qt.Key_Up || event.key === Qt.Key_Down) { - appDrawerHeader.forceActiveFocus(); - event.accepted = true; - } - } - - Connections { - target: folio.HomeScreenState - - function onAppDrawerOpened() { - appDrawer.forceActiveFocus(); - } - - function onAppDrawerClosed() { - // reset app drawer position when closed - appDrawer.flickable.contentY = 0; - } - } - } - - // search component - MobileShell.KRunnerScreen { - id: searchWidget - anchors.fill: parent - - opacity: homeScreenState.searchWidgetOpenProgress - visible: opacity > 0 - transform: Translate { y: (1 - homeScreenState.searchWidgetOpenProgress) * (-Kirigami.Units.gridUnit * 2) } - - onVisibleChanged: { - if (!visible) { - // clear search bar when closed - searchWidget.clearField(); - } - } - - // focus the search bar if it opens - Connections { - target: folio.HomeScreenState - - function onSearchWidgetOpenProgressChanged() { - if (homeScreenState.searchWidgetOpenProgress === 1.0) { - searchWidget.requestFocus(); - } - } - } - - onRequestedClose: (triggeredByKeyEvent) => { - homeScreenState.closeSearchWidget(); - } - - anchors.topMargin: root.topMargin - anchors.bottomMargin: root.bottomMargin - anchors.leftMargin: root.leftMargin - anchors.rightMargin: root.rightMargin } } } diff --git a/containments/homescreens/folio/qml/HomeScreenPage.qml b/containments/homescreens/folio/qml/HomeScreenPage.qml index f72f719b..cf28b5d8 100644 --- a/containments/homescreens/folio/qml/HomeScreenPage.qml +++ b/containments/homescreens/folio/qml/HomeScreenPage.qml @@ -124,11 +124,11 @@ Item { property bool dropDelegateIsWidget: dropDelegate && dropDelegate.type === Folio.FolioDelegate.Widget // only show if it is an empty spot on this page - visible: folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate && - dropPosition.location === Folio.DelegateDragPosition.Pages && - dropPosition.page === root.pageNum && - !dropDelegateIsWidget && - folio.HomeScreenState.getPageDelegateAt(root.pageNum, dropPosition.pageRow, dropPosition.pageColumn) === null + visible: folio.HomeScreenState.isDraggingDelegate && + dropPosition.location === Folio.DelegateDragPosition.Pages && + dropPosition.page === root.pageNum && + !dropDelegateIsWidget && + folio.HomeScreenState.getPageDelegateAt(root.pageNum, dropPosition.pageRow, dropPosition.pageColumn) === null x: dropPosition.pageColumn * folio.HomeScreenState.pageCellWidth y: dropPosition.pageRow * folio.HomeScreenState.pageCellHeight @@ -145,7 +145,7 @@ Item { property bool dropDelegateIsWidget: dropDelegate && dropDelegate.type === Folio.FolioDelegate.Widget // only show if the widget can be placed here - visible: folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate && + visible: folio.HomeScreenState.isDraggingDelegate && dropPosition.location === Folio.DelegateDragPosition.Pages && dropPosition.page === root.pageNum && dropDelegateIsWidget && @@ -180,7 +180,7 @@ Item { dragState.candidateDropPosition.pageRow === delegate.pageDelegate.row && dragState.candidateDropPosition.pageColumn === delegate.pageDelegate.column - property bool isAppHoveredOver: folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate && + property bool isAppHoveredOver: folio.HomeScreenState.isDraggingDelegate && dragState.dropDelegate && dragState.dropDelegate.type === Folio.FolioDelegate.Application && isDropPositionThis @@ -274,7 +274,7 @@ Item { name: folio.FolioSettings.showPagesAppLabels ? delegate.pageDelegate.application.name : "" application: delegate.pageDelegate.application turnToFolder: delegate.isAppHoveredOver - turnToFolderAnimEnabled: folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate + turnToFolderAnimEnabled: folio.HomeScreenState.isDraggingDelegate implicitWidth: folio.HomeScreenState.pageCellWidth implicitHeight: folio.HomeScreenState.pageCellHeight @@ -323,10 +323,8 @@ Item { Connections { target: folio.HomeScreenState - function onSwipeStateChanged() { - if (folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate) { - contextMenu.close(); - } + function onDelegateDragStarted() { + contextMenu.close(); } } @@ -409,10 +407,8 @@ Item { Connections { target: folio.HomeScreenState - function onSwipeStateChanged() { - if (folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate) { - contextMenu.close(); - } + function onDelegateDragStarted() { + contextMenu.close(); } } diff --git a/containments/homescreens/folio/qml/WidgetDragItem.qml b/containments/homescreens/folio/qml/WidgetDragItem.qml index e278e07d..a65d2f50 100644 --- a/containments/homescreens/folio/qml/WidgetDragItem.qml +++ b/containments/homescreens/folio/qml/WidgetDragItem.qml @@ -16,6 +16,8 @@ import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio import './delegate' import './private' +// Placeholder item that the user sees as they drag widgets around. +// See DelegateDragItem for the equivalent for app delegates. Item { id: root property Folio.HomeScreen folio @@ -25,7 +27,9 @@ Item { property Folio.FolioWidget widget - readonly property bool isWidgetDelegate: folio.HomeScreenState.dragState.dropDelegate && folio.HomeScreenState.dragState.dropDelegate.type === Folio.FolioDelegate.Widget + readonly property bool isWidgetDelegate: folio.HomeScreenState.dragState.dropDelegate + && folio.HomeScreenState.dragState.dropDelegate.type === Folio.FolioDelegate.Widget + && folio.HomeScreenState.dragState.dropDelegate.widget.visualApplet readonly property bool dropAnimationRunning: dragXAnim.running || dragYAnim.running visible: false @@ -74,13 +78,12 @@ Item { id: stateWatcher target: folio.HomeScreenState - function onSwipeStateChanged() { - if (folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate && - folio.HomeScreenState.dragState.dropDelegate && - folio.HomeScreenState.dragState.dropDelegate.type === Folio.FolioDelegate.Widget) { - - root.startDrag(folio.HomeScreenState.dragState.dropDelegate.widget); + function onDelegateDragStarted() { + if (!root.isWidgetDelegate) { + return; } + + root.startDrag(folio.HomeScreenState.dragState.dropDelegate.widget); } } diff --git a/containments/homescreens/folio/qml/delegate/WidgetDelegateConfig.qml b/containments/homescreens/folio/qml/delegate/WidgetDelegateConfig.qml index 1f28f5c8..8d1dc308 100644 --- a/containments/homescreens/folio/qml/delegate/WidgetDelegateConfig.qml +++ b/containments/homescreens/folio/qml/delegate/WidgetDelegateConfig.qml @@ -91,11 +91,9 @@ Item { target: folio.HomeScreenState // if we are starting drag-and-drop, close the menu immediately - function onSwipeStateChanged() { - if (folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate) { - configOverlay.animClose(); - root.closed(); - } + function onDelegateDragStarted() { + configOverlay.animClose(); + root.closed(); } } diff --git a/containments/homescreens/folio/qml/settings/AppletListDelegate.qml b/containments/homescreens/folio/qml/settings/AppletListDelegate.qml new file mode 100644 index 00000000..6739f0ba --- /dev/null +++ b/containments/homescreens/folio/qml/settings/AppletListDelegate.qml @@ -0,0 +1,136 @@ +// SPDX-FileCopyrightText: 2023-2025 Devin Lin +// SPDX-License-Identifier: LGPL-2.0-or-later + +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls as QQC2 + +import org.kde.kirigami as Kirigami +import org.kde.plasma.plasmoid +import org.kde.plasma.extras 2.0 as PlasmaExtras +import org.kde.plasma.private.shell 2.0 +import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio +import org.kde.plasma.components 3.0 as PC3 +import org.kde.plasma.private.mobileshell as MobileShell + +Item { + id: delegate + property Folio.HomeScreen folio + + readonly property string pluginName: model.pluginName + + property real zoomScale: (model.isSupported && mouseArea.pressed) ? 0.8 : 1 + transform: Scale { + origin.x: delegate.width / 2; + origin.y: delegate.height / 2; + xScale: delegate.zoomScale + yScale: delegate.zoomScale + } + + Behavior on zoomScale { NumberAnimation { duration: 80 } } + + // Placeholder item used for implement drag & drop + Item { + id: draggable + anchors.fill: parent + + Drag.hotSpot.x: iconWidget.width / 2 + Drag.hotSpot.y: iconWidget.height / 2 + Drag.mimeData: { "text/x-plasmoidservicename": pluginName } + Drag.dragType: Drag.Automatic + Drag.onDragFinished: { + root.requestClose(); + } + } + + MobileShell.HapticsEffect { + id: haptics + } + + MouseArea { + id: mouseArea + anchors.fill: parent + + cursorShape: model.isSupported ? Qt.PointingHandCursor : Qt.ArrowCursor + hoverEnabled: true + + onPressAndHold: { + if (!model.isSupported) { + return + } + + haptics.buttonVibrate(); + iconWidget.grabToImage(function(result) { + // Start drag & drop + folio.HomeScreenState.closeSettingsView(); + draggable.Drag.imageSource = result.url; + draggable.Drag.active = true; + root.requestClose(); + }) + } + } + + Rectangle { + id: background + color: Qt.rgba(255, 255, 255, 0.3) + visible: model.isSupported && mouseArea.containsMouse + radius: Kirigami.Units.cornerRadius + anchors.fill: parent + } + + ColumnLayout { + anchors.fill: parent + anchors.margins: Kirigami.Units.largeSpacing + + Item { + id: iconWidget + Layout.fillWidth: true + Layout.maximumWidth: delegate.width + Layout.preferredHeight: Kirigami.Units.iconSizes.large + Layout.preferredWidth: Kirigami.Units.iconSizes.large + Layout.alignment: Qt.AlignBottom + + Kirigami.Icon { + anchors.centerIn: parent + source: model.decoration + visible: model.screenshot == "" + implicitWidth: Kirigami.Units.iconSizes.large + implicitHeight: Kirigami.Units.iconSizes.large + } + Image { + anchors.centerIn: parent + fillMode: Image.PreserveAspectFit + source: model.screenshot + width: Kirigami.Units.iconSizes.large + height: Kirigami.Units.iconSizes.large + } + } + + PC3.Label { + id: heading + Layout.fillWidth: true + Layout.maximumWidth: delegate.width + Layout.alignment: Qt.AlignCenter + text: model.name + elide: Text.ElideRight + wrapMode: Text.Wrap + maximumLineCount: 2 + horizontalAlignment: Text.AlignHCenter + font.weight: Font.Bold + } + + PC3.Label { + Layout.fillWidth: true + Layout.maximumWidth: delegate.width + Layout.alignment: Qt.AlignTop + // otherwise causes binding loop due to the way the Plasma sets the height + height: implicitHeight + text: model.isSupported ? model.description : model.unsupportedMessage + font.pointSize: Kirigami.Theme.smallFont.pointSize + wrapMode: Text.Wrap + elide: Text.ElideRight + maximumLineCount: heading.lineCount === 1 ? 3 : 2 + horizontalAlignment: Text.AlignHCenter + } + } +} diff --git a/containments/homescreens/folio/qml/settings/AppletListViewer.qml b/containments/homescreens/folio/qml/settings/AppletListViewer.qml index 058225bb..feee1fb4 100644 --- a/containments/homescreens/folio/qml/settings/AppletListViewer.qml +++ b/containments/homescreens/folio/qml/settings/AppletListViewer.qml @@ -19,231 +19,123 @@ import org.kde.plasma.private.mobileshell as MobileShell import '../delegate' import '../private' -MouseArea { +Loader { id: root property Folio.HomeScreen folio property var homeScreen - signal requestClose() - onClicked: root.requestClose() + active: false + + function requestClose() { + active = false; + } Kirigami.Theme.inherit: false Kirigami.Theme.colorSet: Kirigami.Theme.Complementary - MobileShell.HapticsEffect { - id: haptics - } - - Rectangle { - anchors.fill: parent - color: Qt.rgba(0, 0, 0, 0.7) - } - - - PlasmaExtras.ModelContextMenu { - id: getWidgetsDialog - visualParent: getWidgetsButton - placement: PlasmaExtras.Menu.TopPosedLeftAlignedPopup - // model set on first invocation - onClicked: model.trigger() - } - - RowLayout { - id: header - spacing: Kirigami.Units.largeSpacing - anchors.left: parent.left - anchors.leftMargin: Kirigami.Units.gridUnit - anchors.top: parent.top - anchors.topMargin: Kirigami.Units.gridUnit * 3 + root.homeScreen.topMargin - anchors.right: parent.right - anchors.rightMargin: Kirigami.Units.gridUnit - - PC3.ToolButton { - Layout.alignment: Qt.AlignVCenter - icon.name: 'go-previous' - implicitWidth: Kirigami.Units.gridUnit * 2 - implicitHeight: Kirigami.Units.gridUnit * 2 - padding: Kirigami.Units.smallSpacing - onClicked: root.requestClose() - } - - PC3.Label { - Kirigami.Theme.inherit: false - Kirigami.Theme.colorSet: Kirigami.Theme.Complementary - text: i18n("Widgets") - wrapMode: Text.Wrap - font.weight: Font.Bold - font.pointSize: Kirigami.Theme.defaultFont.pointSize * 1.5 - Layout.fillWidth: true - } - - PC3.ToolButton { - id: getWidgetsButton - icon.name: "get-hot-new-stuff" - text: i18ndc("plasma_shell_org.kde.plasma.mobile", "@action:button The word 'new' refers to widgets", "Get New Widgets…") - Accessible.name: i18ndc("plasma_shell_org.kde.plasma.mobile", "@action:button", "Get New Widgets…") - - onClicked: { - getWidgetsDialog.model = widgetExplorer.widgetsMenuActions - getWidgetsDialog.openRelative() - } - } - } - - GridView { - id: gridView - clip: true - reuseItems: true - - opacity: 0 // we display with the opacity gradient below - - anchors.top: header.bottom - anchors.topMargin: Kirigami.Units.gridUnit - anchors.left: parent.left - anchors.leftMargin: root.homeScreen.leftMargin - anchors.right: parent.right - anchors.rightMargin: root.homeScreen.rightMargin - anchors.bottom: parent.bottom - anchors.bottomMargin: root.homeScreen.bottomMargin - - model: widgetExplorer.widgetsModel - - readonly property real maxCellWidth: Kirigami.Units.gridUnit * 20 - readonly property real intendedCellWidth: Kirigami.Units.gridUnit * 8 - readonly property int columns: Math.min(5, (width - leftMargin - rightMargin) / intendedCellWidth) - - cellWidth: (width - leftMargin - rightMargin) / columns - cellHeight: cellWidth + Kirigami.Units.gridUnit * 3 - - readonly property real horizontalMargin: Math.round(width * 0.05) - leftMargin: horizontalMargin - rightMargin: horizontalMargin - - MouseArea { - z: -1 + sourceComponent: Item { + Rectangle { anchors.fill: parent - onClicked: root.requestClose() + color: Qt.rgba(0, 0, 0, 0.7) } - delegate: MouseArea { - id: delegate - width: gridView.cellWidth - height: gridView.cellHeight + PlasmaExtras.ModelContextMenu { + id: getWidgetsDialog + visualParent: getWidgetsButton + placement: PlasmaExtras.Menu.TopPosedLeftAlignedPopup + // model set on first invocation + onClicked: model.trigger() + } - cursorShape: Qt.PointingHandCursor - hoverEnabled: true + RowLayout { + id: header + spacing: Kirigami.Units.largeSpacing + anchors.left: parent.left + anchors.leftMargin: Kirigami.Units.gridUnit + anchors.top: parent.top + anchors.topMargin: Kirigami.Units.gridUnit * 3 + root.homeScreen.topMargin + anchors.right: parent.right + anchors.rightMargin: Kirigami.Units.gridUnit - property real zoomScale: pressed ? 0.8 : 1 - transform: Scale { - origin.x: delegate.width / 2; - origin.y: delegate.height / 2; - xScale: delegate.zoomScale - yScale: delegate.zoomScale + PC3.ToolButton { + Layout.alignment: Qt.AlignVCenter + icon.name: 'go-previous' + implicitWidth: Kirigami.Units.gridUnit * 2 + implicitHeight: Kirigami.Units.gridUnit * 2 + padding: Kirigami.Units.smallSpacing + onClicked: root.requestClose() } - Behavior on zoomScale { NumberAnimation { duration: 80 } } - - readonly property string pluginName: model.pluginName - - onPressAndHold: { - if (!model.isSupported) { - return - } - - root.requestClose(); - folio.HomeScreenState.closeSettingsView(); - haptics.buttonVibrate(); - - let mappedCoords = root.homeScreen.prepareStartDelegateDrag(null, delegate, true); - const widthOffset = folio.HomeScreenState.pageCellWidth / 2; - const heightOffset = folio.HomeScreenState.pageCellHeight / 2; - - folio.HomeScreenState.startDelegateWidgetListDrag( - mappedCoords.x + mouseX - widthOffset, - mappedCoords.y + mouseY - heightOffset, - widthOffset, - heightOffset, - pluginName - ); + PC3.Label { + Kirigami.Theme.inherit: false + Kirigami.Theme.colorSet: Kirigami.Theme.Complementary + text: i18n("Widgets") + wrapMode: Text.Wrap + font.weight: Font.Bold + font.pointSize: Kirigami.Theme.defaultFont.pointSize * 1.5 + Layout.fillWidth: true } - Rectangle { - id: background - color: Qt.rgba(255, 255, 255, 0.3) - visible: delegate.containsMouse - radius: Kirigami.Units.cornerRadius - anchors.fill: parent - } + PC3.ToolButton { + id: getWidgetsButton + icon.name: "get-hot-new-stuff" + text: i18ndc("plasma_shell_org.kde.plasma.mobile", "@action:button The word 'new' refers to widgets", "Get New Widgets…") + Accessible.name: i18ndc("plasma_shell_org.kde.plasma.mobile", "@action:button", "Get New Widgets…") - ColumnLayout { - anchors.fill: parent - anchors.margins: Kirigami.Units.largeSpacing - - Item { - id: iconWidget - Layout.fillWidth: true - Layout.maximumWidth: delegate.width - Layout.preferredHeight: Kirigami.Units.iconSizes.large - Layout.preferredWidth: Kirigami.Units.iconSizes.large - Layout.alignment: Qt.AlignBottom - - Kirigami.Icon { - anchors.centerIn: parent - source: model.decoration - visible: model.screenshot == "" - implicitWidth: Kirigami.Units.iconSizes.large - implicitHeight: Kirigami.Units.iconSizes.large - } - Image { - anchors.centerIn: parent - fillMode: Image.PreserveAspectFit - source: model.screenshot - width: Kirigami.Units.iconSizes.large - height: Kirigami.Units.iconSizes.large - } - } - - PC3.Label { - id: heading - Layout.fillWidth: true - Layout.maximumWidth: delegate.width - Layout.alignment: Qt.AlignCenter - text: model.name - elide: Text.ElideRight - wrapMode: Text.Wrap - maximumLineCount: 2 - horizontalAlignment: Text.AlignHCenter - font.weight: Font.Bold - } - - PC3.Label { - Layout.fillWidth: true - Layout.maximumWidth: delegate.width - Layout.alignment: Qt.AlignTop - // otherwise causes binding loop due to the way the Plasma sets the height - height: implicitHeight - text: model.isSupported ? model.description : model.unsupportedMessage - font.pointSize: Kirigami.Theme.smallFont.pointSize - wrapMode: Text.Wrap - elide: Text.ElideRight - maximumLineCount: heading.lineCount === 1 ? 3 : 2 - horizontalAlignment: Text.AlignHCenter + onClicked: { + getWidgetsDialog.model = widgetExplorer.widgetsMenuActions + getWidgetsDialog.openRelative() } } } - } - // opacity gradient at grid edges - MobileShell.FlickableOpacityGradient { - anchors.fill: gridView - flickable: gridView - } + GridView { + id: gridView + clip: true + reuseItems: true - WidgetExplorer { - id: widgetExplorer - containment: Plasmoid + opacity: 0 // we display with the opacity gradient below - onShouldClose: root.requestClose() + anchors.top: header.bottom + anchors.topMargin: Kirigami.Units.gridUnit + anchors.left: parent.left + anchors.leftMargin: root.homeScreen.leftMargin + anchors.right: parent.right + anchors.rightMargin: root.homeScreen.rightMargin + anchors.bottom: parent.bottom + anchors.bottomMargin: root.homeScreen.bottomMargin + + model: widgetExplorer.widgetsModel + + readonly property real intendedCellWidth: Kirigami.Units.gridUnit * 8 + readonly property int columns: Math.min(5, (width - leftMargin - rightMargin) / intendedCellWidth) + + cellWidth: (width - leftMargin - rightMargin) / columns + cellHeight: cellWidth + Kirigami.Units.gridUnit * 3 + + readonly property real horizontalMargin: Math.round(width * 0.05) + leftMargin: horizontalMargin + rightMargin: horizontalMargin + + delegate: AppletListDelegate { + folio: root.folio + width: gridView.cellWidth + height: gridView.cellHeight + } + } + + // opacity gradient at grid edges + MobileShell.FlickableOpacityGradient { + anchors.fill: gridView + flickable: gridView + } + + WidgetExplorer { + id: widgetExplorer + containment: Plasmoid + + onShouldClose: root.requestClose() + } } } diff --git a/containments/homescreens/folio/qml/settings/SettingsComponent.qml b/containments/homescreens/folio/qml/settings/SettingsComponent.qml index 08cf57d2..7eb34701 100644 --- a/containments/homescreens/folio/qml/settings/SettingsComponent.qml +++ b/containments/homescreens/folio/qml/settings/SettingsComponent.qml @@ -21,23 +21,12 @@ Item { property var homeScreen property real settingsModeHomeScreenScale - readonly property bool homeScreenInteractive: !appletListViewerLoader.active + readonly property bool homeScreenInteractive: !appletListViewer.active property real bottomMargin: 0 property real leftMargin: 0 property real rightMargin: 0 - Connections { - target: folio.HomeScreenState - - // Close applet viewer when settings view closes - function onViewStateChanged() { - if (folio.HomeScreenState.viewState !== Folio.HomeScreenState.SettingsView) { - appletListViewerLoader.requestClose(); - } - } - } - MouseArea { id: closeSettings @@ -84,7 +73,7 @@ Item { iconName: 'widget-alternatives' textLabel: i18n("Widgets") onClicked: { - appletListViewerLoader.active = true; + appletListViewer.active = true; } } } @@ -157,49 +146,13 @@ Item { } ] - Loader { - id: appletListViewerLoader - asynchronous: true - active: false - - signal requestClose() - onRequestClose: item?.requestClose() + AppletListViewer { + id: appletListViewer width: parent.width height: parent.height - opacity: status == Loader.Ready ? 1 : 0 - // move the settings out of the way if it is not visible - // NOTE: we do this instead of setting visible to false, because - // it doesn't mess with widget drag and drop - y: (opacity > 0) ? 0 : parent.height - - Behavior on opacity { - NumberAnimation { duration: Kirigami.Units.shortDuration } - } - - sourceComponent: AppletListViewer { - id: appletListViewer - folio: root.folio - - width: parent.width - height: parent.height - - onRequestClose: parent.active = false - - homeScreen: root.homeScreen - } - } - - PC3.BusyIndicator { - id: appletListLoadingIndicator - anchors.centerIn: parent - visible: appletListViewerLoader.status === Loader.Loading - - implicitHeight: Kirigami.Units.iconSizes.huge - implicitWidth: Kirigami.Units.iconSizes.huge - - Kirigami.Theme.inherit: false - Kirigami.Theme.colorSet: Kirigami.Theme.Complementary + folio: root.folio + homeScreen: root.homeScreen } }