feat: add nexus sub pages
This commit is contained in:
parent
550eb0bf1a
commit
4a77746393
5 changed files with 194 additions and 24 deletions
|
|
@ -5,7 +5,22 @@ QtObject {
|
||||||
property ShellScreen screen
|
property ShellScreen screen
|
||||||
property bool isWindow
|
property bool isWindow
|
||||||
property int currentPageIdx
|
property int currentPageIdx
|
||||||
|
property list<int> subPageIdxStack
|
||||||
property bool searchOpen
|
property bool searchOpen
|
||||||
|
|
||||||
signal close
|
signal close
|
||||||
|
signal subPageOpened(idx: int)
|
||||||
|
signal subPageClosed
|
||||||
|
|
||||||
|
function openSubPage(idx: int): void {
|
||||||
|
subPageIdxStack.push(idx);
|
||||||
|
subPageOpened(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
function closeSubPage(): void {
|
||||||
|
subPageClosed();
|
||||||
|
subPageIdxStack.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
onCurrentPageIdxChanged: subPageIdxStack.length = 0
|
||||||
}
|
}
|
||||||
|
|
|
||||||
20
modules/nexus/PageCompRegistry.qml
Normal file
20
modules/nexus/PageCompRegistry.qml
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
pragma Singleton
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import qs.modules.nexus.common
|
||||||
|
import qs.modules.nexus.pages
|
||||||
|
|
||||||
|
QtObject {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
readonly property list<Component> pageComps: [
|
||||||
|
// Appearance
|
||||||
|
Component {
|
||||||
|
StackPage {
|
||||||
|
Component {
|
||||||
|
WallpaperAndStyle {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
pragma ComponentBehavior: Bound
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
import "pages"
|
|
||||||
import QtQuick
|
import QtQuick
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import Caelestia.Config
|
import Caelestia.Config
|
||||||
|
|
@ -13,23 +12,39 @@ Item {
|
||||||
|
|
||||||
required property NexusState nState
|
required property NexusState nState
|
||||||
|
|
||||||
readonly property list<Component> pageComps: [
|
|
||||||
Component {
|
|
||||||
WallpaperAndStyle {
|
|
||||||
nState: root.nState
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
property int lastPageIdx
|
property int lastPageIdx
|
||||||
property int animOff
|
property int animOff
|
||||||
|
property Item currentItem
|
||||||
|
|
||||||
Loader {
|
function loadPage(idx: int): void {
|
||||||
id: loader
|
if (currentItem)
|
||||||
|
currentItem.destroy();
|
||||||
|
|
||||||
|
const comp = PageCompRegistry.pageComps[idx] ?? placeholderComp;
|
||||||
|
const incubator = comp.incubateObject(container, {
|
||||||
|
nState
|
||||||
|
});
|
||||||
|
|
||||||
|
const attach = () => {
|
||||||
|
incubator.object.anchors.fill = container;
|
||||||
|
currentItem = incubator.object;
|
||||||
|
};
|
||||||
|
|
||||||
|
if (incubator.status === Component.Ready)
|
||||||
|
attach();
|
||||||
|
else
|
||||||
|
incubator.onStatusChanged = status => {
|
||||||
|
if (status === Component.Ready)
|
||||||
|
attach();
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: container
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
layer.enabled: opacity < 1
|
layer.enabled: opacity < 1
|
||||||
Component.onCompleted: sourceComponent = root.pageComps[root.nState.currentPageIdx] ?? placeholderComp
|
Component.onCompleted: root.loadPage(root.nState.currentPageIdx)
|
||||||
}
|
}
|
||||||
|
|
||||||
Connections {
|
Connections {
|
||||||
|
|
@ -47,36 +62,34 @@ Item {
|
||||||
id: switchAnim
|
id: switchAnim
|
||||||
|
|
||||||
Anim {
|
Anim {
|
||||||
target: loader
|
target: container
|
||||||
property: "opacity"
|
property: "opacity"
|
||||||
to: 0
|
to: 0
|
||||||
type: Anim.DefaultEffects
|
type: Anim.DefaultEffects
|
||||||
}
|
}
|
||||||
PropertyAction {
|
ScriptAction {
|
||||||
target: loader
|
script: root.loadPage(root.nState.currentPageIdx)
|
||||||
property: "sourceComponent"
|
|
||||||
value: root.pageComps[root.nState.currentPageIdx] ?? placeholderComp
|
|
||||||
}
|
}
|
||||||
PropertyAction {
|
PropertyAction {
|
||||||
target: loader.anchors
|
target: container.anchors
|
||||||
property: "topMargin"
|
property: "topMargin"
|
||||||
value: root.animOff
|
value: root.animOff
|
||||||
}
|
}
|
||||||
PropertyAction {
|
PropertyAction {
|
||||||
target: loader.anchors
|
target: container.anchors
|
||||||
property: "bottomMargin"
|
property: "bottomMargin"
|
||||||
value: -root.animOff
|
value: -root.animOff
|
||||||
}
|
}
|
||||||
ParallelAnimation {
|
ParallelAnimation {
|
||||||
Anim {
|
Anim {
|
||||||
target: loader
|
target: container
|
||||||
property: "opacity"
|
property: "opacity"
|
||||||
from: 0
|
from: 0
|
||||||
to: 1
|
to: 1
|
||||||
type: Anim.SlowEffects
|
type: Anim.SlowEffects
|
||||||
}
|
}
|
||||||
Anim {
|
Anim {
|
||||||
target: loader.anchors
|
target: container.anchors
|
||||||
properties: "topMargin,bottomMargin"
|
properties: "topMargin,bottomMargin"
|
||||||
to: 0
|
to: 0
|
||||||
type: Anim.SlowEffects
|
type: Anim.SlowEffects
|
||||||
|
|
@ -88,6 +101,8 @@ Item {
|
||||||
id: placeholderComp
|
id: placeholderComp
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
|
property NexusState nState // To avoid the warning from non-existent property
|
||||||
|
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Tokens.padding.extraSmall
|
spacing: Tokens.padding.extraSmall
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,6 @@ ColumnLayout {
|
||||||
|
|
||||||
default property Item contentChild
|
default property Item contentChild
|
||||||
|
|
||||||
signal close
|
|
||||||
|
|
||||||
spacing: Tokens.spacing.extraExtraLarge
|
spacing: Tokens.spacing.extraExtraLarge
|
||||||
|
|
||||||
RowLayout {
|
RowLayout {
|
||||||
|
|
@ -37,7 +35,7 @@ ColumnLayout {
|
||||||
isRound: true
|
isRound: true
|
||||||
inactiveColour: Colours.tPalette.m3surfaceContainerHigh
|
inactiveColour: Colours.tPalette.m3surfaceContainerHigh
|
||||||
inactiveOnColour: Colours.palette.m3onSurface
|
inactiveOnColour: Colours.palette.m3onSurface
|
||||||
onClicked: root.close()
|
onClicked: root.nState.closeSubPage()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
122
modules/nexus/common/StackPage.qml
Normal file
122
modules/nexus/common/StackPage.qml
Normal file
|
|
@ -0,0 +1,122 @@
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Caelestia.Config
|
||||||
|
import qs.components
|
||||||
|
import qs.modules.nexus
|
||||||
|
|
||||||
|
StackView {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property NexusState nState
|
||||||
|
default property list<Component> pages
|
||||||
|
readonly property int animMovement: Tokens.padding.extraExtraLarge * 2
|
||||||
|
|
||||||
|
function openSubPage(idx: int, immediate: bool): void {
|
||||||
|
const page = pages[idx];
|
||||||
|
if (page) {
|
||||||
|
push(page, {
|
||||||
|
nState
|
||||||
|
}, immediate ? StackView.Immediate : StackView.PushTransition);
|
||||||
|
} else {
|
||||||
|
console.warn(logCat, "Attempted to open invalid sub-page index", idx);
|
||||||
|
nState.closeSubPage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
clip: busy
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
openSubPage(0, true);
|
||||||
|
for (const page of nState.subPageIdxStack)
|
||||||
|
openSubPage(page, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
pushEnter: Transition {
|
||||||
|
SequentialAnimation {
|
||||||
|
PropertyAction {
|
||||||
|
property: "opacity"
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
PauseAnimation {
|
||||||
|
duration: Tokens.anim.durations.expressiveDefaultEffects
|
||||||
|
}
|
||||||
|
ParallelAnimation {
|
||||||
|
Anim {
|
||||||
|
property: "opacity"
|
||||||
|
to: 1
|
||||||
|
type: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
Anim {
|
||||||
|
property: "x"
|
||||||
|
from: root.animMovement
|
||||||
|
to: 0
|
||||||
|
type: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pushExit: Transition {
|
||||||
|
Anim {
|
||||||
|
property: "opacity"
|
||||||
|
to: 0
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
popEnter: Transition {
|
||||||
|
SequentialAnimation {
|
||||||
|
PropertyAction {
|
||||||
|
property: "opacity"
|
||||||
|
value: 0
|
||||||
|
}
|
||||||
|
PauseAnimation {
|
||||||
|
duration: Tokens.anim.durations.expressiveDefaultEffects
|
||||||
|
}
|
||||||
|
ParallelAnimation {
|
||||||
|
Anim {
|
||||||
|
property: "opacity"
|
||||||
|
to: 1
|
||||||
|
type: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
Anim {
|
||||||
|
property: "x"
|
||||||
|
from: -root.animMovement
|
||||||
|
to: 0
|
||||||
|
type: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
popExit: Transition {
|
||||||
|
Anim {
|
||||||
|
property: "opacity"
|
||||||
|
to: 0
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LoggingCategory {
|
||||||
|
id: logCat
|
||||||
|
|
||||||
|
name: "caelestia.nexus"
|
||||||
|
defaultLogLevel: LoggingCategory.Info
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onSubPageOpened(idx: int): void {
|
||||||
|
root.openSubPage(idx, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
function onSubPageClosed(): void {
|
||||||
|
if (root.depth < root.nState.subPageIdxStack.length) {
|
||||||
|
console.log(logCat, "Attempted to close page while depth < stack depth. Ignoring.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
root.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
target: root.nState
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue