diff --git a/modules/nexus/common/PageBase.qml b/modules/nexus/common/PageBase.qml new file mode 100644 index 00000000..ba329340 --- /dev/null +++ b/modules/nexus/common/PageBase.qml @@ -0,0 +1,64 @@ +pragma ComponentBehavior: Bound + +import QtQuick +import QtQuick.Layouts +import Caelestia.Config +import qs.components +import qs.components.containers +import qs.components.controls +import qs.services +import qs.modules.nexus + +ColumnLayout { + id: root + + required property string title + required property NexusState nState + property bool isSubPage + readonly property int cappedWidth: Math.min(800, width) + + default property Item contentChild + + signal close + + spacing: Tokens.spacing.extraExtraLarge + + RowLayout { + spacing: Tokens.spacing.largeIncreased + + Loader { + visible: active + active: root.isSubPage + asynchronous: true + sourceComponent: IconButton { + icon: "arrow_back" + font: Tokens.font.icon.medium + type: IconButton.Tonal + isRound: true + inactiveColour: Colours.tPalette.m3surfaceContainerHigh + inactiveOnColour: Colours.palette.m3onSurface + onClicked: root.close() + } + } + + StyledText { + text: root.title + font: Tokens.font.title.large + } + } + + VerticalFadeFlickable { + id: flickable + + Layout.fillWidth: true + Layout.fillHeight: true + + Layout.topMargin: -topMargin + Layout.bottomMargin: -bottomMargin + topMargin: Tokens.padding.large + bottomMargin: Tokens.padding.large + + contentHeight: root.contentChild?.implicitHeight ?? 0 + contentItem.children: [root.contentChild] + } +} diff --git a/modules/nexus/pages/WallpaperAndStyle.qml b/modules/nexus/pages/WallpaperAndStyle.qml index 65fb9a03..5eb8b574 100644 --- a/modules/nexus/pages/WallpaperAndStyle.qml +++ b/modules/nexus/pages/WallpaperAndStyle.qml @@ -2,211 +2,200 @@ 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.components.images import qs.services -import qs.modules.nexus import qs.modules.nexus.common -ColumnLayout { +PageBase { id: root - required property NexusState nState - readonly property int cappedWidth: Math.min(800, width) + title: qsTr("Wallpaper & style") - spacing: Tokens.spacing.large + ColumnLayout { + anchors.horizontalCenter: parent.horizontalCenter + anchors.top: parent.top + width: root.cappedWidth + spacing: Tokens.spacing.large - StyledText { - text: qsTr("Wallpaper & style") - font: Tokens.font.title.large - } + StyledClippingRect { + id: wallWrapper - 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.tPalette.m3surfaceContainer - radius: Tokens.rounding.large - - Loader { - anchors.centerIn: parent - opacity: Config.background.wallpaperEnabled ? 0 : 1 - active: opacity > 0 - - sourceComponent: ColumnLayout { - spacing: Tokens.spacing.extraSmall - - MaterialIcon { - Layout.alignment: Qt.AlignHCenter - text: "hide_image" - color: Colours.palette.m3onSurfaceVariant - font: Tokens.font.icon.extraLarge - } - - StyledText { - Layout.alignment: Qt.AlignHCenter - text: qsTr("Wallpaper disabled") - color: Colours.palette.m3onSurfaceVariant - font: Tokens.font.body.large - } + Layout.alignment: Qt.AlignHCenter + 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); } - Behavior on opacity { - Anim { - type: Anim.SlowEffects - } - } - } - - Item { - anchors.fill: parent - opacity: Config.background.wallpaperEnabled ? 1 : 0 - - Behavior on opacity { - Anim { - type: Anim.SlowEffects - } - } + color: Colours.tPalette.m3surfaceContainer + radius: Tokens.rounding.large Loader { - id: wallIndicatorLoader - anchors.centerIn: parent - - opacity: 0 + opacity: Config.background.wallpaperEnabled ? 0 : 1 active: opacity > 0 - sourceComponent: StyledRect { - implicitWidth: wallLoadingIndicator.implicitSize + Tokens.padding.largeIncreased * 2 - implicitHeight: wallLoadingIndicator.implicitSize + Tokens.padding.largeIncreased * 2 + sourceComponent: ColumnLayout { + spacing: Tokens.spacing.extraSmall - color: Colours.palette.m3primaryContainer - radius: Tokens.rounding.full + MaterialIcon { + Layout.alignment: Qt.AlignHCenter + text: "hide_image" + color: Colours.palette.m3onSurfaceVariant + font: Tokens.font.icon.extraLarge + } - LoadingIndicator { - id: wallLoadingIndicator - - anchors.centerIn: parent - containsIcon: true - implicitSize: Math.min(wallWrapper.implicitWidth, wallWrapper.implicitHeight) * 0.4 + StyledText { + Layout.alignment: Qt.AlignHCenter + text: qsTr("Wallpaper disabled") + color: Colours.palette.m3onSurfaceVariant + font: Tokens.font.body.large } } Behavior on opacity { Anim { - type: Anim.DefaultEffects + type: Anim.SlowEffects } } } - Timer { - id: wallLoadDebounceTimer - - interval: 100 - onTriggered: { - if (wallImg.status !== Image.Ready) - wallIndicatorLoader.opacity = 1; - } - } - - FadeImage { - id: wallImg - + Item { anchors.fill: parent - source: Wallpapers.current - preventInit: wallIndicatorLoader.opacity > 0 - fadeOutAnim: Anim.DefaultEffects - fadeInAnim: Anim.SlowEffects + opacity: Config.background.wallpaperEnabled ? 1 : 0 - onSourceChanged: wallLoadDebounceTimer.restart() + Behavior on opacity { + Anim { + type: Anim.SlowEffects + } + } - onStatusChanged: { - if (status === Image.Ready) { - wallLoadDebounceTimer.stop(); - wallIndicatorLoader.opacity = 0; + Loader { + id: wallIndicatorLoader + + anchors.centerIn: parent + + opacity: 0 + 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: Math.min(wallWrapper.implicitWidth, wallWrapper.implicitHeight) * 0.4 + } + } + + Behavior on opacity { + Anim { + type: Anim.DefaultEffects + } + } + } + + Timer { + id: wallLoadDebounceTimer + + interval: 100 + onTriggered: { + if (wallImg.status !== Image.Ready) + wallIndicatorLoader.opacity = 1; + } + } + + FadeImage { + id: wallImg + + anchors.fill: parent + source: Wallpapers.current + preventInit: wallIndicatorLoader.opacity > 0 + fadeOutAnim: Anim.DefaultEffects + fadeInAnim: Anim.SlowEffects + + onSourceChanged: wallLoadDebounceTimer.restart() + + onStatusChanged: { + if (status === Image.Ready) { + wallLoadDebounceTimer.stop(); + wallIndicatorLoader.opacity = 0; + } } } } } - } - ButtonRow { - Layout.alignment: Qt.AlignHCenter - spacing: Tokens.spacing.small + 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: "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 + } } - 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.fillWidth: true + + first: true + text: qsTr("Display wallpaper") + checked: Config.background.wallpaperEnabled + onToggled: GlobalConfig.background.wallpaperEnabled = checked } - } - ToggleRow { - Layout.alignment: Qt.AlignHCenter - implicitWidth: root.cappedWidth + ToggleRow { + Layout.topMargin: Tokens.spacing.extraSmall / 2 - parent.spacing + Layout.fillWidth: true - first: true - text: qsTr("Display wallpaper") - checked: Config.background.wallpaperEnabled - onToggled: GlobalConfig.background.wallpaperEnabled = checked - } + text: qsTr("Transparency") + subtext: qsTr("Base %1, layers %2").arg(Colours.transparency.base).arg(Colours.transparency.layers) + checked: Colours.transparency.enabled + onToggled: GlobalConfig.appearance.transparency.enabled = checked + } - ToggleRow { - Layout.topMargin: Tokens.spacing.extraSmall / 2 - parent.spacing - Layout.alignment: Qt.AlignHCenter - implicitWidth: root.cappedWidth + ToggleRow { + Layout.topMargin: Tokens.spacing.extraSmall / 2 - parent.spacing + Layout.fillWidth: true - text: qsTr("Transparency") - subtext: qsTr("Base %1, layers %2").arg(Colours.transparency.base).arg(Colours.transparency.layers) - checked: Colours.transparency.enabled - onToggled: GlobalConfig.appearance.transparency.enabled = checked - } - - ToggleRow { - Layout.topMargin: Tokens.spacing.extraSmall / 2 - parent.spacing - Layout.alignment: Qt.AlignHCenter - implicitWidth: root.cappedWidth - - last: true - text: qsTr("Dark theme") - checked: !Colours.light - onToggled: Colours.setMode(checked ? "dark" : "light") - } - - Item { - Layout.fillHeight: true + last: true + text: qsTr("Dark theme") + checked: !Colours.light + onToggled: Colours.setMode(checked ? "dark" : "light") + } } }