feat: add wallpaper & style nexus page
This commit is contained in:
parent
69fe7c1251
commit
c31cb2a7f6
5 changed files with 345 additions and 2 deletions
|
|
@ -9,6 +9,7 @@ MouseArea {
|
||||||
|
|
||||||
property bool disabled
|
property bool disabled
|
||||||
property bool showHoverBackground: true
|
property bool showHoverBackground: true
|
||||||
|
property bool manualPressOverride
|
||||||
readonly property alias rect: base
|
readonly property alias rect: base
|
||||||
|
|
||||||
property bool shapeMorph
|
property bool shapeMorph
|
||||||
|
|
@ -60,12 +61,17 @@ MouseArea {
|
||||||
onPressed: e => press(e.x, e.y)
|
onPressed: e => press(e.x, e.y)
|
||||||
|
|
||||||
onPressedChanged: {
|
onPressedChanged: {
|
||||||
if (!pressed && !rippleAnim.running && circle.opacity > 0)
|
if (!(pressed || manualPressOverride) && !rippleAnim.running && circle.opacity > 0)
|
||||||
|
fadeAnim.start();
|
||||||
|
}
|
||||||
|
|
||||||
|
onManualPressOverrideChanged: {
|
||||||
|
if (!(pressed || manualPressOverride) && circleRadius > endRadiusAtPress * 0.99 && !fadeAnim.running)
|
||||||
fadeAnim.start();
|
fadeAnim.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
onCircleRadiusChanged: {
|
onCircleRadiusChanged: {
|
||||||
if (!pressed && circleRadius > endRadiusAtPress * 0.99 && !fadeAnim.running)
|
if (!(pressed || manualPressOverride) && circleRadius > endRadiusAtPress * 0.99 && !fadeAnim.running)
|
||||||
fadeAnim.start();
|
fadeAnim.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -89,4 +89,15 @@ Item {
|
||||||
nState: nState
|
nState: nState
|
||||||
width: Math.min(Tokens.sizes.nexus.maxNavWidth, Math.round(root.width / 3))
|
width: Math.min(Tokens.sizes.nexus.maxNavWidth, Math.round(root.width / 3))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Pages {
|
||||||
|
anchors.left: navPane.right
|
||||||
|
anchors.right: parent.right
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.bottom: parent.bottom
|
||||||
|
anchors.leftMargin: navPane.anchors.margins + anchors.margins
|
||||||
|
anchors.margins: Tokens.padding.extraLarge
|
||||||
|
|
||||||
|
nState: nState
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
111
modules/nexus/Pages.qml
Normal file
111
modules/nexus/Pages.qml
Normal file
|
|
@ -0,0 +1,111 @@
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import "pages"
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Caelestia.Config
|
||||||
|
import qs.components
|
||||||
|
import qs.services
|
||||||
|
import qs.modules.nexus
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property NexusState nState
|
||||||
|
|
||||||
|
readonly property list<Component> pageComps: [
|
||||||
|
Component {
|
||||||
|
WallpaperAndStyle {
|
||||||
|
nState: root.nState
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
property int lastPageIdx
|
||||||
|
property int animOff
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
id: loader
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
layer.enabled: opacity < 1
|
||||||
|
Component.onCompleted: sourceComponent = root.pageComps[root.nState.currentPageIdx] ?? placeholderComp
|
||||||
|
}
|
||||||
|
|
||||||
|
Connections {
|
||||||
|
function onCurrentPageIdxChanged(): void {
|
||||||
|
switchAnim.complete();
|
||||||
|
root.animOff = root.Tokens.padding.extraLarge * (root.nState.currentPageIdx > root.lastPageIdx ? -1 : 1);
|
||||||
|
switchAnim.start();
|
||||||
|
root.lastPageIdx = root.nState.currentPageIdx;
|
||||||
|
}
|
||||||
|
|
||||||
|
target: root.nState
|
||||||
|
}
|
||||||
|
|
||||||
|
SequentialAnimation {
|
||||||
|
id: switchAnim
|
||||||
|
|
||||||
|
Anim {
|
||||||
|
target: loader
|
||||||
|
property: "opacity"
|
||||||
|
to: 0
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
PropertyAction {
|
||||||
|
target: loader
|
||||||
|
property: "sourceComponent"
|
||||||
|
value: root.pageComps[root.nState.currentPageIdx] ?? placeholderComp
|
||||||
|
}
|
||||||
|
PropertyAction {
|
||||||
|
target: loader.anchors
|
||||||
|
property: "topMargin"
|
||||||
|
value: root.animOff
|
||||||
|
}
|
||||||
|
PropertyAction {
|
||||||
|
target: loader.anchors
|
||||||
|
property: "bottomMargin"
|
||||||
|
value: -root.animOff
|
||||||
|
}
|
||||||
|
ParallelAnimation {
|
||||||
|
Anim {
|
||||||
|
target: loader
|
||||||
|
property: "opacity"
|
||||||
|
from: 0
|
||||||
|
to: 1
|
||||||
|
type: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
Anim {
|
||||||
|
target: loader.anchors
|
||||||
|
properties: "topMargin,bottomMargin"
|
||||||
|
to: 0
|
||||||
|
type: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Component {
|
||||||
|
id: placeholderComp
|
||||||
|
|
||||||
|
Item {
|
||||||
|
ColumnLayout {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Tokens.padding.extraSmall
|
||||||
|
|
||||||
|
MaterialIcon {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: "handyman"
|
||||||
|
color: Colours.palette.m3outlineVariant
|
||||||
|
font: Tokens.font.icon.extraLarge
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
text: qsTr("Page under construction")
|
||||||
|
color: Colours.palette.m3outlineVariant
|
||||||
|
font: Tokens.font.title.large
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
55
modules/nexus/common/ToggleRow.qml
Normal file
55
modules/nexus/common/ToggleRow.qml
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
import QtQuick
|
||||||
|
import Caelestia.Config
|
||||||
|
import qs.components
|
||||||
|
import qs.components.controls
|
||||||
|
import qs.services
|
||||||
|
|
||||||
|
StyledSwitch {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property bool first
|
||||||
|
property bool last
|
||||||
|
|
||||||
|
implicitWidth: implicitContentWidth + implicitIndicatorWidth + Tokens.padding.largeIncreased * 2
|
||||||
|
implicitHeight: Math.max(implicitContentHeight, implicitIndicatorHeight) + Tokens.padding.medium * 2
|
||||||
|
cLayer: 2
|
||||||
|
|
||||||
|
indicator.anchors.verticalCenter: verticalCenter
|
||||||
|
indicator.anchors.right: right
|
||||||
|
indicator.anchors.rightMargin: Tokens.padding.large
|
||||||
|
|
||||||
|
onPressed: stateLayer.press(stateLayer.mouseX, stateLayer.mouseY)
|
||||||
|
|
||||||
|
background: StyledRect {
|
||||||
|
color: Colours.tPalette.m3surfaceContainer
|
||||||
|
topLeftRadius: root.first ? Tokens.rounding.extraLarge : Tokens.rounding.extraSmall
|
||||||
|
topRightRadius: root.first ? Tokens.rounding.extraLarge : Tokens.rounding.extraSmall
|
||||||
|
bottomLeftRadius: root.last ? Tokens.rounding.extraLarge : Tokens.rounding.extraSmall
|
||||||
|
bottomRightRadius: root.last ? Tokens.rounding.extraLarge : Tokens.rounding.extraSmall
|
||||||
|
|
||||||
|
StateLayer {
|
||||||
|
id: stateLayer
|
||||||
|
|
||||||
|
manualPressOverride: root.pressed
|
||||||
|
|
||||||
|
topLeftRadius: parent.topLeftRadius
|
||||||
|
topRightRadius: parent.topRightRadius
|
||||||
|
bottomLeftRadius: parent.bottomLeftRadius
|
||||||
|
bottomRightRadius: parent.bottomRightRadius
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
contentItem: StyledText {
|
||||||
|
id: label
|
||||||
|
|
||||||
|
anchors.left: parent.left
|
||||||
|
anchors.right: root.indicator.left
|
||||||
|
anchors.leftMargin: Tokens.padding.large
|
||||||
|
anchors.rightMargin: Tokens.spacing.medium
|
||||||
|
|
||||||
|
text: root.text
|
||||||
|
font: Tokens.font.body.small
|
||||||
|
elide: Text.ElideRight
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
}
|
||||||
160
modules/nexus/pages/WallpaperAndStyle.qml
Normal file
160
modules/nexus/pages/WallpaperAndStyle.qml
Normal file
|
|
@ -0,0 +1,160 @@
|
||||||
|
pragma ComponentBehavior: Bound
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import QtQuick.Layouts
|
||||||
|
import Quickshell
|
||||||
|
import Caelestia.Components
|
||||||
|
import Caelestia.Config
|
||||||
|
import qs.components
|
||||||
|
import qs.components.controls
|
||||||
|
import qs.services
|
||||||
|
import qs.modules.nexus
|
||||||
|
import qs.modules.nexus.common
|
||||||
|
|
||||||
|
ColumnLayout {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
required property NexusState nState
|
||||||
|
readonly property int cappedWidth: Math.min(800, width)
|
||||||
|
|
||||||
|
spacing: Tokens.spacing.large
|
||||||
|
|
||||||
|
StyledText {
|
||||||
|
text: qsTr("Wallpaper & style")
|
||||||
|
font: Tokens.font.title.large
|
||||||
|
}
|
||||||
|
|
||||||
|
StyledClippingRect {
|
||||||
|
id: wallWrapper
|
||||||
|
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
Layout.topMargin: Tokens.spacing.extraLarge
|
||||||
|
implicitWidth: {
|
||||||
|
const screen = root.nState.screen;
|
||||||
|
return implicitHeight / screen.height * screen.width;
|
||||||
|
}
|
||||||
|
implicitHeight: {
|
||||||
|
const screen = root.nState.screen;
|
||||||
|
const cWidth = root.cappedWidth;
|
||||||
|
return Math.min(Math.round(cWidth * 0.4), cWidth / screen.width * screen.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
color: Colours.palette.m3surfaceContainer
|
||||||
|
radius: Tokens.rounding.large
|
||||||
|
|
||||||
|
Loader {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
|
||||||
|
opacity: wallImg.status === Image.Ready ? 0 : 1
|
||||||
|
active: opacity > 0
|
||||||
|
|
||||||
|
sourceComponent: StyledRect {
|
||||||
|
implicitWidth: wallLoadingIndicator.implicitSize + Tokens.padding.largeIncreased * 2
|
||||||
|
implicitHeight: wallLoadingIndicator.implicitSize + Tokens.padding.largeIncreased * 2
|
||||||
|
|
||||||
|
color: Colours.palette.m3primaryContainer
|
||||||
|
radius: Tokens.rounding.full
|
||||||
|
|
||||||
|
LoadingIndicator {
|
||||||
|
id: wallLoadingIndicator
|
||||||
|
|
||||||
|
anchors.centerIn: parent
|
||||||
|
containsIcon: true
|
||||||
|
implicitSize: wallWrapper.implicitHeight * 0.4
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
type: Anim.DefaultEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Image {
|
||||||
|
id: wallImg
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
source: Wallpapers.current
|
||||||
|
asynchronous: true
|
||||||
|
fillMode: Image.PreserveAspectCrop
|
||||||
|
sourceSize: {
|
||||||
|
const dpr = (QsWindow.window as QsWindow)?.devicePixelRatio ?? 1;
|
||||||
|
return Qt.size(width * dpr, height * dpr);
|
||||||
|
}
|
||||||
|
|
||||||
|
retainWhileLoading: true
|
||||||
|
opacity: status === Image.Ready ? 1 : 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
Anim {
|
||||||
|
type: Anim.SlowEffects
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ButtonRow {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
spacing: Tokens.spacing.small
|
||||||
|
|
||||||
|
IconTextButton {
|
||||||
|
icon: "wallpaper"
|
||||||
|
text: qsTr("Wallpapers")
|
||||||
|
font: Tokens.font.body.large
|
||||||
|
isRound: true
|
||||||
|
shapeMorph: true
|
||||||
|
type: IconTextButton.Tonal
|
||||||
|
horizontalPadding: Tokens.padding.extraLarge
|
||||||
|
verticalPadding: Tokens.padding.medium
|
||||||
|
onClicked: ; // TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
IconTextButton {
|
||||||
|
icon: "palette"
|
||||||
|
text: qsTr("Colours")
|
||||||
|
font: Tokens.font.body.large
|
||||||
|
isRound: true
|
||||||
|
shapeMorph: true
|
||||||
|
type: IconTextButton.Tonal
|
||||||
|
horizontalPadding: Tokens.padding.extraLarge
|
||||||
|
verticalPadding: Tokens.padding.medium
|
||||||
|
onClicked: ; // TODO
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
implicitWidth: root.cappedWidth
|
||||||
|
|
||||||
|
first: true
|
||||||
|
text: qsTr("Display wallpaper")
|
||||||
|
checked: Config.background.wallpaperEnabled
|
||||||
|
onToggled: GlobalConfig.background.wallpaperEnabled = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
Layout.topMargin: Tokens.spacing.extraSmall / 2 - parent.spacing
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
implicitWidth: root.cappedWidth
|
||||||
|
|
||||||
|
text: qsTr("Dark theme")
|
||||||
|
checked: !Colours.light
|
||||||
|
onToggled: Colours.setMode(checked ? "dark" : "light")
|
||||||
|
}
|
||||||
|
|
||||||
|
ToggleRow {
|
||||||
|
Layout.topMargin: Tokens.spacing.extraSmall / 2 - parent.spacing
|
||||||
|
Layout.alignment: Qt.AlignHCenter
|
||||||
|
implicitWidth: root.cappedWidth
|
||||||
|
|
||||||
|
last: true
|
||||||
|
text: qsTr("Transparency")
|
||||||
|
checked: Colours.transparency.enabled
|
||||||
|
onToggled: GlobalConfig.appearance.transparency.enabled = checked
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
Layout.fillHeight: true
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue