Compare commits
13 commits
e54696b5c6
...
6df3bd6ff5
| Author | SHA1 | Date | |
|---|---|---|---|
| 6df3bd6ff5 | |||
| 8a9f31aee2 | |||
| d095eb97bc | |||
| 3076734300 | |||
| 6d766892b5 | |||
| c38b32042b | |||
| ae3319b120 | |||
| 8dd3bfbb07 | |||
| 8e25b68355 | |||
| d1e55a47a7 | |||
| 1de58ed486 | |||
| 85f102a2d1 | |||
| 65efc37410 |
12
.reuse/dep5
|
|
@ -13,7 +13,7 @@ License: CC-BY-SA-4.0
|
||||||
|
|
||||||
Files: icons/org.shift.icons/**/*.svg
|
Files: icons/org.shift.icons/**/*.svg
|
||||||
Copyright: 2023 Phosphor Icons
|
Copyright: 2023 Phosphor Icons
|
||||||
2026 Shift contributors
|
2026 Marco Allegretti
|
||||||
License: MIT
|
License: MIT
|
||||||
Comment: SVG glyphs are adapted from Phosphor Icons regular 256px paths for the Shift icon theme.
|
Comment: SVG glyphs are adapted from Phosphor Icons regular 256px paths for the Shift icon theme.
|
||||||
|
|
||||||
|
|
@ -22,3 +22,13 @@ Files: icons/org.shift.icons/index.theme
|
||||||
Copyright: 2026 Marco Allegretti
|
Copyright: 2026 Marco Allegretti
|
||||||
License: EUPL-1.2
|
License: EUPL-1.2
|
||||||
|
|
||||||
|
Files: cursors/shift-cursors/index.theme
|
||||||
|
Copyright: 2026 Marco Allegretti
|
||||||
|
License: EUPL-1.2
|
||||||
|
|
||||||
|
Files: desktoptheme/shift-dark/metadata.json
|
||||||
|
desktoptheme/shift-light/metadata.json
|
||||||
|
kwin/decorations/org.shift.decoration/metadata.json
|
||||||
|
Copyright: 2026 Marco Allegretti
|
||||||
|
License: EUPL-1.2
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -149,8 +149,11 @@ plasma_install_package(${SHIFT_SHELL_PACKAGE_DIR} org.kde.plasma.mobileshell she
|
||||||
|
|
||||||
add_subdirectory(bin)
|
add_subdirectory(bin)
|
||||||
add_subdirectory(color-schemes)
|
add_subdirectory(color-schemes)
|
||||||
|
add_subdirectory(cursors)
|
||||||
|
add_subdirectory(desktoptheme)
|
||||||
add_subdirectory(fonts)
|
add_subdirectory(fonts)
|
||||||
add_subdirectory(icons)
|
add_subdirectory(icons)
|
||||||
|
add_subdirectory(tools/preview-stubs)
|
||||||
add_subdirectory(wallpapers)
|
add_subdirectory(wallpapers)
|
||||||
add_subdirectory(components)
|
add_subdirectory(components)
|
||||||
add_subdirectory(containments)
|
add_subdirectory(containments)
|
||||||
|
|
@ -185,6 +188,13 @@ kde_configure_git_pre_commit_hook(CHECKS CLANG_FORMAT)
|
||||||
|
|
||||||
ki18n_install(po)
|
ki18n_install(po)
|
||||||
|
|
||||||
|
install(CODE "
|
||||||
|
file(GLOB _stale_shift_lookandfeel_catalogs \"\$ENV{DESTDIR}${CMAKE_INSTALL_FULL_DATADIR}/locale/*/LC_MESSAGES/plasma_lookandfeel_org.kde.breeze.mobile.mo\")
|
||||||
|
foreach(_catalog IN LISTS _stale_shift_lookandfeel_catalogs)
|
||||||
|
file(REMOVE \"\${_catalog}\")
|
||||||
|
endforeach()
|
||||||
|
")
|
||||||
|
|
||||||
if (INSTALL_SYSTEMD_SERVICE)
|
if (INSTALL_SYSTEMD_SERVICE)
|
||||||
install(FILES
|
install(FILES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/plasma-mobile.service
|
${CMAKE_CURRENT_SOURCE_DIR}/plasma-mobile.service
|
||||||
|
|
|
||||||
|
|
@ -201,6 +201,7 @@ export WAYLAND_DISPLAY=shift-kwin
|
||||||
export QT_QPA_PLATFORM=wayland
|
export QT_QPA_PLATFORM=wayland
|
||||||
export QT_QPA_PLATFORMTHEME=KDE
|
export QT_QPA_PLATFORMTHEME=KDE
|
||||||
export EGL_PLATFORM=wayland
|
export EGL_PLATFORM=wayland
|
||||||
|
# Shift does not ship a QQC2 style plugin yet, so this remains an explicit runtime dependency.
|
||||||
export QT_QUICK_CONTROLS_STYLE=org.kde.breeze
|
export QT_QUICK_CONTROLS_STYLE=org.kde.breeze
|
||||||
export QT_QUICK_CONTROLS_MOBILE=true
|
export QT_QUICK_CONTROLS_MOBILE=true
|
||||||
export PLASMA_PLATFORM=phone:handset
|
export PLASMA_PLATFORM=phone:handset
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
export QT_QPA_PLATFORMTHEME=KDE
|
export QT_QPA_PLATFORMTHEME=KDE
|
||||||
export EGL_PLATFORM=wayland
|
export EGL_PLATFORM=wayland
|
||||||
|
|
||||||
|
# Shift does not ship a QQC2 style plugin yet, so this remains an explicit runtime dependency.
|
||||||
export QT_QUICK_CONTROLS_STYLE=org.kde.breeze
|
export QT_QUICK_CONTROLS_STYLE=org.kde.breeze
|
||||||
export QT_ENABLE_GLYPH_CACHE_WORKAROUND=1
|
export QT_ENABLE_GLYPH_CACHE_WORKAROUND=1
|
||||||
export QT_QUICK_CONTROLS_MOBILE=true
|
export QT_QUICK_CONTROLS_MOBILE=true
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
# SPDX-FileCopyrightText: 2026 Shift contributors
|
# SPDX-FileCopyrightText: 2026 Marco Allegretti
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
install(FILES
|
install(FILES
|
||||||
ShiftDark.colors
|
ShiftDark.colors
|
||||||
|
|
|
||||||
|
|
@ -141,7 +141,7 @@ ForegroundVisited=155,89,182
|
||||||
|
|
||||||
[General]
|
[General]
|
||||||
ColorScheme=ShiftDark
|
ColorScheme=ShiftDark
|
||||||
Name=Shift Dark
|
Name=SHIFT Dark
|
||||||
shadeSortColumn=true
|
shadeSortColumn=true
|
||||||
|
|
||||||
[KDE]
|
[KDE]
|
||||||
|
|
|
||||||
|
|
@ -140,7 +140,7 @@ ForegroundVisited=155,89,182
|
||||||
|
|
||||||
[General]
|
[General]
|
||||||
ColorScheme=ShiftLight
|
ColorScheme=ShiftLight
|
||||||
Name=Shift Light
|
Name=SHIFT Light
|
||||||
shadeSortColumn=true
|
shadeSortColumn=true
|
||||||
|
|
||||||
[KDE]
|
[KDE]
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,14 @@ Item {
|
||||||
readonly property real maximizedQuickSettingsOffset: contentContainerLoader.maximizedQuickSettingsOffset
|
readonly property real maximizedQuickSettingsOffset: contentContainerLoader.maximizedQuickSettingsOffset
|
||||||
|
|
||||||
readonly property bool swipeAreaMoving: swipeAreaBase.moving || swipeAreaPortrait.moving
|
readonly property bool swipeAreaMoving: swipeAreaBase.moving || swipeAreaPortrait.moving
|
||||||
|
readonly property bool isConvergence: ShellSettings.Settings.convergenceModeEnabled
|
||||||
|
readonly property real convergenceFrameThickness: MobileShell.Constants.convergenceWorkspaceFrameThickness
|
||||||
|
readonly property real convergenceSurfaceTopInset: MobileShell.Constants.topPanelHeight
|
||||||
|
readonly property real convergenceSurfaceBottomInset: MobileShell.Constants.convergenceDockHeight + convergenceFrameThickness
|
||||||
|
readonly property real convergenceSurfaceSideInset: 0
|
||||||
|
readonly property real convergenceSurfaceWidth: Math.max(0, width - convergenceSurfaceSideInset * 2)
|
||||||
|
readonly property real convergenceSurfaceHeight: Math.max(0, height - convergenceSurfaceTopInset - convergenceSurfaceBottomInset)
|
||||||
|
readonly property real convergenceNotificationRightMargin: Math.max(convergenceSurfaceSideInset, width - (convergenceSurfaceSideInset + convergenceSurfaceWidth * 0.5))
|
||||||
|
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
Kirigami.Theme.colorSet: Kirigami.Theme.Complementary
|
||||||
Kirigami.Theme.inherit: false
|
Kirigami.Theme.inherit: false
|
||||||
|
|
@ -109,9 +117,9 @@ Item {
|
||||||
opacity: Math.max(0, Math.min(root.brightnessPressedValue, actionDrawer.offsetResistance / root.minimizedQuickSettingsOffset))
|
opacity: Math.max(0, Math.min(root.brightnessPressedValue, actionDrawer.offsetResistance / root.minimizedQuickSettingsOffset))
|
||||||
|
|
||||||
anchors {
|
anchors {
|
||||||
topMargin: notificationDrawer.height + 1
|
topMargin: notificationDrawer.y + notificationDrawer.height + 1
|
||||||
leftMargin: actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : (notificationDrawer.isConvergence ? Kirigami.Units.smallSpacing : 10)
|
leftMargin: actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : (notificationDrawer.isConvergence ? root.convergenceSurfaceSideInset : 10)
|
||||||
rightMargin: actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : (notificationDrawer.isConvergence ? parent.width * 0.5 : notificationDrawer.notificationWidget.anchors.rightMargin + Kirigami.Units.gridUnit - notificationDrawer.anchors.leftMargin + 370)
|
rightMargin: actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : (notificationDrawer.isConvergence ? root.convergenceNotificationRightMargin : notificationDrawer.notificationWidget.anchors.rightMargin + Kirigami.Units.gridUnit - notificationDrawer.anchors.leftMargin + 370)
|
||||||
top: parent.top
|
top: parent.top
|
||||||
left: parent.left
|
left: parent.left
|
||||||
right: parent.right
|
right: parent.right
|
||||||
|
|
@ -164,7 +172,7 @@ Item {
|
||||||
NotificationDrawer {
|
NotificationDrawer {
|
||||||
id: notificationDrawer
|
id: notificationDrawer
|
||||||
|
|
||||||
readonly property bool isConvergence: ShellSettings.Settings.convergenceModeEnabled
|
readonly property bool isConvergence: root.isConvergence
|
||||||
|
|
||||||
swipeArea: swipeAreaPortrait
|
swipeArea: swipeAreaPortrait
|
||||||
actionDrawer: root.actionDrawer
|
actionDrawer: root.actionDrawer
|
||||||
|
|
@ -179,13 +187,13 @@ Item {
|
||||||
top: parent.top
|
top: parent.top
|
||||||
left: parent.left
|
left: parent.left
|
||||||
right: parent.right
|
right: parent.right
|
||||||
topMargin: isConvergence ? Kirigami.Units.smallSpacing : 0
|
topMargin: isConvergence ? root.convergenceSurfaceTopInset : 0
|
||||||
rightMargin: root.actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : (isConvergence ? parent.width * 0.5 : 360)
|
rightMargin: root.actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : (isConvergence ? root.convergenceNotificationRightMargin : 360)
|
||||||
leftMargin: actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : (isConvergence ? Kirigami.Units.smallSpacing : notificationDrawer.minWidthHeight * 0.06)
|
leftMargin: actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : (isConvergence ? root.convergenceSurfaceSideInset : notificationDrawer.minWidthHeight * 0.06)
|
||||||
}
|
}
|
||||||
|
|
||||||
// In convergence, cap the height so it doesn't stretch full-screen
|
// In convergence, cap the height so it doesn't stretch full-screen
|
||||||
maximumHeight: isConvergence ? root.height * 0.6 : -1
|
maximumHeight: isConvergence ? root.convergenceSurfaceHeight * 0.6 : -1
|
||||||
toolButtonsItem: toolButtons
|
toolButtonsItem: toolButtons
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,13 @@ Item {
|
||||||
|
|
||||||
readonly property real minimizedQuickSettingsOffset: height
|
readonly property real minimizedQuickSettingsOffset: height
|
||||||
readonly property real maximizedQuickSettingsOffset: height
|
readonly property real maximizedQuickSettingsOffset: height
|
||||||
|
readonly property bool isConvergence: ShellSettings.Settings.convergenceModeEnabled
|
||||||
|
readonly property real convergenceFrameThickness: MobileShell.Constants.convergenceWorkspaceFrameThickness
|
||||||
|
readonly property real convergenceSurfaceTopInset: MobileShell.Constants.topPanelHeight
|
||||||
|
readonly property real convergenceSurfaceBottomInset: MobileShell.Constants.convergenceDockHeight + convergenceFrameThickness
|
||||||
|
readonly property real convergenceSurfaceSideInset: 0
|
||||||
|
readonly property real convergenceSurfaceWidth: Math.max(0, width - convergenceSurfaceSideInset * 2)
|
||||||
|
readonly property real convergenceSurfaceHeight: Math.max(0, height - convergenceSurfaceTopInset - convergenceSurfaceBottomInset)
|
||||||
readonly property bool isOnLargeScreen: width > quickSettingsPanel.width * 2.5
|
readonly property bool isOnLargeScreen: width > quickSettingsPanel.width * 2.5
|
||||||
readonly property real minWidthHeight: Math.min(root.width, root.height)
|
readonly property real minWidthHeight: Math.min(root.width, root.height)
|
||||||
readonly property real opacityValue: Math.max(0, Math.min(1, actionDrawer.offsetResistance / root.minimizedQuickSettingsOffset))
|
readonly property real opacityValue: Math.max(0, Math.min(1, actionDrawer.offsetResistance / root.minimizedQuickSettingsOffset))
|
||||||
|
|
@ -44,29 +51,31 @@ Item {
|
||||||
// right sidebar
|
// right sidebar
|
||||||
MobileShell.QuickSettingsPanel {
|
MobileShell.QuickSettingsPanel {
|
||||||
id: quickSettingsPanel
|
id: quickSettingsPanel
|
||||||
height: quickSettingsPanel.contentImplicitHeight + quickSettingsPanel.topPadding + quickSettingsPanel.bottomPadding
|
height: Math.min(quickSettingsPanel.contentImplicitHeight + quickSettingsPanel.topPadding + quickSettingsPanel.bottomPadding, quickSettingsPanel.availableHeight)
|
||||||
width: intendedWidth
|
width: Math.min(intendedWidth, quickSettingsPanel.availableWidth)
|
||||||
|
|
||||||
readonly property real columnWidth: 6 * Kirigami.Units.gridUnit
|
readonly property real columnWidth: 6 * Kirigami.Units.gridUnit
|
||||||
|
readonly property real availableWidth: root.isConvergence ? root.convergenceSurfaceWidth : intendedWidth
|
||||||
|
readonly property real availableHeight: root.isConvergence ? root.convergenceSurfaceHeight : root.height
|
||||||
// In convergence mode, use up to 45% of screen width so more
|
// In convergence mode, use up to 45% of screen width so more
|
||||||
// tiles are visible without pagination.
|
// tiles are visible without pagination.
|
||||||
readonly property int convergenceColumns: Math.min(6, Math.floor(root.width * 0.45 / columnWidth))
|
readonly property int convergenceColumns: Math.min(6, Math.floor(root.width * 0.45 / columnWidth))
|
||||||
readonly property int effectiveColumns: ShellSettings.Settings.convergenceModeEnabled
|
readonly property int effectiveColumns: root.isConvergence
|
||||||
? Math.max(ShellSettings.Settings.quickSettingsColumns, convergenceColumns)
|
? Math.max(ShellSettings.Settings.quickSettingsColumns, convergenceColumns)
|
||||||
: ShellSettings.Settings.quickSettingsColumns
|
: ShellSettings.Settings.quickSettingsColumns
|
||||||
readonly property real intendedWidth: (columnWidth * effectiveColumns) + Kirigami.Units.gridUnit
|
readonly property real intendedWidth: (columnWidth * effectiveColumns) + Kirigami.Units.gridUnit
|
||||||
|
|
||||||
readonly property bool isConvergence: ShellSettings.Settings.convergenceModeEnabled
|
readonly property bool isConvergence: root.isConvergence
|
||||||
property real offsetRatio: (quickSettingsPanel.height + restingTopMargin) / root.height
|
property real offsetRatio: (quickSettingsPanel.height + restingTopMargin) / root.height
|
||||||
readonly property real restingTopMargin: isConvergence ? Kirigami.Units.smallSpacing : 0
|
readonly property real restingTopMargin: root.isConvergence ? root.convergenceSurfaceTopInset : 0
|
||||||
anchors.topMargin: isConvergence ? restingTopMargin : Math.min(root.actionDrawer.offsetResistance * offsetRatio - quickSettingsPanel.height, 0)
|
anchors.topMargin: isConvergence ? restingTopMargin : Math.min(root.actionDrawer.offsetResistance * offsetRatio - quickSettingsPanel.height, 0)
|
||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: isConvergence ? Kirigami.Units.smallSpacing : 0
|
anchors.rightMargin: isConvergence ? root.convergenceSurfaceSideInset : 0
|
||||||
opacity: isConvergence ? Math.max(0, Math.min(1, root.actionDrawer.offset / root.minimizedQuickSettingsOffset)) : 1
|
opacity: isConvergence ? Math.max(0, Math.min(1, root.actionDrawer.offset / root.minimizedQuickSettingsOffset)) : 1
|
||||||
|
|
||||||
actionDrawer: root.actionDrawer
|
actionDrawer: root.actionDrawer
|
||||||
fullScreenHeight: root.height
|
fullScreenHeight: quickSettingsPanel.availableHeight
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -222,18 +222,61 @@ Item {
|
||||||
// Quick settings view
|
// Quick settings view
|
||||||
ColumnLayout {
|
ColumnLayout {
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.minimumHeight: rowCount * rowHeight
|
Layout.minimumHeight: root.isConvergence ? convergenceFlow.implicitHeight : rowCount * rowHeight
|
||||||
|
|
||||||
opacity: brightnessPressedValue
|
opacity: brightnessPressedValue
|
||||||
|
|
||||||
|
Flow {
|
||||||
|
id: convergenceFlow
|
||||||
|
visible: root.isConvergence
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
Layout.preferredHeight: implicitHeight
|
||||||
|
|
||||||
|
spacing: 0
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
model: root.quickSettingsModel
|
||||||
|
delegate: MobileShell.BaseItem {
|
||||||
|
required property var modelData
|
||||||
|
|
||||||
|
readonly property bool __hidden: root.isManagementTile(modelData.settingsCommand)
|
||||||
|
height: __hidden ? 0 : root.rowHeight
|
||||||
|
width: __hidden ? 0 : root.columnWidth
|
||||||
|
visible: !__hidden
|
||||||
|
padding: Kirigami.Units.smallSpacing
|
||||||
|
|
||||||
|
contentItem: QuickSettingsFullDelegate {
|
||||||
|
restrictedPermissions: actionDrawer.restrictedPermissions
|
||||||
|
|
||||||
|
text: modelData.text
|
||||||
|
status: modelData.status
|
||||||
|
icon: modelData.icon
|
||||||
|
enabled: modelData.enabled
|
||||||
|
settingsCommand: modelData.settingsCommand
|
||||||
|
toggleFunction: modelData.toggle
|
||||||
|
|
||||||
|
onCloseRequested: {
|
||||||
|
actionDrawer.close();
|
||||||
|
}
|
||||||
|
onDetailRequested: (pluginId) => {
|
||||||
|
detailPopup.show(pluginId);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
SwipeView {
|
SwipeView {
|
||||||
id: swipeView
|
id: swipeView
|
||||||
// we need to clip this view here to prevent the other quick settings pages from being visible
|
// we need to clip this view here to prevent the other quick settings pages from being visible
|
||||||
// when fullViewProgress is not less then 1 and the base view is no longer being clipped
|
// when fullViewProgress is not less then 1 and the base view is no longer being clipped
|
||||||
clip: true
|
clip: true
|
||||||
|
visible: !root.isConvergence
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
Layout.preferredHeight: rowCount * rowHeight
|
Layout.preferredHeight: visible ? rowCount * rowHeight : 0
|
||||||
|
Layout.maximumHeight: visible ? rowCount * rowHeight : 0
|
||||||
|
|
||||||
Repeater {
|
Repeater {
|
||||||
model: Math.ceil(quickSettingsCount / pageSize)
|
model: Math.ceil(quickSettingsCount / pageSize)
|
||||||
|
|
@ -292,7 +335,7 @@ Item {
|
||||||
// Avoid wasting space when not loaded
|
// Avoid wasting space when not loaded
|
||||||
Layout.maximumHeight: active ? item.implicitHeight : 0
|
Layout.maximumHeight: active ? item.implicitHeight : 0
|
||||||
|
|
||||||
active: swipeView.count > 1 ? true: false
|
active: !root.isConvergence && swipeView.count > 1 ? true: false
|
||||||
asynchronous: true
|
asynchronous: true
|
||||||
|
|
||||||
sourceComponent: PageIndicator {
|
sourceComponent: PageIndicator {
|
||||||
|
|
|
||||||
|
|
@ -33,24 +33,26 @@ MobileShell.BaseItem {
|
||||||
* Implicit height of the contents of the panel.
|
* Implicit height of the contents of the panel.
|
||||||
*/
|
*/
|
||||||
readonly property real contentImplicitHeight: column.implicitHeight
|
readonly property real contentImplicitHeight: column.implicitHeight
|
||||||
|
readonly property bool isConvergence: ShellSettings.Settings.convergenceModeEnabled
|
||||||
|
readonly property real panelPadding: isConvergence ? Kirigami.Units.smallSpacing : Kirigami.Units.smallSpacing * 4
|
||||||
|
|
||||||
property alias quickSettings: quickSettingsProxy.contentItem
|
property alias quickSettings: quickSettingsProxy.contentItem
|
||||||
property alias statusBar: statusBarProxy.contentItem
|
property alias statusBar: statusBarProxy.contentItem
|
||||||
readonly property double brightnessPressedValue: quickSettings.brightnessPressedValue
|
readonly property double brightnessPressedValue: quickSettings.brightnessPressedValue
|
||||||
|
|
||||||
// we need extra padding since the background side border is enabled
|
topPadding: panelPadding
|
||||||
topPadding: Kirigami.Units.smallSpacing * 4
|
leftPadding: panelPadding
|
||||||
leftPadding: Kirigami.Units.smallSpacing * 4
|
rightPadding: panelPadding
|
||||||
rightPadding: Kirigami.Units.smallSpacing * 4
|
bottomPadding: panelPadding
|
||||||
bottomPadding: Kirigami.Units.smallSpacing * 4
|
|
||||||
|
|
||||||
Kirigami.Theme.inherit: false
|
Kirigami.Theme.inherit: false
|
||||||
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
||||||
|
|
||||||
background: MobileShell.PanelBackground {
|
background: MobileShell.PanelBackground {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
anchors.margins: Kirigami.Units.largeSpacing
|
anchors.margins: root.isConvergence ? 0 : Kirigami.Units.largeSpacing
|
||||||
panelType: MobileShell.PanelBackground.PanelType.Base
|
panelType: root.isConvergence ? MobileShell.PanelBackground.PanelType.Flat : MobileShell.PanelBackground.PanelType.Base
|
||||||
|
radius: root.isConvergence ? 0 : Kirigami.Units.cornerRadius
|
||||||
opacity: brightnessPressedValue
|
opacity: brightnessPressedValue
|
||||||
|
|
||||||
Kirigami.Theme.inherit: false
|
Kirigami.Theme.inherit: false
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,8 @@ QtObject {
|
||||||
readonly property real defaultGesturePanelThickness: Kirigami.Units.gridUnit
|
readonly property real defaultGesturePanelThickness: Kirigami.Units.gridUnit
|
||||||
readonly property real convergenceDockHeight: Kirigami.Units.gridUnit * 3
|
readonly property real convergenceDockHeight: Kirigami.Units.gridUnit * 3
|
||||||
readonly property real convergenceDockRevealHeight: Kirigami.Units.gridUnit
|
readonly property real convergenceDockRevealHeight: Kirigami.Units.gridUnit
|
||||||
|
readonly property real convergenceWorkspaceFrameThickness: Math.max(Kirigami.Units.smallSpacing, Math.round(Kirigami.Units.gridUnit * 0.35))
|
||||||
|
readonly property real convergenceWorkspaceFrameRadius: Math.max(Kirigami.Units.cornerRadius * 2, Kirigami.Units.largeSpacing)
|
||||||
|
|
||||||
readonly property real navigationPanelThickness: {
|
readonly property real navigationPanelThickness: {
|
||||||
if (!ShellSettings.Settings.navigationPanelEnabled) {
|
if (!ShellSettings.Settings.navigationPanelEnabled) {
|
||||||
|
|
|
||||||
|
|
@ -5,6 +5,7 @@ import QtQuick
|
||||||
import QtQuick.Window
|
import QtQuick.Window
|
||||||
import QtQuick.Layouts
|
import QtQuick.Layouts
|
||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
|
import QtQuick.Shapes 1.8
|
||||||
import Qt5Compat.GraphicalEffects
|
import Qt5Compat.GraphicalEffects
|
||||||
|
|
||||||
import org.kde.kirigami as Kirigami
|
import org.kde.kirigami as Kirigami
|
||||||
|
|
@ -430,8 +431,14 @@ ContainmentItem {
|
||||||
homeScreen: folioHomeScreen
|
homeScreen: folioHomeScreen
|
||||||
|
|
||||||
readonly property real popupWidth: Math.min(Kirigami.Units.gridUnit * 28, parent.width * 0.5)
|
readonly property real popupWidth: Math.min(Kirigami.Units.gridUnit * 28, parent.width * 0.5)
|
||||||
readonly property real popupHeight: Math.min(Kirigami.Units.gridUnit * 32, parent.height * 0.7)
|
|
||||||
readonly property real dockHeight: MobileShell.Constants.convergenceDockHeight
|
readonly property real dockHeight: MobileShell.Constants.convergenceDockHeight
|
||||||
|
readonly property real popupTopY: MobileShell.Constants.topPanelHeight
|
||||||
|
+ MobileShell.Constants.convergenceWorkspaceFrameThickness
|
||||||
|
+ Kirigami.Units.smallSpacing
|
||||||
|
readonly property real popupBottomY: parent.height
|
||||||
|
- dockHeight
|
||||||
|
- MobileShell.Constants.convergenceWorkspaceFrameThickness
|
||||||
|
readonly property real popupHeight: Math.max(0, popupBottomY - popupTopY)
|
||||||
|
|
||||||
width: popupWidth
|
width: popupWidth
|
||||||
height: popupHeight
|
height: popupHeight
|
||||||
|
|
@ -443,7 +450,7 @@ ContainmentItem {
|
||||||
|
|
||||||
x: Kirigami.Units.smallSpacing
|
x: Kirigami.Units.smallSpacing
|
||||||
y: (opacity > 0)
|
y: (opacity > 0)
|
||||||
? parent.height - dockHeight - popupHeight - Kirigami.Units.smallSpacing + animationY
|
? popupTopY + animationY
|
||||||
: parent.height
|
: parent.height
|
||||||
|
|
||||||
headerHeight: Math.round(Kirigami.Units.gridUnit * 3)
|
headerHeight: Math.round(Kirigami.Units.gridUnit * 3)
|
||||||
|
|
@ -869,6 +876,64 @@ ContainmentItem {
|
||||||
onHomeTriggered: root.homeAction()
|
onHomeTriggered: root.homeAction()
|
||||||
|
|
||||||
contentItem: Item {
|
contentItem: Item {
|
||||||
|
Item {
|
||||||
|
id: workspaceFrame
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: ShellSettings.Settings.convergenceModeEnabled && !ShellSettings.Settings.gamingModeEnabled
|
||||||
|
z: -1
|
||||||
|
|
||||||
|
readonly property real frameThickness: MobileShell.Constants.convergenceWorkspaceFrameThickness
|
||||||
|
readonly property real frameRadius: Math.min(MobileShell.Constants.convergenceWorkspaceFrameRadius, Math.max(0, Math.min(workAreaWidth, workAreaHeight) / 2))
|
||||||
|
readonly property real topReservedHeight: MobileShell.Constants.topPanelHeight
|
||||||
|
readonly property real bottomReservedHeight: MobileShell.Constants.convergenceDockHeight
|
||||||
|
readonly property real workAreaX: frameThickness
|
||||||
|
readonly property real workAreaY: topReservedHeight + frameThickness
|
||||||
|
readonly property real workAreaWidth: Math.max(0, width - frameThickness * 2)
|
||||||
|
readonly property real workAreaHeight: Math.max(0, height - topReservedHeight - bottomReservedHeight - frameThickness * 2)
|
||||||
|
readonly property color frameColor: Kirigami.Theme.backgroundColor
|
||||||
|
readonly property color edgeColor: Qt.rgba(Kirigami.Theme.textColor.r, Kirigami.Theme.textColor.g, Kirigami.Theme.textColor.b, 0.1)
|
||||||
|
|
||||||
|
Kirigami.Theme.inherit: false
|
||||||
|
Kirigami.Theme.colorSet: Kirigami.Theme.Window
|
||||||
|
|
||||||
|
Shape {
|
||||||
|
anchors.fill: parent
|
||||||
|
|
||||||
|
ShapePath {
|
||||||
|
fillColor: workspaceFrame.frameColor
|
||||||
|
fillRule: ShapePath.OddEvenFill
|
||||||
|
strokeWidth: 0
|
||||||
|
|
||||||
|
startX: 0
|
||||||
|
startY: workspaceFrame.topReservedHeight
|
||||||
|
PathLine { x: workspaceFrame.width; y: workspaceFrame.topReservedHeight }
|
||||||
|
PathLine { x: workspaceFrame.width; y: workspaceFrame.height - workspaceFrame.bottomReservedHeight }
|
||||||
|
PathLine { x: 0; y: workspaceFrame.height - workspaceFrame.bottomReservedHeight }
|
||||||
|
PathLine { x: 0; y: workspaceFrame.topReservedHeight }
|
||||||
|
|
||||||
|
PathMove { x: workspaceFrame.workAreaX + workspaceFrame.frameRadius; y: workspaceFrame.workAreaY }
|
||||||
|
PathLine { x: workspaceFrame.workAreaX + workspaceFrame.workAreaWidth - workspaceFrame.frameRadius; y: workspaceFrame.workAreaY }
|
||||||
|
PathArc { x: workspaceFrame.workAreaX + workspaceFrame.workAreaWidth; y: workspaceFrame.workAreaY + workspaceFrame.frameRadius; radiusX: workspaceFrame.frameRadius; radiusY: workspaceFrame.frameRadius }
|
||||||
|
PathLine { x: workspaceFrame.workAreaX + workspaceFrame.workAreaWidth; y: workspaceFrame.workAreaY + workspaceFrame.workAreaHeight - workspaceFrame.frameRadius }
|
||||||
|
PathArc { x: workspaceFrame.workAreaX + workspaceFrame.workAreaWidth - workspaceFrame.frameRadius; y: workspaceFrame.workAreaY + workspaceFrame.workAreaHeight; radiusX: workspaceFrame.frameRadius; radiusY: workspaceFrame.frameRadius }
|
||||||
|
PathLine { x: workspaceFrame.workAreaX + workspaceFrame.frameRadius; y: workspaceFrame.workAreaY + workspaceFrame.workAreaHeight }
|
||||||
|
PathArc { x: workspaceFrame.workAreaX; y: workspaceFrame.workAreaY + workspaceFrame.workAreaHeight - workspaceFrame.frameRadius; radiusX: workspaceFrame.frameRadius; radiusY: workspaceFrame.frameRadius }
|
||||||
|
PathLine { x: workspaceFrame.workAreaX; y: workspaceFrame.workAreaY + workspaceFrame.frameRadius }
|
||||||
|
PathArc { x: workspaceFrame.workAreaX + workspaceFrame.frameRadius; y: workspaceFrame.workAreaY; radiusX: workspaceFrame.frameRadius; radiusY: workspaceFrame.frameRadius }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
x: workspaceFrame.workAreaX
|
||||||
|
y: workspaceFrame.workAreaY
|
||||||
|
width: workspaceFrame.workAreaWidth
|
||||||
|
height: workspaceFrame.workAreaHeight
|
||||||
|
radius: workspaceFrame.frameRadius
|
||||||
|
color: "transparent"
|
||||||
|
border.width: 1
|
||||||
|
border.color: workspaceFrame.edgeColor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// homescreen component
|
// homescreen component
|
||||||
FolioHomeScreen {
|
FolioHomeScreen {
|
||||||
|
|
|
||||||
|
|
@ -76,6 +76,9 @@ ContainmentItem {
|
||||||
}
|
}
|
||||||
|
|
||||||
readonly property real panelHeight: gamingMode ? 0 : MobileShell.Constants.topPanelHeight
|
readonly property real panelHeight: gamingMode ? 0 : MobileShell.Constants.topPanelHeight
|
||||||
|
readonly property real convergenceWorkspaceFrameThickness: ShellSettings.Settings.convergenceModeEnabled && !gamingMode
|
||||||
|
? MobileShell.Constants.convergenceWorkspaceFrameThickness
|
||||||
|
: 0
|
||||||
onPanelHeightChanged: setWindowProperties()
|
onPanelHeightChanged: setWindowProperties()
|
||||||
|
|
||||||
function setWindowProperties() {
|
function setWindowProperties() {
|
||||||
|
|
@ -150,13 +153,13 @@ ContainmentItem {
|
||||||
visible: ShellSettings.Settings.convergenceModeEnabled && !ShellSettings.Settings.gamingModeEnabled
|
visible: ShellSettings.Settings.convergenceModeEnabled && !ShellSettings.Settings.gamingModeEnabled
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
flags: Qt.FramelessWindowHint | Qt.WindowTransparentForInput
|
flags: Qt.FramelessWindowHint | Qt.WindowTransparentForInput
|
||||||
height: Math.max(1, root.panelHeight)
|
height: Math.max(1, root.panelHeight + root.convergenceWorkspaceFrameThickness)
|
||||||
width: 1
|
width: 1
|
||||||
|
|
||||||
LayerShell.Window.scope: "topbar-space"
|
LayerShell.Window.scope: "topbar-space"
|
||||||
LayerShell.Window.layer: LayerShell.Window.LayerBottom
|
LayerShell.Window.layer: LayerShell.Window.LayerBottom
|
||||||
LayerShell.Window.anchors: LayerShell.Window.AnchorTop | LayerShell.Window.AnchorLeft | LayerShell.Window.AnchorRight
|
LayerShell.Window.anchors: LayerShell.Window.AnchorTop | LayerShell.Window.AnchorLeft | LayerShell.Window.AnchorRight
|
||||||
LayerShell.Window.exclusionZone: Math.max(1, root.panelHeight)
|
LayerShell.Window.exclusionZone: Math.max(1, root.panelHeight + root.convergenceWorkspaceFrameThickness)
|
||||||
LayerShell.Window.keyboardInteractivity: LayerShell.Window.KeyboardInteractivityNone
|
LayerShell.Window.keyboardInteractivity: LayerShell.Window.KeyboardInteractivityNone
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,6 +41,9 @@ ContainmentItem {
|
||||||
readonly property bool gamingMode: ShellSettings.Settings.gamingModeEnabled
|
readonly property bool gamingMode: ShellSettings.Settings.gamingModeEnabled
|
||||||
|
|
||||||
readonly property real navigationPanelHeight: gamingMode ? 0 : MobileShell.Constants.navigationPanelThickness
|
readonly property real navigationPanelHeight: gamingMode ? 0 : MobileShell.Constants.navigationPanelThickness
|
||||||
|
readonly property real convergenceWorkspaceFrameThickness: ShellSettings.Settings.convergenceModeEnabled && !gamingMode
|
||||||
|
? MobileShell.Constants.convergenceWorkspaceFrameThickness
|
||||||
|
: 0
|
||||||
onNavigationPanelHeightChanged: setWindowProperties()
|
onNavigationPanelHeightChanged: setWindowProperties()
|
||||||
|
|
||||||
readonly property real intendedWindowThickness: navigationPanelHeight
|
readonly property real intendedWindowThickness: navigationPanelHeight
|
||||||
|
|
@ -166,13 +169,43 @@ ContainmentItem {
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
flags: Qt.FramelessWindowHint | Qt.WindowTransparentForInput
|
flags: Qt.FramelessWindowHint | Qt.WindowTransparentForInput
|
||||||
// height is set by layer-shell anchoring; provide a fallback.
|
// height is set by layer-shell anchoring; provide a fallback.
|
||||||
height: MobileShell.Constants.convergenceDockHeight
|
height: MobileShell.Constants.convergenceDockHeight + root.convergenceWorkspaceFrameThickness
|
||||||
width: 1 // layer-shell stretches it via AnchorLeft|AnchorRight
|
width: 1 // layer-shell stretches it via AnchorLeft|AnchorRight
|
||||||
|
|
||||||
LayerShell.Window.scope: "dock-space"
|
LayerShell.Window.scope: "dock-space"
|
||||||
LayerShell.Window.layer: LayerShell.Window.LayerBottom
|
LayerShell.Window.layer: LayerShell.Window.LayerBottom
|
||||||
LayerShell.Window.anchors: LayerShell.Window.AnchorBottom | LayerShell.Window.AnchorLeft | LayerShell.Window.AnchorRight
|
LayerShell.Window.anchors: LayerShell.Window.AnchorBottom | LayerShell.Window.AnchorLeft | LayerShell.Window.AnchorRight
|
||||||
LayerShell.Window.exclusionZone: MobileShell.Constants.convergenceDockHeight
|
LayerShell.Window.exclusionZone: MobileShell.Constants.convergenceDockHeight + root.convergenceWorkspaceFrameThickness
|
||||||
|
LayerShell.Window.keyboardInteractivity: LayerShell.Window.KeyboardInteractivityNone
|
||||||
|
}
|
||||||
|
|
||||||
|
Window {
|
||||||
|
id: leftWorkspaceFrameReserver
|
||||||
|
visible: root.convergenceWorkspaceFrameThickness > 0
|
||||||
|
color: "transparent"
|
||||||
|
flags: Qt.FramelessWindowHint | Qt.WindowTransparentForInput
|
||||||
|
width: Math.max(1, root.convergenceWorkspaceFrameThickness)
|
||||||
|
height: 1
|
||||||
|
|
||||||
|
LayerShell.Window.scope: "workspace-frame-left"
|
||||||
|
LayerShell.Window.layer: LayerShell.Window.LayerBottom
|
||||||
|
LayerShell.Window.anchors: LayerShell.Window.AnchorLeft | LayerShell.Window.AnchorTop | LayerShell.Window.AnchorBottom
|
||||||
|
LayerShell.Window.exclusionZone: Math.max(1, root.convergenceWorkspaceFrameThickness)
|
||||||
|
LayerShell.Window.keyboardInteractivity: LayerShell.Window.KeyboardInteractivityNone
|
||||||
|
}
|
||||||
|
|
||||||
|
Window {
|
||||||
|
id: rightWorkspaceFrameReserver
|
||||||
|
visible: root.convergenceWorkspaceFrameThickness > 0
|
||||||
|
color: "transparent"
|
||||||
|
flags: Qt.FramelessWindowHint | Qt.WindowTransparentForInput
|
||||||
|
width: Math.max(1, root.convergenceWorkspaceFrameThickness)
|
||||||
|
height: 1
|
||||||
|
|
||||||
|
LayerShell.Window.scope: "workspace-frame-right"
|
||||||
|
LayerShell.Window.layer: LayerShell.Window.LayerBottom
|
||||||
|
LayerShell.Window.anchors: LayerShell.Window.AnchorRight | LayerShell.Window.AnchorTop | LayerShell.Window.AnchorBottom
|
||||||
|
LayerShell.Window.exclusionZone: Math.max(1, root.convergenceWorkspaceFrameThickness)
|
||||||
LayerShell.Window.keyboardInteractivity: LayerShell.Window.KeyboardInteractivityNone
|
LayerShell.Window.keyboardInteractivity: LayerShell.Window.KeyboardInteractivityNone
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
7
cursors/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
# SPDX-FileCopyrightText: 2026 Marco Allegretti
|
||||||
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
install(
|
||||||
|
DIRECTORY shift-cursors
|
||||||
|
DESTINATION ${KDE_INSTALL_ICONDIR}
|
||||||
|
)
|
||||||
4
cursors/shift-cursors/index.theme
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
[Icon Theme]
|
||||||
|
Name=SHIFT
|
||||||
|
Comment=SHIFT cursor theme
|
||||||
|
Inherits=breeze_cursors
|
||||||
19
desktoptheme/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
# SPDX-FileCopyrightText: 2026 Marco Allegretti
|
||||||
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
install(
|
||||||
|
DIRECTORY shift-dark shift-light
|
||||||
|
DESTINATION ${KDE_INSTALL_DATADIR}/plasma/desktoptheme
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES ${CMAKE_SOURCE_DIR}/color-schemes/ShiftDark.colors
|
||||||
|
DESTINATION ${KDE_INSTALL_DATADIR}/plasma/desktoptheme/shift-dark
|
||||||
|
RENAME colors
|
||||||
|
)
|
||||||
|
|
||||||
|
install(
|
||||||
|
FILES ${CMAKE_SOURCE_DIR}/color-schemes/ShiftLight.colors
|
||||||
|
DESTINATION ${KDE_INSTALL_DATADIR}/plasma/desktoptheme/shift-light
|
||||||
|
RENAME colors
|
||||||
|
)
|
||||||
17
desktoptheme/shift-dark/metadata.json
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"KPlugin": {
|
||||||
|
"Authors": [
|
||||||
|
{
|
||||||
|
"Name": "Marco Allegretti"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Category": "",
|
||||||
|
"Description": "SHIFT dark workspace theme",
|
||||||
|
"EnabledByDefault": true,
|
||||||
|
"Id": "shift-dark",
|
||||||
|
"License": "EUPL-1.2",
|
||||||
|
"Name": "SHIFT Dark",
|
||||||
|
"Website": "https://invent.kde.org/marcoa/shift-shell"
|
||||||
|
},
|
||||||
|
"X-Plasma-API": "5.0"
|
||||||
|
}
|
||||||
8
desktoptheme/shift-dark/plasmarc
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
# SPDX-FileCopyrightText: 2026 Marco Allegretti
|
||||||
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
[Settings]
|
||||||
|
FallbackTheme=breeze-dark
|
||||||
|
|
||||||
|
[AdaptiveTransparency]
|
||||||
|
enabled=true
|
||||||
23
desktoptheme/shift-dark/solid/widgets/panel-background.svg
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
<!-- SPDX-FileCopyrightText: 2026 Marco Allegretti -->
|
||||||
|
<!-- SPDX-License-Identifier: EUPL-1.2 -->
|
||||||
|
<svg width="64" height="64" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect id="hint-tile-center" x="0" y="0" width="2" height="2" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="center" x="8" y="8" width="48" height="48" fill="#0e1118"/>
|
||||||
|
<rect id="top" x="8" y="0" width="48" height="8" fill="#0e1118"/>
|
||||||
|
<rect id="bottom" x="8" y="56" width="48" height="8" fill="#0e1118"/>
|
||||||
|
<rect id="left" x="0" y="8" width="8" height="48" fill="#0e1118"/>
|
||||||
|
<rect id="right" x="56" y="8" width="8" height="48" fill="#0e1118"/>
|
||||||
|
<rect id="topleft" x="0" y="0" width="8" height="8" fill="#0e1118"/>
|
||||||
|
<rect id="topright" x="56" y="0" width="8" height="8" fill="#0e1118"/>
|
||||||
|
<rect id="bottomleft" x="0" y="56" width="8" height="8" fill="#0e1118"/>
|
||||||
|
<rect id="bottomright" x="56" y="56" width="8" height="8" fill="#0e1118"/>
|
||||||
|
<rect id="hint-top-margin" x="30" y="0" width="4" height="8" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-bottom-margin" x="30" y="56" width="4" height="8" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-left-margin" x="0" y="30" width="8" height="4" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-right-margin" x="56" y="30" width="8" height="4" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="thick-center" x="12" y="12" width="40" height="40" fill="#0e1118"/>
|
||||||
|
<rect id="thick-hint-top-margin" x="30" y="0" width="4" height="12" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="thick-hint-bottom-margin" x="30" y="52" width="4" height="12" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="thick-hint-left-margin" x="0" y="30" width="12" height="4" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="thick-hint-right-margin" x="52" y="30" width="12" height="4" fill="#2eb8a8" opacity="0"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
22
desktoptheme/shift-dark/widgets/background.svg
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<!-- SPDX-FileCopyrightText: 2026 Marco Allegretti -->
|
||||||
|
<!-- SPDX-License-Identifier: EUPL-1.2 -->
|
||||||
|
<svg width="64" height="64" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect id="hint-tile-center" x="0" y="0" width="2" height="2" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="center" x="8" y="8" width="48" height="48" rx="3" fill="#171c29"/>
|
||||||
|
<rect id="top" x="8" y="0" width="48" height="8" fill="#171c29"/>
|
||||||
|
<rect id="bottom" x="8" y="56" width="48" height="8" fill="#171c29"/>
|
||||||
|
<rect id="left" x="0" y="8" width="8" height="48" fill="#171c29"/>
|
||||||
|
<rect id="right" x="56" y="8" width="8" height="48" fill="#171c29"/>
|
||||||
|
<rect id="topleft" x="0" y="0" width="8" height="8" fill="#171c29"/>
|
||||||
|
<rect id="topright" x="56" y="0" width="8" height="8" fill="#171c29"/>
|
||||||
|
<rect id="bottomleft" x="0" y="56" width="8" height="8" fill="#171c29"/>
|
||||||
|
<rect id="bottomright" x="56" y="56" width="8" height="8" fill="#171c29"/>
|
||||||
|
<rect id="hint-top-margin" x="30" y="0" width="4" height="8" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-bottom-margin" x="30" y="56" width="4" height="8" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-left-margin" x="0" y="30" width="8" height="4" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-right-margin" x="56" y="30" width="8" height="4" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-top-inset" x="30" y="8" width="4" height="1" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-bottom-inset" x="30" y="55" width="4" height="1" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-left-inset" x="8" y="30" width="1" height="4" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-right-inset" x="55" y="30" width="1" height="4" fill="#2eb8a8" opacity="0"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
33
desktoptheme/shift-dark/widgets/panel-background.svg
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
<!-- SPDX-FileCopyrightText: 2026 Marco Allegretti -->
|
||||||
|
<!-- SPDX-License-Identifier: EUPL-1.2 -->
|
||||||
|
<svg width="64" height="64" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<defs>
|
||||||
|
<style id="current-color-scheme" type="text/css">
|
||||||
|
.ColorScheme-Background { color: #0e1118; }
|
||||||
|
.ColorScheme-Highlight { color: #2eb8a8; }
|
||||||
|
</style>
|
||||||
|
</defs>
|
||||||
|
<rect id="hint-tile-center" x="0" y="0" width="2" height="2" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="center" x="8" y="8" width="48" height="48" rx="0" fill="#111622"/>
|
||||||
|
<rect id="top" x="8" y="0" width="48" height="8" fill="#111622"/>
|
||||||
|
<rect id="bottom" x="8" y="56" width="48" height="8" fill="#111622"/>
|
||||||
|
<rect id="left" x="0" y="8" width="8" height="48" fill="#111622"/>
|
||||||
|
<rect id="right" x="56" y="8" width="8" height="48" fill="#111622"/>
|
||||||
|
<rect id="topleft" x="0" y="0" width="8" height="8" fill="#111622"/>
|
||||||
|
<rect id="topright" x="56" y="0" width="8" height="8" fill="#111622"/>
|
||||||
|
<rect id="bottomleft" x="0" y="56" width="8" height="8" fill="#111622"/>
|
||||||
|
<rect id="bottomright" x="56" y="56" width="8" height="8" fill="#111622"/>
|
||||||
|
<rect id="hint-top-margin" x="30" y="0" width="4" height="8" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-bottom-margin" x="30" y="56" width="4" height="8" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-left-margin" x="0" y="30" width="8" height="4" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-right-margin" x="56" y="30" width="8" height="4" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-top-inset" x="30" y="8" width="4" height="1" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-bottom-inset" x="30" y="55" width="4" height="1" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-left-inset" x="8" y="30" width="1" height="4" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-right-inset" x="55" y="30" width="1" height="4" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="thick-center" x="12" y="12" width="40" height="40" fill="#111622"/>
|
||||||
|
<rect id="thick-hint-top-margin" x="30" y="0" width="4" height="12" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="thick-hint-bottom-margin" x="30" y="52" width="4" height="12" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="thick-hint-left-margin" x="0" y="30" width="12" height="4" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="thick-hint-right-margin" x="52" y="30" width="12" height="4" fill="#2eb8a8" opacity="0"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.3 KiB |
18
desktoptheme/shift-dark/widgets/translucentbackground.svg
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<!-- SPDX-FileCopyrightText: 2026 Marco Allegretti -->
|
||||||
|
<!-- SPDX-License-Identifier: EUPL-1.2 -->
|
||||||
|
<svg width="64" height="64" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect id="hint-tile-center" x="0" y="0" width="2" height="2" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="center" x="8" y="8" width="48" height="48" fill="#0e1118" opacity="0.72"/>
|
||||||
|
<rect id="top" x="8" y="0" width="48" height="8" fill="#0e1118" opacity="0.72"/>
|
||||||
|
<rect id="bottom" x="8" y="56" width="48" height="8" fill="#0e1118" opacity="0.72"/>
|
||||||
|
<rect id="left" x="0" y="8" width="8" height="48" fill="#0e1118" opacity="0.72"/>
|
||||||
|
<rect id="right" x="56" y="8" width="8" height="48" fill="#0e1118" opacity="0.72"/>
|
||||||
|
<rect id="topleft" x="0" y="0" width="8" height="8" fill="#0e1118" opacity="0.72"/>
|
||||||
|
<rect id="topright" x="56" y="0" width="8" height="8" fill="#0e1118" opacity="0.72"/>
|
||||||
|
<rect id="bottomleft" x="0" y="56" width="8" height="8" fill="#0e1118" opacity="0.72"/>
|
||||||
|
<rect id="bottomright" x="56" y="56" width="8" height="8" fill="#0e1118" opacity="0.72"/>
|
||||||
|
<rect id="hint-top-margin" x="30" y="0" width="4" height="8" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-bottom-margin" x="30" y="56" width="4" height="8" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-left-margin" x="0" y="30" width="8" height="4" fill="#2eb8a8" opacity="0"/>
|
||||||
|
<rect id="hint-right-margin" x="56" y="30" width="8" height="4" fill="#2eb8a8" opacity="0"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
17
desktoptheme/shift-light/metadata.json
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
{
|
||||||
|
"KPlugin": {
|
||||||
|
"Authors": [
|
||||||
|
{
|
||||||
|
"Name": "Marco Allegretti"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"Category": "",
|
||||||
|
"Description": "SHIFT light workspace theme",
|
||||||
|
"EnabledByDefault": true,
|
||||||
|
"Id": "shift-light",
|
||||||
|
"License": "EUPL-1.2",
|
||||||
|
"Name": "SHIFT Light",
|
||||||
|
"Website": "https://invent.kde.org/marcoa/shift-shell"
|
||||||
|
},
|
||||||
|
"X-Plasma-API": "5.0"
|
||||||
|
}
|
||||||
14
desktoptheme/shift-light/plasmarc
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
# SPDX-FileCopyrightText: 2026 Marco Allegretti
|
||||||
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
[Settings]
|
||||||
|
FallbackTheme=breeze-light
|
||||||
|
|
||||||
|
[ContrastEffect]
|
||||||
|
enabled=true
|
||||||
|
contrast=0.2
|
||||||
|
intensity=2.0
|
||||||
|
saturation=1.7
|
||||||
|
|
||||||
|
[AdaptiveTransparency]
|
||||||
|
enabled=true
|
||||||
23
desktoptheme/shift-light/solid/widgets/panel-background.svg
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
<!-- SPDX-FileCopyrightText: 2026 Marco Allegretti -->
|
||||||
|
<!-- SPDX-License-Identifier: EUPL-1.2 -->
|
||||||
|
<svg width="64" height="64" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect id="hint-tile-center" x="0" y="0" width="2" height="2" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="center" x="8" y="8" width="48" height="48" fill="#ffffff"/>
|
||||||
|
<rect id="top" x="8" y="0" width="48" height="8" fill="#ffffff"/>
|
||||||
|
<rect id="bottom" x="8" y="56" width="48" height="8" fill="#ffffff"/>
|
||||||
|
<rect id="left" x="0" y="8" width="8" height="48" fill="#ffffff"/>
|
||||||
|
<rect id="right" x="56" y="8" width="8" height="48" fill="#ffffff"/>
|
||||||
|
<rect id="topleft" x="0" y="0" width="8" height="8" fill="#ffffff"/>
|
||||||
|
<rect id="topright" x="56" y="0" width="8" height="8" fill="#ffffff"/>
|
||||||
|
<rect id="bottomleft" x="0" y="56" width="8" height="8" fill="#ffffff"/>
|
||||||
|
<rect id="bottomright" x="56" y="56" width="8" height="8" fill="#ffffff"/>
|
||||||
|
<rect id="hint-top-margin" x="30" y="0" width="4" height="8" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-bottom-margin" x="30" y="56" width="4" height="8" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-left-margin" x="0" y="30" width="8" height="4" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-right-margin" x="56" y="30" width="8" height="4" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="thick-center" x="12" y="12" width="40" height="40" fill="#ffffff"/>
|
||||||
|
<rect id="thick-hint-top-margin" x="30" y="0" width="4" height="12" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="thick-hint-bottom-margin" x="30" y="52" width="4" height="12" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="thick-hint-left-margin" x="0" y="30" width="12" height="4" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="thick-hint-right-margin" x="52" y="30" width="12" height="4" fill="#0f766e" opacity="0"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.7 KiB |
22
desktoptheme/shift-light/widgets/background.svg
Normal file
|
|
@ -0,0 +1,22 @@
|
||||||
|
<!-- SPDX-FileCopyrightText: 2026 Marco Allegretti -->
|
||||||
|
<!-- SPDX-License-Identifier: EUPL-1.2 -->
|
||||||
|
<svg width="64" height="64" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect id="hint-tile-center" x="0" y="0" width="2" height="2" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="center" x="8" y="8" width="48" height="48" rx="3" fill="#ffffff"/>
|
||||||
|
<rect id="top" x="8" y="0" width="48" height="8" fill="#ffffff"/>
|
||||||
|
<rect id="bottom" x="8" y="56" width="48" height="8" fill="#ffffff"/>
|
||||||
|
<rect id="left" x="0" y="8" width="8" height="48" fill="#ffffff"/>
|
||||||
|
<rect id="right" x="56" y="8" width="8" height="48" fill="#ffffff"/>
|
||||||
|
<rect id="topleft" x="0" y="0" width="8" height="8" fill="#ffffff"/>
|
||||||
|
<rect id="topright" x="56" y="0" width="8" height="8" fill="#ffffff"/>
|
||||||
|
<rect id="bottomleft" x="0" y="56" width="8" height="8" fill="#ffffff"/>
|
||||||
|
<rect id="bottomright" x="56" y="56" width="8" height="8" fill="#ffffff"/>
|
||||||
|
<rect id="hint-top-margin" x="30" y="0" width="4" height="8" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-bottom-margin" x="30" y="56" width="4" height="8" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-left-margin" x="0" y="30" width="8" height="4" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-right-margin" x="56" y="30" width="8" height="4" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-top-inset" x="30" y="8" width="4" height="1" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-bottom-inset" x="30" y="55" width="4" height="1" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-left-inset" x="8" y="30" width="1" height="4" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-right-inset" x="55" y="30" width="1" height="4" fill="#0f766e" opacity="0"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.6 KiB |
27
desktoptheme/shift-light/widgets/panel-background.svg
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
<!-- SPDX-FileCopyrightText: 2026 Marco Allegretti -->
|
||||||
|
<!-- SPDX-License-Identifier: EUPL-1.2 -->
|
||||||
|
<svg width="64" height="64" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect id="hint-tile-center" x="0" y="0" width="2" height="2" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="center" x="8" y="8" width="48" height="48" fill="#f6f8fb"/>
|
||||||
|
<rect id="top" x="8" y="0" width="48" height="8" fill="#f6f8fb"/>
|
||||||
|
<rect id="bottom" x="8" y="56" width="48" height="8" fill="#f6f8fb"/>
|
||||||
|
<rect id="left" x="0" y="8" width="8" height="48" fill="#f6f8fb"/>
|
||||||
|
<rect id="right" x="56" y="8" width="8" height="48" fill="#f6f8fb"/>
|
||||||
|
<rect id="topleft" x="0" y="0" width="8" height="8" fill="#f6f8fb"/>
|
||||||
|
<rect id="topright" x="56" y="0" width="8" height="8" fill="#f6f8fb"/>
|
||||||
|
<rect id="bottomleft" x="0" y="56" width="8" height="8" fill="#f6f8fb"/>
|
||||||
|
<rect id="bottomright" x="56" y="56" width="8" height="8" fill="#f6f8fb"/>
|
||||||
|
<rect id="hint-top-margin" x="30" y="0" width="4" height="8" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-bottom-margin" x="30" y="56" width="4" height="8" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-left-margin" x="0" y="30" width="8" height="4" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-right-margin" x="56" y="30" width="8" height="4" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-top-inset" x="30" y="8" width="4" height="1" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-bottom-inset" x="30" y="55" width="4" height="1" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-left-inset" x="8" y="30" width="1" height="4" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-right-inset" x="55" y="30" width="1" height="4" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="thick-center" x="12" y="12" width="40" height="40" fill="#f6f8fb"/>
|
||||||
|
<rect id="thick-hint-top-margin" x="30" y="0" width="4" height="12" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="thick-hint-bottom-margin" x="30" y="52" width="4" height="12" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="thick-hint-left-margin" x="0" y="30" width="12" height="4" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="thick-hint-right-margin" x="52" y="30" width="12" height="4" fill="#0f766e" opacity="0"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.1 KiB |
18
desktoptheme/shift-light/widgets/translucentbackground.svg
Normal file
|
|
@ -0,0 +1,18 @@
|
||||||
|
<!-- SPDX-FileCopyrightText: 2026 Marco Allegretti -->
|
||||||
|
<!-- SPDX-License-Identifier: EUPL-1.2 -->
|
||||||
|
<svg width="64" height="64" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||||
|
<rect id="hint-tile-center" x="0" y="0" width="2" height="2" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="center" x="8" y="8" width="48" height="48" fill="#ffffff" opacity="0.78"/>
|
||||||
|
<rect id="top" x="8" y="0" width="48" height="8" fill="#ffffff" opacity="0.78"/>
|
||||||
|
<rect id="bottom" x="8" y="56" width="48" height="8" fill="#ffffff" opacity="0.78"/>
|
||||||
|
<rect id="left" x="0" y="8" width="8" height="48" fill="#ffffff" opacity="0.78"/>
|
||||||
|
<rect id="right" x="56" y="8" width="8" height="48" fill="#ffffff" opacity="0.78"/>
|
||||||
|
<rect id="topleft" x="0" y="0" width="8" height="8" fill="#ffffff" opacity="0.78"/>
|
||||||
|
<rect id="topright" x="56" y="0" width="8" height="8" fill="#ffffff" opacity="0.78"/>
|
||||||
|
<rect id="bottomleft" x="0" y="56" width="8" height="8" fill="#ffffff" opacity="0.78"/>
|
||||||
|
<rect id="bottomright" x="56" y="56" width="8" height="8" fill="#ffffff" opacity="0.78"/>
|
||||||
|
<rect id="hint-top-margin" x="30" y="0" width="4" height="8" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-bottom-margin" x="30" y="56" width="4" height="8" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-left-margin" x="0" y="30" width="8" height="4" fill="#0f766e" opacity="0"/>
|
||||||
|
<rect id="hint-right-margin" x="56" y="30" width="8" height="4" fill="#0f766e" opacity="0"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 1.4 KiB |
|
|
@ -1,5 +1,5 @@
|
||||||
# SPDX-FileCopyrightText: 2026 SHIFT Contributors
|
# SPDX-FileCopyrightText: 2026 Marco Allegretti
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
# Install bundled font files (if any are present) into the system font dir
|
# Install bundled font files (if any are present) into the system font dir
|
||||||
# so the shell session can render the configured default font even on
|
# so the shell session can render the configured default font even on
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<!--
|
<!--
|
||||||
SPDX-FileCopyrightText: 2026 SHIFT Contributors
|
SPDX-FileCopyrightText: 2026 Marco Allegretti
|
||||||
SPDX-License-Identifier: GPL-2.0-or-later
|
SPDX-License-Identifier: EUPL-1.2
|
||||||
-->
|
-->
|
||||||
|
|
||||||
# Shift bundled fonts
|
# Shift bundled fonts
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
dialog-information.svg
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
preferences-desktop-display-randr.svg
|
||||||
|
|
@ -0,0 +1 @@
|
||||||
|
redshift-status-on.svg
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
[Icon Theme]
|
[Icon Theme]
|
||||||
Name=Shift
|
Name=SHIFT
|
||||||
Comment=Shift icon theme
|
Comment=SHIFT icon theme
|
||||||
Inherits=hicolor
|
Inherits=hicolor
|
||||||
Example=folder
|
Example=folder
|
||||||
DisplayDepth=32
|
DisplayDepth=32
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
<!-- SPDX-FileCopyrightText: 2026 Shift contributors -->
|
<!-- SPDX-FileCopyrightText: 2026 Marco Allegretti -->
|
||||||
<!-- SPDX-License-Identifier: GPL-2.0-or-later -->
|
<!-- SPDX-License-Identifier: EUPL-1.2 -->
|
||||||
<svg viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg">
|
<svg viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg">
|
||||||
<!-- top-left circle -->
|
<!-- top-left circle -->
|
||||||
<circle cx="16" cy="16" r="16" fill="#FBFBFB"/>
|
<circle cx="16" cy="16" r="16" fill="#FBFBFB"/>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 509 B After Width: | Height: | Size: 499 B |
|
|
@ -40,9 +40,9 @@ int main(int argc, char *argv[])
|
||||||
QStringLiteral(PLASMA_MOBILE_VERSION_STRING),
|
QStringLiteral(PLASMA_MOBILE_VERSION_STRING),
|
||||||
QStringLiteral(""),
|
QStringLiteral(""),
|
||||||
KAboutLicense::GPL,
|
KAboutLicense::GPL,
|
||||||
i18n("© 2023-2026 Plasma Mobile and SHIFT contributors"));
|
i18n("© 2023-2026 Plasma Mobile contributors and Marco Allegretti"));
|
||||||
aboutData.addAuthor(i18n("Devin Lin"), QString(), QStringLiteral("devin@kde.org"));
|
aboutData.addAuthor(i18n("Devin Lin"), QString(), QStringLiteral("devin@kde.org"));
|
||||||
aboutData.addAuthor(i18n("SHIFT Contributors"));
|
aboutData.addAuthor(i18n("Marco Allegretti"));
|
||||||
aboutData.setBugAddress("https://invent.kde.org/marcoa/shift-shell/-/issues");
|
aboutData.setBugAddress("https://invent.kde.org/marcoa/shift-shell/-/issues");
|
||||||
KAboutData::setApplicationData(aboutData);
|
KAboutData::setApplicationData(aboutData);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,12 @@
|
||||||
"KPlugin": {
|
"KPlugin": {
|
||||||
"Authors": [
|
"Authors": [
|
||||||
{
|
{
|
||||||
"Name": "SHIFT Contributors"
|
"Name": "Marco Allegretti"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Description": "Shift window decoration",
|
"Description": "SHIFT window decoration",
|
||||||
"Id": "org.shift.decoration",
|
"Id": "org.shift.decoration",
|
||||||
"License": "GPL-2.0-or-later",
|
"License": "EUPL-1.2",
|
||||||
"Name": "Shift"
|
"Name": "SHIFT"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ widgetStyle=Breeze
|
||||||
|
|
||||||
[kdeglobals][General]
|
[kdeglobals][General]
|
||||||
ColorScheme=ShiftDark
|
ColorScheme=ShiftDark
|
||||||
Name=Shift Dark
|
Name=SHIFT Dark
|
||||||
font=Atkinson Hyperlegible Next,11,-1,5,400,0,0,0,0,0,0,0,0,0,0,1
|
font=Atkinson Hyperlegible Next,11,-1,5,400,0,0,0,0,0,0,0,0,0,0,1
|
||||||
fixed=Atkinson Hyperlegible Mono,11,-1,5,400,0,0,0,0,0,0,0,0,0,0,1
|
fixed=Atkinson Hyperlegible Mono,11,-1,5,400,0,0,0,0,0,0,0,0,0,0,1
|
||||||
smallestReadableFont=Atkinson Hyperlegible Next,9,-1,5,400,0,0,0,0,0,0,0,0,0,0,1
|
smallestReadableFont=Atkinson Hyperlegible Next,9,-1,5,400,0,0,0,0,0,0,0,0,0,0,1
|
||||||
|
|
@ -24,14 +24,11 @@ Image=SHIFT
|
||||||
|
|
||||||
# Set default cursor theme
|
# Set default cursor theme
|
||||||
[kcminputrc][Mouse]
|
[kcminputrc][Mouse]
|
||||||
cursorTheme=breeze_cursors
|
cursorTheme=shift-cursors
|
||||||
|
|
||||||
[plasmarc][Theme]
|
[plasmarc][Theme]
|
||||||
name=breeze-dark
|
name=shift-dark
|
||||||
|
|
||||||
[kwinrc][org.kde.kdecoration2]
|
[kwinrc][org.kde.kdecoration2]
|
||||||
library=org.kde.kwin.aurorae
|
library=org.kde.kwin.aurorae
|
||||||
theme=org.shift.decoration
|
theme=org.shift.decoration
|
||||||
|
|
||||||
[KSplash]
|
|
||||||
Theme=org.kde.Breeze
|
|
||||||
|
|
|
||||||
|
|
@ -138,7 +138,7 @@ Item {
|
||||||
|
|
||||||
ActionButton {
|
ActionButton {
|
||||||
iconSource: "system-reboot"
|
iconSource: "system-reboot"
|
||||||
text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Restart")
|
text: i18nd("plasma_lookandfeel_org.shift.mobile", "Restart")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
closeAnim.closeToBlack = true;
|
closeAnim.closeToBlack = true;
|
||||||
closeAnim.execute(root.rebootRequested);
|
closeAnim.execute(root.rebootRequested);
|
||||||
|
|
@ -147,7 +147,7 @@ Item {
|
||||||
|
|
||||||
ActionButton {
|
ActionButton {
|
||||||
iconSource: "system-shutdown"
|
iconSource: "system-shutdown"
|
||||||
text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Shut Down")
|
text: i18nd("plasma_lookandfeel_org.shift.mobile", "Shut Down")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
closeAnim.closeToBlack = true;
|
closeAnim.closeToBlack = true;
|
||||||
closeAnim.execute(root.haltRequested);
|
closeAnim.execute(root.haltRequested);
|
||||||
|
|
@ -156,7 +156,7 @@ Item {
|
||||||
|
|
||||||
ActionButton {
|
ActionButton {
|
||||||
iconSource: "system-log-out"
|
iconSource: "system-log-out"
|
||||||
text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Log Out")
|
text: i18nd("plasma_lookandfeel_org.shift.mobile", "Log Out")
|
||||||
visible: ShellSettings.Settings.allowLogout
|
visible: ShellSettings.Settings.allowLogout
|
||||||
onClicked: {
|
onClicked: {
|
||||||
closeAnim.closeToBlack = true;
|
closeAnim.closeToBlack = true;
|
||||||
|
|
@ -172,7 +172,7 @@ Item {
|
||||||
horizontalCenter: parent.horizontalCenter
|
horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
iconSource: "dialog-cancel"
|
iconSource: "dialog-cancel"
|
||||||
text: i18nd("plasma_lookandfeel_org.kde.lookandfeel", "Cancel")
|
text: i18nd("plasma_lookandfeel_org.shift.mobile", "Cancel")
|
||||||
onClicked: {
|
onClicked: {
|
||||||
closeAnim.closeToBlack = false;
|
closeAnim.closeToBlack = false;
|
||||||
closeAnim.execute(root.cancelRequested);
|
closeAnim.execute(root.cancelRequested);
|
||||||
|
|
|
||||||
98
lookandfeel/contents/splash/Splash.qml
Normal file
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
SPDX-FileCopyrightText: 2026 Marco Allegretti
|
||||||
|
|
||||||
|
SPDX-License-Identifier: EUPL-1.2
|
||||||
|
*/
|
||||||
|
|
||||||
|
import QtQuick
|
||||||
|
import org.kde.kirigami as Kirigami
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
color: "#0e0f16"
|
||||||
|
|
||||||
|
property int stage
|
||||||
|
|
||||||
|
readonly property bool busy: stage > 1 && stage < 6
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: content
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: Math.min(parent.width, Kirigami.Units.gridUnit * 24)
|
||||||
|
height: Kirigami.Units.gridUnit * 12
|
||||||
|
opacity: root.stage > 1 ? 1 : 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
OpacityAnimator {
|
||||||
|
duration: Kirigami.Units.veryLongDuration
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: wordmark
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: "SHIFT"
|
||||||
|
color: "#fcfcfc"
|
||||||
|
font.family: "Atkinson Hyperlegible Next"
|
||||||
|
font.pixelSize: Math.round(Kirigami.Units.gridUnit * 3.2)
|
||||||
|
font.weight: Font.DemiBold
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: Math.round(Kirigami.Units.gridUnit * 5)
|
||||||
|
height: Math.max(2, Math.round(Kirigami.Units.devicePixelRatio * 2))
|
||||||
|
radius: height / 2
|
||||||
|
color: "#2eb8a8"
|
||||||
|
anchors.top: wordmark.bottom
|
||||||
|
anchors.topMargin: Kirigami.Units.largeSpacing
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: busyIndicator
|
||||||
|
width: Kirigami.Units.gridUnit * 1.6
|
||||||
|
height: width
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: wordmark.bottom
|
||||||
|
anchors.topMargin: Kirigami.Units.gridUnit * 2.2
|
||||||
|
opacity: root.busy ? 1 : 0
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
OpacityAnimator {
|
||||||
|
duration: Kirigami.Units.longDuration
|
||||||
|
easing.type: Easing.InOutQuad
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
radius: width / 2
|
||||||
|
color: "transparent"
|
||||||
|
border.width: Math.max(2, Math.round(Kirigami.Units.devicePixelRatio * 2))
|
||||||
|
border.color: "#2eb8a8"
|
||||||
|
opacity: 0.28
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
width: parent.width
|
||||||
|
height: Math.max(2, Math.round(Kirigami.Units.devicePixelRatio * 2))
|
||||||
|
radius: height / 2
|
||||||
|
color: "#2eb8a8"
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
anchors.top: parent.top
|
||||||
|
}
|
||||||
|
|
||||||
|
RotationAnimator on rotation {
|
||||||
|
from: 0
|
||||||
|
to: 360
|
||||||
|
duration: 1400
|
||||||
|
loops: Animation.Infinite
|
||||||
|
running: root.busy && Kirigami.Units.longDuration > 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,14 +3,14 @@
|
||||||
"KPlugin": {
|
"KPlugin": {
|
||||||
"Authors": [
|
"Authors": [
|
||||||
{
|
{
|
||||||
"Name": "SHIFT Contributors"
|
"Name": "Marco Allegretti"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Category": "",
|
"Category": "",
|
||||||
"Description": "SHIFT for mobile and convergent devices",
|
"Description": "SHIFT shell appearance for mobile and convergent devices",
|
||||||
"Id": "org.shift.mobile",
|
"Id": "org.shift.mobile",
|
||||||
"License": "GPLv2+",
|
"License": "GPLv2+",
|
||||||
"Name": "SHIFT Mobile"
|
"Name": "SHIFT"
|
||||||
},
|
},
|
||||||
"Keywords": "Phone;Mobile;Desktop;Workspace;Appearance;Look and Feel;Logout;Lock;Suspend;Shutdown;Hibernate;",
|
"Keywords": "Phone;Mobile;Desktop;Workspace;Appearance;Look and Feel;Logout;Lock;Suspend;Shutdown;Hibernate;",
|
||||||
"X-Plasma-APIVersion": "2"
|
"X-Plasma-APIVersion": "2"
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@
|
||||||
<component>
|
<component>
|
||||||
<id>org.shift.mobile</id>
|
<id>org.shift.mobile</id>
|
||||||
<developer id="org.shift">
|
<developer id="org.shift">
|
||||||
<name translate="no">SHIFT Contributors</name>
|
<name translate="no">Marco Allegretti</name>
|
||||||
</developer>
|
</developer>
|
||||||
<metadata_license>CC0-1.0</metadata_license>
|
<metadata_license>CC0-1.0</metadata_license>
|
||||||
<project_license>GPL-2.0-or-later</project_license>
|
<project_license>GPL-2.0-or-later</project_license>
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import org.kde.plasma.private.mobileshell.quicksettingsplugin as QS
|
||||||
|
|
||||||
QS.QuickSetting {
|
QS.QuickSetting {
|
||||||
text: i18n("Docked Mode")
|
text: i18n("Docked Mode")
|
||||||
icon: "preferences-desktop-display-randr"
|
icon: "preferences-desktop-display-randr-symbolic"
|
||||||
enabled: ShellSettings.Settings.convergenceModeEnabled
|
enabled: ShellSettings.Settings.convergenceModeEnabled
|
||||||
|
|
||||||
function toggle() {
|
function toggle() {
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import org.kde.plasma.private.mobileshell.quicksettingsplugin as QS
|
||||||
|
|
||||||
QS.QuickSetting {
|
QS.QuickSetting {
|
||||||
text: i18n("Launch Hint")
|
text: i18n("Launch Hint")
|
||||||
icon: "dialog-information"
|
icon: "dialog-information-symbolic"
|
||||||
status: ShellSettings.Settings.gamingDismissHintEnabled ? i18n("On") : i18n("Off")
|
status: ShellSettings.Settings.gamingDismissHintEnabled ? i18n("On") : i18n("Off")
|
||||||
enabled: true
|
enabled: true
|
||||||
available: ShellSettings.Settings.gamingModeEnabled
|
available: ShellSettings.Settings.gamingModeEnabled
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ QS.QuickSetting {
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
text: i18n("Hotspot")
|
text: i18n("Hotspot")
|
||||||
icon: "network-wireless-hotspot"
|
icon: "network-wireless-hotspot-symbolic"
|
||||||
|
|
||||||
enabled: MobileShell.NetworkInfo.wirelessStatus.hotspotSSID.length !== 0
|
enabled: MobileShell.NetworkInfo.wirelessStatus.hotspotSSID.length !== 0
|
||||||
status: enabled ? MobileShell.NetworkInfo.wirelessStatus.hotspotSSID : ""
|
status: enabled ? MobileShell.NetworkInfo.wirelessStatus.hotspotSSID : ""
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import org.kde.plasma.workspace.keyboardlayout 1.0 as Keyboards
|
||||||
|
|
||||||
QS.QuickSetting {
|
QS.QuickSetting {
|
||||||
text: i18n("Virtual Keyboard")
|
text: i18n("Virtual Keyboard")
|
||||||
icon: "input-keyboard-virtual"
|
icon: "input-keyboard-virtual-symbolic"
|
||||||
status: enabled ? i18n("On") :
|
status: enabled ? i18n("On") :
|
||||||
(Keyboards.KWinVirtualKeyboard.available ? i18n("Off") : i18n("Tap to open settings"))
|
(Keyboards.KWinVirtualKeyboard.available ? i18n("Off") : i18n("Tap to open settings"))
|
||||||
enabled: Keyboards.KWinVirtualKeyboard.enabled && Keyboards.KWinVirtualKeyboard.available
|
enabled: Keyboards.KWinVirtualKeyboard.enabled && Keyboards.KWinVirtualKeyboard.available
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ import org.kde.plasma.private.mobileshell.quicksettingsplugin as QS
|
||||||
|
|
||||||
QS.QuickSetting {
|
QS.QuickSetting {
|
||||||
text: i18n("Night Color")
|
text: i18n("Night Color")
|
||||||
icon: "redshift-status-on"
|
icon: "redshift-status-on-symbolic"
|
||||||
enabled: NightColor.NightColorUtil.enabled
|
enabled: NightColor.NightColorUtil.enabled
|
||||||
status: ""
|
status: ""
|
||||||
settingsCommand: "plasma-open-settings kcm_nightcolor"
|
settingsCommand: "plasma-open-settings kcm_nightcolor"
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
"Name": "Devin Lin"
|
"Name": "Devin Lin"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"Name": "SHIFT Contributors"
|
"Name": "Marco Allegretti"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"Category": "",
|
"Category": "",
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,16 @@ if(BASH_EXECUTABLE)
|
||||||
COMMAND ${BASH_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/check-shift-product-metadata.sh
|
COMMAND ${BASH_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/check-shift-product-metadata.sh
|
||||||
)
|
)
|
||||||
|
|
||||||
|
add_test(
|
||||||
|
NAME shift-theme-identity
|
||||||
|
COMMAND ${BASH_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/check-shift-theme-identity.sh
|
||||||
|
)
|
||||||
|
|
||||||
|
add_test(
|
||||||
|
NAME shift-preview-qml-stubs
|
||||||
|
COMMAND ${BASH_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/check-preview-qml-stubs.sh
|
||||||
|
)
|
||||||
|
|
||||||
add_test(
|
add_test(
|
||||||
NAME shift-initialstart-metadata
|
NAME shift-initialstart-metadata
|
||||||
COMMAND ${BASH_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/check-shift-initialstart-metadata.sh
|
COMMAND ${BASH_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/check-shift-initialstart-metadata.sh
|
||||||
|
|
|
||||||
|
|
@ -7,15 +7,20 @@ set -euo pipefail
|
||||||
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
repo_root="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
|
||||||
constants="$repo_root/components/mobileshell/qml/components/Constants.qml"
|
constants="$repo_root/components/mobileshell/qml/components/Constants.qml"
|
||||||
|
panel="$repo_root/containments/panel/qml/main.qml"
|
||||||
taskpanel="$repo_root/containments/taskpanel/qml/main.qml"
|
taskpanel="$repo_root/containments/taskpanel/qml/main.qml"
|
||||||
folio_main="$repo_root/containments/homescreens/folio/qml/main.qml"
|
folio_main="$repo_root/containments/homescreens/folio/qml/main.qml"
|
||||||
folio_home="$repo_root/containments/homescreens/folio/qml/FolioHomeScreen.qml"
|
folio_home="$repo_root/containments/homescreens/folio/qml/FolioHomeScreen.qml"
|
||||||
|
action_content="$repo_root/components/mobileshell/qml/actiondrawer/private/ContentContainer.qml"
|
||||||
|
action_landscape="$repo_root/components/mobileshell/qml/actiondrawer/private/LandscapeContentContainer.qml"
|
||||||
|
quick_settings="$repo_root/components/mobileshell/qml/actiondrawer/private/QuickSettings.qml"
|
||||||
|
quick_settings_panel="$repo_root/components/mobileshell/qml/actiondrawer/private/QuickSettingsPanel.qml"
|
||||||
|
|
||||||
require_line() {
|
require_line() {
|
||||||
local file="$1"
|
local file="$1"
|
||||||
local needle="$2"
|
local needle="$2"
|
||||||
|
|
||||||
if ! grep -Fq "$needle" "$file"; then
|
if ! grep -Fq -- "$needle" "$file"; then
|
||||||
echo "Missing invariant in ${file#$repo_root/}: $needle" >&2
|
echo "Missing invariant in ${file#$repo_root/}: $needle" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
@ -23,15 +28,75 @@ require_line() {
|
||||||
|
|
||||||
require_line "$constants" "readonly property real convergenceDockHeight: Kirigami.Units.gridUnit * 3"
|
require_line "$constants" "readonly property real convergenceDockHeight: Kirigami.Units.gridUnit * 3"
|
||||||
require_line "$constants" "readonly property real convergenceDockRevealHeight: Kirigami.Units.gridUnit"
|
require_line "$constants" "readonly property real convergenceDockRevealHeight: Kirigami.Units.gridUnit"
|
||||||
|
require_line "$constants" "readonly property real convergenceWorkspaceFrameThickness:"
|
||||||
|
require_line "$constants" "readonly property real convergenceWorkspaceFrameRadius:"
|
||||||
|
|
||||||
require_line "$taskpanel" "height: MobileShell.Constants.convergenceDockHeight"
|
require_line "$panel" "readonly property real convergenceWorkspaceFrameThickness:"
|
||||||
require_line "$taskpanel" "LayerShell.Window.exclusionZone: MobileShell.Constants.convergenceDockHeight"
|
require_line "$panel" "height: Math.max(1, root.panelHeight + root.convergenceWorkspaceFrameThickness)"
|
||||||
|
require_line "$panel" "LayerShell.Window.exclusionZone: Math.max(1, root.panelHeight + root.convergenceWorkspaceFrameThickness)"
|
||||||
|
|
||||||
|
require_line "$taskpanel" "readonly property real convergenceWorkspaceFrameThickness:"
|
||||||
|
require_line "$taskpanel" "height: MobileShell.Constants.convergenceDockHeight + root.convergenceWorkspaceFrameThickness"
|
||||||
|
require_line "$taskpanel" "LayerShell.Window.exclusionZone: MobileShell.Constants.convergenceDockHeight + root.convergenceWorkspaceFrameThickness"
|
||||||
|
require_line "$taskpanel" "LayerShell.Window.scope: \"workspace-frame-left\""
|
||||||
|
require_line "$taskpanel" "LayerShell.Window.scope: \"workspace-frame-right\""
|
||||||
|
|
||||||
require_line "$folio_main" "height: MobileShell.Constants.convergenceDockHeight"
|
require_line "$folio_main" "height: MobileShell.Constants.convergenceDockHeight"
|
||||||
require_line "$folio_main" "readonly property real dockHeight: MobileShell.Constants.convergenceDockHeight"
|
require_line "$folio_main" "readonly property real dockHeight: MobileShell.Constants.convergenceDockHeight"
|
||||||
require_line "$folio_main" "readonly property real revealStripHeight: MobileShell.Constants.convergenceDockRevealHeight"
|
require_line "$folio_main" "readonly property real revealStripHeight: MobileShell.Constants.convergenceDockRevealHeight"
|
||||||
|
require_line "$folio_main" "import QtQuick.Shapes 1.8"
|
||||||
|
require_line "$folio_main" "id: workspaceFrame"
|
||||||
|
require_line "$folio_main" "readonly property real frameThickness: MobileShell.Constants.convergenceWorkspaceFrameThickness"
|
||||||
|
require_line "$folio_main" "readonly property real frameRadius:"
|
||||||
|
require_line "$folio_main" "readonly property real workAreaX: frameThickness"
|
||||||
|
require_line "$folio_main" "readonly property real workAreaY: topReservedHeight + frameThickness"
|
||||||
|
require_line "$folio_main" "readonly property real workAreaWidth: Math.max(0, width - frameThickness * 2)"
|
||||||
|
require_line "$folio_main" "readonly property real workAreaHeight: Math.max(0, height - topReservedHeight - bottomReservedHeight - frameThickness * 2)"
|
||||||
|
require_line "$folio_main" "fillRule: ShapePath.OddEvenFill"
|
||||||
|
require_line "$folio_main" "readonly property real popupTopY: MobileShell.Constants.topPanelHeight"
|
||||||
|
require_line "$folio_main" "+ MobileShell.Constants.convergenceWorkspaceFrameThickness"
|
||||||
|
require_line "$folio_main" "readonly property real popupBottomY: parent.height"
|
||||||
|
require_line "$folio_main" "- MobileShell.Constants.convergenceWorkspaceFrameThickness"
|
||||||
|
require_line "$folio_main" "readonly property real popupHeight: Math.max(0, popupBottomY - popupTopY)"
|
||||||
|
require_line "$folio_main" "? popupTopY + animationY"
|
||||||
require_line "$folio_home" "height: ShellSettings.Settings.convergenceModeEnabled ? MobileShell.Constants.convergenceDockHeight : Kirigami.Units.gridUnit * 6"
|
require_line "$folio_home" "height: ShellSettings.Settings.convergenceModeEnabled ? MobileShell.Constants.convergenceDockHeight : Kirigami.Units.gridUnit * 6"
|
||||||
|
|
||||||
|
require_line "$action_content" "readonly property real convergenceSurfaceTopInset: MobileShell.Constants.topPanelHeight"
|
||||||
|
require_line "$action_content" "readonly property real convergenceSurfaceBottomInset: MobileShell.Constants.convergenceDockHeight + convergenceFrameThickness"
|
||||||
|
require_line "$action_content" "readonly property real convergenceSurfaceSideInset: 0"
|
||||||
|
require_line "$action_content" "topMargin: isConvergence ? root.convergenceSurfaceTopInset : 0"
|
||||||
|
require_line "$action_content" "leftMargin: actionDrawer.mode == MobileShell.ActionDrawer.Portrait ? 0 : (isConvergence ? root.convergenceSurfaceSideInset"
|
||||||
|
require_line "$action_content" "maximumHeight: isConvergence ? root.convergenceSurfaceHeight * 0.6 : -1"
|
||||||
|
|
||||||
|
require_line "$action_landscape" "readonly property real convergenceSurfaceTopInset: MobileShell.Constants.topPanelHeight"
|
||||||
|
require_line "$action_landscape" "readonly property real convergenceSurfaceBottomInset: MobileShell.Constants.convergenceDockHeight + convergenceFrameThickness"
|
||||||
|
require_line "$action_landscape" "readonly property real convergenceSurfaceSideInset: 0"
|
||||||
|
require_line "$action_landscape" "anchors.topMargin: isConvergence ? restingTopMargin"
|
||||||
|
require_line "$action_landscape" "anchors.rightMargin: isConvergence ? root.convergenceSurfaceSideInset : 0"
|
||||||
|
require_line "$action_landscape" "fullScreenHeight: quickSettingsPanel.availableHeight"
|
||||||
|
|
||||||
|
require_line "$quick_settings_panel" "readonly property bool isConvergence: ShellSettings.Settings.convergenceModeEnabled"
|
||||||
|
require_line "$quick_settings_panel" "readonly property real panelPadding: isConvergence ? Kirigami.Units.smallSpacing : Kirigami.Units.smallSpacing * 4"
|
||||||
|
require_line "$quick_settings_panel" "anchors.margins: root.isConvergence ? 0 : Kirigami.Units.largeSpacing"
|
||||||
|
require_line "$quick_settings_panel" "panelType: root.isConvergence ? MobileShell.PanelBackground.PanelType.Flat : MobileShell.PanelBackground.PanelType.Base"
|
||||||
|
require_line "$quick_settings_panel" "radius: root.isConvergence ? 0 : Kirigami.Units.cornerRadius"
|
||||||
|
|
||||||
|
require_line "$quick_settings" "id: convergenceFlow"
|
||||||
|
require_line "$quick_settings" "visible: root.isConvergence"
|
||||||
|
require_line "$quick_settings" "visible: !root.isConvergence"
|
||||||
|
require_line "$quick_settings" "active: !root.isConvergence && swipeView.count > 1 ? true: false"
|
||||||
|
|
||||||
|
frame_arc_count="$(grep -F "PathArc {" "$folio_main" | wc -l)"
|
||||||
|
if [[ "$frame_arc_count" -ne 4 ]]; then
|
||||||
|
echo "Expected the workspace frame cutout to have four rounded inner corners; found $frame_arc_count arcs" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if grep -Fq "convergenceWallpaperLayer" "$folio_main"; then
|
||||||
|
echo "Do not replace the real wallpaper with a custom convergence wallpaper layer" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
dock_offset_transforms="$(grep -F "transform: Translate { y: dockOverlay.dockOffset }" "$folio_main" | wc -l)"
|
dock_offset_transforms="$(grep -F "transform: Translate { y: dockOverlay.dockOffset }" "$folio_main" | wc -l)"
|
||||||
if [[ "$dock_offset_transforms" -ne 1 ]]; then
|
if [[ "$dock_offset_transforms" -ne 1 ]]; then
|
||||||
echo "Expected only dock contents to slide with dockOverlay.dockOffset; found $dock_offset_transforms transforms" >&2
|
echo "Expected only dock contents to slide with dockOverlay.dockOffset; found $dock_offset_transforms transforms" >&2
|
||||||
|
|
|
||||||
44
tests/check-preview-qml-stubs.sh
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# SPDX-FileCopyrightText: 2026 Marco Allegretti
|
||||||
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
cd "$repo_dir"
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
printf '%s\n' "$1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
[[ -f tools/preview-stubs/CMakeLists.txt ]] || fail "preview QML stubs must have tracked CMake integration"
|
||||||
|
grep -Fq 'set(SHIFT_INSTALL_PREVIEW_QML_STUBS "AUTO"' tools/preview-stubs/CMakeLists.txt \
|
||||||
|
|| fail "preview QML stubs must default to AUTO, not unconditional installation"
|
||||||
|
grep -Fq 'PROPERTY STRINGS AUTO ON OFF' tools/preview-stubs/CMakeLists.txt \
|
||||||
|
|| fail "preview QML stubs must provide an explicit OFF mode"
|
||||||
|
grep -Fq 'CMAKE_INSTALL_PREFIX MATCHES "/\\.prefix$"' tools/preview-stubs/CMakeLists.txt \
|
||||||
|
|| fail "preview QML stubs must be limited to local .prefix installs by default"
|
||||||
|
grep -Eq 'DESTINATION \$\{KDE_INSTALL_QMLDIR\}' tools/preview-stubs/CMakeLists.txt \
|
||||||
|
|| fail "preview QML stubs must install into the Qt QML import tree"
|
||||||
|
|
||||||
|
while IFS= read -r -d '' qmldir; do
|
||||||
|
module_dir="$(dirname "$qmldir")"
|
||||||
|
while IFS= read -r line; do
|
||||||
|
line="${line%%#*}"
|
||||||
|
[[ -n "${line//[[:space:]]/}" ]] || continue
|
||||||
|
|
||||||
|
case "$line" in
|
||||||
|
module\ *|plugin\ *|classname\ *|typeinfo\ *|depends\ *|prefer\ *)
|
||||||
|
continue
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
set -- $line
|
||||||
|
qml_file="${3:-}"
|
||||||
|
[[ -n "$qml_file" ]] || continue
|
||||||
|
[[ -f "$module_dir/$qml_file" ]] || fail "$qmldir declares missing file: $qml_file"
|
||||||
|
done < "$qmldir"
|
||||||
|
done < <(find tools/preview-stubs/qml -name qmldir -print0)
|
||||||
|
|
||||||
|
printf 'preview-qml-stubs-ok\n'
|
||||||
|
|
@ -256,3 +256,28 @@ if [[ -s "$missing_icons" ]]; then
|
||||||
sed 's/^/ - /' "$missing_icons" >&2
|
sed 's/^/ - /' "$missing_icons" >&2
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Quick-setting tiles render with Kirigami.Icon { isMask: true }; if their icon
|
||||||
|
# name resolves to a colored preferences/scalable tile it collapses to a solid
|
||||||
|
# rounded square. Require an explicit -symbolic suffix for any quick-setting
|
||||||
|
# icon name that also exists as a colored tile.
|
||||||
|
masked_collisions="$(mktemp)"
|
||||||
|
trap 'rm -f "$required_icons" "$missing_icons" "$broken_icons" "$plasma_files" "$masked_collisions"' EXIT
|
||||||
|
|
||||||
|
while IFS= read -r -d '' qml; do
|
||||||
|
perl -ne 'if (/^\s*icon:\s*"([^"]+)"\s*$/) { print "$1\n"; }' "$qml"
|
||||||
|
done < <(find quicksettings -name 'main.qml' -print0) \
|
||||||
|
| sort -u \
|
||||||
|
| while IFS= read -r icon_name; do
|
||||||
|
case "$icon_name" in
|
||||||
|
*-symbolic) continue ;;
|
||||||
|
esac
|
||||||
|
[[ -e "$theme_dir/preferences/scalable/$icon_name.svg" ]] || continue
|
||||||
|
printf '%s\n' "$icon_name"
|
||||||
|
done > "$masked_collisions"
|
||||||
|
|
||||||
|
if [[ -s "$masked_collisions" ]]; then
|
||||||
|
printf 'Quick-setting icon names must use a -symbolic suffix when a colored preferences/scalable tile exists, otherwise the masked tile renders as a solid square:\n' >&2
|
||||||
|
sed 's/^/ - /' "$masked_collisions" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
188
tests/check-shift-theme-identity.sh
Normal file
|
|
@ -0,0 +1,188 @@
|
||||||
|
#!/usr/bin/env bash
|
||||||
|
# SPDX-FileCopyrightText: 2026 Marco Allegretti
|
||||||
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||||
|
cd "$repo_dir"
|
||||||
|
|
||||||
|
fail() {
|
||||||
|
printf '%s\n' "$1" >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
require_line() {
|
||||||
|
local file="$1"
|
||||||
|
local pattern="$2"
|
||||||
|
local message="$3"
|
||||||
|
|
||||||
|
grep -Eq "$pattern" "$file" || fail "$message"
|
||||||
|
}
|
||||||
|
|
||||||
|
reject_line() {
|
||||||
|
local file="$1"
|
||||||
|
local pattern="$2"
|
||||||
|
local message="$3"
|
||||||
|
|
||||||
|
! grep -Eq "$pattern" "$file" || fail "$message"
|
||||||
|
}
|
||||||
|
|
||||||
|
readonly spdx_copyright_tag='SPDX-FileCopyrightText'
|
||||||
|
readonly spdx_license_tag='SPDX-License-Identifier'
|
||||||
|
readonly shift_copyright_pattern="${spdx_copyright_tag}: 2026 Marco Allegretti"
|
||||||
|
readonly shift_license_pattern="${spdx_license_tag}: EUPL-1[.]2"
|
||||||
|
|
||||||
|
require_line CMakeLists.txt '^add_subdirectory\(cursors\)$' \
|
||||||
|
"top-level build must install the Shift cursor theme"
|
||||||
|
require_line CMakeLists.txt '^add_subdirectory\(desktoptheme\)$' \
|
||||||
|
"top-level build must install the Shift Plasma desktop themes"
|
||||||
|
|
||||||
|
require_line lookandfeel/metadata.json '"Id": "org\.shift\.mobile"' \
|
||||||
|
"look-and-feel id must remain org.shift.mobile"
|
||||||
|
require_line lookandfeel/metadata.json '"Name": "SHIFT"' \
|
||||||
|
"look-and-feel visible name must be SHIFT"
|
||||||
|
|
||||||
|
require_line color-schemes/ShiftDark.colors '^ColorScheme=ShiftDark$' \
|
||||||
|
"dark color scheme id must remain ShiftDark"
|
||||||
|
require_line color-schemes/ShiftDark.colors '^Name=SHIFT Dark$' \
|
||||||
|
"dark color scheme visible name must be SHIFT Dark"
|
||||||
|
require_line color-schemes/ShiftLight.colors '^ColorScheme=ShiftLight$' \
|
||||||
|
"light color scheme id must remain ShiftLight"
|
||||||
|
require_line color-schemes/ShiftLight.colors '^Name=SHIFT Light$' \
|
||||||
|
"light color scheme visible name must be SHIFT Light"
|
||||||
|
|
||||||
|
require_line icons/org.shift.icons/index.theme '^Name=SHIFT$' \
|
||||||
|
"icon theme visible name must be SHIFT"
|
||||||
|
require_line kwin/decorations/org.shift.decoration/metadata.json '"Name": "SHIFT"' \
|
||||||
|
"window decoration visible name must be SHIFT"
|
||||||
|
require_line wallpapers/SHIFT/metadata.json '"Name": "SHIFT"' \
|
||||||
|
"wallpaper visible name must be SHIFT"
|
||||||
|
|
||||||
|
require_line desktoptheme/shift-dark/metadata.json '"Id": "shift-dark"' \
|
||||||
|
"dark Plasma desktop theme id must be shift-dark"
|
||||||
|
require_line desktoptheme/shift-dark/metadata.json '"Name": "SHIFT Dark"' \
|
||||||
|
"dark Plasma desktop theme visible name must be SHIFT Dark"
|
||||||
|
require_line desktoptheme/shift-light/metadata.json '"Id": "shift-light"' \
|
||||||
|
"light Plasma desktop theme id must be shift-light"
|
||||||
|
require_line desktoptheme/shift-light/metadata.json '"Name": "SHIFT Light"' \
|
||||||
|
"light Plasma desktop theme visible name must be SHIFT Light"
|
||||||
|
require_line cursors/shift-cursors/index.theme '^Name=SHIFT$' \
|
||||||
|
"cursor theme visible name must be SHIFT"
|
||||||
|
|
||||||
|
for desktop_asset in \
|
||||||
|
desktoptheme/shift-dark/widgets/panel-background.svg \
|
||||||
|
desktoptheme/shift-dark/solid/widgets/panel-background.svg \
|
||||||
|
desktoptheme/shift-dark/widgets/background.svg \
|
||||||
|
desktoptheme/shift-dark/widgets/translucentbackground.svg \
|
||||||
|
desktoptheme/shift-light/widgets/panel-background.svg \
|
||||||
|
desktoptheme/shift-light/solid/widgets/panel-background.svg \
|
||||||
|
desktoptheme/shift-light/widgets/background.svg \
|
||||||
|
desktoptheme/shift-light/widgets/translucentbackground.svg; do
|
||||||
|
[[ -f "$desktop_asset" ]] || fail "Shift desktop theme must provide $desktop_asset"
|
||||||
|
require_line "$desktop_asset" "$shift_copyright_pattern" \
|
||||||
|
"$desktop_asset must attribute Shift-owned work to Marco Allegretti"
|
||||||
|
require_line "$desktop_asset" "$shift_license_pattern" \
|
||||||
|
"$desktop_asset must use EUPL-1.2"
|
||||||
|
done
|
||||||
|
|
||||||
|
require_line lookandfeel/contents/defaults '^ColorScheme=ShiftDark$' \
|
||||||
|
"look-and-feel defaults must select ShiftDark"
|
||||||
|
require_line lookandfeel/contents/defaults '^Theme=org\.shift\.icons$' \
|
||||||
|
"look-and-feel defaults must select org.shift.icons"
|
||||||
|
require_line lookandfeel/contents/defaults '^cursorTheme=shift-cursors$' \
|
||||||
|
"look-and-feel defaults must select shift-cursors"
|
||||||
|
require_line lookandfeel/contents/defaults '^name=shift-dark$' \
|
||||||
|
"look-and-feel defaults must select the Shift dark Plasma desktop theme"
|
||||||
|
require_line lookandfeel/contents/defaults '^theme=org\.shift\.decoration$' \
|
||||||
|
"look-and-feel defaults must select org.shift.decoration"
|
||||||
|
require_line lookandfeel/contents/defaults '^widgetStyle=Breeze$' \
|
||||||
|
"look-and-feel defaults must keep Breeze widget style until Shift ships a QQC2 style"
|
||||||
|
reject_line lookandfeel/contents/defaults 'breeze-dark|breeze-light|breeze_cursors|org\.kde\.Breeze' \
|
||||||
|
"look-and-feel defaults must not select Breeze desktop, cursor, or splash themes"
|
||||||
|
reject_line lookandfeel/contents/defaults 'widgetStyle=Shift|widgetStyle=SHIFT|widgetStyle=org\.shift' \
|
||||||
|
"look-and-feel defaults must not reference a non-existent Shift widget style"
|
||||||
|
|
||||||
|
[[ -f lookandfeel/contents/splash/Splash.qml ]] || fail "look-and-feel must provide a Shift splash implementation"
|
||||||
|
reject_line lookandfeel/contents/logout/Logout.qml 'plasma_lookandfeel_org\.kde\.lookandfeel' \
|
||||||
|
"look-and-feel QML must use the Shift translation domain"
|
||||||
|
require_line lookandfeel/contents/logout/Logout.qml 'plasma_lookandfeel_org\.shift\.mobile' \
|
||||||
|
"look-and-feel logout QML must use plasma_lookandfeel_org.shift.mobile"
|
||||||
|
require_line lookandfeel/Messages.sh 'plasma_lookandfeel_org\.shift\.mobile\.pot' \
|
||||||
|
"look-and-feel Messages.sh must generate the Shift translation domain"
|
||||||
|
|
||||||
|
require_line preview.sh 'PLASMA_THEME=shift-light' \
|
||||||
|
"preview light mode must select the Shift light Plasma desktop theme"
|
||||||
|
require_line preview.sh 'PLASMA_THEME=shift-dark' \
|
||||||
|
"preview dark mode must select the Shift dark Plasma desktop theme"
|
||||||
|
reject_line preview.sh 'PLASMA_THEME=breeze-' \
|
||||||
|
"preview must not select Breeze Plasma desktop themes"
|
||||||
|
require_line preview.sh 'Shift does not ship a QQC2 style plugin yet' \
|
||||||
|
"preview must document the Breeze QQC2 fallback"
|
||||||
|
require_line bin/startplasmamobile.in 'Shift does not ship a QQC2 style plugin yet' \
|
||||||
|
"runtime launcher must document the Breeze QQC2 fallback"
|
||||||
|
require_line HACKING.md 'Shift does not ship a QQC2 style plugin yet' \
|
||||||
|
"HACKING.md must document the Breeze QQC2 fallback"
|
||||||
|
require_line .kde-ci.yml 'plasma/qqc2-breeze-style' \
|
||||||
|
"CI must keep the Breeze QQC2 runtime dependency until Shift ships a QQC2 style"
|
||||||
|
reject_line preview.sh 'QT_QUICK_CONTROLS_STYLE=org\.shift|QT_QUICK_CONTROLS_STYLE=SHIFT|QT_QUICK_CONTROLS_STYLE=Shift' \
|
||||||
|
"preview must not reference a non-existent Shift QQC2 style"
|
||||||
|
reject_line bin/startplasmamobile.in 'QT_QUICK_CONTROLS_STYLE=org\.shift|QT_QUICK_CONTROLS_STYLE=SHIFT|QT_QUICK_CONTROLS_STYLE=Shift' \
|
||||||
|
"runtime launcher must not reference a non-existent Shift QQC2 style"
|
||||||
|
|
||||||
|
generic_attribution_pattern='Shift contributor[s]|SHIFT Contributor[s]'
|
||||||
|
|
||||||
|
if grep -RInE "$generic_attribution_pattern" \
|
||||||
|
.reuse \
|
||||||
|
color-schemes/CMakeLists.txt \
|
||||||
|
cursors \
|
||||||
|
desktoptheme \
|
||||||
|
fonts/CMakeLists.txt \
|
||||||
|
fonts/README.md \
|
||||||
|
icons/sc-places-start-here-shift.svg \
|
||||||
|
kwin/decorations/org.shift.decoration/metadata.json \
|
||||||
|
lookandfeel/contents/splash \
|
||||||
|
lookandfeel/metadata.json \
|
||||||
|
org.shift.mobile.metainfo.xml \
|
||||||
|
shell/metadata.json \
|
||||||
|
tests/check-shift-theme-identity.sh >/dev/null; then
|
||||||
|
fail "Shift-owned theme identity files must not use generic Shift contributor attribution"
|
||||||
|
fi
|
||||||
|
|
||||||
|
for license_file in \
|
||||||
|
color-schemes/CMakeLists.txt \
|
||||||
|
cursors/CMakeLists.txt \
|
||||||
|
desktoptheme/CMakeLists.txt \
|
||||||
|
desktoptheme/shift-dark/plasmarc \
|
||||||
|
desktoptheme/shift-light/plasmarc \
|
||||||
|
fonts/CMakeLists.txt \
|
||||||
|
fonts/README.md \
|
||||||
|
icons/sc-places-start-here-shift.svg \
|
||||||
|
lookandfeel/contents/splash/Splash.qml \
|
||||||
|
tests/check-shift-theme-identity.sh; do
|
||||||
|
require_line "$license_file" "$shift_copyright_pattern" \
|
||||||
|
"$license_file must attribute Shift-owned work to Marco Allegretti"
|
||||||
|
require_line "$license_file" "$shift_license_pattern" \
|
||||||
|
"$license_file must use EUPL-1.2"
|
||||||
|
done
|
||||||
|
|
||||||
|
for metadata_file in \
|
||||||
|
desktoptheme/shift-dark/metadata.json \
|
||||||
|
desktoptheme/shift-light/metadata.json \
|
||||||
|
kwin/decorations/org.shift.decoration/metadata.json; do
|
||||||
|
require_line "$metadata_file" '"Name": "Marco Allegretti"' \
|
||||||
|
"$metadata_file must attribute Shift-owned metadata to Marco Allegretti"
|
||||||
|
require_line "$metadata_file" '"License": "EUPL-1\.2"' \
|
||||||
|
"$metadata_file must use EUPL-1.2"
|
||||||
|
done
|
||||||
|
|
||||||
|
for author_file in \
|
||||||
|
lookandfeel/metadata.json \
|
||||||
|
shell/metadata.json \
|
||||||
|
org.shift.mobile.metainfo.xml; do
|
||||||
|
require_line "$author_file" 'Marco Allegretti' \
|
||||||
|
"$author_file must not use generic Shift contributor attribution"
|
||||||
|
done
|
||||||
|
|
||||||
|
result='shift-theme-identity-ok'
|
||||||
|
printf '%s\n' "$result"
|
||||||
26
tools/preview-stubs/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
# SPDX-FileCopyrightText: 2026 Marco Allegretti
|
||||||
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
set(SHIFT_INSTALL_PREVIEW_QML_STUBS "AUTO" CACHE STRING "Install preview fallback QML stubs: AUTO, ON, or OFF")
|
||||||
|
set_property(CACHE SHIFT_INSTALL_PREVIEW_QML_STUBS PROPERTY STRINGS AUTO ON OFF)
|
||||||
|
|
||||||
|
if(NOT SHIFT_INSTALL_PREVIEW_QML_STUBS MATCHES "^(AUTO|ON|OFF)$")
|
||||||
|
message(FATAL_ERROR "SHIFT_INSTALL_PREVIEW_QML_STUBS must be AUTO, ON, or OFF")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
set(_shift_install_preview_qml_stubs OFF)
|
||||||
|
if(SHIFT_INSTALL_PREVIEW_QML_STUBS STREQUAL "ON")
|
||||||
|
set(_shift_install_preview_qml_stubs ON)
|
||||||
|
elseif(SHIFT_INSTALL_PREVIEW_QML_STUBS STREQUAL "AUTO" AND CMAKE_INSTALL_PREFIX MATCHES "/\\.prefix$")
|
||||||
|
set(_shift_install_preview_qml_stubs ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(_shift_install_preview_qml_stubs)
|
||||||
|
install(
|
||||||
|
DIRECTORY qml/
|
||||||
|
DESTINATION ${KDE_INSTALL_QMLDIR}
|
||||||
|
FILES_MATCHING
|
||||||
|
PATTERN "*.qml"
|
||||||
|
PATTERN "qmldir"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
28
tools/preview-stubs/README.md
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<!-- SPDX-FileCopyrightText: 2026 Marco Allegretti -->
|
||||||
|
<!-- SPDX-License-Identifier: EUPL-1.2 -->
|
||||||
|
|
||||||
|
# Preview-only QML stubs
|
||||||
|
|
||||||
|
These stub modules satisfy QML imports that **upstream Plasma Mobile expects**
|
||||||
|
but that are not provided by the QML packages shipped on the host distro used
|
||||||
|
for preview/development.
|
||||||
|
|
||||||
|
They are installed only for local preview prefixes by default:
|
||||||
|
`SHIFT_INSTALL_PREVIEW_QML_STUBS=AUTO` enables installation when
|
||||||
|
`CMAKE_INSTALL_PREFIX` ends in `.prefix`. Set it to `ON` to force installation
|
||||||
|
for another prefix, or `OFF` to disable it. Production installs using normal
|
||||||
|
system prefixes leave these stubs out.
|
||||||
|
|
||||||
|
## Current stubs
|
||||||
|
|
||||||
|
- `org/kde/plasma/networkmanagement/cellular/` — `CellularModemList`,
|
||||||
|
`CellularModem`. Required by
|
||||||
|
`components/mobileshell/qml/dataproviders/SignalStrengthInfo.qml`.
|
||||||
|
openSUSE Tumbleweed's `plasma6-nm 6.6.4` package does not ship this
|
||||||
|
QML submodule (only the cellular KCM `.so`). Without the stub the
|
||||||
|
entire MobileShell QML namespace fails to load and the homescreen
|
||||||
|
is blank.
|
||||||
|
|
||||||
|
When the host distro starts providing a real module at the same import path,
|
||||||
|
disable the local fallback by configuring with `SHIFT_INSTALL_PREVIEW_QML_STUBS=OFF`
|
||||||
|
before comparing against the system module.
|
||||||
|
|
@ -0,0 +1,12 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 Marco Allegretti
|
||||||
|
// SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
// Minimal stub for the upstream plasma-nm cellular QML module.
|
||||||
|
// See CellularModemList.qml for rationale.
|
||||||
|
import QtQuick
|
||||||
|
QtObject {
|
||||||
|
property bool mobileDataEnabled: false
|
||||||
|
property bool mobileDataSupported: false
|
||||||
|
property bool needsAPNAdded: false
|
||||||
|
property bool simEmpty: true
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,13 @@
|
||||||
|
// SPDX-FileCopyrightText: 2026 Marco Allegretti
|
||||||
|
// SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
// Minimal stub for the upstream plasma-nm cellular QML module.
|
||||||
|
// openSUSE Tumbleweed's plasma6-nm 6.6.4 package does not yet ship this
|
||||||
|
// module, but components/mobileshell/.../SignalStrengthInfo.qml imports
|
||||||
|
// it unconditionally. Without this stub, every MobileShell type fails to
|
||||||
|
// load and the homescreen is blank.
|
||||||
|
import QtQuick
|
||||||
|
QtObject {
|
||||||
|
property bool modemAvailable: false
|
||||||
|
property var primaryModem: null
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,6 @@
|
||||||
|
# SPDX-FileCopyrightText: 2026 Marco Allegretti
|
||||||
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
|
module org.kde.plasma.networkmanagement.cellular
|
||||||
|
CellularModemList 1.0 CellularModemList.qml
|
||||||
|
CellularModem 1.0 CellularModem.qml
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# SPDX-FileCopyrightText: 2026 SHIFT Contributors
|
# SPDX-FileCopyrightText: 2026 Marco Allegretti
|
||||||
# SPDX-License-Identifier: EUPL-1.2
|
# SPDX-License-Identifier: EUPL-1.2
|
||||||
|
|
||||||
install(DIRECTORY SHIFT
|
install(DIRECTORY SHIFT
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,6 @@
|
||||||
],
|
],
|
||||||
"Id": "SHIFT",
|
"Id": "SHIFT",
|
||||||
"License": "EUPL-1.2",
|
"License": "EUPL-1.2",
|
||||||
"Name": "SHIFT Light / SHIFT Dark"
|
"Name": "SHIFT"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||