mirror of
https://invent.kde.org/marcoa/shift-shell.git
synced 2026-04-26 14:23:09 +00:00
folio: Refactor and implement support for proper drag & drop
This refactors the homescreen state object to isolate drag & drop from swipe states, allowing for using proper system-level drag & drop for delegate movement. This then ports the new applet list to use it.
This commit is contained in:
parent
1250180c45
commit
4c76f55b5c
16 changed files with 901 additions and 787 deletions
|
|
@ -9,6 +9,7 @@ plasma_add_applet(org.kde.plasma.mobile.homescreen.folio
|
||||||
qml/AppDrawerGrid.qml
|
qml/AppDrawerGrid.qml
|
||||||
qml/AppDrawerHeader.qml
|
qml/AppDrawerHeader.qml
|
||||||
qml/DelegateDragItem.qml
|
qml/DelegateDragItem.qml
|
||||||
|
qml/DelegateDropArea.qml
|
||||||
qml/FavouritesBar.qml
|
qml/FavouritesBar.qml
|
||||||
qml/FolderView.qml
|
qml/FolderView.qml
|
||||||
qml/FolderViewTitle.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
|
ecm_target_qml_sources(org.kde.plasma.mobile.homescreen.folio SOURCES
|
||||||
|
qml/settings/AppletListDelegate.qml
|
||||||
qml/settings/AppletListViewer.qml
|
qml/settings/AppletListViewer.qml
|
||||||
qml/settings/SettingsButton.qml
|
qml/settings/SettingsButton.qml
|
||||||
qml/settings/SettingsComponent.qml
|
qml/settings/SettingsComponent.qml
|
||||||
|
|
|
||||||
|
|
@ -175,12 +175,9 @@ DragState::DragState(HomeScreenState *state, HomeScreen *parent)
|
||||||
connect(m_state, &HomeScreenState::delegateDragFromFavouritesStarted, this, &DragState::onDelegateDragFromFavouritesStarted);
|
connect(m_state, &HomeScreenState::delegateDragFromFavouritesStarted, this, &DragState::onDelegateDragFromFavouritesStarted);
|
||||||
connect(m_state, &HomeScreenState::delegateDragFromFolderStarted, this, &DragState::onDelegateDragFromFolderStarted);
|
connect(m_state, &HomeScreenState::delegateDragFromFolderStarted, this, &DragState::onDelegateDragFromFolderStarted);
|
||||||
connect(m_state, &HomeScreenState::delegateDragFromWidgetListStarted, this, &DragState::onDelegateDragFromWidgetListStarted);
|
connect(m_state, &HomeScreenState::delegateDragFromWidgetListStarted, this, &DragState::onDelegateDragFromWidgetListStarted);
|
||||||
connect(m_state, &HomeScreenState::swipeStateChanged, this, [this]() {
|
connect(m_state, &HomeScreenState::delegateDragStarted, this, &DragState::onDelegateDraggingStarted);
|
||||||
if (m_state->swipeState() == HomeScreenState::DraggingDelegate) {
|
connect(m_state, &HomeScreenState::delegateDragDropped, this, &DragState::onDelegateDropped);
|
||||||
onDelegateDraggingStarted();
|
connect(m_state, &HomeScreenState::delegateDragCancelled, this, &DragState::onDelegateDraggingCancelled);
|
||||||
}
|
|
||||||
});
|
|
||||||
connect(m_state, &HomeScreenState::delegateDragEnded, this, &DragState::onDelegateDropped);
|
|
||||||
|
|
||||||
connect(m_state, &HomeScreenState::pageNumChanged, this, [this]() {
|
connect(m_state, &HomeScreenState::pageNumChanged, this, [this]() {
|
||||||
m_candidateDropPosition->setPageRow(m_state->currentPage());
|
m_candidateDropPosition->setPageRow(m_state->currentPage());
|
||||||
|
|
@ -546,19 +543,8 @@ void DragState::onDelegateDropped()
|
||||||
// add dropped delegate
|
// add dropped delegate
|
||||||
bool success = createDropPositionDelegate();
|
bool success = createDropPositionDelegate();
|
||||||
|
|
||||||
// delete empty pages at the end if they exist
|
// Cleanup timers and state
|
||||||
// (it can be created if user drags app to new page, but doesn't place it there)
|
dragStopCleanup();
|
||||||
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();
|
|
||||||
|
|
||||||
// emit corresponding signal
|
// emit corresponding signal
|
||||||
// -> if we couldn't drop a new delegate at a spot, emit newDelegateDropAbandoned()
|
// -> 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()
|
void DragState::onLeaveCurrentFolder()
|
||||||
{
|
{
|
||||||
if (!m_state) {
|
if (!m_state) {
|
||||||
|
|
@ -589,7 +610,7 @@ void DragState::onLeaveCurrentFolder()
|
||||||
|
|
||||||
void DragState::onChangePageTimerFinished()
|
void DragState::onChangePageTimerFinished()
|
||||||
{
|
{
|
||||||
if (!m_state || (m_state->swipeState() != HomeScreenState::DraggingDelegate)) {
|
if (!m_state || !m_state->isDraggingDelegate()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -624,7 +645,7 @@ void DragState::onChangePageTimerFinished()
|
||||||
|
|
||||||
void DragState::onOpenFolderTimerFinished()
|
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)) {
|
|| (m_candidateDropPosition->location() != DelegateDragPosition::Pages && m_candidateDropPosition->location() != DelegateDragPosition::Favourites)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -672,7 +693,7 @@ void DragState::onOpenFolderTimerFinished()
|
||||||
|
|
||||||
void DragState::onLeaveFolderTimerFinished()
|
void DragState::onLeaveFolderTimerFinished()
|
||||||
{
|
{
|
||||||
if (!m_state || (m_state->swipeState() != HomeScreenState::DraggingDelegate) || !m_state->currentFolder()) {
|
if (!m_state || !m_state->isDraggingDelegate() || !m_state->currentFolder()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -684,7 +705,7 @@ void DragState::onLeaveFolderTimerFinished()
|
||||||
|
|
||||||
void DragState::onChangeFolderPageTimerFinished()
|
void DragState::onChangeFolderPageTimerFinished()
|
||||||
{
|
{
|
||||||
if (!m_state || (m_state->swipeState() != HomeScreenState::DraggingDelegate) || !m_state->currentFolder()) {
|
if (!m_state || !m_state->isDraggingDelegate() || !m_state->currentFolder()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -720,7 +741,7 @@ void DragState::onChangeFolderPageTimerFinished()
|
||||||
|
|
||||||
void DragState::onFolderInsertBetweenTimerFinished()
|
void DragState::onFolderInsertBetweenTimerFinished()
|
||||||
{
|
{
|
||||||
if (!m_state || (m_state->swipeState() != HomeScreenState::DraggingDelegate) || !m_state->currentFolder()) {
|
if (!m_state || !m_state->isDraggingDelegate() || !m_state->currentFolder()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -118,6 +118,7 @@ private Q_SLOTS:
|
||||||
void onDelegateDragFromFolderStarted(FolioApplicationFolder *folder, int position);
|
void onDelegateDragFromFolderStarted(FolioApplicationFolder *folder, int position);
|
||||||
void onDelegateDragFromWidgetListStarted(QString appletPluginId);
|
void onDelegateDragFromWidgetListStarted(QString appletPluginId);
|
||||||
void onDelegateDropped();
|
void onDelegateDropped();
|
||||||
|
void onDelegateDraggingCancelled();
|
||||||
|
|
||||||
void onLeaveCurrentFolder();
|
void onLeaveCurrentFolder();
|
||||||
|
|
||||||
|
|
@ -129,6 +130,9 @@ private Q_SLOTS:
|
||||||
void onFavouritesInsertBetweenTimerFinished();
|
void onFavouritesInsertBetweenTimerFinished();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// Cleanup after a drag event (stop timers etc.)
|
||||||
|
void dragStopCleanup();
|
||||||
|
|
||||||
// deletes the delegate at m_startPosition
|
// deletes the delegate at m_startPosition
|
||||||
void deleteStartPositionDelegate();
|
void deleteStartPositionDelegate();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -195,6 +195,7 @@ void HomeScreenState::setSwipeState(SwipeState swipeState)
|
||||||
if (swipeState != m_swipeState) {
|
if (swipeState != m_swipeState) {
|
||||||
m_swipeState = swipeState;
|
m_swipeState = swipeState;
|
||||||
Q_EMIT swipeStateChanged();
|
Q_EMIT swipeStateChanged();
|
||||||
|
Q_EMIT isDraggingDelegateChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -692,6 +693,11 @@ int HomeScreenState::currentFolderPage()
|
||||||
return m_folderPageNum;
|
return m_folderPageNum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool HomeScreenState::isDraggingDelegate()
|
||||||
|
{
|
||||||
|
return m_dragDropActive || m_swipeState == SwipeState::DraggingDelegate;
|
||||||
|
}
|
||||||
|
|
||||||
FolioDelegate *HomeScreenState::getPageDelegateAt(int page, int row, int column)
|
FolioDelegate *HomeScreenState::getPageDelegateAt(int page, int row, int column)
|
||||||
{
|
{
|
||||||
PageModel *pageModel = m_homeScreen->pageListModel()->getPage(page);
|
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!
|
// 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
|
// NOTE: this has to happen after delegateDragFromAppDrawerStarted, because slots for that expect SwipeState::AwaitingDraggingDelegate
|
||||||
setSwipeState(SwipeState::DraggingDelegate);
|
setSwipeState(SwipeState::DraggingDelegate);
|
||||||
|
Q_EMIT delegateDragStarted();
|
||||||
}
|
}
|
||||||
|
|
||||||
void HomeScreenState::startDelegateFolderDrag(qreal startX,
|
void HomeScreenState::startDelegateFolderDrag(qreal startX,
|
||||||
|
|
@ -922,10 +929,6 @@ void HomeScreenState::startDelegateWidgetListDrag(qreal startX, qreal startY, qr
|
||||||
{
|
{
|
||||||
startDelegateDrag(startX, startY, pointerOffsetX, pointerOffsetY);
|
startDelegateDrag(startX, startY, pointerOffsetX, pointerOffsetY);
|
||||||
Q_EMIT delegateDragFromWidgetListStarted(appletPluginId);
|
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()
|
void HomeScreenState::cancelDelegateDrag()
|
||||||
|
|
@ -991,7 +994,7 @@ void HomeScreenState::swipeEnded()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case SwipeState::DraggingDelegate:
|
case SwipeState::DraggingDelegate:
|
||||||
Q_EMIT delegateDragEnded();
|
Q_EMIT delegateDragDropped();
|
||||||
break;
|
break;
|
||||||
case SwipeState::AwaitingDraggingDelegate:
|
case SwipeState::AwaitingDraggingDelegate:
|
||||||
case SwipeState::DeterminingSwipeType:
|
case SwipeState::DeterminingSwipeType:
|
||||||
|
|
@ -1003,6 +1006,45 @@ void HomeScreenState::swipeEnded()
|
||||||
setSwipeState(SwipeState::None);
|
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()
|
void HomeScreenState::swipeCancelled()
|
||||||
{
|
{
|
||||||
setSwipeState(SwipeState::None);
|
setSwipeState(SwipeState::None);
|
||||||
|
|
@ -1038,6 +1080,7 @@ void HomeScreenState::swipeMoved(qreal totalDeltaX, qreal totalDeltaY, qreal del
|
||||||
break;
|
break;
|
||||||
case SwipeState::AwaitingDraggingDelegate:
|
case SwipeState::AwaitingDraggingDelegate:
|
||||||
setSwipeState(SwipeState::DraggingDelegate);
|
setSwipeState(SwipeState::DraggingDelegate);
|
||||||
|
Q_EMIT delegateDragStarted();
|
||||||
break;
|
break;
|
||||||
case SwipeState::DraggingDelegate:
|
case SwipeState::DraggingDelegate:
|
||||||
setDelegateDragX(m_delegateDragX + deltaX);
|
setDelegateDragX(m_delegateDragX + deltaX);
|
||||||
|
|
|
||||||
|
|
@ -80,6 +80,8 @@ class HomeScreenState : public QObject
|
||||||
Q_PROPERTY(int currentPage READ currentPage NOTIFY pageNumChanged)
|
Q_PROPERTY(int currentPage READ currentPage NOTIFY pageNumChanged)
|
||||||
Q_PROPERTY(int currentFolderPage READ currentFolderPage NOTIFY folderPageNumChanged)
|
Q_PROPERTY(int currentFolderPage READ currentFolderPage NOTIFY folderPageNumChanged)
|
||||||
|
|
||||||
|
Q_PROPERTY(bool isDraggingDelegate READ isDraggingDelegate NOTIFY isDraggingDelegateChanged)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum SwipeState {
|
enum SwipeState {
|
||||||
None,
|
None,
|
||||||
|
|
@ -258,6 +260,9 @@ public:
|
||||||
|
|
||||||
int currentFolderPage();
|
int currentFolderPage();
|
||||||
|
|
||||||
|
// Whether something is being dragged (either from SwipeArea or Drag & Drop)
|
||||||
|
bool isDraggingDelegate();
|
||||||
|
|
||||||
// QML helpers
|
// QML helpers
|
||||||
Q_INVOKABLE FolioDelegate *getPageDelegateAt(int page, int row, int column);
|
Q_INVOKABLE FolioDelegate *getPageDelegateAt(int page, int row, int column);
|
||||||
Q_INVOKABLE FolioDelegate *getFavouritesDelegateAt(int position);
|
Q_INVOKABLE FolioDelegate *getFavouritesDelegateAt(int position);
|
||||||
|
|
@ -305,7 +310,9 @@ Q_SIGNALS:
|
||||||
void searchWidgetYChanged();
|
void searchWidgetYChanged();
|
||||||
void delegateDragXChanged();
|
void delegateDragXChanged();
|
||||||
void delegateDragYChanged();
|
void delegateDragYChanged();
|
||||||
void delegateDragEnded();
|
void delegateDragStarted();
|
||||||
|
void delegateDragDropped();
|
||||||
|
void delegateDragCancelled();
|
||||||
void delegateDragFromPageStarted(int page, int row, int column);
|
void delegateDragFromPageStarted(int page, int row, int column);
|
||||||
void delegateDragFromFavouritesStarted(int position);
|
void delegateDragFromFavouritesStarted(int position);
|
||||||
void delegateDragFromAppDrawerStarted(QString storageId);
|
void delegateDragFromAppDrawerStarted(QString storageId);
|
||||||
|
|
@ -313,6 +320,7 @@ Q_SIGNALS:
|
||||||
void delegateDragFromWidgetListStarted(QString appletPluginId);
|
void delegateDragFromWidgetListStarted(QString appletPluginId);
|
||||||
void pageNumChanged();
|
void pageNumChanged();
|
||||||
void folderPageNumChanged();
|
void folderPageNumChanged();
|
||||||
|
void isDraggingDelegateChanged();
|
||||||
|
|
||||||
void leftCurrentFolder();
|
void leftCurrentFolder();
|
||||||
void folderAboutToOpen(qreal x, qreal y); // the position on the screen where the delegate is at, for animations
|
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 swipeCancelled();
|
||||||
void swipeMoved(qreal totalDeltaX, qreal totalDeltaY, qreal deltaX, qreal deltaY);
|
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:
|
private:
|
||||||
void setViewState(ViewState viewState);
|
void setViewState(ViewState viewState);
|
||||||
void setSwipeState(SwipeState swipeState);
|
void setSwipeState(SwipeState swipeState);
|
||||||
|
|
@ -410,6 +424,7 @@ private:
|
||||||
qreal m_delegateDragY{0};
|
qreal m_delegateDragY{0};
|
||||||
qreal m_delegateDragPointerOffsetX{0};
|
qreal m_delegateDragPointerOffsetX{0};
|
||||||
qreal m_delegateDragPointerOffsetY{0};
|
qreal m_delegateDragPointerOffsetY{0};
|
||||||
|
bool m_dragDropActive{false};
|
||||||
|
|
||||||
int m_pageNum{0};
|
int m_pageNum{0};
|
||||||
int m_folderPageNum{0};
|
int m_folderPageNum{0};
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ import org.kde.plasma.private.mobileshell as MobileShell
|
||||||
|
|
||||||
import "./delegate"
|
import "./delegate"
|
||||||
|
|
||||||
|
// Placeholder item that the user sees as they drag app/folder delegates around.
|
||||||
|
// See WidgetDragItem for the equivalent for widgets.
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
property Folio.HomeScreen folio
|
property Folio.HomeScreen folio
|
||||||
|
|
@ -75,15 +77,16 @@ Item {
|
||||||
property var delegateDroppedOn: null
|
property var delegateDroppedOn: null
|
||||||
|
|
||||||
// reset and show drag item
|
// reset and show drag item
|
||||||
function onSwipeStateChanged() {
|
function onDelegateDragStarted() {
|
||||||
if (folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate && !isWidgetDrag) {
|
if (isWidgetDrag) {
|
||||||
root.scale = 1.0;
|
return;
|
||||||
root.visible = true;
|
|
||||||
}
|
}
|
||||||
|
root.scale = 1.0;
|
||||||
|
root.visible = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// save the existing delegate at the spot (this is called before the delegate is dropped)
|
// save the existing delegate at the spot (this is called before the delegate is dropped)
|
||||||
function onDelegateDragEnded() {
|
function onDelegateDragDropped() {
|
||||||
if (root.isWidgetDrag) {
|
if (root.isWidgetDrag) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -103,6 +106,7 @@ Item {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
|
|
@ -142,7 +146,7 @@ Item {
|
||||||
|
|
||||||
// scale animation if we are creating, or inserting into a folder
|
// scale animation if we are creating, or inserting into a folder
|
||||||
scaleAnim.restart();
|
scaleAnim.restart();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if the drop has been abandoned, just hide
|
// if the drop has been abandoned, just hide
|
||||||
|
|
|
||||||
57
containments/homescreens/folio/qml/DelegateDropArea.qml
Normal file
57
containments/homescreens/folio/qml/DelegateDropArea.qml
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
// SPDX-FileCopyrightText: 2025 Devin Lin <devin@kde.org>
|
||||||
|
// 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();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -66,7 +66,7 @@ MouseArea {
|
||||||
readonly property var dragState: folio.HomeScreenState.dragState
|
readonly property var dragState: folio.HomeScreenState.dragState
|
||||||
readonly property bool isDropPositionThis: dragState.candidateDropPosition.location === Folio.DelegateDragPosition.Favourites &&
|
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 &&
|
readonly property bool isAppHoveredOver: folio.HomeScreenState.isDraggingDelegate &&
|
||||||
dragState.dropDelegate &&
|
dragState.dropDelegate &&
|
||||||
dragState.dropDelegate.type === Folio.FolioDelegate.Application &&
|
dragState.dropDelegate.type === Folio.FolioDelegate.Application &&
|
||||||
isDropPositionThis
|
isDropPositionThis
|
||||||
|
|
@ -178,7 +178,7 @@ MouseArea {
|
||||||
shadow: true
|
shadow: true
|
||||||
|
|
||||||
turnToFolder: delegate.isAppHoveredOver
|
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
|
// do not show if the drop animation is running to this delegate
|
||||||
visible: !(root.homeScreen.dropAnimationRunning && delegate.isDropPositionThis)
|
visible: !(root.homeScreen.dropAnimationRunning && delegate.isDropPositionThis)
|
||||||
|
|
@ -221,10 +221,8 @@ MouseArea {
|
||||||
Connections {
|
Connections {
|
||||||
target: folio.HomeScreenState
|
target: folio.HomeScreenState
|
||||||
|
|
||||||
function onSwipeStateChanged() {
|
function onDelegateDragStarted() {
|
||||||
if (folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate) {
|
contextMenu.close();
|
||||||
contextMenu.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -298,10 +296,8 @@ MouseArea {
|
||||||
Connections {
|
Connections {
|
||||||
target: folio.HomeScreenState
|
target: folio.HomeScreenState
|
||||||
|
|
||||||
function onSwipeStateChanged() {
|
function onDelegateDragStarted() {
|
||||||
if (folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate) {
|
contextMenu.close();
|
||||||
contextMenu.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -326,7 +326,7 @@ Folio.DelegateTouchArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
sourceComponent: {
|
sourceComponent: {
|
||||||
if (delegate.delegateModel.type === Folio.FolioDelegate.Application) {
|
if (delegate.delegateModel && delegate.delegateModel.type === Folio.FolioDelegate.Application) {
|
||||||
return appComponent;
|
return appComponent;
|
||||||
} else {
|
} else {
|
||||||
return noneComponent;
|
return noneComponent;
|
||||||
|
|
@ -391,10 +391,8 @@ Folio.DelegateTouchArea {
|
||||||
Connections {
|
Connections {
|
||||||
target: folio.HomeScreenState
|
target: folio.HomeScreenState
|
||||||
|
|
||||||
function onSwipeStateChanged() {
|
function onDelegateDragStarted() {
|
||||||
if (folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate) {
|
contextMenu.close();
|
||||||
contextMenu.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -117,497 +117,493 @@ Item {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// area that can be swiped
|
// Drag and drop area
|
||||||
MobileShell.SwipeArea {
|
DelegateDropArea {
|
||||||
id: swipeArea
|
id: dropArea
|
||||||
|
folio: root.folio
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
interactive: root.interactive &&
|
// Area that can be swiped
|
||||||
settingsLoader.homeScreenInteractive &&
|
MobileShell.SwipeArea {
|
||||||
(appDrawer.flickable.atYBeginning || // there are cases where contentY > 0 but atYBeginning is true
|
id: swipeArea
|
||||||
appDrawer.flickable.contentY <= 10 ||
|
anchors.fill: parent
|
||||||
// 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) => {
|
interactive: root.interactive &&
|
||||||
const deltaX = currentPos.x - startPos.x;
|
settings.homeScreenInteractive &&
|
||||||
const deltaY = currentPos.y - startPos.y;
|
!dropArea.containsDrag &&
|
||||||
homeScreenState.swipeStarted(deltaX, deltaY);
|
(appDrawer.flickable.atYBeginning || // there are cases where contentY > 0 but atYBeginning is true
|
||||||
}
|
appDrawer.flickable.contentY <= 10 ||
|
||||||
onSwipeEnded: {
|
// disable the swipe area when we are swiping in the app drawer, and not in drag-and-drop
|
||||||
homeScreenState.swipeEnded();
|
folio.HomeScreenState.swipeState === Folio.HomeScreenState.AwaitingDraggingDelegate ||
|
||||||
}
|
folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate ||
|
||||||
onSwipeMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => {
|
folio.HomeScreenState.swipeState === Folio.HomeScreenState.SwipingAppDrawerGrid ||
|
||||||
// cancel swipe when settings component is opening to prevent conflicts
|
folio.HomeScreenState.viewState !== Folio.HomeScreenState.AppDrawerView)
|
||||||
if (folio.HomeScreenState.settingsOpenProgress && folio.HomeScreenState.viewState !== Folio.HomeScreenState.SettingsView) {
|
|
||||||
homeScreenState.swipeCancelled();
|
onSwipeStarted: (currentPos, startPos) => {
|
||||||
return;
|
const deltaX = currentPos.x - startPos.x;
|
||||||
|
const deltaY = currentPos.y - startPos.y;
|
||||||
|
homeScreenState.swipeStarted(deltaX, deltaY);
|
||||||
}
|
}
|
||||||
homeScreenState.swipeMoved(totalDeltaX, totalDeltaY, deltaX, deltaY);
|
onSwipeEnded: {
|
||||||
}
|
homeScreenState.swipeEnded();
|
||||||
|
}
|
||||||
onTouchpadScrollStarted: homeScreenState.swipeStarted(0, 0);
|
onSwipeMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => {
|
||||||
onTouchpadScrollEnded: homeScreenState.swipeEnded();
|
// cancel swipe when settings component is opening to prevent conflicts
|
||||||
onTouchpadScrollMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => homeScreenState.swipeMoved(totalDeltaX, totalDeltaY, deltaX, deltaY);
|
if (folio.HomeScreenState.settingsOpenProgress && folio.HomeScreenState.viewState !== Folio.HomeScreenState.SettingsView) {
|
||||||
|
homeScreenState.swipeCancelled();
|
||||||
onPressedChanged: {
|
return;
|
||||||
if (pressed) {
|
}
|
||||||
// ensures that components like the widget settings overlay close when swiping
|
homeScreenState.swipeMoved(totalDeltaX, totalDeltaY, deltaX, deltaY);
|
||||||
noFocus.forceActiveFocus();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Loader {
|
onTouchpadScrollStarted: homeScreenState.swipeStarted(0, 0);
|
||||||
id: settingsLoader
|
onTouchpadScrollEnded: homeScreenState.swipeEnded();
|
||||||
asynchronous: true
|
onTouchpadScrollMove: (totalDeltaX, totalDeltaY, deltaX, deltaY) => homeScreenState.swipeMoved(totalDeltaX, totalDeltaY, deltaX, deltaY);
|
||||||
active: true
|
|
||||||
|
|
||||||
// Don't anchor, since we set y
|
onPressedChanged: {
|
||||||
width: parent.width
|
if (pressed) {
|
||||||
height: parent.height
|
// ensures that components like the widget settings overlay close when swiping
|
||||||
opacity: folio.HomeScreenState.settingsOpenProgress
|
noFocus.forceActiveFocus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// move the settings out of the way if it is not visible
|
SettingsComponent {
|
||||||
// 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 {
|
|
||||||
id: settings
|
id: settings
|
||||||
folio: root.folio
|
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
|
bottomMargin: root.bottomMargin
|
||||||
leftMargin: root.leftMargin
|
leftMargin: root.leftMargin
|
||||||
rightMargin: root.rightMargin
|
rightMargin: root.rightMargin
|
||||||
|
|
||||||
settingsModeHomeScreenScale: root.settingsModeHomeScreenScale
|
|
||||||
homeScreen: root
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: mainHomeScreen
|
id: mainHomeScreen
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
// we stop showing halfway through the animation
|
// we stop showing halfway through the animation
|
||||||
opacity: 1 - Math.max(homeScreenState.appDrawerOpenProgress, homeScreenState.searchWidgetOpenProgress, homeScreenState.folderOpenProgress) * 2
|
opacity: 1 - Math.max(homeScreenState.appDrawerOpenProgress, homeScreenState.searchWidgetOpenProgress, homeScreenState.folderOpenProgress) * 2
|
||||||
visible: opacity > 0 // prevent handlers from picking up events
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
transform: [
|
transform: [
|
||||||
Scale {
|
Scale {
|
||||||
// animation when settings opens
|
property real scaleFactor: Math.max(homeScreenState.appDrawerOpenProgress, homeScreenState.searchWidgetOpenProgress)
|
||||||
property real scaleFactor: 1 - folio.HomeScreenState.settingsOpenProgress * (1 - settingsModeHomeScreenScale)
|
origin.x: mainHomeScreen.width / 2
|
||||||
origin.x: root.leftMargin + (root.width - root.rightMargin - root.leftMargin) / 2
|
origin.y: mainHomeScreen.height / 2
|
||||||
origin.y: root.height * settingsModeHomeScreenScale / 2
|
yScale: 1 - (scaleFactor * 2) * 0.1
|
||||||
xScale: scaleFactor
|
xScale: 1 - (scaleFactor * 2) * 0.1
|
||||||
yScale: scaleFactor
|
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
states: [
|
HomeScreenPages {
|
||||||
State {
|
id: homeScreenPages
|
||||||
name: "bottom"
|
folio: root.folio
|
||||||
when: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom
|
maskManager: root.maskManager
|
||||||
AnchorChanges {
|
homeScreen: root
|
||||||
target: homeScreenPages
|
|
||||||
anchors.top: parent.top
|
anchors.topMargin: root.topMargin
|
||||||
anchors.bottom: favouritesBar.top
|
anchors.leftMargin: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Left ? 0 : root.leftMargin
|
||||||
anchors.left: parent.left
|
anchors.rightMargin: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Right ? 0 : root.rightMargin
|
||||||
anchors.right: parent.right
|
anchors.bottomMargin: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Bottom ? 0 : root.bottomMargin
|
||||||
}
|
|
||||||
}, State {
|
// update the model with page dimensions
|
||||||
name: "left"
|
onWidthChanged: {
|
||||||
when: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Left
|
homeScreenState.pageWidth = homeScreenPages.width;
|
||||||
AnchorChanges {
|
}
|
||||||
target: homeScreenPages
|
onHeightChanged: {
|
||||||
anchors.top: parent.top
|
homeScreenState.pageHeight = homeScreenPages.height;
|
||||||
anchors.bottom: parent.bottom
|
}
|
||||||
anchors.left: favouritesBar.right
|
|
||||||
anchors.right: parent.right
|
// Keyboard navigation from pages
|
||||||
}
|
Keys.onPressed: (event) => {
|
||||||
}, State {
|
switch (event.key) {
|
||||||
name: "right"
|
case Qt.Key_Up:
|
||||||
when: folio.HomeScreenState.favouritesBarLocation === Folio.HomeScreenState.Right
|
// Open search widget when going up
|
||||||
AnchorChanges {
|
folio.HomeScreenState.openSearchWidget();
|
||||||
target: homeScreenPages
|
event.accepted = true;
|
||||||
anchors.top: parent.top
|
break;
|
||||||
anchors.bottom: parent.bottom
|
case Qt.Key_Down:
|
||||||
anchors.left: parent.left
|
// Focus on favorites bar or app drawer, depending on its physical location
|
||||||
anchors.right: favouritesBar.left
|
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 {
|
// folder view
|
||||||
id: favouritesBarScrim
|
FolderView {
|
||||||
color: Qt.rgba(255, 255, 255, 0.2)
|
id: folderView
|
||||||
|
|
||||||
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
|
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
|
homeScreen: root
|
||||||
|
|
||||||
// don't show in settings mode
|
// we only start showing it halfway through
|
||||||
opacity: 1 - folio.HomeScreenState.settingsOpenProgress
|
opacity: homeScreenState.appDrawerOpenProgress < 0.5 ? 0 : (homeScreenState.appDrawerOpenProgress - 0.5) * 2
|
||||||
visible: opacity > 0
|
|
||||||
|
|
||||||
// one is ignored as anchors are set
|
// position for animation
|
||||||
height: Kirigami.Units.gridUnit * 6
|
property real animationY: (1 - homeScreenState.appDrawerOpenProgress) * (Kirigami.Units.gridUnit * 2)
|
||||||
width: Kirigami.Units.gridUnit * 6
|
|
||||||
|
// 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.topMargin: root.topMargin
|
||||||
anchors.bottomMargin: root.bottomMargin
|
anchors.bottomMargin: root.bottomMargin
|
||||||
anchors.leftMargin: root.leftMargin
|
anchors.leftMargin: root.leftMargin
|
||||||
anchors.rightMargin: root.rightMargin
|
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -124,11 +124,11 @@ Item {
|
||||||
property bool dropDelegateIsWidget: dropDelegate && dropDelegate.type === Folio.FolioDelegate.Widget
|
property bool dropDelegateIsWidget: dropDelegate && dropDelegate.type === Folio.FolioDelegate.Widget
|
||||||
|
|
||||||
// only show if it is an empty spot on this page
|
// only show if it is an empty spot on this page
|
||||||
visible: folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate &&
|
visible: folio.HomeScreenState.isDraggingDelegate &&
|
||||||
dropPosition.location === Folio.DelegateDragPosition.Pages &&
|
dropPosition.location === Folio.DelegateDragPosition.Pages &&
|
||||||
dropPosition.page === root.pageNum &&
|
dropPosition.page === root.pageNum &&
|
||||||
!dropDelegateIsWidget &&
|
!dropDelegateIsWidget &&
|
||||||
folio.HomeScreenState.getPageDelegateAt(root.pageNum, dropPosition.pageRow, dropPosition.pageColumn) === null
|
folio.HomeScreenState.getPageDelegateAt(root.pageNum, dropPosition.pageRow, dropPosition.pageColumn) === null
|
||||||
|
|
||||||
x: dropPosition.pageColumn * folio.HomeScreenState.pageCellWidth
|
x: dropPosition.pageColumn * folio.HomeScreenState.pageCellWidth
|
||||||
y: dropPosition.pageRow * folio.HomeScreenState.pageCellHeight
|
y: dropPosition.pageRow * folio.HomeScreenState.pageCellHeight
|
||||||
|
|
@ -145,7 +145,7 @@ Item {
|
||||||
property bool dropDelegateIsWidget: dropDelegate && dropDelegate.type === Folio.FolioDelegate.Widget
|
property bool dropDelegateIsWidget: dropDelegate && dropDelegate.type === Folio.FolioDelegate.Widget
|
||||||
|
|
||||||
// only show if the widget can be placed here
|
// 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.location === Folio.DelegateDragPosition.Pages &&
|
||||||
dropPosition.page === root.pageNum &&
|
dropPosition.page === root.pageNum &&
|
||||||
dropDelegateIsWidget &&
|
dropDelegateIsWidget &&
|
||||||
|
|
@ -180,7 +180,7 @@ Item {
|
||||||
dragState.candidateDropPosition.pageRow === delegate.pageDelegate.row &&
|
dragState.candidateDropPosition.pageRow === delegate.pageDelegate.row &&
|
||||||
dragState.candidateDropPosition.pageColumn === delegate.pageDelegate.column
|
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 &&
|
||||||
dragState.dropDelegate.type === Folio.FolioDelegate.Application &&
|
dragState.dropDelegate.type === Folio.FolioDelegate.Application &&
|
||||||
isDropPositionThis
|
isDropPositionThis
|
||||||
|
|
@ -274,7 +274,7 @@ Item {
|
||||||
name: folio.FolioSettings.showPagesAppLabels ? delegate.pageDelegate.application.name : ""
|
name: folio.FolioSettings.showPagesAppLabels ? delegate.pageDelegate.application.name : ""
|
||||||
application: delegate.pageDelegate.application
|
application: delegate.pageDelegate.application
|
||||||
turnToFolder: delegate.isAppHoveredOver
|
turnToFolder: delegate.isAppHoveredOver
|
||||||
turnToFolderAnimEnabled: folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate
|
turnToFolderAnimEnabled: folio.HomeScreenState.isDraggingDelegate
|
||||||
|
|
||||||
implicitWidth: folio.HomeScreenState.pageCellWidth
|
implicitWidth: folio.HomeScreenState.pageCellWidth
|
||||||
implicitHeight: folio.HomeScreenState.pageCellHeight
|
implicitHeight: folio.HomeScreenState.pageCellHeight
|
||||||
|
|
@ -323,10 +323,8 @@ Item {
|
||||||
Connections {
|
Connections {
|
||||||
target: folio.HomeScreenState
|
target: folio.HomeScreenState
|
||||||
|
|
||||||
function onSwipeStateChanged() {
|
function onDelegateDragStarted() {
|
||||||
if (folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate) {
|
contextMenu.close();
|
||||||
contextMenu.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -409,10 +407,8 @@ Item {
|
||||||
Connections {
|
Connections {
|
||||||
target: folio.HomeScreenState
|
target: folio.HomeScreenState
|
||||||
|
|
||||||
function onSwipeStateChanged() {
|
function onDelegateDragStarted() {
|
||||||
if (folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate) {
|
contextMenu.close();
|
||||||
contextMenu.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ import plasma.applet.org.kde.plasma.mobile.homescreen.folio as Folio
|
||||||
import './delegate'
|
import './delegate'
|
||||||
import './private'
|
import './private'
|
||||||
|
|
||||||
|
// Placeholder item that the user sees as they drag widgets around.
|
||||||
|
// See DelegateDragItem for the equivalent for app delegates.
|
||||||
Item {
|
Item {
|
||||||
id: root
|
id: root
|
||||||
property Folio.HomeScreen folio
|
property Folio.HomeScreen folio
|
||||||
|
|
@ -25,7 +27,9 @@ Item {
|
||||||
|
|
||||||
property Folio.FolioWidget widget
|
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
|
readonly property bool dropAnimationRunning: dragXAnim.running || dragYAnim.running
|
||||||
|
|
||||||
visible: false
|
visible: false
|
||||||
|
|
@ -74,13 +78,12 @@ Item {
|
||||||
id: stateWatcher
|
id: stateWatcher
|
||||||
target: folio.HomeScreenState
|
target: folio.HomeScreenState
|
||||||
|
|
||||||
function onSwipeStateChanged() {
|
function onDelegateDragStarted() {
|
||||||
if (folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate &&
|
if (!root.isWidgetDelegate) {
|
||||||
folio.HomeScreenState.dragState.dropDelegate &&
|
return;
|
||||||
folio.HomeScreenState.dragState.dropDelegate.type === Folio.FolioDelegate.Widget) {
|
|
||||||
|
|
||||||
root.startDrag(folio.HomeScreenState.dragState.dropDelegate.widget);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
root.startDrag(folio.HomeScreenState.dragState.dropDelegate.widget);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,11 +91,9 @@ Item {
|
||||||
target: folio.HomeScreenState
|
target: folio.HomeScreenState
|
||||||
|
|
||||||
// if we are starting drag-and-drop, close the menu immediately
|
// if we are starting drag-and-drop, close the menu immediately
|
||||||
function onSwipeStateChanged() {
|
function onDelegateDragStarted() {
|
||||||
if (folio.HomeScreenState.swipeState === Folio.HomeScreenState.DraggingDelegate) {
|
configOverlay.animClose();
|
||||||
configOverlay.animClose();
|
root.closed();
|
||||||
root.closed();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,136 @@
|
||||||
|
// SPDX-FileCopyrightText: 2023-2025 Devin Lin <devin@kde.org>
|
||||||
|
// 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -19,231 +19,123 @@ import org.kde.plasma.private.mobileshell as MobileShell
|
||||||
import '../delegate'
|
import '../delegate'
|
||||||
import '../private'
|
import '../private'
|
||||||
|
|
||||||
MouseArea {
|
Loader {
|
||||||
id: root
|
id: root
|
||||||
property Folio.HomeScreen folio
|
property Folio.HomeScreen folio
|
||||||
|
|
||||||
property var homeScreen
|
property var homeScreen
|
||||||
|
|
||||||
signal requestClose()
|
active: false
|
||||||
onClicked: root.requestClose()
|
|
||||||
|
function requestClose() {
|
||||||
|
active = false;
|
||||||
|
}
|
||||||
|
|
||||||
Kirigami.Theme.inherit: false
|
Kirigami.Theme.inherit: false
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
||||||
|
|
||||||
MobileShell.HapticsEffect {
|
sourceComponent: Item {
|
||||||
id: haptics
|
Rectangle {
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
onClicked: root.requestClose()
|
color: Qt.rgba(0, 0, 0, 0.7)
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate: MouseArea {
|
PlasmaExtras.ModelContextMenu {
|
||||||
id: delegate
|
id: getWidgetsDialog
|
||||||
width: gridView.cellWidth
|
visualParent: getWidgetsButton
|
||||||
height: gridView.cellHeight
|
placement: PlasmaExtras.Menu.TopPosedLeftAlignedPopup
|
||||||
|
// model set on first invocation
|
||||||
|
onClicked: model.trigger()
|
||||||
|
}
|
||||||
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
RowLayout {
|
||||||
hoverEnabled: true
|
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
|
PC3.ToolButton {
|
||||||
transform: Scale {
|
Layout.alignment: Qt.AlignVCenter
|
||||||
origin.x: delegate.width / 2;
|
icon.name: 'go-previous'
|
||||||
origin.y: delegate.height / 2;
|
implicitWidth: Kirigami.Units.gridUnit * 2
|
||||||
xScale: delegate.zoomScale
|
implicitHeight: Kirigami.Units.gridUnit * 2
|
||||||
yScale: delegate.zoomScale
|
padding: Kirigami.Units.smallSpacing
|
||||||
|
onClicked: root.requestClose()
|
||||||
}
|
}
|
||||||
|
|
||||||
Behavior on zoomScale { NumberAnimation { duration: 80 } }
|
PC3.Label {
|
||||||
|
Kirigami.Theme.inherit: false
|
||||||
readonly property string pluginName: model.pluginName
|
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
||||||
|
text: i18n("Widgets")
|
||||||
onPressAndHold: {
|
wrapMode: Text.Wrap
|
||||||
if (!model.isSupported) {
|
font.weight: Font.Bold
|
||||||
return
|
font.pointSize: Kirigami.Theme.defaultFont.pointSize * 1.5
|
||||||
}
|
Layout.fillWidth: true
|
||||||
|
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
PC3.ToolButton {
|
||||||
id: background
|
id: getWidgetsButton
|
||||||
color: Qt.rgba(255, 255, 255, 0.3)
|
icon.name: "get-hot-new-stuff"
|
||||||
visible: delegate.containsMouse
|
text: i18ndc("plasma_shell_org.kde.plasma.mobile", "@action:button The word 'new' refers to widgets", "Get New Widgets…")
|
||||||
radius: Kirigami.Units.cornerRadius
|
Accessible.name: i18ndc("plasma_shell_org.kde.plasma.mobile", "@action:button", "Get New Widgets…")
|
||||||
anchors.fill: parent
|
|
||||||
}
|
|
||||||
|
|
||||||
ColumnLayout {
|
onClicked: {
|
||||||
anchors.fill: parent
|
getWidgetsDialog.model = widgetExplorer.widgetsMenuActions
|
||||||
anchors.margins: Kirigami.Units.largeSpacing
|
getWidgetsDialog.openRelative()
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// opacity gradient at grid edges
|
GridView {
|
||||||
MobileShell.FlickableOpacityGradient {
|
id: gridView
|
||||||
anchors.fill: gridView
|
clip: true
|
||||||
flickable: gridView
|
reuseItems: true
|
||||||
}
|
|
||||||
|
|
||||||
WidgetExplorer {
|
opacity: 0 // we display with the opacity gradient below
|
||||||
id: widgetExplorer
|
|
||||||
containment: Plasmoid
|
|
||||||
|
|
||||||
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -21,23 +21,12 @@ Item {
|
||||||
property var homeScreen
|
property var homeScreen
|
||||||
property real settingsModeHomeScreenScale
|
property real settingsModeHomeScreenScale
|
||||||
|
|
||||||
readonly property bool homeScreenInteractive: !appletListViewerLoader.active
|
readonly property bool homeScreenInteractive: !appletListViewer.active
|
||||||
|
|
||||||
property real bottomMargin: 0
|
property real bottomMargin: 0
|
||||||
property real leftMargin: 0
|
property real leftMargin: 0
|
||||||
property real rightMargin: 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 {
|
MouseArea {
|
||||||
id: closeSettings
|
id: closeSettings
|
||||||
|
|
||||||
|
|
@ -84,7 +73,7 @@ Item {
|
||||||
iconName: 'widget-alternatives'
|
iconName: 'widget-alternatives'
|
||||||
textLabel: i18n("Widgets")
|
textLabel: i18n("Widgets")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
appletListViewerLoader.active = true;
|
appletListViewer.active = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -157,49 +146,13 @@ Item {
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
Loader {
|
AppletListViewer {
|
||||||
id: appletListViewerLoader
|
id: appletListViewer
|
||||||
asynchronous: true
|
|
||||||
active: false
|
|
||||||
|
|
||||||
signal requestClose()
|
|
||||||
onRequestClose: item?.requestClose()
|
|
||||||
|
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: parent.height
|
height: parent.height
|
||||||
|
|
||||||
opacity: status == Loader.Ready ? 1 : 0
|
folio: root.folio
|
||||||
// move the settings out of the way if it is not visible
|
homeScreen: root.homeScreen
|
||||||
// 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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue