mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-25 05:52:50 -05:00
Compare commits
1 Commits
v0.0.28
...
surface-co
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8e103d7ba7 |
167
CLAUDE.md
167
CLAUDE.md
@@ -63,9 +63,6 @@ quickshell -p shell.qml
|
||||
# Or use the shorthand
|
||||
qs -p .
|
||||
|
||||
# Run with verbose output for debugging
|
||||
qs -v -p shell.qml
|
||||
|
||||
# Code formatting and linting
|
||||
qmlfmt -t 4 -i 4 -b 250 -w /path/to/file.qml # Format a QML file (requires qmlfmt, do not use qmlformat)
|
||||
qmllint **/*.qml # Lint all QML files for syntax errors
|
||||
@@ -92,7 +89,6 @@ shell.qml # Main entry point (minimal orchestration)
|
||||
│ ├── DisplayService.qml
|
||||
│ ├── NotificationService.qml
|
||||
│ ├── WeatherService.qml
|
||||
│ ├── PluginService.qml
|
||||
│ └── [14 more services]
|
||||
├── Modules/ # UI components (93 files)
|
||||
│ ├── TopBar/ # Panel components (13 files)
|
||||
@@ -108,21 +104,15 @@ shell.qml # Main entry point (minimal orchestration)
|
||||
│ ├── SettingsModal.qml
|
||||
│ ├── ClipboardHistoryModal.qml
|
||||
│ ├── ProcessListModal.qml
|
||||
│ ├── PluginSettingsModal.qml
|
||||
│ └── [7 more modals]
|
||||
├── Widgets/ # Reusable UI controls (19 files)
|
||||
│ ├── DankIcon.qml
|
||||
│ ├── DankSlider.qml
|
||||
│ ├── DankToggle.qml
|
||||
│ ├── DankTabBar.qml
|
||||
│ ├── DankGridView.qml
|
||||
│ ├── DankListView.qml
|
||||
│ └── [13 more widgets]
|
||||
└── plugins/ # External plugins directory ($CONFIGPATH/DankMaterialShell/plugins/)
|
||||
└── PluginName/ # Example Plugin structure
|
||||
├── plugin.json # Plugin manifest
|
||||
├── PluginNameWidget.qml # Widget component
|
||||
└── PluginNameSettings.qml # Settings UI
|
||||
└── Widgets/ # Reusable UI controls (19 files)
|
||||
├── DankIcon.qml
|
||||
├── DankSlider.qml
|
||||
├── DankToggle.qml
|
||||
├── DankTabBar.qml
|
||||
├── DankGridView.qml
|
||||
├── DankListView.qml
|
||||
└── [13 more widgets]
|
||||
```
|
||||
|
||||
### Component Organization
|
||||
@@ -173,12 +163,6 @@ shell.qml # Main entry point (minimal orchestration)
|
||||
- **DankLocationSearch**: Location picker with search
|
||||
- **SystemLogo**: Animated system branding component
|
||||
|
||||
7. **Plugins/** - External plugin system (`$CONFIGPATH/DankMaterialShell/plugins/`)
|
||||
- **PluginService**: Discovers, loads, and manages plugin lifecycle
|
||||
- **Dynamic Loading**: Plugins loaded at runtime from external directory
|
||||
- **DankBar Integration**: Plugin widgets rendered alongside built-in widgets
|
||||
- **Settings System**: Per-plugin settings with persistence
|
||||
|
||||
### Key Architectural Patterns
|
||||
|
||||
1. **Singleton Services Pattern**:
|
||||
@@ -424,10 +408,10 @@ When modifying the shell:
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
|
||||
property bool featureAvailable: false
|
||||
property type currentValue: defaultValue
|
||||
|
||||
|
||||
function performAction(param) {
|
||||
// Implementation
|
||||
}
|
||||
@@ -438,7 +422,7 @@ When modifying the shell:
|
||||
```qml
|
||||
// In module files
|
||||
property alias serviceValue: NewService.currentValue
|
||||
|
||||
|
||||
SomeControl {
|
||||
visible: NewService.featureAvailable
|
||||
enabled: NewService.featureAvailable
|
||||
@@ -446,134 +430,6 @@ When modifying the shell:
|
||||
}
|
||||
```
|
||||
|
||||
### Creating Plugins
|
||||
|
||||
Plugins are external, dynamically-loaded components that extend DankBar functionality. Plugins are stored in `~/.config/DankMaterialShell/plugins/` and have their settings isolated from core DMS settings.
|
||||
|
||||
1. **Create plugin directory**:
|
||||
```bash
|
||||
mkdir -p ~/.config/DankMaterialShell/plugins/YourPlugin
|
||||
```
|
||||
|
||||
2. **Create manifest** (`plugin.json`):
|
||||
```json
|
||||
{
|
||||
"id": "yourPlugin",
|
||||
"name": "Your Plugin",
|
||||
"description": "Widget description",
|
||||
"version": "1.0.0",
|
||||
"author": "Your Name",
|
||||
"icon": "extension",
|
||||
"component": "./YourWidget.qml",
|
||||
"settings": "./YourSettings.qml",
|
||||
"permissions": ["settings_read", "settings_write"]
|
||||
}
|
||||
```
|
||||
|
||||
3. **Create widget component** (`YourWidget.qml`):
|
||||
```qml
|
||||
import QtQuick
|
||||
import qs.Services
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property bool compactMode: false
|
||||
property string section: "center"
|
||||
property real widgetHeight: 30
|
||||
property var pluginService: null
|
||||
|
||||
width: content.implicitWidth + 16
|
||||
height: widgetHeight
|
||||
radius: 8
|
||||
color: "#20FFFFFF"
|
||||
|
||||
Component.onCompleted: {
|
||||
if (pluginService) {
|
||||
var data = pluginService.loadPluginData("yourPlugin", "key", defaultValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
4. **Create settings component** (`YourSettings.qml`):
|
||||
```qml
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
|
||||
FocusScope {
|
||||
id: root
|
||||
|
||||
property var pluginService: null
|
||||
|
||||
implicitHeight: settingsColumn.implicitHeight
|
||||
height: implicitHeight
|
||||
|
||||
Column {
|
||||
id: settingsColumn
|
||||
anchors.fill: parent
|
||||
anchors.margins: 16
|
||||
spacing: 12
|
||||
|
||||
Text {
|
||||
text: "Your Plugin Settings"
|
||||
font.pixelSize: 18
|
||||
font.weight: Font.Bold
|
||||
}
|
||||
|
||||
// Your settings UI here
|
||||
}
|
||||
|
||||
function saveSettings(key, value) {
|
||||
if (pluginService) {
|
||||
pluginService.savePluginData("yourPlugin", key, value)
|
||||
}
|
||||
}
|
||||
|
||||
function loadSettings(key, defaultValue) {
|
||||
if (pluginService) {
|
||||
return pluginService.loadPluginData("yourPlugin", key, defaultValue)
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
5. **Enable plugin**:
|
||||
- Open Settings → Plugins
|
||||
- Click "Scan for Plugins"
|
||||
- Toggle plugin to enable
|
||||
- Add plugin ID to DankBar widget list
|
||||
|
||||
**Plugin Directory Structure:**
|
||||
```
|
||||
~/.config/DankMaterialShell/
|
||||
├── settings.json # Core DMS settings + plugin settings
|
||||
│ └── pluginSettings: {
|
||||
│ └── yourPlugin: {
|
||||
│ ├── enabled: true,
|
||||
│ └── customData: {...}
|
||||
│ }
|
||||
│ }
|
||||
└── plugins/ # Plugin files directory
|
||||
└── YourPlugin/ # Plugin directory (matches manifest ID)
|
||||
├── plugin.json # Plugin manifest
|
||||
├── YourWidget.qml # Widget component
|
||||
└── YourSettings.qml # Settings UI (optional)
|
||||
```
|
||||
|
||||
**Key Plugin APIs:**
|
||||
- `pluginService.loadPluginData(pluginId, key, default)` - Load persistent data
|
||||
- `pluginService.savePluginData(pluginId, key, value)` - Save persistent data
|
||||
- `PluginService.enablePlugin(pluginId)` - Load plugin
|
||||
- `PluginService.disablePlugin(pluginId)` - Unload plugin
|
||||
|
||||
**Important Notes:**
|
||||
- Plugin settings are automatically injected by the PluginService via `item.pluginService = PluginService`
|
||||
- Settings are stored in the main settings.json but namespaced under `pluginSettings.{pluginId}`
|
||||
- Plugin directories must match the plugin ID in the manifest
|
||||
- Use the injected `pluginService` property in both widget and settings components
|
||||
|
||||
### Debugging Common Issues
|
||||
|
||||
1. **Import errors**: Check import paths
|
||||
@@ -598,7 +454,6 @@ Plugins are external, dynamically-loaded components that extend DankBar function
|
||||
- **Function Discovery**: Use grep/search tools to find existing utility functions before implementing new ones
|
||||
- **Modern QML Patterns**: Leverage new widgets like DankTextField, DankDropdown, CachingImage
|
||||
- **Structured Organization**: Follow the established Services/Modules/Widgets/Modals separation
|
||||
- **Plugin System**: For user extensions, create plugins instead of modifying core modules - see docs/PLUGINS.md
|
||||
|
||||
### Common Widget Patterns
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Contributing
|
||||
|
||||
Contributions are welcome and encouraged.
|
||||
Contributions are welcome and encourages.
|
||||
|
||||
## Formatting
|
||||
|
||||
@@ -27,4 +27,4 @@ Sometimes it just breaks code though. Like turning `"_\""` into `"_""`, so you m
|
||||
|
||||
## Pull request
|
||||
|
||||
Include screenshots/video if applicable in your pull request if applicable, to visualize what your change is affecting.
|
||||
Include screenshots/video if applicable in your pull request if applicable, to visualize what your change is affecting.
|
||||
@@ -1,53 +0,0 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property var facts: [
|
||||
"A photon takes 100,000 to 200,000 years bouncing through the Sun's dense core, then races to Earth in just 8 minutes 20 seconds.",
|
||||
"A teaspoon of neutron star matter would weigh a billion metric tons here on Earth.",
|
||||
"Right now, 100 trillion solar neutrinos are passing through your body every second.",
|
||||
"The Sun converts 4 million metric tons of matter into pure energy every second—enough to power Earth for 500,000 years.",
|
||||
"The universe still glows with leftover heat from the Big Bang—just 2.7 degrees above absolute zero.",
|
||||
"There's a nebula out there that's actually colder than empty space itself.",
|
||||
"We've detected black holes crashing together by measuring spacetime stretch by less than 1/10,000th the width of a proton.",
|
||||
"Fast radio bursts can release more energy in 5 milliseconds than our Sun produces in 3 days.",
|
||||
"Our galaxy might be crawling with billions of rogue planets drifting alone in the dark.",
|
||||
"Distant galaxies can move away from us faster than light because space itself is stretching.",
|
||||
"The edge of what we can see is 46.5 billion light-years away, even though the universe is only 13.8 billion years old.",
|
||||
"The universe is mostly invisible: 5% regular matter, 27% dark matter, 68% dark energy.",
|
||||
"A day on Venus lasts longer than its entire year around the Sun.",
|
||||
"On Mercury, the time between sunrises is 176 Earth days long.",
|
||||
"In about 4.5 billion years, our galaxy will smash into Andromeda.",
|
||||
"Most of the gold in your jewelry was forged when neutron stars collided somewhere in space.",
|
||||
"PSR J1748-2446ad, the fastest spinning star, rotates 716 times per second—its equator moves at 24% the speed of light.",
|
||||
"Cosmic rays create particles that shouldn't make it to Earth's surface, but time dilation lets them sneak through.",
|
||||
"Jupiter's magnetic field is so huge that if we could see it, it would look bigger than the Moon in our sky.",
|
||||
"Interstellar space is so empty it's like a cube 32 kilometers wide containing just a single grain of sand.",
|
||||
"Voyager 1 is 24 billion kilometers away but won't leave the Sun's gravitational influence for another 30,000 years.",
|
||||
"Counting to a billion at one number per second would take over 31 years.",
|
||||
"Space is so vast, even speeding at light-speed, you'd never return past the cosmic horizon.",
|
||||
"Astronauts on the ISS age about 0.01 seconds less each year than people on Earth.",
|
||||
"Sagittarius B2, a dust cloud near our galaxy's center, contains ethyl formate—the compound that gives raspberries their flavor and rum its smell.",
|
||||
"Beyond 16 billion light-years, the cosmic event horizon marks where space expands too fast for light to ever reach us again.",
|
||||
"Even at light-speed, you'd never catch up to most galaxies—space expands faster.",
|
||||
"Only around 5% of galaxies are ever reachable—even at light-speed.",
|
||||
"If the Sun vanished, we'd still orbit it for 8 minutes before drifting away.",
|
||||
"If a planet 65 million light-years away looked at Earth now, it'd see dinosaurs.",
|
||||
"Our oldest radio signals will reach the Milky Way's center in 26,000 years.",
|
||||
"Every atom in your body heavier than hydrogen was forged in the nuclear furnace of a dying star.",
|
||||
"The Moon moves 3.8 centimeters farther from Earth every year.",
|
||||
"The universe creates 275 million new stars every single day.",
|
||||
"Jupiter's Great Red Spot is a storm twice the size of Earth that has been raging for at least 350 years.",
|
||||
"If you watched someone fall into a black hole, they'd appear frozen at the event horizon forever—time effectively stops from your perspective.",
|
||||
"The Boötes Supervoid is a cosmic desert 1.8 billion light-years across with 60% fewer galaxies than it should have."
|
||||
]
|
||||
|
||||
function getRandomFact() {
|
||||
return facts[Math.floor(Math.random() * facts.length)]
|
||||
}
|
||||
}
|
||||
@@ -12,19 +12,12 @@ Singleton {
|
||||
|
||||
id: root
|
||||
|
||||
readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true"
|
||||
|
||||
property bool isLightMode: false
|
||||
property string wallpaperPath: ""
|
||||
property string wallpaperLastPath: ""
|
||||
property string profileLastPath: ""
|
||||
property bool perMonitorWallpaper: false
|
||||
property var monitorWallpapers: ({})
|
||||
property bool perModeWallpaper: false
|
||||
property string wallpaperPathLight: ""
|
||||
property string wallpaperPathDark: ""
|
||||
property var monitorWallpapersLight: ({})
|
||||
property var monitorWallpapersDark: ({})
|
||||
property bool doNotDisturb: false
|
||||
property bool nightModeEnabled: false
|
||||
property int nightModeTemperature: 4500
|
||||
@@ -73,17 +66,11 @@ Singleton {
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!isGreeterMode) {
|
||||
loadSettings()
|
||||
}
|
||||
loadSettings()
|
||||
}
|
||||
|
||||
function loadSettings() {
|
||||
if (isGreeterMode) {
|
||||
parseSettings(greeterSessionFile.text())
|
||||
} else {
|
||||
parseSettings(settingsFile.text())
|
||||
}
|
||||
parseSettings(settingsFile.text())
|
||||
}
|
||||
|
||||
function parseSettings(content) {
|
||||
@@ -96,11 +83,6 @@ Singleton {
|
||||
profileLastPath = settings.profileLastPath !== undefined ? settings.profileLastPath : ""
|
||||
perMonitorWallpaper = settings.perMonitorWallpaper !== undefined ? settings.perMonitorWallpaper : false
|
||||
monitorWallpapers = settings.monitorWallpapers !== undefined ? settings.monitorWallpapers : {}
|
||||
perModeWallpaper = settings.perModeWallpaper !== undefined ? settings.perModeWallpaper : false
|
||||
wallpaperPathLight = settings.wallpaperPathLight !== undefined ? settings.wallpaperPathLight : ""
|
||||
wallpaperPathDark = settings.wallpaperPathDark !== undefined ? settings.wallpaperPathDark : ""
|
||||
monitorWallpapersLight = settings.monitorWallpapersLight !== undefined ? settings.monitorWallpapersLight : {}
|
||||
monitorWallpapersDark = settings.monitorWallpapersDark !== undefined ? settings.monitorWallpapersDark : {}
|
||||
doNotDisturb = settings.doNotDisturb !== undefined ? settings.doNotDisturb : false
|
||||
nightModeEnabled = settings.nightModeEnabled !== undefined ? settings.nightModeEnabled : false
|
||||
nightModeTemperature = settings.nightModeTemperature !== undefined ? settings.nightModeTemperature : 4500
|
||||
@@ -150,11 +132,10 @@ Singleton {
|
||||
batterySuspendTimeout = settings.batterySuspendTimeout !== undefined ? settings.batterySuspendTimeout : 0
|
||||
batteryHibernateTimeout = settings.batteryHibernateTimeout !== undefined ? settings.batteryHibernateTimeout : 0
|
||||
lockBeforeSuspend = settings.lockBeforeSuspend !== undefined ? settings.lockBeforeSuspend : false
|
||||
|
||||
if (!isGreeterMode) {
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
|
||||
// Generate system themes but don't override user's theme choice
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
@@ -163,7 +144,6 @@ Singleton {
|
||||
}
|
||||
|
||||
function saveSettings() {
|
||||
if (isGreeterMode) return
|
||||
settingsFile.setText(JSON.stringify({
|
||||
"isLightMode": isLightMode,
|
||||
"wallpaperPath": wallpaperPath,
|
||||
@@ -171,11 +151,6 @@ Singleton {
|
||||
"profileLastPath": profileLastPath,
|
||||
"perMonitorWallpaper": perMonitorWallpaper,
|
||||
"monitorWallpapers": monitorWallpapers,
|
||||
"perModeWallpaper": perModeWallpaper,
|
||||
"wallpaperPathLight": wallpaperPathLight,
|
||||
"wallpaperPathDark": wallpaperPathDark,
|
||||
"monitorWallpapersLight": monitorWallpapersLight,
|
||||
"monitorWallpapersDark": monitorWallpapersDark,
|
||||
"doNotDisturb": doNotDisturb,
|
||||
"nightModeEnabled": nightModeEnabled,
|
||||
"nightModeTemperature": nightModeTemperature,
|
||||
@@ -216,21 +191,9 @@ Singleton {
|
||||
|
||||
function setLightMode(lightMode) {
|
||||
isLightMode = lightMode
|
||||
syncWallpaperForCurrentMode()
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function syncWallpaperForCurrentMode() {
|
||||
if (!perModeWallpaper) return
|
||||
|
||||
if (perMonitorWallpaper) {
|
||||
monitorWallpapers = isLightMode ? Object.assign({}, monitorWallpapersLight) : Object.assign({}, monitorWallpapersDark)
|
||||
return
|
||||
}
|
||||
|
||||
wallpaperPath = isLightMode ? wallpaperPathLight : wallpaperPathDark
|
||||
}
|
||||
|
||||
function setDoNotDisturb(enabled) {
|
||||
doNotDisturb = enabled
|
||||
saveSettings()
|
||||
@@ -301,32 +264,24 @@ Singleton {
|
||||
|
||||
function setWallpaper(imagePath) {
|
||||
wallpaperPath = imagePath
|
||||
if (perModeWallpaper) {
|
||||
if (isLightMode) {
|
||||
wallpaperPathLight = imagePath
|
||||
} else {
|
||||
wallpaperPathDark = imagePath
|
||||
}
|
||||
}
|
||||
saveSettings()
|
||||
|
||||
if (typeof Theme !== "undefined") {
|
||||
if (Theme.currentTheme === Theme.dynamic) {
|
||||
Theme.extractColors()
|
||||
}
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
}
|
||||
|
||||
function setWallpaperColor(color) {
|
||||
wallpaperPath = color
|
||||
if (perModeWallpaper) {
|
||||
if (isLightMode) {
|
||||
wallpaperPathLight = color
|
||||
} else {
|
||||
wallpaperPathDark = color
|
||||
}
|
||||
}
|
||||
saveSettings()
|
||||
|
||||
if (typeof Theme !== "undefined") {
|
||||
if (Theme.currentTheme === Theme.dynamic) {
|
||||
Theme.extractColors()
|
||||
}
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
}
|
||||
@@ -471,52 +426,13 @@ Singleton {
|
||||
|
||||
function setPerMonitorWallpaper(enabled) {
|
||||
perMonitorWallpaper = enabled
|
||||
if (enabled && perModeWallpaper) {
|
||||
syncWallpaperForCurrentMode()
|
||||
}
|
||||
saveSettings()
|
||||
|
||||
// Refresh dynamic theming when per-monitor mode changes
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
}
|
||||
|
||||
function setPerModeWallpaper(enabled) {
|
||||
if (enabled && wallpaperCyclingEnabled) {
|
||||
setWallpaperCyclingEnabled(false)
|
||||
}
|
||||
if (enabled && perMonitorWallpaper) {
|
||||
var monitorCyclingAny = false
|
||||
for (var key in monitorCyclingSettings) {
|
||||
if (monitorCyclingSettings[key].enabled) {
|
||||
monitorCyclingAny = true
|
||||
break
|
||||
}
|
||||
if (Theme.currentTheme === Theme.dynamic) {
|
||||
Theme.extractColors()
|
||||
}
|
||||
if (monitorCyclingAny) {
|
||||
var newSettings = Object.assign({}, monitorCyclingSettings)
|
||||
for (var screenName in newSettings) {
|
||||
newSettings[screenName].enabled = false
|
||||
}
|
||||
monitorCyclingSettings = newSettings
|
||||
}
|
||||
}
|
||||
|
||||
perModeWallpaper = enabled
|
||||
if (enabled) {
|
||||
if (perMonitorWallpaper) {
|
||||
monitorWallpapersLight = Object.assign({}, monitorWallpapers)
|
||||
monitorWallpapersDark = Object.assign({}, monitorWallpapers)
|
||||
} else {
|
||||
wallpaperPathLight = wallpaperPath
|
||||
wallpaperPathDark = wallpaperPath
|
||||
}
|
||||
} else {
|
||||
syncWallpaperForCurrentMode()
|
||||
}
|
||||
saveSettings()
|
||||
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
}
|
||||
@@ -529,32 +445,15 @@ Singleton {
|
||||
delete newMonitorWallpapers[screenName]
|
||||
}
|
||||
monitorWallpapers = newMonitorWallpapers
|
||||
|
||||
if (perModeWallpaper) {
|
||||
if (isLightMode) {
|
||||
var newLight = Object.assign({}, monitorWallpapersLight)
|
||||
if (path && path !== "") {
|
||||
newLight[screenName] = path
|
||||
} else {
|
||||
delete newLight[screenName]
|
||||
}
|
||||
monitorWallpapersLight = newLight
|
||||
} else {
|
||||
var newDark = Object.assign({}, monitorWallpapersDark)
|
||||
if (path && path !== "") {
|
||||
newDark[screenName] = path
|
||||
} else {
|
||||
delete newDark[screenName]
|
||||
}
|
||||
monitorWallpapersDark = newDark
|
||||
}
|
||||
}
|
||||
|
||||
saveSettings()
|
||||
|
||||
// Trigger dynamic theming if this is the first monitor and dynamic theming is enabled
|
||||
if (typeof Theme !== "undefined" && typeof Quickshell !== "undefined") {
|
||||
var screens = Quickshell.screens
|
||||
if (screens.length > 0 && screenName === screens[0].name) {
|
||||
if (Theme.currentTheme === Theme.dynamic) {
|
||||
Theme.extractColors()
|
||||
}
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
}
|
||||
@@ -630,43 +529,22 @@ Singleton {
|
||||
FileView {
|
||||
id: settingsFile
|
||||
|
||||
path: isGreeterMode ? "" : StandardPaths.writableLocation(StandardPaths.GenericStateLocation) + "/DankMaterialShell/session.json"
|
||||
blockLoading: isGreeterMode
|
||||
path: StandardPaths.writableLocation(StandardPaths.GenericStateLocation) + "/DankMaterialShell/session.json"
|
||||
blockLoading: true
|
||||
blockWrites: true
|
||||
watchChanges: !isGreeterMode
|
||||
watchChanges: true
|
||||
onLoaded: {
|
||||
if (!isGreeterMode) {
|
||||
parseSettings(settingsFile.text())
|
||||
hasTriedDefaultSession = false
|
||||
}
|
||||
parseSettings(settingsFile.text())
|
||||
hasTriedDefaultSession = false
|
||||
}
|
||||
onLoadFailed: error => {
|
||||
if (!isGreeterMode && !hasTriedDefaultSettings) {
|
||||
hasTriedDefaultSettings = true
|
||||
if (!hasTriedDefaultSession) {
|
||||
hasTriedDefaultSession = true
|
||||
defaultSessionCheckProcess.running = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: greeterSessionFile
|
||||
|
||||
path: {
|
||||
const greetCfgDir = Quickshell.env("DMS_GREET_CFG_DIR") || "/etc/greetd/.dms"
|
||||
return greetCfgDir + "/session.json"
|
||||
}
|
||||
preload: isGreeterMode
|
||||
blockLoading: false
|
||||
blockWrites: true
|
||||
watchChanges: false
|
||||
printErrors: true
|
||||
onLoaded: {
|
||||
if (isGreeterMode) {
|
||||
parseSettings(greeterSessionFile.text())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: defaultSessionCheckProcess
|
||||
|
||||
|
||||
@@ -12,30 +12,13 @@ import qs.Services
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property bool isGreeterMode: Quickshell.env("DMS_RUN_GREETER") === "1" || Quickshell.env("DMS_RUN_GREETER") === "true"
|
||||
|
||||
enum Position {
|
||||
Top,
|
||||
Bottom,
|
||||
Left,
|
||||
Right
|
||||
}
|
||||
|
||||
enum AnimationSpeed {
|
||||
None,
|
||||
Shortest,
|
||||
Short,
|
||||
Medium,
|
||||
Long
|
||||
}
|
||||
|
||||
// Theme settings
|
||||
property string currentThemeName: "blue"
|
||||
property string customThemeFile: ""
|
||||
property string matugenScheme: "scheme-tonal-spot"
|
||||
property real dankBarTransparency: 1.0
|
||||
property real dankBarWidgetTransparency: 1.0
|
||||
property real popupTransparency: 1.0
|
||||
property real topBarTransparency: 0.75
|
||||
property real topBarWidgetTransparency: 0.85
|
||||
property real popupTransparency: 0.92
|
||||
property real dockTransparency: 1
|
||||
property bool use24HourClock: true
|
||||
property bool useFahrenheit: false
|
||||
@@ -87,13 +70,12 @@ Singleton {
|
||||
property string clockDateFormat: ""
|
||||
property string lockDateFormat: ""
|
||||
property int mediaSize: 1
|
||||
property var dankBarLeftWidgets: ["launcherButton", "workspaceSwitcher", "focusedWindow"]
|
||||
property var dankBarCenterWidgets: ["music", "clock", "weather"]
|
||||
property var dankBarRightWidgets: ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"]
|
||||
property var dankBarWidgetOrder: []
|
||||
property alias dankBarLeftWidgetsModel: leftWidgetsModel
|
||||
property alias dankBarCenterWidgetsModel: centerWidgetsModel
|
||||
property alias dankBarRightWidgetsModel: rightWidgetsModel
|
||||
property var topBarLeftWidgets: ["launcherButton", "workspaceSwitcher", "focusedWindow"]
|
||||
property var topBarCenterWidgets: ["music", "clock", "weather"]
|
||||
property var topBarRightWidgets: ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"]
|
||||
property alias topBarLeftWidgetsModel: leftWidgetsModel
|
||||
property alias topBarCenterWidgetsModel: centerWidgetsModel
|
||||
property alias topBarRightWidgetsModel: rightWidgetsModel
|
||||
property string appLauncherViewMode: "list"
|
||||
property string spotlightModalViewMode: "list"
|
||||
property string networkPreference: "auto"
|
||||
@@ -135,48 +117,37 @@ Singleton {
|
||||
property bool showDock: false
|
||||
property bool dockAutoHide: false
|
||||
property bool dockGroupByApp: false
|
||||
property bool dockOpenOnOverview: false
|
||||
property int dockPosition: SettingsData.Position.Bottom
|
||||
property real dockSpacing: 4
|
||||
property real dockBottomGap: 0
|
||||
property real cornerRadius: 12
|
||||
property bool notificationOverlayEnabled: false
|
||||
property bool dankBarAutoHide: false
|
||||
property bool dankBarOpenOnOverview: false
|
||||
property bool dankBarVisible: true
|
||||
property real dankBarSpacing: 4
|
||||
property real dankBarBottomGap: 0
|
||||
property real dankBarInnerPadding: 4
|
||||
property bool dankBarSquareCorners: false
|
||||
property bool dankBarNoBackground: false
|
||||
property bool dankBarGothCornersEnabled: false
|
||||
property int dankBarPosition: SettingsData.Position.Top
|
||||
property bool dankBarIsVertical: dankBarPosition === SettingsData.Position.Left || dankBarPosition === SettingsData.Position.Right
|
||||
property bool topBarAutoHide: false
|
||||
property bool topBarOpenOnOverview: false
|
||||
property bool topBarVisible: true
|
||||
property real topBarSpacing: 4
|
||||
property real topBarBottomGap: 0
|
||||
property real topBarInnerPadding: 8
|
||||
property bool topBarSquareCorners: false
|
||||
property bool topBarNoBackground: false
|
||||
property bool topBarGothCornersEnabled: false
|
||||
property bool lockScreenShowPowerActions: true
|
||||
property bool hideBrightnessSlider: false
|
||||
property string widgetBackgroundColor: "sch"
|
||||
property string surfaceBase: "s"
|
||||
property string surfaceBase: "sc"
|
||||
property int notificationTimeoutLow: 5000
|
||||
property int notificationTimeoutNormal: 5000
|
||||
property int notificationTimeoutCritical: 0
|
||||
property int notificationPopupPosition: SettingsData.Position.Top
|
||||
property var screenPreferences: ({})
|
||||
property int animationSpeed: SettingsData.AnimationSpeed.Short
|
||||
readonly property string defaultFontFamily: "Inter Variable"
|
||||
readonly property string defaultMonoFontFamily: "Fira Code"
|
||||
readonly property string _homeUrl: StandardPaths.writableLocation(StandardPaths.HomeLocation)
|
||||
readonly property string _configUrl: StandardPaths.writableLocation(StandardPaths.ConfigLocation)
|
||||
readonly property string _configDir: Paths.strip(_configUrl)
|
||||
|
||||
signal forceDankBarLayoutRefresh
|
||||
signal forceDockLayoutRefresh
|
||||
signal forceTopBarLayoutRefresh
|
||||
signal widgetDataChanged
|
||||
signal workspaceIconsUpdated
|
||||
|
||||
property bool _loading: false
|
||||
|
||||
property var pluginSettings: ({})
|
||||
|
||||
function getEffectiveTimeFormat() {
|
||||
if (use24HourClock) {
|
||||
return Locale.ShortFormat
|
||||
@@ -208,9 +179,9 @@ Singleton {
|
||||
centerWidgetsModel.append(dummyItem)
|
||||
rightWidgetsModel.append(dummyItem)
|
||||
|
||||
updateListModel(leftWidgetsModel, dankBarLeftWidgets)
|
||||
updateListModel(centerWidgetsModel, dankBarCenterWidgets)
|
||||
updateListModel(rightWidgetsModel, dankBarRightWidgets)
|
||||
updateListModel(leftWidgetsModel, topBarLeftWidgets)
|
||||
updateListModel(centerWidgetsModel, topBarCenterWidgets)
|
||||
updateListModel(rightWidgetsModel, topBarRightWidgets)
|
||||
}
|
||||
|
||||
function loadSettings() {
|
||||
@@ -238,9 +209,9 @@ Singleton {
|
||||
}
|
||||
customThemeFile = settings.customThemeFile !== undefined ? settings.customThemeFile : ""
|
||||
matugenScheme = settings.matugenScheme !== undefined ? settings.matugenScheme : "scheme-tonal-spot"
|
||||
dankBarTransparency = settings.dankBarTransparency !== undefined ? (settings.dankBarTransparency > 1 ? settings.dankBarTransparency / 100 : settings.dankBarTransparency) : (settings.topBarTransparency !== undefined ? (settings.topBarTransparency > 1 ? settings.topBarTransparency / 100 : settings.topBarTransparency) : 1.0)
|
||||
dankBarWidgetTransparency = settings.dankBarWidgetTransparency !== undefined ? (settings.dankBarWidgetTransparency > 1 ? settings.dankBarWidgetTransparency / 100 : settings.dankBarWidgetTransparency) : (settings.topBarWidgetTransparency !== undefined ? (settings.topBarWidgetTransparency > 1 ? settings.topBarWidgetTransparency / 100 : settings.topBarWidgetTransparency) : 1.0)
|
||||
popupTransparency = settings.popupTransparency !== undefined ? (settings.popupTransparency > 1 ? settings.popupTransparency / 100 : settings.popupTransparency) : 1.0
|
||||
topBarTransparency = settings.topBarTransparency !== undefined ? (settings.topBarTransparency > 1 ? settings.topBarTransparency / 100 : settings.topBarTransparency) : 0.75
|
||||
topBarWidgetTransparency = settings.topBarWidgetTransparency !== undefined ? (settings.topBarWidgetTransparency > 1 ? settings.topBarWidgetTransparency / 100 : settings.topBarWidgetTransparency) : 0.85
|
||||
popupTransparency = settings.popupTransparency !== undefined ? (settings.popupTransparency > 1 ? settings.popupTransparency / 100 : settings.popupTransparency) : 0.92
|
||||
dockTransparency = settings.dockTransparency !== undefined ? (settings.dockTransparency > 1 ? settings.dockTransparency / 100 : settings.dockTransparency) : 1
|
||||
use24HourClock = settings.use24HourClock !== undefined ? settings.use24HourClock : true
|
||||
useFahrenheit = settings.useFahrenheit !== undefined ? settings.useFahrenheit : false
|
||||
@@ -293,24 +264,23 @@ Singleton {
|
||||
clockDateFormat = settings.clockDateFormat !== undefined ? settings.clockDateFormat : ""
|
||||
lockDateFormat = settings.lockDateFormat !== undefined ? settings.lockDateFormat : ""
|
||||
mediaSize = settings.mediaSize !== undefined ? settings.mediaSize : (settings.mediaCompactMode !== undefined ? (settings.mediaCompactMode ? 0 : 1) : 1)
|
||||
if (settings.dankBarWidgetOrder || settings.topBarWidgetOrder) {
|
||||
var widgetOrder = settings.dankBarWidgetOrder || settings.topBarWidgetOrder
|
||||
dankBarLeftWidgets = widgetOrder.filter(w => {
|
||||
if (settings.topBarWidgetOrder) {
|
||||
topBarLeftWidgets = settings.topBarWidgetOrder.filter(w => {
|
||||
return ["launcherButton", "workspaceSwitcher", "focusedWindow"].includes(w)
|
||||
})
|
||||
dankBarCenterWidgets = widgetOrder.filter(w => {
|
||||
topBarCenterWidgets = settings.topBarWidgetOrder.filter(w => {
|
||||
return ["clock", "music", "weather"].includes(w)
|
||||
})
|
||||
dankBarRightWidgets = widgetOrder.filter(w => {
|
||||
topBarRightWidgets = settings.topBarWidgetOrder.filter(w => {
|
||||
return ["systemTray", "clipboard", "systemResources", "notificationButton", "battery", "controlCenterButton"].includes(w)
|
||||
})
|
||||
} else {
|
||||
var leftWidgets = settings.dankBarLeftWidgets !== undefined ? settings.dankBarLeftWidgets : (settings.topBarLeftWidgets !== undefined ? settings.topBarLeftWidgets : ["launcherButton", "workspaceSwitcher", "focusedWindow"])
|
||||
var centerWidgets = settings.dankBarCenterWidgets !== undefined ? settings.dankBarCenterWidgets : (settings.topBarCenterWidgets !== undefined ? settings.topBarCenterWidgets : ["music", "clock", "weather"])
|
||||
var rightWidgets = settings.dankBarRightWidgets !== undefined ? settings.dankBarRightWidgets : (settings.topBarRightWidgets !== undefined ? settings.topBarRightWidgets : ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"])
|
||||
dankBarLeftWidgets = leftWidgets
|
||||
dankBarCenterWidgets = centerWidgets
|
||||
dankBarRightWidgets = rightWidgets
|
||||
var leftWidgets = settings.topBarLeftWidgets !== undefined ? settings.topBarLeftWidgets : ["launcherButton", "workspaceSwitcher", "focusedWindow"]
|
||||
var centerWidgets = settings.topBarCenterWidgets !== undefined ? settings.topBarCenterWidgets : ["music", "clock", "weather"]
|
||||
var rightWidgets = settings.topBarRightWidgets !== undefined ? settings.topBarRightWidgets : ["systemTray", "clipboard", "cpuUsage", "memUsage", "notificationButton", "battery", "controlCenterButton"]
|
||||
topBarLeftWidgets = leftWidgets
|
||||
topBarCenterWidgets = centerWidgets
|
||||
topBarRightWidgets = rightWidgets
|
||||
updateListModel(leftWidgetsModel, leftWidgets)
|
||||
updateListModel(centerWidgetsModel, centerWidgets)
|
||||
updateListModel(rightWidgetsModel, rightWidgets)
|
||||
@@ -338,33 +308,25 @@ Singleton {
|
||||
showDock = settings.showDock !== undefined ? settings.showDock : false
|
||||
dockAutoHide = settings.dockAutoHide !== undefined ? settings.dockAutoHide : false
|
||||
dockGroupByApp = settings.dockGroupByApp !== undefined ? settings.dockGroupByApp : false
|
||||
dockPosition = settings.dockPosition !== undefined ? settings.dockPosition : SettingsData.Position.Bottom
|
||||
dockSpacing = settings.dockSpacing !== undefined ? settings.dockSpacing : 4
|
||||
dockBottomGap = settings.dockBottomGap !== undefined ? settings.dockBottomGap : 0
|
||||
cornerRadius = settings.cornerRadius !== undefined ? settings.cornerRadius : 12
|
||||
notificationOverlayEnabled = settings.notificationOverlayEnabled !== undefined ? settings.notificationOverlayEnabled : false
|
||||
dankBarAutoHide = settings.dankBarAutoHide !== undefined ? settings.dankBarAutoHide : (settings.topBarAutoHide !== undefined ? settings.topBarAutoHide : false)
|
||||
dankBarOpenOnOverview = settings.dankBarOpenOnOverview !== undefined ? settings.dankBarOpenOnOverview : (settings.topBarOpenOnOverview !== undefined ? settings.topBarOpenOnOverview : false)
|
||||
dankBarVisible = settings.dankBarVisible !== undefined ? settings.dankBarVisible : (settings.topBarVisible !== undefined ? settings.topBarVisible : true)
|
||||
dockOpenOnOverview = settings.dockOpenOnOverview !== undefined ? settings.dockOpenOnOverview : false
|
||||
topBarAutoHide = settings.topBarAutoHide !== undefined ? settings.topBarAutoHide : false
|
||||
topBarOpenOnOverview = settings.topBarOpenOnOverview !== undefined ? settings.topBarOpenOnOverview : false
|
||||
topBarVisible = settings.topBarVisible !== undefined ? settings.topBarVisible : true
|
||||
notificationTimeoutLow = settings.notificationTimeoutLow !== undefined ? settings.notificationTimeoutLow : 5000
|
||||
notificationTimeoutNormal = settings.notificationTimeoutNormal !== undefined ? settings.notificationTimeoutNormal : 5000
|
||||
notificationTimeoutCritical = settings.notificationTimeoutCritical !== undefined ? settings.notificationTimeoutCritical : 0
|
||||
notificationPopupPosition = settings.notificationPopupPosition !== undefined ? settings.notificationPopupPosition : SettingsData.Position.Top
|
||||
dankBarSpacing = settings.dankBarSpacing !== undefined ? settings.dankBarSpacing : (settings.topBarSpacing !== undefined ? settings.topBarSpacing : 4)
|
||||
dankBarBottomGap = settings.dankBarBottomGap !== undefined ? settings.dankBarBottomGap : (settings.topBarBottomGap !== undefined ? settings.topBarBottomGap : 0)
|
||||
dankBarInnerPadding = settings.dankBarInnerPadding !== undefined ? settings.dankBarInnerPadding : (settings.topBarInnerPadding !== undefined ? settings.topBarInnerPadding : 4)
|
||||
dankBarSquareCorners = settings.dankBarSquareCorners !== undefined ? settings.dankBarSquareCorners : (settings.topBarSquareCorners !== undefined ? settings.topBarSquareCorners : false)
|
||||
dankBarNoBackground = settings.dankBarNoBackground !== undefined ? settings.dankBarNoBackground : (settings.topBarNoBackground !== undefined ? settings.topBarNoBackground : false)
|
||||
dankBarGothCornersEnabled = settings.dankBarGothCornersEnabled !== undefined ? settings.dankBarGothCornersEnabled : (settings.topBarGothCornersEnabled !== undefined ? settings.topBarGothCornersEnabled : false)
|
||||
dankBarPosition = settings.dankBarPosition !== undefined ? settings.dankBarPosition : (settings.dankBarAtBottom !== undefined ? (settings.dankBarAtBottom ? SettingsData.Position.Bottom : SettingsData.Position.Top) : (settings.topBarAtBottom !== undefined ? (settings.topBarAtBottom ? SettingsData.Position.Bottom : SettingsData.Position.Top) : SettingsData.Position.Top))
|
||||
topBarSpacing = settings.topBarSpacing !== undefined ? settings.topBarSpacing : 4
|
||||
topBarBottomGap = settings.topBarBottomGap !== undefined ? settings.topBarBottomGap : 0
|
||||
topBarInnerPadding = settings.topBarInnerPadding !== undefined ? settings.topBarInnerPadding : 8
|
||||
topBarSquareCorners = settings.topBarSquareCorners !== undefined ? settings.topBarSquareCorners : false
|
||||
topBarNoBackground = settings.topBarNoBackground !== undefined ? settings.topBarNoBackground : false
|
||||
topBarGothCornersEnabled = settings.topBarGothCornersEnabled !== undefined ? settings.topBarGothCornersEnabled : false
|
||||
lockScreenShowPowerActions = settings.lockScreenShowPowerActions !== undefined ? settings.lockScreenShowPowerActions : true
|
||||
hideBrightnessSlider = settings.hideBrightnessSlider !== undefined ? settings.hideBrightnessSlider : false
|
||||
widgetBackgroundColor = settings.widgetBackgroundColor !== undefined ? settings.widgetBackgroundColor : "sch"
|
||||
surfaceBase = settings.surfaceBase !== undefined ? settings.surfaceBase : "s"
|
||||
surfaceBase = settings.surfaceBase !== undefined ? settings.surfaceBase : "sc"
|
||||
screenPreferences = settings.screenPreferences !== undefined ? settings.screenPreferences : ({})
|
||||
pluginSettings = settings.pluginSettings !== undefined ? settings.pluginSettings : ({})
|
||||
animationSpeed = settings.animationSpeed !== undefined ? settings.animationSpeed : SettingsData.AnimationSpeed.Short
|
||||
applyStoredTheme()
|
||||
detectAvailableIconThemes()
|
||||
detectQtTools()
|
||||
@@ -387,8 +349,8 @@ Singleton {
|
||||
"currentThemeName": currentThemeName,
|
||||
"customThemeFile": customThemeFile,
|
||||
"matugenScheme": matugenScheme,
|
||||
"dankBarTransparency": dankBarTransparency,
|
||||
"dankBarWidgetTransparency": dankBarWidgetTransparency,
|
||||
"topBarTransparency": topBarTransparency,
|
||||
"topBarWidgetTransparency": topBarWidgetTransparency,
|
||||
"popupTransparency": popupTransparency,
|
||||
"dockTransparency": dockTransparency,
|
||||
"use24HourClock": use24HourClock,
|
||||
@@ -433,9 +395,9 @@ Singleton {
|
||||
"clockDateFormat": clockDateFormat,
|
||||
"lockDateFormat": lockDateFormat,
|
||||
"mediaSize": mediaSize,
|
||||
"dankBarLeftWidgets": dankBarLeftWidgets,
|
||||
"dankBarCenterWidgets": dankBarCenterWidgets,
|
||||
"dankBarRightWidgets": dankBarRightWidgets,
|
||||
"topBarLeftWidgets": topBarLeftWidgets,
|
||||
"topBarCenterWidgets": topBarCenterWidgets,
|
||||
"topBarRightWidgets": topBarRightWidgets,
|
||||
"appLauncherViewMode": appLauncherViewMode,
|
||||
"spotlightModalViewMode": spotlightModalViewMode,
|
||||
"networkPreference": networkPreference,
|
||||
@@ -459,22 +421,17 @@ Singleton {
|
||||
"showDock": showDock,
|
||||
"dockAutoHide": dockAutoHide,
|
||||
"dockGroupByApp": dockGroupByApp,
|
||||
"dockOpenOnOverview": dockOpenOnOverview,
|
||||
"dockPosition": dockPosition,
|
||||
"dockSpacing": dockSpacing,
|
||||
"dockBottomGap": dockBottomGap,
|
||||
"cornerRadius": cornerRadius,
|
||||
"notificationOverlayEnabled": notificationOverlayEnabled,
|
||||
"dankBarAutoHide": dankBarAutoHide,
|
||||
"dankBarOpenOnOverview": dankBarOpenOnOverview,
|
||||
"dankBarVisible": dankBarVisible,
|
||||
"dankBarSpacing": dankBarSpacing,
|
||||
"dankBarBottomGap": dankBarBottomGap,
|
||||
"dankBarInnerPadding": dankBarInnerPadding,
|
||||
"dankBarSquareCorners": dankBarSquareCorners,
|
||||
"dankBarNoBackground": dankBarNoBackground,
|
||||
"dankBarGothCornersEnabled": dankBarGothCornersEnabled,
|
||||
"dankBarPosition": dankBarPosition,
|
||||
"topBarAutoHide": topBarAutoHide,
|
||||
"topBarOpenOnOverview": topBarOpenOnOverview,
|
||||
"topBarVisible": topBarVisible,
|
||||
"topBarSpacing": topBarSpacing,
|
||||
"topBarBottomGap": topBarBottomGap,
|
||||
"topBarInnerPadding": topBarInnerPadding,
|
||||
"topBarSquareCorners": topBarSquareCorners,
|
||||
"topBarNoBackground": topBarNoBackground,
|
||||
"topBarGothCornersEnabled": topBarGothCornersEnabled,
|
||||
"lockScreenShowPowerActions": lockScreenShowPowerActions,
|
||||
"hideBrightnessSlider": hideBrightnessSlider,
|
||||
"widgetBackgroundColor": widgetBackgroundColor,
|
||||
@@ -482,10 +439,7 @@ Singleton {
|
||||
"notificationTimeoutLow": notificationTimeoutLow,
|
||||
"notificationTimeoutNormal": notificationTimeoutNormal,
|
||||
"notificationTimeoutCritical": notificationTimeoutCritical,
|
||||
"notificationPopupPosition": notificationPopupPosition,
|
||||
"screenPreferences": screenPreferences,
|
||||
"pluginSettings": pluginSettings,
|
||||
"animationSpeed": animationSpeed
|
||||
"screenPreferences": screenPreferences
|
||||
}, null, 2))
|
||||
}
|
||||
|
||||
@@ -601,11 +555,11 @@ Singleton {
|
||||
|
||||
function applyStoredTheme() {
|
||||
if (typeof Theme !== "undefined")
|
||||
Theme.switchTheme(currentThemeName, false, false)
|
||||
Theme.switchTheme(currentThemeName, false)
|
||||
else
|
||||
Qt.callLater(() => {
|
||||
if (typeof Theme !== "undefined")
|
||||
Theme.switchTheme(currentThemeName, false, false)
|
||||
Theme.switchTheme(currentThemeName, false)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -628,17 +582,20 @@ Singleton {
|
||||
saveSettings()
|
||||
|
||||
if (typeof Theme !== "undefined") {
|
||||
if (Theme.currentTheme === Theme.dynamic) {
|
||||
Theme.extractColors()
|
||||
}
|
||||
Theme.generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
}
|
||||
|
||||
function setDankBarTransparency(transparency) {
|
||||
dankBarTransparency = transparency
|
||||
function setTopBarTransparency(transparency) {
|
||||
topBarTransparency = transparency
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDankBarWidgetTransparency(transparency) {
|
||||
dankBarWidgetTransparency = transparency
|
||||
function setTopBarWidgetTransparency(transparency) {
|
||||
topBarWidgetTransparency = transparency
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
@@ -773,25 +730,25 @@ Singleton {
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDankBarWidgetOrder(order) {
|
||||
dankBarWidgetOrder = order
|
||||
function setTopBarWidgetOrder(order) {
|
||||
topBarWidgetOrder = order
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDankBarLeftWidgets(order) {
|
||||
dankBarLeftWidgets = order
|
||||
function setTopBarLeftWidgets(order) {
|
||||
topBarLeftWidgets = order
|
||||
updateListModel(leftWidgetsModel, order)
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDankBarCenterWidgets(order) {
|
||||
dankBarCenterWidgets = order
|
||||
function setTopBarCenterWidgets(order) {
|
||||
topBarCenterWidgets = order
|
||||
updateListModel(centerWidgetsModel, order)
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDankBarRightWidgets(order) {
|
||||
dankBarRightWidgets = order
|
||||
function setTopBarRightWidgets(order) {
|
||||
topBarRightWidgets = order
|
||||
updateListModel(rightWidgetsModel, order)
|
||||
saveSettings()
|
||||
}
|
||||
@@ -824,13 +781,13 @@ Singleton {
|
||||
widgetDataChanged()
|
||||
}
|
||||
|
||||
function resetDankBarWidgetsToDefault() {
|
||||
function resetTopBarWidgetsToDefault() {
|
||||
var defaultLeft = ["launcherButton", "workspaceSwitcher", "focusedWindow"]
|
||||
var defaultCenter = ["music", "clock", "weather"]
|
||||
var defaultRight = ["systemTray", "clipboard", "notificationButton", "battery", "controlCenterButton"]
|
||||
dankBarLeftWidgets = defaultLeft
|
||||
dankBarCenterWidgets = defaultCenter
|
||||
dankBarRightWidgets = defaultRight
|
||||
topBarLeftWidgets = defaultLeft
|
||||
topBarCenterWidgets = defaultCenter
|
||||
topBarRightWidgets = defaultRight
|
||||
updateListModel(leftWidgetsModel, defaultLeft)
|
||||
updateListModel(centerWidgetsModel, defaultCenter)
|
||||
updateListModel(rightWidgetsModel, defaultRight)
|
||||
@@ -997,24 +954,6 @@ Singleton {
|
||||
|
||||
function setShowDock(enabled) {
|
||||
showDock = enabled
|
||||
if (enabled && dockPosition === dankBarPosition) {
|
||||
if (dankBarPosition === SettingsData.Position.Top) {
|
||||
setDockPosition(SettingsData.Position.Bottom)
|
||||
return
|
||||
}
|
||||
if (dankBarPosition === SettingsData.Position.Bottom) {
|
||||
setDockPosition(SettingsData.Position.Top)
|
||||
return
|
||||
}
|
||||
if (dankBarPosition === SettingsData.Position.Left) {
|
||||
setDockPosition(SettingsData.Position.Right)
|
||||
return
|
||||
}
|
||||
if (dankBarPosition === SettingsData.Position.Right) {
|
||||
setDockPosition(SettingsData.Position.Left)
|
||||
return
|
||||
}
|
||||
}
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
@@ -1028,11 +967,6 @@ Singleton {
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setdockOpenOnOverview(enabled) {
|
||||
dockOpenOnOverview = enabled
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setCornerRadius(radius) {
|
||||
cornerRadius = radius
|
||||
saveSettings()
|
||||
@@ -1043,23 +977,23 @@ Singleton {
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDankBarAutoHide(enabled) {
|
||||
dankBarAutoHide = enabled
|
||||
function setTopBarAutoHide(enabled) {
|
||||
topBarAutoHide = enabled
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDankBarOpenOnOverview(enabled) {
|
||||
dankBarOpenOnOverview = enabled
|
||||
function setTopBarOpenOnOverview(enabled) {
|
||||
topBarOpenOnOverview = enabled
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDankBarVisible(visible) {
|
||||
dankBarVisible = visible
|
||||
function setTopBarVisible(visible) {
|
||||
topBarVisible = visible
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function toggleDankBarVisible() {
|
||||
dankBarVisible = !dankBarVisible
|
||||
function toggleTopBarVisible() {
|
||||
topBarVisible = !topBarVisible
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
@@ -1078,162 +1012,36 @@ Singleton {
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setNotificationPopupPosition(position) {
|
||||
notificationPopupPosition = position
|
||||
function setTopBarSpacing(spacing) {
|
||||
topBarSpacing = spacing
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function sendTestNotifications() {
|
||||
sendTestNotification(0)
|
||||
testNotifTimer1.start()
|
||||
testNotifTimer2.start()
|
||||
}
|
||||
|
||||
function sendTestNotification(index) {
|
||||
const notifications = [
|
||||
["Notification Position Test", "DMS test notification 1 of 3 ~ Hi there!", "dialog-information"],
|
||||
["Second Test", "DMS Notification 2 of 3 ~ Check it out!", "emblem-default"],
|
||||
["Third Test", "DMS notification 3 of 3 ~ Enjoy!", "emblem-favorite"]
|
||||
]
|
||||
|
||||
if (index < 0 || index >= notifications.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const notif = notifications[index]
|
||||
testNotificationProcess.command = ["notify-send", "-h", "int:transient:1", "-a", "DMS", "-i", notif[2], notif[0], notif[1]]
|
||||
testNotificationProcess.running = true
|
||||
}
|
||||
|
||||
property Process testNotificationProcess
|
||||
|
||||
testNotificationProcess: Process {
|
||||
command: []
|
||||
running: false
|
||||
}
|
||||
|
||||
property Timer testNotifTimer1
|
||||
|
||||
testNotifTimer1: Timer {
|
||||
interval: 400
|
||||
repeat: false
|
||||
onTriggered: sendTestNotification(1)
|
||||
}
|
||||
|
||||
property Timer testNotifTimer2
|
||||
|
||||
testNotifTimer2: Timer {
|
||||
interval: 800
|
||||
repeat: false
|
||||
onTriggered: sendTestNotification(2)
|
||||
}
|
||||
|
||||
function setDankBarSpacing(spacing) {
|
||||
dankBarSpacing = spacing
|
||||
function setTopBarBottomGap(gap) {
|
||||
topBarBottomGap = gap
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDankBarBottomGap(gap) {
|
||||
dankBarBottomGap = gap
|
||||
function setTopBarInnerPadding(padding) {
|
||||
topBarInnerPadding = padding
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDankBarInnerPadding(padding) {
|
||||
dankBarInnerPadding = padding
|
||||
function setTopBarSquareCorners(enabled) {
|
||||
topBarSquareCorners = enabled
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDankBarSquareCorners(enabled) {
|
||||
dankBarSquareCorners = enabled
|
||||
function setTopBarNoBackground(enabled) {
|
||||
topBarNoBackground = enabled
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDankBarNoBackground(enabled) {
|
||||
dankBarNoBackground = enabled
|
||||
function setTopBarGothCornersEnabled(enabled) {
|
||||
topBarGothCornersEnabled = enabled
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDankBarGothCornersEnabled(enabled) {
|
||||
dankBarGothCornersEnabled = enabled
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDankBarPosition(position) {
|
||||
dankBarPosition = position
|
||||
if (position === SettingsData.Position.Bottom && dockPosition === SettingsData.Position.Bottom && showDock) {
|
||||
setDockPosition(SettingsData.Position.Top)
|
||||
return
|
||||
}
|
||||
if (position === SettingsData.Position.Top && dockPosition === SettingsData.Position.Top && showDock) {
|
||||
setDockPosition(SettingsData.Position.Bottom)
|
||||
return
|
||||
}
|
||||
if (position === SettingsData.Position.Left && dockPosition === SettingsData.Position.Left && showDock) {
|
||||
setDockPosition(SettingsData.Position.Right)
|
||||
return
|
||||
}
|
||||
if (position === SettingsData.Position.Right && dockPosition === SettingsData.Position.Right && showDock) {
|
||||
setDockPosition(SettingsData.Position.Left)
|
||||
return
|
||||
}
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function setDockPosition(position) {
|
||||
dockPosition = position
|
||||
if (position === SettingsData.Position.Bottom && dankBarPosition === SettingsData.Position.Bottom && showDock) {
|
||||
setDankBarPosition(SettingsData.Position.Top)
|
||||
}
|
||||
if (position === SettingsData.Position.Top && dankBarPosition === SettingsData.Position.Top && showDock) {
|
||||
setDankBarPosition(SettingsData.Position.Bottom)
|
||||
}
|
||||
if (position === SettingsData.Position.Left && dankBarPosition === SettingsData.Position.Left && showDock) {
|
||||
setDankBarPosition(SettingsData.Position.Right)
|
||||
}
|
||||
if (position === SettingsData.Position.Right && dankBarPosition === SettingsData.Position.Right && showDock) {
|
||||
setDankBarPosition(SettingsData.Position.Left)
|
||||
}
|
||||
saveSettings()
|
||||
Qt.callLater(() => forceDockLayoutRefresh())
|
||||
}
|
||||
function setDockSpacing(spacing) {
|
||||
dockSpacing = spacing
|
||||
saveSettings()
|
||||
}
|
||||
function setDockBottomGap(gap) {
|
||||
dockBottomGap = gap
|
||||
saveSettings()
|
||||
}
|
||||
function setDockOpenOnOverview(enabled) {
|
||||
dockOpenOnOverview = enabled
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function getPopupYPosition(barHeight) {
|
||||
const gothOffset = dankBarGothCornersEnabled ? Theme.cornerRadius : 0
|
||||
return barHeight + dankBarSpacing + dankBarBottomGap - gothOffset + Theme.popupDistance
|
||||
}
|
||||
|
||||
function getPopupTriggerPosition(globalPos, screen, barThickness, widgetWidth) {
|
||||
const screenX = screen ? screen.x : 0
|
||||
const screenY = screen ? screen.y : 0
|
||||
const relativeX = globalPos.x - screenX
|
||||
const relativeY = globalPos.y - screenY
|
||||
|
||||
if (dankBarPosition === SettingsData.Position.Left || dankBarPosition === SettingsData.Position.Right) {
|
||||
return {
|
||||
x: relativeY,
|
||||
y: barThickness + dankBarSpacing + Theme.popupDistance,
|
||||
width: widgetWidth
|
||||
}
|
||||
}
|
||||
return {
|
||||
x: relativeX,
|
||||
y: barThickness + dankBarSpacing + dankBarBottomGap + Theme.popupDistance,
|
||||
width: widgetWidth
|
||||
}
|
||||
}
|
||||
|
||||
function setLockScreenShowPowerActions(enabled) {
|
||||
lockScreenShowPowerActions = enabled
|
||||
saveSettings()
|
||||
@@ -1270,48 +1078,14 @@ Singleton {
|
||||
return Quickshell.screens.filter(screen => prefs.includes(screen.name))
|
||||
}
|
||||
|
||||
// Plugin settings functions
|
||||
function getPluginSetting(pluginId, key, defaultValue) {
|
||||
if (!pluginSettings[pluginId]) {
|
||||
return defaultValue
|
||||
}
|
||||
return pluginSettings[pluginId][key] !== undefined ? pluginSettings[pluginId][key] : defaultValue
|
||||
}
|
||||
|
||||
function setPluginSetting(pluginId, key, value) {
|
||||
if (!pluginSettings[pluginId]) {
|
||||
pluginSettings[pluginId] = {}
|
||||
}
|
||||
pluginSettings[pluginId][key] = value
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function removePluginSettings(pluginId) {
|
||||
if (pluginSettings[pluginId]) {
|
||||
delete pluginSettings[pluginId]
|
||||
saveSettings()
|
||||
}
|
||||
}
|
||||
|
||||
function getPluginSettingsForPlugin(pluginId) {
|
||||
return pluginSettings[pluginId] || {}
|
||||
}
|
||||
|
||||
function setAnimationSpeed(speed) {
|
||||
animationSpeed = speed
|
||||
saveSettings()
|
||||
}
|
||||
|
||||
function _shq(s) {
|
||||
return "'" + String(s).replace(/'/g, "'\\''") + "'"
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
if (!isGreeterMode) {
|
||||
loadSettings()
|
||||
fontCheckTimer.start()
|
||||
initializeListModels()
|
||||
}
|
||||
loadSettings()
|
||||
fontCheckTimer.start()
|
||||
initializeListModels()
|
||||
}
|
||||
|
||||
ListModel {
|
||||
@@ -1352,22 +1126,20 @@ Singleton {
|
||||
FileView {
|
||||
id: settingsFile
|
||||
|
||||
path: isGreeterMode ? "" : StandardPaths.writableLocation(StandardPaths.ConfigLocation) + "/DankMaterialShell/settings.json"
|
||||
path: StandardPaths.writableLocation(StandardPaths.ConfigLocation) + "/DankMaterialShell/settings.json"
|
||||
blockLoading: true
|
||||
blockWrites: true
|
||||
atomicWrites: true
|
||||
watchChanges: !isGreeterMode
|
||||
watchChanges: true
|
||||
onLoaded: {
|
||||
if (!isGreeterMode) {
|
||||
parseSettings(settingsFile.text())
|
||||
hasTriedDefaultSettings = false
|
||||
}
|
||||
parseSettings(settingsFile.text())
|
||||
hasTriedDefaultSettings = false
|
||||
}
|
||||
onLoadFailed: error => {
|
||||
if (!isGreeterMode && !hasTriedDefaultSettings) {
|
||||
if (!hasTriedDefaultSettings) {
|
||||
hasTriedDefaultSettings = true
|
||||
defaultSettingsCheckProcess.running = true
|
||||
} else if (!isGreeterMode) {
|
||||
} else {
|
||||
applyStoredTheme()
|
||||
}
|
||||
}
|
||||
@@ -1452,22 +1224,22 @@ Singleton {
|
||||
|
||||
IpcHandler {
|
||||
function reveal(): string {
|
||||
root.setDankBarVisible(true)
|
||||
root.setTopBarVisible(true)
|
||||
return "BAR_SHOW_SUCCESS"
|
||||
}
|
||||
|
||||
function hide(): string {
|
||||
root.setDankBarVisible(false)
|
||||
root.setTopBarVisible(false)
|
||||
return "BAR_HIDE_SUCCESS"
|
||||
}
|
||||
|
||||
function toggle(): string {
|
||||
root.toggleDankBarVisible()
|
||||
return root.dankBarVisible ? "BAR_SHOW_SUCCESS" : "BAR_HIDE_SUCCESS"
|
||||
root.toggleTopBarVisible()
|
||||
return topBarVisible ? "BAR_SHOW_SUCCESS" : "BAR_HIDE_SUCCESS"
|
||||
}
|
||||
|
||||
function status(): string {
|
||||
return root.dankBarVisible ? "visible" : "hidden"
|
||||
return topBarVisible ? "visible" : "hidden"
|
||||
}
|
||||
|
||||
target: "bar"
|
||||
|
||||
@@ -2,101 +2,101 @@
|
||||
// Separated from Theme.qml to keep that file clean
|
||||
|
||||
const CatppuccinMocha = {
|
||||
surface: "#313244",
|
||||
surface: "#45475a",
|
||||
surfaceText: "#cdd6f4",
|
||||
surfaceVariant: "#313244",
|
||||
surfaceVariant: "#45475a",
|
||||
surfaceVariantText: "#a6adc8",
|
||||
background: "#1e1e2e",
|
||||
backgroundText: "#cdd6f4",
|
||||
outline: "#6c7086",
|
||||
surfaceContainer: "#45475a",
|
||||
surfaceContainer: "#313244",
|
||||
surfaceContainerHigh: "#585b70",
|
||||
surfaceContainerHighest: "#6c7086"
|
||||
surfaceContainerHighest: "#7f849c"
|
||||
}
|
||||
|
||||
const CatppuccinLatte = {
|
||||
surface: "#e6e9ef",
|
||||
surface: "#bcc0cc",
|
||||
surfaceText: "#4c4f69",
|
||||
surfaceVariant: "#e6e9ef",
|
||||
surfaceVariant: "#bcc0cc",
|
||||
surfaceVariantText: "#6c6f85",
|
||||
background: "#eff1f5",
|
||||
backgroundText: "#4c4f69",
|
||||
outline: "#9ca0b0",
|
||||
surfaceContainer: "#dce0e8",
|
||||
surfaceContainerHigh: "#ccd0da",
|
||||
surfaceContainerHighest: "#bcc0cc"
|
||||
surfaceContainer: "#ccd0da",
|
||||
surfaceContainerHigh: "#acb0be",
|
||||
surfaceContainerHighest: "#8c8fa1"
|
||||
}
|
||||
|
||||
const CatppuccinVariants = {
|
||||
"cat-rosewater": {
|
||||
name: "Rosewater",
|
||||
dark: { primary: "#f5e0dc", secondary: "#f2cdcd", primaryText: "#1e1e2e", primaryContainer: "#7d5d56", surfaceTint: "#f5e0dc" },
|
||||
light: { primary: "#dc8a78", secondary: "#dd7878", primaryText: "#ffffff", primaryContainer: "#f6e7e3", surfaceTint: "#dc8a78" }
|
||||
dark: { primary: "#f5e0dc", secondary: "#f2cdcd", primaryText: "#1e1e2e", primaryContainer: "#8b6b5e", surfaceTint: "#f5e0dc" },
|
||||
light: { primary: "#dc8a78", secondary: "#dd7878", primaryText: "#ffffff", primaryContainer: "#f4d2ca", surfaceTint: "#dc8a78" }
|
||||
},
|
||||
"cat-flamingo": {
|
||||
name: "Flamingo",
|
||||
dark: { primary: "#f2cdcd", secondary: "#f5e0dc", primaryText: "#1e1e2e", primaryContainer: "#7a555a", surfaceTint: "#f2cdcd" },
|
||||
light: { primary: "#dd7878", secondary: "#dc8a78", primaryText: "#ffffff", primaryContainer: "#f6e5e5", surfaceTint: "#dd7878" }
|
||||
dark: { primary: "#f2cdcd", secondary: "#f5e0dc", primaryText: "#1e1e2e", primaryContainer: "#885d62", surfaceTint: "#f2cdcd" },
|
||||
light: { primary: "#dd7878", secondary: "#dc8a78", primaryText: "#ffffff", primaryContainer: "#f4caca", surfaceTint: "#dd7878" }
|
||||
},
|
||||
"cat-pink": {
|
||||
name: "Pink",
|
||||
dark: { primary: "#f5c2e7", secondary: "#cba6f7", primaryText: "#1e1e2e", primaryContainer: "#7a3f69", surfaceTint: "#f5c2e7" },
|
||||
light: { primary: "#ea76cb", secondary: "#8839ef", primaryText: "#ffffff", primaryContainer: "#f7d7ee", surfaceTint: "#ea76cb" }
|
||||
dark: { primary: "#f5c2e7", secondary: "#cba6f7", primaryText: "#1e1e2e", primaryContainer: "#8b537a", surfaceTint: "#f5c2e7" },
|
||||
light: { primary: "#ea76cb", secondary: "#8839ef", primaryText: "#ffffff", primaryContainer: "#f7c9e7", surfaceTint: "#ea76cb" }
|
||||
},
|
||||
"cat-mauve": {
|
||||
name: "Mauve",
|
||||
dark: { primary: "#cba6f7", secondary: "#b4befe", primaryText: "#1e1e2e", primaryContainer: "#55307f", surfaceTint: "#cba6f7" },
|
||||
light: { primary: "#8839ef", secondary: "#7287fd", primaryText: "#ffffff", primaryContainer: "#eadcff", surfaceTint: "#8839ef" }
|
||||
dark: { primary: "#cba6f7", secondary: "#b4befe", primaryText: "#1e1e2e", primaryContainer: "#61378a", surfaceTint: "#cba6f7" },
|
||||
light: { primary: "#8839ef", secondary: "#7287fd", primaryText: "#ffffff", primaryContainer: "#e4d3ff", surfaceTint: "#8839ef" }
|
||||
},
|
||||
"cat-red": {
|
||||
name: "Red",
|
||||
dark: { primary: "#f38ba8", secondary: "#eba0ac", primaryText: "#1e1e2e", primaryContainer: "#6f2438", surfaceTint: "#f38ba8" },
|
||||
light: { primary: "#d20f39", secondary: "#e64553", primaryText: "#ffffff", primaryContainer: "#f6d0d6", surfaceTint: "#d20f39" }
|
||||
dark: { primary: "#f38ba8", secondary: "#eba0ac", primaryText: "#1e1e2e", primaryContainer: "#891c3b", surfaceTint: "#f38ba8" },
|
||||
light: { primary: "#d20f39", secondary: "#e64553", primaryText: "#ffffff", primaryContainer: "#f1b8c4", surfaceTint: "#d20f39" }
|
||||
},
|
||||
"cat-maroon": {
|
||||
name: "Maroon",
|
||||
dark: { primary: "#eba0ac", secondary: "#f38ba8", primaryText: "#1e1e2e", primaryContainer: "#6d3641", surfaceTint: "#eba0ac" },
|
||||
light: { primary: "#e64553", secondary: "#d20f39", primaryText: "#ffffff", primaryContainer: "#f7d8dc", surfaceTint: "#e64553" }
|
||||
dark: { primary: "#eba0ac", secondary: "#f38ba8", primaryText: "#1e1e2e", primaryContainer: "#81313f", surfaceTint: "#eba0ac" },
|
||||
light: { primary: "#e64553", secondary: "#d20f39", primaryText: "#ffffff", primaryContainer: "#f4c3c8", surfaceTint: "#e64553" }
|
||||
},
|
||||
"cat-peach": {
|
||||
name: "Peach",
|
||||
dark: { primary: "#fab387", secondary: "#f9e2af", primaryText: "#1e1e2e", primaryContainer: "#734226", surfaceTint: "#fab387" },
|
||||
light: { primary: "#fe640b", secondary: "#df8e1d", primaryText: "#ffffff", primaryContainer: "#ffe4d5", surfaceTint: "#fe640b" }
|
||||
dark: { primary: "#fab387", secondary: "#f9e2af", primaryText: "#1e1e2e", primaryContainer: "#90441a", surfaceTint: "#fab387" },
|
||||
light: { primary: "#fe640b", secondary: "#df8e1d", primaryText: "#ffffff", primaryContainer: "#ffddcc", surfaceTint: "#fe640b" }
|
||||
},
|
||||
"cat-yellow": {
|
||||
name: "Yellow",
|
||||
dark: { primary: "#f9e2af", secondary: "#a6e3a1", primaryText: "#1e1e2e", primaryContainer: "#6e5a2f", surfaceTint: "#f9e2af" },
|
||||
light: { primary: "#df8e1d", secondary: "#40a02b", primaryText: "#ffffff", primaryContainer: "#fff6d6", surfaceTint: "#df8e1d" }
|
||||
dark: { primary: "#f9e2af", secondary: "#a6e3a1", primaryText: "#1e1e2e", primaryContainer: "#8f7342", surfaceTint: "#f9e2af" },
|
||||
light: { primary: "#df8e1d", secondary: "#40a02b", primaryText: "#ffffff", primaryContainer: "#fff3cc", surfaceTint: "#df8e1d" }
|
||||
},
|
||||
"cat-green": {
|
||||
name: "Green",
|
||||
dark: { primary: "#a6e3a1", secondary: "#94e2d5", primaryText: "#1e1e2e", primaryContainer: "#2f5f36", surfaceTint: "#a6e3a1" },
|
||||
light: { primary: "#40a02b", secondary: "#179299", primaryText: "#ffffff", primaryContainer: "#dff4e0", surfaceTint: "#40a02b" }
|
||||
dark: { primary: "#a6e3a1", secondary: "#94e2d5", primaryText: "#1e1e2e", primaryContainer: "#3c7534", surfaceTint: "#a6e3a1" },
|
||||
light: { primary: "#40a02b", secondary: "#179299", primaryText: "#ffffff", primaryContainer: "#d4f5d4", surfaceTint: "#40a02b" }
|
||||
},
|
||||
"cat-teal": {
|
||||
name: "Teal",
|
||||
dark: { primary: "#94e2d5", secondary: "#89dceb", primaryText: "#1e1e2e", primaryContainer: "#2e5e59", surfaceTint: "#94e2d5" },
|
||||
light: { primary: "#179299", secondary: "#04a5e5", primaryText: "#ffffff", primaryContainer: "#daf3f1", surfaceTint: "#179299" }
|
||||
dark: { primary: "#94e2d5", secondary: "#89dceb", primaryText: "#1e1e2e", primaryContainer: "#2a7468", surfaceTint: "#94e2d5" },
|
||||
light: { primary: "#179299", secondary: "#04a5e5", primaryText: "#ffffff", primaryContainer: "#ccf2f2", surfaceTint: "#179299" }
|
||||
},
|
||||
"cat-sky": {
|
||||
name: "Sky",
|
||||
dark: { primary: "#89dceb", secondary: "#74c7ec", primaryText: "#1e1e2e", primaryContainer: "#24586a", surfaceTint: "#89dceb" },
|
||||
light: { primary: "#04a5e5", secondary: "#209fb5", primaryText: "#ffffff", primaryContainer: "#dbf1fb", surfaceTint: "#04a5e5" }
|
||||
dark: { primary: "#89dceb", secondary: "#74c7ec", primaryText: "#1e1e2e", primaryContainer: "#196e7e", surfaceTint: "#89dceb" },
|
||||
light: { primary: "#04a5e5", secondary: "#209fb5", primaryText: "#ffffff", primaryContainer: "#ccebff", surfaceTint: "#04a5e5" }
|
||||
},
|
||||
"cat-sapphire": {
|
||||
name: "Sapphire",
|
||||
dark: { primary: "#74c7ec", secondary: "#89b4fa", primaryText: "#1e1e2e", primaryContainer: "#1f4d6f", surfaceTint: "#74c7ec" },
|
||||
light: { primary: "#209fb5", secondary: "#1e66f5", primaryText: "#ffffff", primaryContainer: "#def3f8", surfaceTint: "#209fb5" }
|
||||
dark: { primary: "#74c7ec", secondary: "#89b4fa", primaryText: "#1e1e2e", primaryContainer: "#0a597f", surfaceTint: "#74c7ec" },
|
||||
light: { primary: "#209fb5", secondary: "#1e66f5", primaryText: "#ffffff", primaryContainer: "#d0f0f5", surfaceTint: "#209fb5" }
|
||||
},
|
||||
"cat-blue": {
|
||||
name: "Blue",
|
||||
dark: { primary: "#89b4fa", secondary: "#b4befe", primaryText: "#1e1e2e", primaryContainer: "#243f75", surfaceTint: "#89b4fa" },
|
||||
light: { primary: "#1e66f5", secondary: "#7287fd", primaryText: "#ffffff", primaryContainer: "#e0e9ff", surfaceTint: "#1e66f5" }
|
||||
dark: { primary: "#89b4fa", secondary: "#b4befe", primaryText: "#1e1e2e", primaryContainer: "#19468d", surfaceTint: "#89b4fa" },
|
||||
light: { primary: "#1e66f5", secondary: "#7287fd", primaryText: "#ffffff", primaryContainer: "#ccd9ff", surfaceTint: "#1e66f5" }
|
||||
},
|
||||
"cat-lavender": {
|
||||
name: "Lavender",
|
||||
dark: { primary: "#b4befe", secondary: "#cba6f7", primaryText: "#1e1e2e", primaryContainer: "#3f4481", surfaceTint: "#b4befe" },
|
||||
light: { primary: "#7287fd", secondary: "#8839ef", primaryText: "#ffffff", primaryContainer: "#e5e8ff", surfaceTint: "#7287fd" }
|
||||
dark: { primary: "#b4befe", secondary: "#cba6f7", primaryText: "#1e1e2e", primaryContainer: "#4a5091", surfaceTint: "#b4befe" },
|
||||
light: { primary: "#7287fd", secondary: "#8839ef", primaryText: "#ffffff", primaryContainer: "#dde1ff", surfaceTint: "#7287fd" }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,17 +120,17 @@ const StockThemes = {
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#0d47a1",
|
||||
secondary: "#8ab4f8",
|
||||
surface: "#101418",
|
||||
surfaceText: "#e0e2e8",
|
||||
surfaceVariant: "#42474e",
|
||||
surfaceVariantText: "#c2c7cf",
|
||||
surface: "#1a1c1e",
|
||||
surfaceText: "#e3e8ef",
|
||||
surfaceVariant: "#44464f",
|
||||
surfaceVariantText: "#c4c7c5",
|
||||
surfaceTint: "#8ab4f8",
|
||||
background: "#101418",
|
||||
backgroundText: "#e0e2e8",
|
||||
outline: "#8c9199",
|
||||
surfaceContainer: "#1d2024",
|
||||
surfaceContainerHigh: "#272a2f",
|
||||
surfaceContainerHighest: "#32353a"
|
||||
background: "#1a1c1e",
|
||||
backgroundText: "#e3e8ef",
|
||||
outline: "#8e918f",
|
||||
surfaceContainer: "#1e2023",
|
||||
surfaceContainerHigh: "#292b2f",
|
||||
surfaceContainerHighest: "#343740"
|
||||
},
|
||||
purple: {
|
||||
name: "Purple",
|
||||
@@ -138,17 +138,17 @@ const StockThemes = {
|
||||
primaryText: "#381E72",
|
||||
primaryContainer: "#4F378B",
|
||||
secondary: "#CCC2DC",
|
||||
surface: "#141218",
|
||||
surfaceText: "#e6e0e9",
|
||||
surfaceVariant: "#49454e",
|
||||
surfaceVariantText: "#cac4cf",
|
||||
surface: "#10121E",
|
||||
surfaceText: "#E6E0E9",
|
||||
surfaceVariant: "#49454F",
|
||||
surfaceVariantText: "#CAC4D0",
|
||||
surfaceTint: "#D0BCFF",
|
||||
background: "#141218",
|
||||
backgroundText: "#e6e0e9",
|
||||
outline: "#948f99",
|
||||
surfaceContainer: "#211f24",
|
||||
surfaceContainerHigh: "#2b292f",
|
||||
surfaceContainerHighest: "#36343a"
|
||||
background: "#10121E",
|
||||
backgroundText: "#E6E0E9",
|
||||
outline: "#938F99",
|
||||
surfaceContainer: "#1D1B20",
|
||||
surfaceContainerHigh: "#2B2930",
|
||||
surfaceContainerHighest: "#36343B"
|
||||
},
|
||||
green: {
|
||||
name: "Green",
|
||||
@@ -156,17 +156,17 @@ const StockThemes = {
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#1b5e20",
|
||||
secondary: "#81c995",
|
||||
surface: "#10140f",
|
||||
surfaceText: "#e0e4db",
|
||||
surfaceVariant: "#424940",
|
||||
surfaceVariantText: "#c2c9bd",
|
||||
surface: "#0f1411",
|
||||
surfaceText: "#e1f5e3",
|
||||
surfaceVariant: "#404943",
|
||||
surfaceVariantText: "#c1cbc4",
|
||||
surfaceTint: "#81c995",
|
||||
background: "#10140f",
|
||||
backgroundText: "#e0e4db",
|
||||
outline: "#8c9388",
|
||||
surfaceContainer: "#1d211b",
|
||||
surfaceContainerHigh: "#272b25",
|
||||
surfaceContainerHighest: "#323630"
|
||||
background: "#0f1411",
|
||||
backgroundText: "#e1f5e3",
|
||||
outline: "#8b938c",
|
||||
surfaceContainer: "#1a1f1b",
|
||||
surfaceContainerHigh: "#252a26",
|
||||
surfaceContainerHighest: "#30352f"
|
||||
},
|
||||
orange: {
|
||||
name: "Orange",
|
||||
@@ -174,17 +174,17 @@ const StockThemes = {
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#3e2723",
|
||||
secondary: "#ffb74d",
|
||||
surface: "#1a120e",
|
||||
surfaceText: "#f0dfd8",
|
||||
surfaceVariant: "#52443d",
|
||||
surfaceVariantText: "#d7c2b9",
|
||||
surface: "#1c1410",
|
||||
surfaceText: "#f5f1ea",
|
||||
surfaceVariant: "#4a453a",
|
||||
surfaceVariantText: "#cbc5b8",
|
||||
surfaceTint: "#ffb74d",
|
||||
background: "#1a120e",
|
||||
backgroundText: "#f0dfd8",
|
||||
outline: "#a08d85",
|
||||
surfaceContainer: "#271e1a",
|
||||
surfaceContainerHigh: "#322824",
|
||||
surfaceContainerHighest: "#3d332e"
|
||||
background: "#1c1410",
|
||||
backgroundText: "#f5f1ea",
|
||||
outline: "#958f84",
|
||||
surfaceContainer: "#211e17",
|
||||
surfaceContainerHigh: "#2c291f",
|
||||
surfaceContainerHighest: "#373427"
|
||||
},
|
||||
red: {
|
||||
name: "Red",
|
||||
@@ -192,17 +192,17 @@ const StockThemes = {
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#4a0e0e",
|
||||
secondary: "#f28b82",
|
||||
surface: "#1a1110",
|
||||
surfaceText: "#f1dedc",
|
||||
surfaceVariant: "#534341",
|
||||
surfaceVariantText: "#d8c2be",
|
||||
surface: "#1c1011",
|
||||
surfaceText: "#f5e8ea",
|
||||
surfaceVariant: "#4a3f41",
|
||||
surfaceVariantText: "#cbc2c4",
|
||||
surfaceTint: "#f28b82",
|
||||
background: "#1a1110",
|
||||
backgroundText: "#f1dedc",
|
||||
outline: "#a08c89",
|
||||
surfaceContainer: "#271d1c",
|
||||
surfaceContainerHigh: "#322826",
|
||||
surfaceContainerHighest: "#3d3231"
|
||||
background: "#1c1011",
|
||||
backgroundText: "#f5e8ea",
|
||||
outline: "#958b8d",
|
||||
surfaceContainer: "#211b1c",
|
||||
surfaceContainerHigh: "#2c2426",
|
||||
surfaceContainerHighest: "#372f30"
|
||||
},
|
||||
cyan: {
|
||||
name: "Cyan",
|
||||
@@ -210,15 +210,15 @@ const StockThemes = {
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#004d5c",
|
||||
secondary: "#4dd0e1",
|
||||
surface: "#0e1416",
|
||||
surfaceText: "#dee3e5",
|
||||
surfaceVariant: "#3f484a",
|
||||
surfaceVariantText: "#bfc8ca",
|
||||
surface: "#0f1617",
|
||||
surfaceText: "#e8f4f5",
|
||||
surfaceVariant: "#3f474a",
|
||||
surfaceVariantText: "#c2c9cb",
|
||||
surfaceTint: "#4dd0e1",
|
||||
background: "#0e1416",
|
||||
backgroundText: "#dee3e5",
|
||||
outline: "#899295",
|
||||
surfaceContainer: "#1b2122",
|
||||
background: "#0f1617",
|
||||
backgroundText: "#e8f4f5",
|
||||
outline: "#8c9194",
|
||||
surfaceContainer: "#1a1f20",
|
||||
surfaceContainerHigh: "#252b2c",
|
||||
surfaceContainerHighest: "#303637"
|
||||
},
|
||||
@@ -228,17 +228,17 @@ const StockThemes = {
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#4a0e2f",
|
||||
secondary: "#f8bbd9",
|
||||
surface: "#191112",
|
||||
surfaceText: "#f0dee0",
|
||||
surfaceVariant: "#524345",
|
||||
surfaceVariantText: "#d6c2c3",
|
||||
surface: "#1a1014",
|
||||
surfaceText: "#f3e8ee",
|
||||
surfaceVariant: "#483f45",
|
||||
surfaceVariantText: "#c9c2c7",
|
||||
surfaceTint: "#f8bbd9",
|
||||
background: "#191112",
|
||||
backgroundText: "#f0dee0",
|
||||
outline: "#9f8c8e",
|
||||
surfaceContainer: "#261d1e",
|
||||
surfaceContainerHigh: "#312829",
|
||||
surfaceContainerHighest: "#3c3233"
|
||||
background: "#1a1014",
|
||||
backgroundText: "#f3e8ee",
|
||||
outline: "#938a90",
|
||||
surfaceContainer: "#1f1b1e",
|
||||
surfaceContainerHigh: "#2a2428",
|
||||
surfaceContainerHighest: "#352f32"
|
||||
},
|
||||
amber: {
|
||||
name: "Amber",
|
||||
@@ -246,17 +246,17 @@ const StockThemes = {
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#4a3c00",
|
||||
secondary: "#ffd54f",
|
||||
surface: "#17130b",
|
||||
surfaceText: "#ebe1d4",
|
||||
surfaceVariant: "#4d4639",
|
||||
surfaceVariantText: "#d0c5b4",
|
||||
surface: "#1a1710",
|
||||
surfaceText: "#f3f0e8",
|
||||
surfaceVariant: "#49453a",
|
||||
surfaceVariantText: "#cac5b8",
|
||||
surfaceTint: "#ffd54f",
|
||||
background: "#17130b",
|
||||
backgroundText: "#ebe1d4",
|
||||
outline: "#998f80",
|
||||
surfaceContainer: "#231f17",
|
||||
surfaceContainerHigh: "#2e2921",
|
||||
surfaceContainerHighest: "#39342b"
|
||||
background: "#1a1710",
|
||||
backgroundText: "#f3f0e8",
|
||||
outline: "#949084",
|
||||
surfaceContainer: "#1f1e17",
|
||||
surfaceContainerHigh: "#2a281f",
|
||||
surfaceContainerHighest: "#353327"
|
||||
},
|
||||
coral: {
|
||||
name: "Coral",
|
||||
@@ -265,16 +265,16 @@ const StockThemes = {
|
||||
primaryContainer: "#8c1d18",
|
||||
secondary: "#f9dedc",
|
||||
surface: "#1a1110",
|
||||
surfaceText: "#f1dedc",
|
||||
surfaceVariant: "#534341",
|
||||
surfaceVariantText: "#d8c2bf",
|
||||
surfaceText: "#f1e8e7",
|
||||
surfaceVariant: "#4a4142",
|
||||
surfaceVariantText: "#cdc2c1",
|
||||
surfaceTint: "#ffb4ab",
|
||||
background: "#1a1110",
|
||||
backgroundText: "#f1dedc",
|
||||
outline: "#a08c8a",
|
||||
surfaceContainer: "#271d1c",
|
||||
surfaceContainerHigh: "#322826",
|
||||
surfaceContainerHighest: "#3d3231"
|
||||
backgroundText: "#f1e8e7",
|
||||
outline: "#968b8a",
|
||||
surfaceContainer: "#201a19",
|
||||
surfaceContainerHigh: "#2b2221",
|
||||
surfaceContainerHighest: "#362d29"
|
||||
},
|
||||
monochrome: {
|
||||
name: "Monochrome",
|
||||
@@ -290,9 +290,9 @@ const StockThemes = {
|
||||
background: "#131315",
|
||||
backgroundText: "#e4e2e3",
|
||||
outline: "#929092",
|
||||
surfaceContainer: "#353535",
|
||||
surfaceContainerHigh: "#424242",
|
||||
surfaceContainerHighest: "#505050",
|
||||
surfaceContainer: "#2a2a2a",
|
||||
surfaceContainerHigh: "#2a2a2b",
|
||||
surfaceContainerHighest: "#353535",
|
||||
error: "#ffb4ab",
|
||||
warning: "#3f4759",
|
||||
info: "#595e6c",
|
||||
@@ -306,17 +306,17 @@ const StockThemes = {
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#e3f2fd",
|
||||
secondary: "#42a5f5",
|
||||
surface: "#f7f9ff",
|
||||
surfaceText: "#181c20",
|
||||
surfaceVariant: "#dee3eb",
|
||||
surfaceVariantText: "#42474e",
|
||||
surface: "#fefefe",
|
||||
surfaceText: "#1a1c1e",
|
||||
surfaceVariant: "#e7e0ec",
|
||||
surfaceVariantText: "#49454f",
|
||||
surfaceTint: "#1976d2",
|
||||
background: "#f7f9ff",
|
||||
backgroundText: "#181c20",
|
||||
outline: "#72777f",
|
||||
surfaceContainer: "#eceef4",
|
||||
surfaceContainerHigh: "#e6e8ee",
|
||||
surfaceContainerHighest: "#e0e2e8"
|
||||
background: "#fefefe",
|
||||
backgroundText: "#1a1c1e",
|
||||
outline: "#79747e",
|
||||
surfaceContainer: "#f3f3f3",
|
||||
surfaceContainerHigh: "#ececec",
|
||||
surfaceContainerHighest: "#e6e6e6"
|
||||
},
|
||||
purple: {
|
||||
name: "Purple Light",
|
||||
@@ -324,17 +324,17 @@ const StockThemes = {
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#EADDFF",
|
||||
secondary: "#625B71",
|
||||
surface: "#fef7ff",
|
||||
surfaceText: "#1d1b20",
|
||||
surfaceVariant: "#e7e0eb",
|
||||
surfaceVariantText: "#49454e",
|
||||
surface: "#FFFBFE",
|
||||
surfaceText: "#1C1B1F",
|
||||
surfaceVariant: "#E7E0EC",
|
||||
surfaceVariantText: "#49454F",
|
||||
surfaceTint: "#6750A4",
|
||||
background: "#fef7ff",
|
||||
backgroundText: "#1d1b20",
|
||||
outline: "#7a757f",
|
||||
surfaceContainer: "#f2ecf4",
|
||||
surfaceContainerHigh: "#ece6ee",
|
||||
surfaceContainerHighest: "#e6e0e9"
|
||||
background: "#FFFBFE",
|
||||
backgroundText: "#1C1B1F",
|
||||
outline: "#79747E",
|
||||
surfaceContainer: "#F3EDF7",
|
||||
surfaceContainerHigh: "#ECE6F0",
|
||||
surfaceContainerHighest: "#E6DFE9"
|
||||
},
|
||||
green: {
|
||||
name: "Green Light",
|
||||
@@ -342,17 +342,17 @@ const StockThemes = {
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#e8f5e8",
|
||||
secondary: "#4caf50",
|
||||
surface: "#f7fbf1",
|
||||
surfaceText: "#191d17",
|
||||
surfaceVariant: "#dee5d8",
|
||||
surfaceVariantText: "#424940",
|
||||
surface: "#fefefe",
|
||||
surfaceText: "#1a1c1e",
|
||||
surfaceVariant: "#e7e0ec",
|
||||
surfaceVariantText: "#49454f",
|
||||
surfaceTint: "#2e7d32",
|
||||
background: "#f7fbf1",
|
||||
backgroundText: "#191d17",
|
||||
outline: "#72796f",
|
||||
surfaceContainer: "#ecefe6",
|
||||
surfaceContainerHigh: "#e6e9e0",
|
||||
surfaceContainerHighest: "#e0e4db"
|
||||
background: "#fefefe",
|
||||
backgroundText: "#1a1c1e",
|
||||
outline: "#79747e",
|
||||
surfaceContainer: "#f3f3f3",
|
||||
surfaceContainerHigh: "#ececec",
|
||||
surfaceContainerHighest: "#e6e6e6"
|
||||
},
|
||||
orange: {
|
||||
name: "Orange Light",
|
||||
@@ -360,17 +360,17 @@ const StockThemes = {
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#ffecb3",
|
||||
secondary: "#ff9800",
|
||||
surface: "#fff8f6",
|
||||
surfaceText: "#221a16",
|
||||
surfaceVariant: "#f4ded5",
|
||||
surfaceVariantText: "#52443d",
|
||||
surface: "#fefefe",
|
||||
surfaceText: "#1a1c1e",
|
||||
surfaceVariant: "#e7e0ec",
|
||||
surfaceVariantText: "#49454f",
|
||||
surfaceTint: "#e65100",
|
||||
background: "#fff8f6",
|
||||
backgroundText: "#221a16",
|
||||
outline: "#85736c",
|
||||
surfaceContainer: "#fceae3",
|
||||
surfaceContainerHigh: "#f6e5de",
|
||||
surfaceContainerHighest: "#f0dfd8"
|
||||
background: "#fefefe",
|
||||
backgroundText: "#1a1c1e",
|
||||
outline: "#79747e",
|
||||
surfaceContainer: "#f3f3f3",
|
||||
surfaceContainerHigh: "#ececec",
|
||||
surfaceContainerHighest: "#e6e6e6"
|
||||
},
|
||||
red: {
|
||||
name: "Red Light",
|
||||
@@ -378,17 +378,17 @@ const StockThemes = {
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#ffebee",
|
||||
secondary: "#f44336",
|
||||
surface: "#fff8f7",
|
||||
surfaceText: "#231918",
|
||||
surfaceVariant: "#f5ddda",
|
||||
surfaceVariantText: "#534341",
|
||||
surface: "#fefefe",
|
||||
surfaceText: "#1a1c1e",
|
||||
surfaceVariant: "#e7e0ec",
|
||||
surfaceVariantText: "#49454f",
|
||||
surfaceTint: "#d32f2f",
|
||||
background: "#fff8f7",
|
||||
backgroundText: "#231918",
|
||||
outline: "#857370",
|
||||
surfaceContainer: "#fceae7",
|
||||
surfaceContainerHigh: "#f7e4e1",
|
||||
surfaceContainerHighest: "#f1dedc"
|
||||
background: "#fefefe",
|
||||
backgroundText: "#1a1c1e",
|
||||
outline: "#79747e",
|
||||
surfaceContainer: "#f3f3f3",
|
||||
surfaceContainerHigh: "#ececec",
|
||||
surfaceContainerHighest: "#e6e6e6"
|
||||
},
|
||||
cyan: {
|
||||
name: "Cyan Light",
|
||||
@@ -396,17 +396,17 @@ const StockThemes = {
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#e0f2f1",
|
||||
secondary: "#00bcd4",
|
||||
surface: "#f5fafc",
|
||||
surfaceText: "#171d1e",
|
||||
surfaceVariant: "#dbe4e6",
|
||||
surfaceVariantText: "#3f484a",
|
||||
surface: "#fefefe",
|
||||
surfaceText: "#1a1c1e",
|
||||
surfaceVariant: "#e7e0ec",
|
||||
surfaceVariantText: "#49454f",
|
||||
surfaceTint: "#0097a7",
|
||||
background: "#f5fafc",
|
||||
backgroundText: "#171d1e",
|
||||
outline: "#6f797b",
|
||||
surfaceContainer: "#e9eff0",
|
||||
surfaceContainerHigh: "#e3e9eb",
|
||||
surfaceContainerHighest: "#dee3e5"
|
||||
background: "#fefefe",
|
||||
backgroundText: "#1a1c1e",
|
||||
outline: "#79747e",
|
||||
surfaceContainer: "#f3f3f3",
|
||||
surfaceContainerHigh: "#ececec",
|
||||
surfaceContainerHighest: "#e6e6e6"
|
||||
},
|
||||
pink: {
|
||||
name: "Pink Light",
|
||||
@@ -414,17 +414,17 @@ const StockThemes = {
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#fce4ec",
|
||||
secondary: "#e91e63",
|
||||
surface: "#fff8f7",
|
||||
surfaceText: "#22191a",
|
||||
surfaceVariant: "#f3dddf",
|
||||
surfaceVariantText: "#524345",
|
||||
surface: "#fefefe",
|
||||
surfaceText: "#1a1c1e",
|
||||
surfaceVariant: "#e7e0ec",
|
||||
surfaceVariantText: "#49454f",
|
||||
surfaceTint: "#c2185b",
|
||||
background: "#fff8f7",
|
||||
backgroundText: "#22191a",
|
||||
outline: "#847375",
|
||||
surfaceContainer: "#fbeaeb",
|
||||
surfaceContainerHigh: "#f5e4e5",
|
||||
surfaceContainerHighest: "#f0dee0"
|
||||
background: "#fefefe",
|
||||
backgroundText: "#1a1c1e",
|
||||
outline: "#79747e",
|
||||
surfaceContainer: "#f3f3f3",
|
||||
surfaceContainerHigh: "#ececec",
|
||||
surfaceContainerHighest: "#e6e6e6"
|
||||
},
|
||||
amber: {
|
||||
name: "Amber Light",
|
||||
@@ -432,17 +432,17 @@ const StockThemes = {
|
||||
primaryText: "#000000",
|
||||
primaryContainer: "#fff8e1",
|
||||
secondary: "#ffc107",
|
||||
surface: "#fff8f2",
|
||||
surfaceText: "#1f1b13",
|
||||
surfaceVariant: "#ede1cf",
|
||||
surfaceVariantText: "#4d4639",
|
||||
surface: "#fefefe",
|
||||
surfaceText: "#1a1c1e",
|
||||
surfaceVariant: "#e7e0ec",
|
||||
surfaceVariantText: "#49454f",
|
||||
surfaceTint: "#ff8f00",
|
||||
background: "#fff8f2",
|
||||
backgroundText: "#1f1b13",
|
||||
outline: "#7f7667",
|
||||
surfaceContainer: "#f6ecdf",
|
||||
surfaceContainerHigh: "#f1e7d9",
|
||||
surfaceContainerHighest: "#ebe1d4"
|
||||
background: "#fefefe",
|
||||
backgroundText: "#1a1c1e",
|
||||
outline: "#79747e",
|
||||
surfaceContainer: "#f3f3f3",
|
||||
surfaceContainerHigh: "#ececec",
|
||||
surfaceContainerHighest: "#e6e6e6"
|
||||
},
|
||||
coral: {
|
||||
name: "Coral Light",
|
||||
@@ -450,17 +450,17 @@ const StockThemes = {
|
||||
primaryText: "#ffffff",
|
||||
primaryContainer: "#ffdad6",
|
||||
secondary: "#ff5449",
|
||||
surface: "#fff8f7",
|
||||
surfaceText: "#231918",
|
||||
surfaceVariant: "#f5ddda",
|
||||
surfaceVariantText: "#534341",
|
||||
surface: "#fefefe",
|
||||
surfaceText: "#1a1c1e",
|
||||
surfaceVariant: "#e7e0ec",
|
||||
surfaceVariantText: "#49454f",
|
||||
surfaceTint: "#8c1d18",
|
||||
background: "#fff8f7",
|
||||
backgroundText: "#231918",
|
||||
outline: "#857371",
|
||||
surfaceContainer: "#fceae7",
|
||||
surfaceContainerHigh: "#f6e4e2",
|
||||
surfaceContainerHighest: "#f1dedc"
|
||||
background: "#fefefe",
|
||||
backgroundText: "#1a1c1e",
|
||||
outline: "#79747e",
|
||||
surfaceContainer: "#f3f3f3",
|
||||
surfaceContainerHigh: "#ececec",
|
||||
surfaceContainerHighest: "#e6e6e6"
|
||||
},
|
||||
monochrome: {
|
||||
name: "Monochrome Light",
|
||||
@@ -476,9 +476,8 @@ const StockThemes = {
|
||||
background: "#ffffff",
|
||||
backgroundText: "#1a1a1a",
|
||||
outline: "#757577",
|
||||
surfaceContainer: "#e8e8ea",
|
||||
surfaceContainerHigh: "#dcdcde",
|
||||
surfaceContainerHighest: "#d0d0d2",
|
||||
surfaceContainer: "#f5f5f6",
|
||||
surfaceContainerHigh: "#eaeaeb",
|
||||
error: "#ba1a1a",
|
||||
warning: "#f9e79f",
|
||||
info: "#5d6475",
|
||||
|
||||
385
Common/Theme.qml
385
Common/Theme.qml
@@ -16,12 +16,9 @@ Singleton {
|
||||
|
||||
readonly property bool envDisableMatugen: Quickshell.env("DMS_DISABLE_MATUGEN") === "1" || Quickshell.env("DMS_DISABLE_MATUGEN") === "true"
|
||||
|
||||
// ! TODO - Synchronize with niri/hyprland gaps?
|
||||
readonly property real popupDistance: 2
|
||||
|
||||
property string currentTheme: "blue"
|
||||
property string currentThemeCategory: "generic"
|
||||
property bool isLightMode: typeof SessionData !== "undefined" ? SessionData.isLightMode : false
|
||||
property bool isLightMode: false
|
||||
|
||||
readonly property string dynamic: "dynamic"
|
||||
readonly property string custom : "custom"
|
||||
@@ -31,8 +28,9 @@ Singleton {
|
||||
readonly property string shellDir: Paths.strip(Qt.resolvedUrl(".").toString()).replace("/Common/", "")
|
||||
readonly property string wallpaperPath: {
|
||||
if (typeof SessionData === "undefined") return ""
|
||||
|
||||
|
||||
if (SessionData.perMonitorWallpaper) {
|
||||
// Use first monitor's wallpaper for dynamic theming
|
||||
var screens = Quickshell.screens
|
||||
if (screens.length > 0) {
|
||||
var firstMonitorWallpaper = SessionData.getMonitorWallpaper(screens[0].name)
|
||||
@@ -74,6 +72,7 @@ Singleton {
|
||||
property bool qtThemingEnabled: typeof SettingsData !== "undefined" ? (SettingsData.qt5ctAvailable || SettingsData.qt6ctAvailable) : false
|
||||
property var workerRunning: false
|
||||
property var matugenColors: ({})
|
||||
property bool extractionRequested: false
|
||||
property int colorUpdateTrigger: 0
|
||||
property var customThemeData: null
|
||||
|
||||
@@ -82,20 +81,11 @@ Singleton {
|
||||
Component.onCompleted: {
|
||||
Quickshell.execDetached(["mkdir", "-p", stateDir])
|
||||
matugenCheck.running = true
|
||||
if (typeof SessionData !== "undefined") {
|
||||
if (typeof SessionData !== "undefined")
|
||||
SessionData.isLightModeChanged.connect(root.onLightModeChanged)
|
||||
isLightMode = SessionData.isLightMode
|
||||
}
|
||||
|
||||
|
||||
if (typeof SettingsData !== "undefined" && SettingsData.currentThemeName) {
|
||||
switchTheme(SettingsData.currentThemeName, false, false)
|
||||
}
|
||||
}
|
||||
|
||||
function applyGreeterTheme(themeName) {
|
||||
switchTheme(themeName, false, false)
|
||||
if (themeName === dynamic && dynamicColorsFileView.path) {
|
||||
dynamicColorsFileView.reload()
|
||||
switchTheme(SettingsData.currentThemeName, false)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,22 +231,11 @@ Singleton {
|
||||
property color shadowMedium: Qt.rgba(0, 0, 0, 0.08)
|
||||
property color shadowStrong: Qt.rgba(0, 0, 0, 0.3)
|
||||
|
||||
readonly property var animationDurations: [
|
||||
{ shorter: 0, short: 0, medium: 0, long: 0, extraLong: 0 },
|
||||
{ shorter: 50, short: 75, medium: 150, long: 250, extraLong: 500 },
|
||||
{ shorter: 100, short: 150, medium: 300, long: 500, extraLong: 1000 },
|
||||
{ shorter: 150, short: 225, medium: 450, long: 750, extraLong: 1500 },
|
||||
{ shorter: 200, short: 300, medium: 600, long: 1000, extraLong: 2000 }
|
||||
]
|
||||
|
||||
readonly property int currentAnimationSpeed: typeof SettingsData !== "undefined" ? SettingsData.animationSpeed : SettingsData.AnimationSpeed.Short
|
||||
readonly property var currentDurations: animationDurations[currentAnimationSpeed] || animationDurations[SettingsData.AnimationSpeed.Short]
|
||||
|
||||
property int shorterDuration: currentDurations.shorter
|
||||
property int shortDuration: currentDurations.short
|
||||
property int mediumDuration: currentDurations.medium
|
||||
property int longDuration: currentDurations.long
|
||||
property int extraLongDuration: currentDurations.extraLong
|
||||
property int shorterDuration: 100
|
||||
property int shortDuration: 150
|
||||
property int mediumDuration: 300
|
||||
property int longDuration: 500
|
||||
property int extraLongDuration: 1000
|
||||
property int standardEasing: Easing.OutCubic
|
||||
property int emphasizedEasing: Easing.OutQuart
|
||||
|
||||
@@ -276,8 +255,8 @@ Singleton {
|
||||
property real iconSizeLarge: 32
|
||||
|
||||
property real panelTransparency: 0.85
|
||||
property real widgetTransparency: typeof SettingsData !== "undefined" && SettingsData.dankBarWidgetTransparency !== undefined ? SettingsData.dankBarWidgetTransparency : 1.0
|
||||
property real popupTransparency: typeof SettingsData !== "undefined" && SettingsData.popupTransparency !== undefined ? SettingsData.popupTransparency : 1.0
|
||||
property real widgetTransparency: typeof SettingsData !== "undefined" && SettingsData.topBarWidgetTransparency !== undefined ? SettingsData.topBarWidgetTransparency : 0.85
|
||||
property real popupTransparency: typeof SettingsData !== "undefined" && SettingsData.popupTransparency !== undefined ? SettingsData.popupTransparency : 0.92
|
||||
|
||||
function screenTransition() {
|
||||
CompositorService.isNiri && NiriService.doScreenTransition()
|
||||
@@ -286,15 +265,11 @@ Singleton {
|
||||
function switchTheme(themeName, savePrefs = true, enableTransition = true) {
|
||||
if (enableTransition) {
|
||||
screenTransition()
|
||||
themeTransitionTimer.themeName = themeName
|
||||
themeTransitionTimer.savePrefs = savePrefs
|
||||
themeTransitionTimer.restart()
|
||||
return
|
||||
}
|
||||
|
||||
if (themeName === dynamic) {
|
||||
currentTheme = dynamic
|
||||
currentThemeCategory = dynamic
|
||||
extractColors()
|
||||
} else if (themeName === custom) {
|
||||
currentTheme = custom
|
||||
currentThemeCategory = custom
|
||||
@@ -303,45 +278,34 @@ Singleton {
|
||||
}
|
||||
} else {
|
||||
currentTheme = themeName
|
||||
// Determine category based on theme name
|
||||
if (StockThemes.isCatppuccinVariant(themeName)) {
|
||||
currentThemeCategory = "catppuccin"
|
||||
} else {
|
||||
currentThemeCategory = "generic"
|
||||
}
|
||||
}
|
||||
const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode)
|
||||
if (savePrefs && typeof SettingsData !== "undefined" && !isGreeterMode)
|
||||
if (savePrefs && typeof SettingsData !== "undefined")
|
||||
SettingsData.setTheme(currentTheme)
|
||||
|
||||
if (!isGreeterMode) {
|
||||
generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
|
||||
function setLightMode(light, savePrefs = true, enableTransition = false) {
|
||||
if (enableTransition) {
|
||||
screenTransition()
|
||||
lightModeTransitionTimer.lightMode = light
|
||||
lightModeTransitionTimer.savePrefs = savePrefs
|
||||
lightModeTransitionTimer.restart()
|
||||
return
|
||||
}
|
||||
|
||||
const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode)
|
||||
function setLightMode(light, savePrefs = true) {
|
||||
screenTransition()
|
||||
isLightMode = light
|
||||
if (savePrefs && typeof SessionData !== "undefined" && !isGreeterMode)
|
||||
if (savePrefs && typeof SessionData !== "undefined")
|
||||
SessionData.setLightMode(isLightMode)
|
||||
if (!isGreeterMode) {
|
||||
PortalService.setLightMode(isLightMode)
|
||||
generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
PortalService.setLightMode(isLightMode)
|
||||
generateSystemThemesFromCurrentTheme()
|
||||
}
|
||||
|
||||
function toggleLightMode(savePrefs = true) {
|
||||
setLightMode(!isLightMode, savePrefs, true)
|
||||
setLightMode(!isLightMode, savePrefs)
|
||||
}
|
||||
|
||||
function forceGenerateSystemThemes() {
|
||||
screenTransition()
|
||||
if (!matugenAvailable) {
|
||||
return
|
||||
}
|
||||
@@ -365,10 +329,8 @@ Singleton {
|
||||
}
|
||||
|
||||
function switchThemeCategory(category, defaultTheme) {
|
||||
screenTransition()
|
||||
themeCategoryTransitionTimer.category = category
|
||||
themeCategoryTransitionTimer.defaultTheme = defaultTheme
|
||||
themeCategoryTransitionTimer.restart()
|
||||
currentThemeCategory = category
|
||||
switchTheme(defaultTheme, true, false)
|
||||
}
|
||||
|
||||
function getCatppuccinColor(variantName) {
|
||||
@@ -392,6 +354,7 @@ Singleton {
|
||||
}
|
||||
|
||||
function loadCustomTheme(themeData) {
|
||||
screenTransition()
|
||||
if (themeData.dark || themeData.light) {
|
||||
const colorMode = (typeof SessionData !== "undefined" && SessionData.isLightMode) ? "light" : "dark"
|
||||
const selectedTheme = themeData[colorMode] || themeData.dark || themeData.light
|
||||
@@ -563,6 +526,17 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
function extractColors() {
|
||||
extractionRequested = true
|
||||
if (matugenAvailable)
|
||||
if (rawWallpaperPath.startsWith("we:")) {
|
||||
fileCheckerTimer.start()
|
||||
} else {
|
||||
fileChecker.running = true
|
||||
}
|
||||
else
|
||||
matugenCheck.running = true
|
||||
}
|
||||
|
||||
function onLightModeChanged() {
|
||||
if (matugenColors && Object.keys(matugenColors).length > 0) {
|
||||
@@ -611,8 +585,7 @@ Singleton {
|
||||
}
|
||||
|
||||
function generateSystemThemesFromCurrentTheme() {
|
||||
const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode)
|
||||
if (!matugenAvailable || isGreeterMode)
|
||||
if (!matugenAvailable)
|
||||
return
|
||||
|
||||
const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode)
|
||||
@@ -676,18 +649,78 @@ Singleton {
|
||||
qtApplier.running = true
|
||||
}
|
||||
|
||||
function withAlpha(c, a) { return Qt.rgba(c.r, c.g, c.b, a); }
|
||||
function extractJsonFromText(text) {
|
||||
if (!text)
|
||||
return null
|
||||
|
||||
const start = text.search(/[{\[]/)
|
||||
if (start === -1)
|
||||
return null
|
||||
|
||||
const open = text[start]
|
||||
const pairs = {
|
||||
"{": '}',
|
||||
"[": ']'
|
||||
}
|
||||
const close = pairs[open]
|
||||
if (!close)
|
||||
return null
|
||||
|
||||
let inString = false
|
||||
let escape = false
|
||||
const stack = [open]
|
||||
|
||||
for (var i = start + 1; i < text.length; i++) {
|
||||
const ch = text[i]
|
||||
|
||||
if (inString) {
|
||||
if (escape) {
|
||||
escape = false
|
||||
} else if (ch === '\\') {
|
||||
escape = true
|
||||
} else if (ch === '"') {
|
||||
inString = false
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if (ch === '"') {
|
||||
inString = true
|
||||
continue
|
||||
}
|
||||
if (ch === '{' || ch === '[') {
|
||||
stack.push(ch)
|
||||
continue
|
||||
}
|
||||
if (ch === '}' || ch === ']') {
|
||||
const last = stack.pop()
|
||||
if (!last || pairs[last] !== ch) {
|
||||
return null
|
||||
}
|
||||
if (stack.length === 0) {
|
||||
return text.slice(start, i + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
Process {
|
||||
id: matugenCheck
|
||||
command: ["which", "matugen"]
|
||||
onExited: code => {
|
||||
matugenAvailable = (code === 0) && !envDisableMatugen
|
||||
const isGreeterMode = (typeof SessionData !== "undefined" && SessionData.isGreeterMode)
|
||||
|
||||
if (!matugenAvailable || isGreeterMode) {
|
||||
if (!matugenAvailable) {
|
||||
console.log("matugen not not available in path or disabled via DMS_DISABLE_MATUGEN")
|
||||
return
|
||||
}
|
||||
if (extractionRequested) {
|
||||
if (rawWallpaperPath.startsWith("we:")) {
|
||||
fileCheckerTimer.start()
|
||||
} else {
|
||||
fileChecker.running = true
|
||||
}
|
||||
}
|
||||
|
||||
const isLight = (typeof SessionData !== "undefined" && SessionData.isLightMode)
|
||||
const iconTheme = (typeof SettingsData !== "undefined" && SettingsData.iconTheme) ? SettingsData.iconTheme : "System Default"
|
||||
@@ -723,7 +756,128 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: fileChecker
|
||||
command: ["test", "-r", wallpaperPath]
|
||||
onExited: code => {
|
||||
if (code === 0) {
|
||||
matugenProcess.running = true
|
||||
} else if (wallpaperPath.startsWith("#")) {
|
||||
colorMatugenProcess.running = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: fileCheckerTimer
|
||||
interval: 1000
|
||||
repeat: false
|
||||
onTriggered: {
|
||||
fileChecker.running = true
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: matugenProcess
|
||||
command: {
|
||||
const scheme = (typeof SettingsData !== "undefined" && SettingsData.matugenScheme) ? SettingsData.matugenScheme : "scheme-tonal-spot"
|
||||
return ["matugen", "image", wallpaperPath, "--json", "hex", "-t", scheme]
|
||||
}
|
||||
|
||||
stdout: StdioCollector {
|
||||
id: matugenCollector
|
||||
onStreamFinished: {
|
||||
if (!matugenCollector.text) {
|
||||
if (typeof ToastService !== "undefined") {
|
||||
ToastService.wallpaperErrorStatus = "error"
|
||||
ToastService.showError("Wallpaper Processing Failed: Empty JSON extracted from matugen output.")
|
||||
}
|
||||
return
|
||||
}
|
||||
const extractedJson = extractJsonFromText(matugenCollector.text)
|
||||
if (!extractedJson) {
|
||||
if (typeof ToastService !== "undefined") {
|
||||
ToastService.wallpaperErrorStatus = "error"
|
||||
ToastService.showError("Wallpaper Processing Failed: Invalid JSON extracted from matugen output.")
|
||||
}
|
||||
console.log("Raw matugen output:", matugenCollector.text)
|
||||
return
|
||||
}
|
||||
try {
|
||||
root.matugenColors = JSON.parse(extractedJson)
|
||||
root.colorUpdateTrigger++
|
||||
if (typeof ToastService !== "undefined") {
|
||||
ToastService.clearWallpaperError()
|
||||
}
|
||||
} catch (e) {
|
||||
if (typeof ToastService !== "undefined") {
|
||||
ToastService.wallpaperErrorStatus = "error"
|
||||
ToastService.showError("Wallpaper processing failed (JSON parse error after extraction)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExited: code => {
|
||||
if (code !== 0) {
|
||||
if (typeof ToastService !== "undefined") {
|
||||
ToastService.wallpaperErrorStatus = "error"
|
||||
ToastService.showError("Matugen command failed with exit code " + code)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: colorMatugenProcess
|
||||
command: {
|
||||
const scheme = (typeof SettingsData !== "undefined" && SettingsData.matugenScheme) ? SettingsData.matugenScheme : "scheme-tonal-spot"
|
||||
return ["matugen", "color", "hex", wallpaperPath, "--json", "hex", "-t", scheme]
|
||||
}
|
||||
|
||||
stdout: StdioCollector {
|
||||
id: colorMatugenCollector
|
||||
onStreamFinished: {
|
||||
if (!colorMatugenCollector.text) {
|
||||
if (typeof ToastService !== "undefined") {
|
||||
ToastService.wallpaperErrorStatus = "error"
|
||||
ToastService.showError("Color Processing Failed: Empty JSON extracted from matugen output.")
|
||||
}
|
||||
return
|
||||
}
|
||||
const extractedJson = extractJsonFromText(colorMatugenCollector.text)
|
||||
if (!extractedJson) {
|
||||
if (typeof ToastService !== "undefined") {
|
||||
ToastService.wallpaperErrorStatus = "error"
|
||||
ToastService.showError("Color Processing Failed: Invalid JSON extracted from matugen output.")
|
||||
}
|
||||
console.log("Raw matugen output:", colorMatugenCollector.text)
|
||||
return
|
||||
}
|
||||
try {
|
||||
root.matugenColors = JSON.parse(extractedJson)
|
||||
root.colorUpdateTrigger++
|
||||
if (typeof ToastService !== "undefined") {
|
||||
ToastService.clearWallpaperError()
|
||||
}
|
||||
} catch (e) {
|
||||
if (typeof ToastService !== "undefined") {
|
||||
ToastService.wallpaperErrorStatus = "error"
|
||||
ToastService.showError("Color processing failed (JSON parse error after extraction)")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onExited: code => {
|
||||
if (code !== 0) {
|
||||
if (typeof ToastService !== "undefined") {
|
||||
ToastService.wallpaperErrorStatus = "error"
|
||||
ToastService.showError("Matugen color command failed with exit code " + code)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: ensureStateDir
|
||||
@@ -736,7 +890,10 @@ Singleton {
|
||||
onExited: exitCode => {
|
||||
workerRunning = false
|
||||
|
||||
if (exitCode !== 0 && exitCode !== 2) {
|
||||
if (exitCode === 2) {
|
||||
// Exit code 2 means wallpaper/color not found - this is expected on first run
|
||||
console.log("Theme worker: wallpaper/color not found, skipping theme generation")
|
||||
} else if (exitCode !== 0) {
|
||||
if (typeof ToastService !== "undefined") {
|
||||
ToastService.showError("Theme worker failed (" + exitCode + ")")
|
||||
}
|
||||
@@ -823,55 +980,6 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: dynamicColorsFileView
|
||||
path: {
|
||||
const greetCfgDir = Quickshell.env("DMS_GREET_CFG_DIR") || "/etc/greetd/.dms"
|
||||
const colorsPath = SessionData.isGreeterMode
|
||||
? greetCfgDir + "/colors.json"
|
||||
: stateDir + "/dms-colors.json"
|
||||
return colorsPath
|
||||
}
|
||||
watchChanges: currentTheme === dynamic && !SessionData.isGreeterMode
|
||||
|
||||
function parseAndLoadColors() {
|
||||
try {
|
||||
const colorsText = dynamicColorsFileView.text()
|
||||
if (colorsText) {
|
||||
root.matugenColors = JSON.parse(colorsText)
|
||||
root.colorUpdateTrigger++
|
||||
if (typeof ToastService !== "undefined") {
|
||||
ToastService.clearWallpaperError()
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.error("Theme: Failed to parse dynamic colors:", e)
|
||||
if (typeof ToastService !== "undefined") {
|
||||
ToastService.wallpaperErrorStatus = "error"
|
||||
ToastService.showError("Dynamic colors parse error: " + e.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onLoaded: {
|
||||
if (currentTheme === dynamic) {
|
||||
parseAndLoadColors()
|
||||
}
|
||||
}
|
||||
|
||||
onFileChanged: {
|
||||
if (currentTheme === dynamic) {
|
||||
dynamicColorsFileView.reload()
|
||||
}
|
||||
}
|
||||
|
||||
onLoadFailed: function (error) {
|
||||
if (currentTheme === dynamic && typeof ToastService !== "undefined") {
|
||||
ToastService.showError("Failed to read dynamic colors: " + error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
target: "theme"
|
||||
|
||||
@@ -881,12 +989,12 @@ Singleton {
|
||||
}
|
||||
|
||||
function light(): string {
|
||||
root.setLightMode(true, true, true)
|
||||
root.setLightMode(true)
|
||||
return "light"
|
||||
}
|
||||
|
||||
function dark(): string {
|
||||
root.setLightMode(false, true, true)
|
||||
root.setLightMode(false)
|
||||
return "dark"
|
||||
}
|
||||
|
||||
@@ -894,35 +1002,4 @@ Singleton {
|
||||
return root.isLightMode ? "light" : "dark"
|
||||
}
|
||||
}
|
||||
|
||||
// These timers are for screen transitions, since sometimes QML still beats the niri call
|
||||
Timer {
|
||||
id: themeTransitionTimer
|
||||
interval: 50
|
||||
repeat: false
|
||||
property string themeName: ""
|
||||
property bool savePrefs: true
|
||||
onTriggered: root.switchTheme(themeName, savePrefs, false)
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: lightModeTransitionTimer
|
||||
interval: 100
|
||||
repeat: false
|
||||
property bool lightMode: false
|
||||
property bool savePrefs: true
|
||||
onTriggered: root.setLightMode(lightMode, savePrefs, false)
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: themeCategoryTransitionTimer
|
||||
interval: 50
|
||||
repeat: false
|
||||
property string category: ""
|
||||
property string defaultTheme: ""
|
||||
onTriggered: {
|
||||
root.currentThemeCategory = category
|
||||
root.switchTheme(defaultTheme, true, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Services.Greetd
|
||||
import qs.Common
|
||||
import qs.Modules.Greetd
|
||||
|
||||
ShellRoot {
|
||||
id: root
|
||||
|
||||
WlSessionLock {
|
||||
id: sessionLock
|
||||
locked: true
|
||||
|
||||
onLockedChanged: {
|
||||
if (!locked) {
|
||||
console.log("Greetd session unlocked, exiting")
|
||||
}
|
||||
}
|
||||
|
||||
GreeterSurface {
|
||||
lock: sessionLock
|
||||
}
|
||||
}
|
||||
}
|
||||
641
DMSShell.qml
641
DMSShell.qml
@@ -1,641 +0,0 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
import qs.Modals
|
||||
import qs.Modals.Clipboard
|
||||
import qs.Modals.Common
|
||||
import qs.Modals.Settings
|
||||
import qs.Modals.Spotlight
|
||||
import qs.Modules
|
||||
import qs.Modules.AppDrawer
|
||||
import qs.Modules.DankDash
|
||||
import qs.Modules.ControlCenter
|
||||
import qs.Modules.Dock
|
||||
import qs.Modules.Lock
|
||||
import qs.Modules.Notepad
|
||||
import qs.Modules.Notifications.Center
|
||||
import qs.Widgets
|
||||
import qs.Modules.Notifications.Popup
|
||||
import qs.Modules.OSD
|
||||
import qs.Modules.ProcessList
|
||||
import qs.Modules.Settings
|
||||
import qs.Modules.DankBar
|
||||
import qs.Modules.DankBar.Popouts
|
||||
import qs.Modules.Plugins
|
||||
import qs.Services
|
||||
|
||||
|
||||
Item {
|
||||
Component.onCompleted: {
|
||||
PortalService.init()
|
||||
// Initialize DisplayService night mode functionality
|
||||
DisplayService.nightModeEnabled
|
||||
// Initialize WallpaperCyclingService
|
||||
WallpaperCyclingService.cyclingActive
|
||||
// Initialize PluginService by accessing its properties
|
||||
PluginService.pluginDirectory
|
||||
}
|
||||
|
||||
WallpaperBackground {}
|
||||
|
||||
Lock {
|
||||
id: lock
|
||||
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: dankBarLoader
|
||||
asynchronous: false
|
||||
|
||||
property var currentPosition: SettingsData.dankBarPosition
|
||||
|
||||
sourceComponent: DankBar {
|
||||
onColorPickerRequested: colorPickerModal.show()
|
||||
}
|
||||
|
||||
onCurrentPositionChanged: {
|
||||
const component = sourceComponent
|
||||
sourceComponent = null
|
||||
Qt.callLater(() => {
|
||||
sourceComponent = component
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: dockLoader
|
||||
active: true
|
||||
asynchronous: false
|
||||
|
||||
property var currentPosition: SettingsData.dockPosition
|
||||
|
||||
sourceComponent: Dock {
|
||||
contextMenu: dockContextMenuLoader.item ? dockContextMenuLoader.item : null
|
||||
}
|
||||
|
||||
onLoaded: {
|
||||
if (item) {
|
||||
dockContextMenuLoader.active = true
|
||||
}
|
||||
}
|
||||
|
||||
onCurrentPositionChanged: {
|
||||
console.log("DEBUG: Dock position changed to:", currentPosition, "- recreating dock")
|
||||
const comp = sourceComponent
|
||||
sourceComponent = null
|
||||
Qt.callLater(() => {
|
||||
sourceComponent = comp
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: dankDashPopoutLoader
|
||||
|
||||
active: false
|
||||
asynchronous: true
|
||||
|
||||
sourceComponent: Component {
|
||||
DankDashPopout {
|
||||
id: dankDashPopout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: dockContextMenuLoader
|
||||
|
||||
active: false
|
||||
|
||||
DockContextMenu {
|
||||
id: dockContextMenu
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: notificationCenterLoader
|
||||
|
||||
active: false
|
||||
|
||||
NotificationCenterPopout {
|
||||
id: notificationCenter
|
||||
}
|
||||
}
|
||||
|
||||
Variants {
|
||||
model: SettingsData.getFilteredScreens("notifications")
|
||||
|
||||
delegate: NotificationPopupManager {
|
||||
modelData: item
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: controlCenterLoader
|
||||
|
||||
active: false
|
||||
|
||||
property var modalRef: colorPickerModal
|
||||
|
||||
ControlCenterPopout {
|
||||
id: controlCenterPopout
|
||||
colorPickerModal: controlCenterLoader.modalRef
|
||||
|
||||
onPowerActionRequested: (action, title, message) => {
|
||||
powerConfirmModalLoader.active = true
|
||||
if (powerConfirmModalLoader.item) {
|
||||
powerConfirmModalLoader.item.confirmButtonColor = action === "poweroff" ? Theme.error : action === "reboot" ? Theme.warning : Theme.primary
|
||||
powerConfirmModalLoader.item.show(title, message, function () {
|
||||
switch (action) {
|
||||
case "logout":
|
||||
SessionService.logout()
|
||||
break
|
||||
case "suspend":
|
||||
SessionService.suspend()
|
||||
break
|
||||
case "hibernate":
|
||||
SessionService.hibernate()
|
||||
break
|
||||
case "reboot":
|
||||
SessionService.reboot()
|
||||
break
|
||||
case "poweroff":
|
||||
SessionService.poweroff()
|
||||
break
|
||||
}
|
||||
}, function () {})
|
||||
}
|
||||
}
|
||||
onLockRequested: {
|
||||
lock.activate()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: wifiPasswordModalLoader
|
||||
|
||||
active: false
|
||||
|
||||
WifiPasswordModal {
|
||||
id: wifiPasswordModal
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: networkInfoModalLoader
|
||||
|
||||
active: false
|
||||
|
||||
NetworkInfoModal {
|
||||
id: networkInfoModal
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: batteryPopoutLoader
|
||||
|
||||
active: false
|
||||
|
||||
BatteryPopout {
|
||||
id: batteryPopout
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: vpnPopoutLoader
|
||||
|
||||
active: false
|
||||
|
||||
VpnPopout {
|
||||
id: vpnPopout
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: powerMenuLoader
|
||||
|
||||
active: false
|
||||
|
||||
PowerMenu {
|
||||
id: powerMenu
|
||||
|
||||
onPowerActionRequested: (action, title, message) => {
|
||||
powerConfirmModalLoader.active = true
|
||||
if (powerConfirmModalLoader.item) {
|
||||
powerConfirmModalLoader.item.confirmButtonColor = action === "poweroff" ? Theme.error : action === "reboot" ? Theme.warning : Theme.primary
|
||||
powerConfirmModalLoader.item.show(title, message, function () {
|
||||
switch (action) {
|
||||
case "logout":
|
||||
SessionService.logout()
|
||||
break
|
||||
case "suspend":
|
||||
SessionService.suspend()
|
||||
break
|
||||
case "hibernate":
|
||||
SessionService.hibernate()
|
||||
break
|
||||
case "reboot":
|
||||
SessionService.reboot()
|
||||
break
|
||||
case "poweroff":
|
||||
SessionService.poweroff()
|
||||
break
|
||||
}
|
||||
}, function () {})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: powerConfirmModalLoader
|
||||
|
||||
active: false
|
||||
|
||||
ConfirmModal {
|
||||
id: powerConfirmModal
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: processListPopoutLoader
|
||||
|
||||
active: false
|
||||
|
||||
ProcessListPopout {
|
||||
id: processListPopout
|
||||
}
|
||||
}
|
||||
|
||||
SettingsModal {
|
||||
id: settingsModal
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: appDrawerLoader
|
||||
|
||||
active: false
|
||||
|
||||
AppDrawerPopout {
|
||||
id: appDrawerPopout
|
||||
}
|
||||
}
|
||||
|
||||
SpotlightModal {
|
||||
id: spotlightModal
|
||||
}
|
||||
|
||||
ClipboardHistoryModal {
|
||||
id: clipboardHistoryModalPopup
|
||||
}
|
||||
|
||||
NotificationModal {
|
||||
id: notificationModal
|
||||
}
|
||||
ColorPickerModal {
|
||||
id: colorPickerModal
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: processListModalLoader
|
||||
|
||||
active: false
|
||||
|
||||
ProcessListModal {
|
||||
id: processListModal
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: systemUpdateLoader
|
||||
|
||||
active: false
|
||||
|
||||
SystemUpdatePopout {
|
||||
id: systemUpdatePopout
|
||||
}
|
||||
}
|
||||
|
||||
Variants {
|
||||
id: notepadSlideoutVariants
|
||||
model: SettingsData.getFilteredScreens("notepad")
|
||||
|
||||
delegate: DankSlideout {
|
||||
id: notepadSlideout
|
||||
modelData: item
|
||||
title: qsTr("Notepad")
|
||||
slideoutWidth: 480
|
||||
expandable: true
|
||||
expandedWidthValue: 960
|
||||
customTransparency: SettingsData.notepadTransparencyOverride
|
||||
|
||||
content: Component {
|
||||
Notepad {
|
||||
onHideRequested: {
|
||||
notepadSlideout.hide()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
if (isVisible) {
|
||||
hide()
|
||||
} else {
|
||||
show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LazyLoader {
|
||||
id: powerMenuModalLoader
|
||||
|
||||
active: false
|
||||
|
||||
PowerMenuModal {
|
||||
id: powerMenuModal
|
||||
|
||||
onPowerActionRequested: (action, title, message) => {
|
||||
powerConfirmModalLoader.active = true
|
||||
if (powerConfirmModalLoader.item) {
|
||||
powerConfirmModalLoader.item.confirmButtonColor = action === "poweroff" ? Theme.error : action === "reboot" ? Theme.warning : Theme.primary
|
||||
powerConfirmModalLoader.item.show(title, message, function () {
|
||||
switch (action) {
|
||||
case "logout":
|
||||
SessionService.logout()
|
||||
break
|
||||
case "suspend":
|
||||
SessionService.suspend()
|
||||
break
|
||||
case "hibernate":
|
||||
SessionService.hibernate()
|
||||
break
|
||||
case "reboot":
|
||||
SessionService.reboot()
|
||||
break
|
||||
case "poweroff":
|
||||
SessionService.poweroff()
|
||||
break
|
||||
}
|
||||
}, function () {})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
function open() {
|
||||
powerMenuModalLoader.active = true
|
||||
if (powerMenuModalLoader.item)
|
||||
powerMenuModalLoader.item.open()
|
||||
|
||||
return "POWERMENU_OPEN_SUCCESS"
|
||||
}
|
||||
|
||||
function close() {
|
||||
if (powerMenuModalLoader.item)
|
||||
powerMenuModalLoader.item.close()
|
||||
|
||||
return "POWERMENU_CLOSE_SUCCESS"
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
powerMenuModalLoader.active = true
|
||||
if (powerMenuModalLoader.item)
|
||||
powerMenuModalLoader.item.toggle()
|
||||
|
||||
return "POWERMENU_TOGGLE_SUCCESS"
|
||||
}
|
||||
|
||||
target: "powermenu"
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
function open(): string {
|
||||
processListModalLoader.active = true
|
||||
if (processListModalLoader.item)
|
||||
processListModalLoader.item.show()
|
||||
|
||||
return "PROCESSLIST_OPEN_SUCCESS"
|
||||
}
|
||||
|
||||
function close(): string {
|
||||
if (processListModalLoader.item)
|
||||
processListModalLoader.item.hide()
|
||||
|
||||
return "PROCESSLIST_CLOSE_SUCCESS"
|
||||
}
|
||||
|
||||
function toggle(): string {
|
||||
processListModalLoader.active = true
|
||||
if (processListModalLoader.item)
|
||||
processListModalLoader.item.toggle()
|
||||
|
||||
return "PROCESSLIST_TOGGLE_SUCCESS"
|
||||
}
|
||||
|
||||
target: "processlist"
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
function open(): string {
|
||||
controlCenterLoader.active = true
|
||||
if (controlCenterLoader.item) {
|
||||
controlCenterLoader.item.open()
|
||||
return "CONTROL_CENTER_OPEN_SUCCESS"
|
||||
}
|
||||
return "CONTROL_CENTER_OPEN_FAILED"
|
||||
}
|
||||
|
||||
function close(): string {
|
||||
if (controlCenterLoader.item) {
|
||||
controlCenterLoader.item.close()
|
||||
return "CONTROL_CENTER_CLOSE_SUCCESS"
|
||||
}
|
||||
return "CONTROL_CENTER_CLOSE_FAILED"
|
||||
}
|
||||
|
||||
function toggle(): string {
|
||||
controlCenterLoader.active = true
|
||||
if (controlCenterLoader.item) {
|
||||
controlCenterLoader.item.toggle()
|
||||
return "CONTROL_CENTER_TOGGLE_SUCCESS"
|
||||
}
|
||||
return "CONTROL_CENTER_TOGGLE_FAILED"
|
||||
}
|
||||
|
||||
target: "control-center"
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
function open(tab: string): string {
|
||||
dankDashPopoutLoader.active = true
|
||||
if (dankDashPopoutLoader.item) {
|
||||
switch (tab.toLowerCase()) {
|
||||
case "media":
|
||||
dankDashPopoutLoader.item.currentTabIndex = 1
|
||||
break
|
||||
case "weather":
|
||||
dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 2 : 0
|
||||
break
|
||||
default:
|
||||
dankDashPopoutLoader.item.currentTabIndex = 0
|
||||
break
|
||||
}
|
||||
dankDashPopoutLoader.item.setTriggerPosition(Screen.width / 2, Theme.barHeight + Theme.spacingS, 100, "center", Screen)
|
||||
dankDashPopoutLoader.item.dashVisible = true
|
||||
return "DASH_OPEN_SUCCESS"
|
||||
}
|
||||
return "DASH_OPEN_FAILED"
|
||||
}
|
||||
|
||||
function close(): string {
|
||||
if (dankDashPopoutLoader.item) {
|
||||
dankDashPopoutLoader.item.dashVisible = false
|
||||
return "DASH_CLOSE_SUCCESS"
|
||||
}
|
||||
return "DASH_CLOSE_FAILED"
|
||||
}
|
||||
|
||||
function toggle(tab: string): string {
|
||||
dankDashPopoutLoader.active = true
|
||||
if (dankDashPopoutLoader.item) {
|
||||
if (dankDashPopoutLoader.item.dashVisible) {
|
||||
dankDashPopoutLoader.item.dashVisible = false
|
||||
} else {
|
||||
switch (tab.toLowerCase()) {
|
||||
case "media":
|
||||
dankDashPopoutLoader.item.currentTabIndex = 1
|
||||
break
|
||||
case "weather":
|
||||
dankDashPopoutLoader.item.currentTabIndex = SettingsData.weatherEnabled ? 2 : 0
|
||||
break
|
||||
default:
|
||||
dankDashPopoutLoader.item.currentTabIndex = 0
|
||||
break
|
||||
}
|
||||
dankDashPopoutLoader.item.setTriggerPosition(Screen.width / 2, Theme.barHeight + Theme.spacingS, 100, "center", Screen)
|
||||
dankDashPopoutLoader.item.dashVisible = true
|
||||
}
|
||||
return "DASH_TOGGLE_SUCCESS"
|
||||
}
|
||||
return "DASH_TOGGLE_FAILED"
|
||||
}
|
||||
|
||||
target: "dash"
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
function getFocusedScreenName() {
|
||||
if (CompositorService.isHyprland && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor) {
|
||||
return Hyprland.focusedWorkspace.monitor.name
|
||||
}
|
||||
if (CompositorService.isNiri && NiriService.currentOutput) {
|
||||
return NiriService.currentOutput
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
function getActiveNotepadInstance() {
|
||||
if (notepadSlideoutVariants.instances.length === 0) {
|
||||
return null
|
||||
}
|
||||
|
||||
if (notepadSlideoutVariants.instances.length === 1) {
|
||||
return notepadSlideoutVariants.instances[0]
|
||||
}
|
||||
|
||||
var focusedScreen = getFocusedScreenName()
|
||||
if (focusedScreen && notepadSlideoutVariants.instances.length > 0) {
|
||||
for (var i = 0; i < notepadSlideoutVariants.instances.length; i++) {
|
||||
var slideout = notepadSlideoutVariants.instances[i]
|
||||
if (slideout.modelData && slideout.modelData.name === focusedScreen) {
|
||||
return slideout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < notepadSlideoutVariants.instances.length; i++) {
|
||||
var slideout = notepadSlideoutVariants.instances[i]
|
||||
if (slideout.isVisible) {
|
||||
return slideout
|
||||
}
|
||||
}
|
||||
|
||||
return notepadSlideoutVariants.instances[0]
|
||||
}
|
||||
|
||||
function open(): string {
|
||||
var instance = getActiveNotepadInstance()
|
||||
if (instance) {
|
||||
instance.show()
|
||||
return "NOTEPAD_OPEN_SUCCESS"
|
||||
}
|
||||
return "NOTEPAD_OPEN_FAILED"
|
||||
}
|
||||
|
||||
function close(): string {
|
||||
var instance = getActiveNotepadInstance()
|
||||
if (instance) {
|
||||
instance.hide()
|
||||
return "NOTEPAD_CLOSE_SUCCESS"
|
||||
}
|
||||
return "NOTEPAD_CLOSE_FAILED"
|
||||
}
|
||||
|
||||
function toggle(): string {
|
||||
var instance = getActiveNotepadInstance()
|
||||
if (instance) {
|
||||
instance.toggle()
|
||||
return "NOTEPAD_TOGGLE_SUCCESS"
|
||||
}
|
||||
return "NOTEPAD_TOGGLE_FAILED"
|
||||
}
|
||||
|
||||
target: "notepad"
|
||||
}
|
||||
|
||||
Variants {
|
||||
model: SettingsData.getFilteredScreens("toast")
|
||||
|
||||
delegate: Toast {
|
||||
modelData: item
|
||||
visible: ToastService.toastVisible
|
||||
}
|
||||
}
|
||||
|
||||
Variants {
|
||||
model: SettingsData.getFilteredScreens("osd")
|
||||
|
||||
delegate: VolumeOSD {
|
||||
modelData: item
|
||||
}
|
||||
}
|
||||
|
||||
Variants {
|
||||
model: SettingsData.getFilteredScreens("osd")
|
||||
|
||||
delegate: MicMuteOSD {
|
||||
modelData: item
|
||||
}
|
||||
}
|
||||
|
||||
Variants {
|
||||
model: SettingsData.getFilteredScreens("osd")
|
||||
|
||||
delegate: BrightnessOSD {
|
||||
modelData: item
|
||||
}
|
||||
}
|
||||
|
||||
Variants {
|
||||
model: SettingsData.getFilteredScreens("osd")
|
||||
|
||||
delegate: IdleInhibitorOSD {
|
||||
modelData: item
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -77,12 +77,15 @@ Item {
|
||||
width: parent.width
|
||||
height: parent.height - ClipboardConstants.headerHeight - 70
|
||||
radius: Theme.cornerRadius
|
||||
color: "transparent"
|
||||
color: Theme.surfaceLight
|
||||
border.color: Theme.outlineLight
|
||||
border.width: 1
|
||||
clip: true
|
||||
|
||||
DankListView {
|
||||
id: clipboardListView
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingS
|
||||
model: filteredModel
|
||||
|
||||
currentIndex: clipboardContent.modal ? clipboardContent.modal.selectedIndex : 0
|
||||
|
||||
@@ -24,10 +24,17 @@ Rectangle {
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (isSelected) {
|
||||
return Theme.primaryPressed
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.2)
|
||||
}
|
||||
return mouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceContainerHigh
|
||||
return mouseArea.containsMouse ? Theme.primaryHover : Theme.primaryBackground
|
||||
}
|
||||
border.color: {
|
||||
if (isSelected) {
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.5)
|
||||
}
|
||||
return Theme.outlineStrong
|
||||
}
|
||||
border.width: isSelected ? 1.5 : 1
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
|
||||
@@ -53,7 +53,7 @@ QtObject {
|
||||
modal.hide()
|
||||
event.accepted = true
|
||||
}
|
||||
} else if (event.key === Qt.Key_Down || event.key === Qt.Key_Tab) {
|
||||
} else if (event.key === Qt.Key_Down) {
|
||||
if (!modal.keyboardNavigationActive) {
|
||||
modal.keyboardNavigationActive = true
|
||||
modal.selectedIndex = 0
|
||||
@@ -62,7 +62,7 @@ QtObject {
|
||||
selectNext()
|
||||
event.accepted = true
|
||||
}
|
||||
} else if (event.key === Qt.Key_Up || event.key === Qt.Key_Backtab) {
|
||||
} else if (event.key === Qt.Key_Up) {
|
||||
if (!modal.keyboardNavigationActive) {
|
||||
modal.keyboardNavigationActive = true
|
||||
modal.selectedIndex = 0
|
||||
@@ -74,42 +74,6 @@ QtObject {
|
||||
selectPrevious()
|
||||
event.accepted = true
|
||||
}
|
||||
} else if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) {
|
||||
if (!modal.keyboardNavigationActive) {
|
||||
modal.keyboardNavigationActive = true
|
||||
modal.selectedIndex = 0
|
||||
} else {
|
||||
selectNext()
|
||||
}
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) {
|
||||
if (!modal.keyboardNavigationActive) {
|
||||
modal.keyboardNavigationActive = true
|
||||
modal.selectedIndex = 0
|
||||
} else if (modal.selectedIndex === 0) {
|
||||
modal.keyboardNavigationActive = false
|
||||
} else {
|
||||
selectPrevious()
|
||||
}
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) {
|
||||
if (!modal.keyboardNavigationActive) {
|
||||
modal.keyboardNavigationActive = true
|
||||
modal.selectedIndex = 0
|
||||
} else {
|
||||
selectNext()
|
||||
}
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_K && event.modifiers & Qt.ControlModifier) {
|
||||
if (!modal.keyboardNavigationActive) {
|
||||
modal.keyboardNavigationActive = true
|
||||
modal.selectedIndex = 0
|
||||
} else if (modal.selectedIndex === 0) {
|
||||
modal.keyboardNavigationActive = false
|
||||
} else {
|
||||
selectPrevious()
|
||||
}
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_Delete && (event.modifiers & Qt.ShiftModifier)) {
|
||||
modal.clearAll()
|
||||
modal.hide()
|
||||
|
||||
@@ -93,48 +93,6 @@ DankModal {
|
||||
selectedButton = 1
|
||||
event.accepted = true
|
||||
break
|
||||
case Qt.Key_N:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
keyboardNavigation = true
|
||||
selectedButton = (selectedButton + 1) % 2
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_P:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
keyboardNavigation = true
|
||||
selectedButton = selectedButton === -1 ? 1 : (selectedButton - 1 + 2) % 2
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_J:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
keyboardNavigation = true
|
||||
selectedButton = 1
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_K:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
keyboardNavigation = true
|
||||
selectedButton = 0
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_H:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
keyboardNavigation = true
|
||||
selectedButton = 0
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_L:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
keyboardNavigation = true
|
||||
selectedButton = 1
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_Tab:
|
||||
keyboardNavigation = true
|
||||
selectedButton = selectedButton === -1 ? 0 : (selectedButton + 1) % 2
|
||||
|
||||
@@ -22,7 +22,7 @@ PanelWindow {
|
||||
property bool closeOnEscapeKey: true
|
||||
property bool closeOnBackgroundClick: true
|
||||
property string animationType: "scale"
|
||||
property int animationDuration: Theme.shortDuration
|
||||
property int animationDuration: Theme.shorterDuration
|
||||
property var animationEasing: Theme.emphasizedEasing
|
||||
property color backgroundColor: Theme.surfaceContainer
|
||||
property color borderColor: Theme.outlineMedium
|
||||
@@ -34,7 +34,6 @@ PanelWindow {
|
||||
property bool shouldHaveFocus: shouldBeVisible
|
||||
property bool allowFocusOverride: false
|
||||
property bool allowStacking: false
|
||||
property bool keepContentLoaded: false
|
||||
|
||||
signal opened
|
||||
signal dialogClosed
|
||||
@@ -91,7 +90,7 @@ PanelWindow {
|
||||
Timer {
|
||||
id: closeTimer
|
||||
|
||||
interval: animationDuration + 100
|
||||
interval: animationDuration + 50
|
||||
onTriggered: {
|
||||
visible = false
|
||||
}
|
||||
@@ -159,6 +158,7 @@ PanelWindow {
|
||||
border.width: root.borderWidth
|
||||
layer.enabled: root.enableShadow
|
||||
opacity: root.shouldBeVisible ? 1 : 0
|
||||
scale: root.animationType === "scale" ? (root.shouldBeVisible ? 1 : 0.9) : 1
|
||||
transform: root.animationType === "slide" ? slideTransform : null
|
||||
|
||||
Translate {
|
||||
@@ -172,7 +172,7 @@ PanelWindow {
|
||||
id: contentLoader
|
||||
|
||||
anchors.fill: parent
|
||||
active: root.keepContentLoaded || root.shouldBeVisible || root.visible
|
||||
active: root.visible
|
||||
asynchronous: false
|
||||
}
|
||||
|
||||
@@ -183,6 +183,15 @@ PanelWindow {
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
enabled: root.animationType === "scale"
|
||||
|
||||
NumberAnimation {
|
||||
duration: root.animationDuration
|
||||
easing.type: root.animationEasing
|
||||
}
|
||||
}
|
||||
|
||||
layer.effect: MultiEffect {
|
||||
shadowEnabled: true
|
||||
shadowHorizontalOffset: 0
|
||||
@@ -198,8 +207,8 @@ PanelWindow {
|
||||
|
||||
objectName: "modalFocusScope"
|
||||
anchors.fill: parent
|
||||
visible: root.shouldBeVisible || root.visible
|
||||
focus: root.shouldBeVisible
|
||||
visible: root.visible // Only active when the modal is visible
|
||||
focus: root.visible
|
||||
Keys.onEscapePressed: event => {
|
||||
if (root.closeOnEscapeKey && shouldHaveFocus) {
|
||||
root.close()
|
||||
@@ -214,7 +223,7 @@ PanelWindow {
|
||||
|
||||
Connections {
|
||||
function onShouldHaveFocusChanged() {
|
||||
if (shouldHaveFocus && shouldBeVisible) {
|
||||
if (shouldHaveFocus && visible) {
|
||||
Qt.callLater(() => focusScope.forceActiveFocus())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,12 +239,7 @@ DankModal {
|
||||
return
|
||||
}
|
||||
if (!keyboardNavigationActive) {
|
||||
const isInitKey = event.key === Qt.Key_Tab || event.key === Qt.Key_Down || event.key === Qt.Key_Right ||
|
||||
(event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) ||
|
||||
(event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) ||
|
||||
(event.key === Qt.Key_L && event.modifiers & Qt.ControlModifier)
|
||||
|
||||
if (isInitKey) {
|
||||
if (event.key === Qt.Key_Tab || event.key === Qt.Key_Down || event.key === Qt.Key_Right) {
|
||||
keyboardNavigationActive = true
|
||||
if (currentPath !== homeDir) {
|
||||
backButtonFocused = true
|
||||
@@ -286,69 +281,6 @@ DankModal {
|
||||
}
|
||||
event.accepted = true
|
||||
break
|
||||
case Qt.Key_N:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
if (backButtonFocused) {
|
||||
backButtonFocused = false
|
||||
selectedIndex = 0
|
||||
} else if (selectedIndex < totalItems - 1) {
|
||||
selectedIndex++
|
||||
}
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_P:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
if (selectedIndex > 0) {
|
||||
selectedIndex--
|
||||
} else if (currentPath !== homeDir) {
|
||||
backButtonFocused = true
|
||||
selectedIndex = -1
|
||||
}
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_J:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
if (selectedIndex < totalItems - 1) {
|
||||
selectedIndex++
|
||||
}
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_K:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
if (selectedIndex > 0) {
|
||||
selectedIndex--
|
||||
} else if (currentPath !== homeDir) {
|
||||
backButtonFocused = true
|
||||
selectedIndex = -1
|
||||
}
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_H:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
if (!backButtonFocused && selectedIndex > 0) {
|
||||
selectedIndex--
|
||||
} else if (currentPath !== homeDir) {
|
||||
backButtonFocused = true
|
||||
selectedIndex = -1
|
||||
}
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_L:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
if (backButtonFocused) {
|
||||
backButtonFocused = false
|
||||
selectedIndex = 0
|
||||
} else if (selectedIndex < totalItems - 1) {
|
||||
selectedIndex++
|
||||
}
|
||||
event.accepted = true
|
||||
}
|
||||
break
|
||||
case Qt.Key_Left:
|
||||
if (backButtonFocused)
|
||||
return
|
||||
|
||||
@@ -57,11 +57,13 @@ DankModal {
|
||||
modalFocusScope.Keys.onPressed: (event) => {
|
||||
switch (event.key) {
|
||||
case Qt.Key_Up:
|
||||
case Qt.Key_Backtab:
|
||||
selectedIndex = (selectedIndex - 1 + optionCount) % optionCount;
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_Down:
|
||||
selectedIndex = (selectedIndex + 1) % optionCount;
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_Tab:
|
||||
selectedIndex = (selectedIndex + 1) % optionCount;
|
||||
event.accepted = true;
|
||||
@@ -76,30 +78,6 @@ DankModal {
|
||||
}
|
||||
event.accepted = true;
|
||||
break;
|
||||
case Qt.Key_N:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
selectedIndex = (selectedIndex + 1) % optionCount;
|
||||
event.accepted = true;
|
||||
}
|
||||
break;
|
||||
case Qt.Key_P:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
selectedIndex = (selectedIndex - 1 + optionCount) % optionCount;
|
||||
event.accepted = true;
|
||||
}
|
||||
break;
|
||||
case Qt.Key_J:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
selectedIndex = (selectedIndex + 1) % optionCount;
|
||||
event.accepted = true;
|
||||
}
|
||||
break;
|
||||
case Qt.Key_K:
|
||||
if (event.modifiers & Qt.ControlModifier) {
|
||||
selectedIndex = (selectedIndex - 1 + optionCount) % optionCount;
|
||||
event.accepted = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -79,6 +79,7 @@ Item {
|
||||
property var timeoutOptions: ["Never", "1 minute", "2 minutes", "3 minutes", "5 minutes", "10 minutes", "15 minutes", "20 minutes", "30 minutes", "1 hour", "1 hour 30 minutes", "2 hours", "3 hours"]
|
||||
property var timeoutValues: [0, 60, 120, 180, 300, 600, 900, 1200, 1800, 3600, 5400, 7200, 10800]
|
||||
|
||||
width: parent.width
|
||||
text: "Automatically lock after"
|
||||
options: timeoutOptions
|
||||
|
||||
@@ -115,6 +116,7 @@ Item {
|
||||
property var timeoutOptions: ["Never", "1 minute", "2 minutes", "3 minutes", "5 minutes", "10 minutes", "15 minutes", "20 minutes", "30 minutes", "1 hour", "1 hour 30 minutes", "2 hours", "3 hours"]
|
||||
property var timeoutValues: [0, 60, 120, 180, 300, 600, 900, 1200, 1800, 3600, 5400, 7200, 10800]
|
||||
|
||||
width: parent.width
|
||||
text: "Turn off monitors after"
|
||||
options: timeoutOptions
|
||||
|
||||
@@ -151,6 +153,7 @@ Item {
|
||||
property var timeoutOptions: ["Never", "1 minute", "2 minutes", "3 minutes", "5 minutes", "10 minutes", "15 minutes", "20 minutes", "30 minutes", "1 hour", "1 hour 30 minutes", "2 hours", "3 hours"]
|
||||
property var timeoutValues: [0, 60, 120, 180, 300, 600, 900, 1200, 1800, 3600, 5400, 7200, 10800]
|
||||
|
||||
width: parent.width
|
||||
text: "Suspend system after"
|
||||
options: timeoutOptions
|
||||
|
||||
@@ -187,6 +190,7 @@ Item {
|
||||
property var timeoutOptions: ["Never", "1 minute", "2 minutes", "3 minutes", "5 minutes", "10 minutes", "15 minutes", "20 minutes", "30 minutes", "1 hour", "1 hour 30 minutes", "2 hours", "3 hours"]
|
||||
property var timeoutValues: [0, 60, 120, 180, 300, 600, 900, 1200, 1800, 3600, 5400, 7200, 10800]
|
||||
|
||||
width: parent.width
|
||||
text: "Hibernate system after"
|
||||
options: timeoutOptions
|
||||
visible: SessionService.hibernateSupported
|
||||
|
||||
@@ -67,7 +67,7 @@ Item {
|
||||
visible: active
|
||||
asynchronous: true
|
||||
|
||||
sourceComponent: DankBarTab {
|
||||
sourceComponent: TopBarTab {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -153,24 +153,11 @@ Item {
|
||||
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: pluginsLoader
|
||||
|
||||
anchors.fill: parent
|
||||
active: root.currentIndex === 10
|
||||
visible: active
|
||||
asynchronous: true
|
||||
|
||||
sourceComponent: PluginsTab {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: aboutLoader
|
||||
|
||||
anchors.fill: parent
|
||||
active: root.currentIndex === 11
|
||||
active: root.currentIndex === 10
|
||||
visible: active
|
||||
asynchronous: true
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ DankModal {
|
||||
|
||||
objectName: "settingsModal"
|
||||
width: 800
|
||||
height: 800
|
||||
height: 750
|
||||
visible: false
|
||||
onBackgroundClicked: () => {
|
||||
return hide();
|
||||
|
||||
@@ -18,7 +18,7 @@ Rectangle {
|
||||
"text": "Weather",
|
||||
"icon": "cloud"
|
||||
}, {
|
||||
"text": "Dank Bar",
|
||||
"text": "Top Bar",
|
||||
"icon": "toolbar"
|
||||
}, {
|
||||
"text": "Widgets",
|
||||
@@ -38,9 +38,6 @@ Rectangle {
|
||||
}, {
|
||||
"text": "Power",
|
||||
"icon": "power_settings_new"
|
||||
}, {
|
||||
"text": "Plugins",
|
||||
"icon": "extension"
|
||||
}, {
|
||||
"text": "About",
|
||||
"icon": "info"
|
||||
@@ -86,7 +83,7 @@ Rectangle {
|
||||
width: parent.width - Theme.spacingS * 2
|
||||
height: 44
|
||||
radius: Theme.cornerRadius
|
||||
color: isActive ? Theme.primaryContainer : tabMouseArea.containsMouse ? Theme.surfaceHover : Theme.withAlpha(Theme.primaryContainer, 0)
|
||||
color: isActive ? Theme.primaryContainer : tabMouseArea.containsMouse ? Theme.surfaceHover : "transparent"
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
|
||||
@@ -33,46 +33,6 @@ Item {
|
||||
} else if (event.key === Qt.Key_Left && appLauncher.viewMode === "grid") {
|
||||
appLauncher.selectPreviousInRow()
|
||||
event.accepted = true
|
||||
} else if (event.key == Qt.Key_J && event.modifiers & Qt.ControlModifier) {
|
||||
appLauncher.selectNext()
|
||||
event.accepted = true
|
||||
} else if (event.key == Qt.Key_K && event.modifiers & Qt.ControlModifier) {
|
||||
appLauncher.selectPrevious()
|
||||
event.accepted = true
|
||||
} else if (event.key == Qt.Key_L && event.modifiers & Qt.ControlModifier && appLauncher.viewMode === "grid") {
|
||||
appLauncher.selectNextInRow()
|
||||
event.accepted = true
|
||||
} else if (event.key == Qt.Key_H && event.modifiers & Qt.ControlModifier && appLauncher.viewMode === "grid") {
|
||||
appLauncher.selectPreviousInRow()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_Tab) {
|
||||
if (appLauncher.viewMode === "grid") {
|
||||
appLauncher.selectNextInRow()
|
||||
} else {
|
||||
appLauncher.selectNext()
|
||||
}
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_Backtab) {
|
||||
if (appLauncher.viewMode === "grid") {
|
||||
appLauncher.selectPreviousInRow()
|
||||
} else {
|
||||
appLauncher.selectPrevious()
|
||||
}
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) {
|
||||
if (appLauncher.viewMode === "grid") {
|
||||
appLauncher.selectNextInRow()
|
||||
} else {
|
||||
appLauncher.selectNext()
|
||||
}
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) {
|
||||
if (appLauncher.viewMode === "grid") {
|
||||
appLauncher.selectPreviousInRow()
|
||||
} else {
|
||||
appLauncher.selectPrevious()
|
||||
}
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
|
||||
appLauncher.launchSelected()
|
||||
event.accepted = true
|
||||
@@ -99,21 +59,23 @@ Item {
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
spacing: Theme.spacingM
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingL
|
||||
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: categorySelector.height + Theme.spacingS * 2
|
||||
height: categorySelector.height + Theme.spacingM * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: "transparent"
|
||||
color: Theme.surfaceVariantAlpha
|
||||
border.color: Theme.outlineMedium
|
||||
border.width: 1
|
||||
visible: appLauncher.categories.length > 1 || appLauncher.model.count > 0
|
||||
|
||||
CategorySelector {
|
||||
id: categorySelector
|
||||
|
||||
anchors.centerIn: parent
|
||||
width: parent.width - Theme.spacingS * 2
|
||||
width: parent.width - Theme.spacingM * 2
|
||||
categories: appLauncher.categories
|
||||
selectedCategory: appLauncher.selectedCategory
|
||||
compact: false
|
||||
@@ -126,12 +88,11 @@ Item {
|
||||
Row {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
leftPadding: Theme.spacingS
|
||||
|
||||
DankTextField {
|
||||
id: searchField
|
||||
|
||||
width: parent.width - 80 - Theme.spacingL
|
||||
width: parent.width - 80 - Theme.spacingM
|
||||
height: 56
|
||||
cornerRadius: Theme.cornerRadius
|
||||
backgroundColor: Theme.surfaceContainerHigh
|
||||
@@ -164,7 +125,7 @@ Item {
|
||||
else if (appLauncher.model.count > 0)
|
||||
appLauncher.launchApp(appLauncher.model.get(0))
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || event.key === Qt.Key_Left || event.key === Qt.Key_Right || event.key === Qt.Key_Tab || event.key === Qt.Key_Backtab || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) {
|
||||
} else if (event.key === Qt.Key_Down || event.key === Qt.Key_Up || event.key === Qt.Key_Left || event.key === Qt.Key_Right || ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && text.length === 0)) {
|
||||
event.accepted = false
|
||||
}
|
||||
}
|
||||
@@ -180,6 +141,8 @@ Item {
|
||||
height: 36
|
||||
radius: Theme.cornerRadius
|
||||
color: appLauncher.viewMode === "list" ? Theme.primaryHover : listViewArea.containsMouse ? Theme.surfaceHover : "transparent"
|
||||
border.color: appLauncher.viewMode === "list" ? Theme.primarySelected : "transparent"
|
||||
border.width: 1
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
@@ -205,6 +168,8 @@ Item {
|
||||
height: 36
|
||||
radius: Theme.cornerRadius
|
||||
color: appLauncher.viewMode === "grid" ? Theme.primaryHover : gridViewArea.containsMouse ? Theme.surfaceHover : "transparent"
|
||||
border.color: appLauncher.viewMode === "grid" ? Theme.primarySelected : "transparent"
|
||||
border.width: 1
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
|
||||
@@ -32,7 +32,11 @@ DankModal {
|
||||
function hide() {
|
||||
spotlightOpen = false
|
||||
close()
|
||||
cleanupTimer.restart()
|
||||
if (contentLoader.item && contentLoader.item.appLauncher) {
|
||||
contentLoader.item.appLauncher.searchQuery = ""
|
||||
contentLoader.item.appLauncher.selectedIndex = 0
|
||||
contentLoader.item.appLauncher.setCategory("All")
|
||||
}
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
@@ -51,7 +55,6 @@ DankModal {
|
||||
borderColor: Theme.outlineMedium
|
||||
borderWidth: 1
|
||||
enableShadow: true
|
||||
keepContentLoaded: true
|
||||
onVisibleChanged: () => {
|
||||
if (visible && !spotlightOpen) {
|
||||
show()
|
||||
@@ -69,19 +72,6 @@ DankModal {
|
||||
}
|
||||
content: spotlightContent
|
||||
|
||||
Timer {
|
||||
id: cleanupTimer
|
||||
|
||||
interval: animationDuration + 50
|
||||
onTriggered: {
|
||||
if (contentLoader.item && contentLoader.item.appLauncher) {
|
||||
contentLoader.item.appLauncher.searchQuery = ""
|
||||
contentLoader.item.appLauncher.selectedIndex = 0
|
||||
contentLoader.item.appLauncher.setCategory("All")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onCloseAllModalsExcept(excludedModal) {
|
||||
if (excludedModal !== spotlightModal && !allowStacking && spotlightOpen) {
|
||||
|
||||
@@ -13,7 +13,9 @@ Rectangle {
|
||||
width: parent.width
|
||||
height: parent.height - y
|
||||
radius: Theme.cornerRadius
|
||||
color: "transparent"
|
||||
color: Theme.surfaceContainerHigh
|
||||
border.color: Theme.outlineLight
|
||||
border.width: 1
|
||||
|
||||
DankListView {
|
||||
id: resultsList
|
||||
@@ -73,7 +75,9 @@ Rectangle {
|
||||
width: ListView.view.width
|
||||
height: resultsList.itemHeight
|
||||
radius: Theme.cornerRadius
|
||||
color: ListView.isCurrentItem ? Theme.primaryPressed : listMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceContainerHigh
|
||||
color: ListView.isCurrentItem ? Theme.primaryPressed : listMouseArea.containsMouse ? Theme.primaryHoverLight : "transparent"
|
||||
border.color: ListView.isCurrentItem ? Theme.primarySelected : Theme.outlineMedium
|
||||
border.width: ListView.isCurrentItem ? 2 : 1
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
@@ -234,7 +238,9 @@ Rectangle {
|
||||
width: resultsGrid.cellWidth - resultsGrid.cellPadding
|
||||
height: resultsGrid.cellHeight - resultsGrid.cellPadding
|
||||
radius: Theme.cornerRadius
|
||||
color: resultsGrid.currentIndex === index ? Theme.primaryPressed : gridMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceContainerHigh
|
||||
color: resultsGrid.currentIndex === index ? Theme.primaryPressed : gridMouseArea.containsMouse ? Theme.primaryHoverLight : "transparent"
|
||||
border.color: resultsGrid.currentIndex === index ? Theme.primarySelected : Theme.outlineMedium
|
||||
border.width: resultsGrid.currentIndex === index ? 2 : 1
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
|
||||
@@ -12,6 +12,7 @@ import qs.Widgets
|
||||
DankPopout {
|
||||
id: appDrawerPopout
|
||||
|
||||
property string triggerSection: "left"
|
||||
property var triggerScreen: null
|
||||
|
||||
// Setting to Exclusive, so virtual keyboards can send input to app drawer
|
||||
@@ -32,9 +33,9 @@ DankPopout {
|
||||
popupWidth: 520
|
||||
popupHeight: 600
|
||||
triggerX: Theme.spacingL
|
||||
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2
|
||||
triggerY: Theme.barHeight - 4 + SettingsData.topBarSpacing + Theme.spacingXS
|
||||
triggerWidth: 40
|
||||
positioning: ""
|
||||
positioning: "center"
|
||||
screen: triggerScreen
|
||||
|
||||
onShouldBeVisibleChanged: {
|
||||
@@ -94,7 +95,7 @@ DankPopout {
|
||||
color: "transparent"
|
||||
radius: parent.radius + Math.abs(modelData.margin)
|
||||
border.color: modelData.color
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
z: modelData.z
|
||||
}
|
||||
}
|
||||
@@ -127,44 +128,6 @@ DankPopout {
|
||||
return
|
||||
}
|
||||
|
||||
if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) {
|
||||
appLauncher.selectNext()
|
||||
event.accepted = true
|
||||
return
|
||||
}
|
||||
|
||||
if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) {
|
||||
appLauncher.selectPrevious()
|
||||
event.accepted = true
|
||||
return
|
||||
}
|
||||
|
||||
if (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) {
|
||||
appLauncher.selectNext()
|
||||
event.accepted = true
|
||||
return
|
||||
}
|
||||
|
||||
if (event.key === Qt.Key_K && event.modifiers & Qt.ControlModifier) {
|
||||
appLauncher.selectPrevious()
|
||||
event.accepted = true
|
||||
return
|
||||
}
|
||||
|
||||
if (appLauncher.viewMode === "grid") {
|
||||
if (event.key === Qt.Key_L && event.modifiers & Qt.ControlModifier) {
|
||||
appLauncher.selectNextInRow()
|
||||
event.accepted = true
|
||||
return
|
||||
}
|
||||
|
||||
if (event.key === Qt.Key_H && event.modifiers & Qt.ControlModifier) {
|
||||
appLauncher.selectPreviousInRow()
|
||||
event.accepted = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (!searchField.activeFocus && event.text && /[a-zA-Z0-9\s]/.test(event.text)) {
|
||||
searchField.forceActiveFocus()
|
||||
searchField.insertText(event.text)
|
||||
@@ -173,16 +136,15 @@ DankPopout {
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - Theme.spacingS * 2
|
||||
height: parent.height - Theme.spacingS * 2
|
||||
x: Theme.spacingS
|
||||
y: Theme.spacingS
|
||||
spacing: Theme.spacingS
|
||||
width: parent.width - Theme.spacingL * 2
|
||||
height: parent.height - Theme.spacingL * 2
|
||||
x: Theme.spacingL
|
||||
y: Theme.spacingL
|
||||
spacing: Theme.spacingL
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 40
|
||||
leftPadding: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
@@ -208,8 +170,7 @@ DankPopout {
|
||||
DankTextField {
|
||||
id: searchField
|
||||
|
||||
width: parent.width - Theme.spacingS * 2
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: parent.width
|
||||
height: 52
|
||||
cornerRadius: Theme.cornerRadius
|
||||
backgroundColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, Theme.getContentBackgroundAlpha() * 0.7)
|
||||
@@ -270,18 +231,14 @@ DankPopout {
|
||||
height: 40
|
||||
spacing: Theme.spacingM
|
||||
visible: searchField.text.length === 0
|
||||
leftPadding: Theme.spacingS
|
||||
|
||||
Rectangle {
|
||||
width: 180
|
||||
height: 40
|
||||
radius: Theme.cornerRadius
|
||||
color: "transparent"
|
||||
Item {
|
||||
width: 200
|
||||
height: 36
|
||||
|
||||
DankDropdown {
|
||||
anchors.fill: parent
|
||||
text: ""
|
||||
dropdownWidth: 180
|
||||
currentValue: appLauncher.selectedCategory
|
||||
options: appLauncher.categories
|
||||
optionIcons: appLauncher.categoryIcons
|
||||
@@ -292,7 +249,7 @@ DankPopout {
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width - 290
|
||||
width: parent.width - 300
|
||||
height: 1
|
||||
}
|
||||
|
||||
@@ -329,13 +286,15 @@ DankPopout {
|
||||
Rectangle {
|
||||
width: parent.width
|
||||
height: {
|
||||
let usedHeight = 40 + Theme.spacingS
|
||||
usedHeight += 52 + Theme.spacingS
|
||||
usedHeight += (searchField.text.length === 0 ? 40 : 0)
|
||||
let usedHeight = 40 + Theme.spacingL
|
||||
usedHeight += 52 + Theme.spacingL
|
||||
usedHeight += (searchField.text.length === 0 ? 40 + Theme.spacingL : 0)
|
||||
return parent.height - usedHeight
|
||||
}
|
||||
radius: Theme.cornerRadius
|
||||
color: "transparent"
|
||||
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.1)
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05)
|
||||
border.width: 1
|
||||
|
||||
DankListView {
|
||||
id: appList
|
||||
@@ -364,9 +323,7 @@ DankPopout {
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.bottomMargin: Theme.spacingS
|
||||
anchors.margins: Theme.spacingS
|
||||
visible: appLauncher.viewMode === "list"
|
||||
model: appLauncher.model
|
||||
currentIndex: appLauncher.selectedIndex
|
||||
@@ -396,7 +353,9 @@ DankPopout {
|
||||
width: ListView.view.width
|
||||
height: appList.itemHeight
|
||||
radius: Theme.cornerRadius
|
||||
color: ListView.isCurrentItem ? Theme.primaryPressed : listMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceContainerHigh
|
||||
color: ListView.isCurrentItem ? Theme.primaryPressed : listMouseArea.containsMouse ? Theme.primaryHoverLight : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.03)
|
||||
border.color: ListView.isCurrentItem ? Theme.primarySelected : Theme.outlineMedium
|
||||
border.width: ListView.isCurrentItem ? 2 : 1
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
@@ -412,7 +371,6 @@ DankPopout {
|
||||
id: listIconImg
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingXS
|
||||
source: Quickshell.iconPath(model.icon, true)
|
||||
smooth: true
|
||||
asynchronous: true
|
||||
@@ -421,13 +379,10 @@ DankPopout {
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.bottomMargin: Theme.spacingM
|
||||
visible: !listIconImg.visible
|
||||
color: Theme.surfaceLight
|
||||
radius: Theme.cornerRadius
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
border.color: Theme.primarySelected
|
||||
|
||||
StyledText {
|
||||
@@ -470,9 +425,6 @@ DankPopout {
|
||||
id: listMouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.bottomMargin: Theme.spacingM
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
@@ -532,9 +484,7 @@ DankPopout {
|
||||
}
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.bottomMargin: Theme.spacingS
|
||||
anchors.margins: Theme.spacingS
|
||||
visible: appLauncher.viewMode === "grid"
|
||||
model: appLauncher.model
|
||||
clip: true
|
||||
@@ -566,7 +516,9 @@ DankPopout {
|
||||
width: appGrid.cellWidth - appGrid.cellPadding
|
||||
height: appGrid.cellHeight - appGrid.cellPadding
|
||||
radius: Theme.cornerRadius
|
||||
color: appGrid.currentIndex === index ? Theme.primaryPressed : gridMouseArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceContainerHigh
|
||||
color: appGrid.currentIndex === index ? Theme.primaryPressed : gridMouseArea.containsMouse ? Theme.primaryHoverLight : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.03)
|
||||
border.color: appGrid.currentIndex === index ? Theme.primarySelected : Theme.outlineMedium
|
||||
border.width: appGrid.currentIndex === index ? 2 : 1
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
@@ -583,9 +535,6 @@ DankPopout {
|
||||
id: gridIconImg
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.bottomMargin: Theme.spacingS
|
||||
source: Quickshell.iconPath(model.icon, true)
|
||||
smooth: true
|
||||
asynchronous: true
|
||||
@@ -594,13 +543,10 @@ DankPopout {
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.bottomMargin: Theme.spacingS
|
||||
visible: !gridIconImg.visible
|
||||
color: Theme.surfaceLight
|
||||
radius: Theme.cornerRadius
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
border.color: Theme.primarySelected
|
||||
|
||||
StyledText {
|
||||
@@ -631,9 +577,6 @@ DankPopout {
|
||||
id: gridMouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.bottomMargin: Theme.spacingS
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
@@ -710,7 +653,7 @@ DankPopout {
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.popupBackground()
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
z: 1000
|
||||
opacity: menuVisible ? 1 : 0
|
||||
scale: menuVisible ? 1 : 0.85
|
||||
|
||||
@@ -15,7 +15,7 @@ Item {
|
||||
readonly property int maxCompactItems: 8
|
||||
readonly property int itemHeight: 36
|
||||
readonly property color selectedBorderColor: "transparent"
|
||||
readonly property color unselectedBorderColor: "transparent"
|
||||
readonly property color unselectedBorderColor: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
|
||||
|
||||
function handleCategoryClick(category) {
|
||||
selectedCategory = category
|
||||
@@ -42,7 +42,8 @@ Item {
|
||||
height: root.itemHeight
|
||||
width: root.getButtonWidth(itemCount, parent.width)
|
||||
radius: Theme.cornerRadius
|
||||
color: selectedCategory === modelData ? Theme.primary : Theme.surfaceContainerHigh
|
||||
color: selectedCategory === modelData ? Theme.primary : "transparent"
|
||||
border.color: selectedCategory === modelData ? selectedBorderColor : unselectedBorderColor
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
@@ -81,7 +82,7 @@ Item {
|
||||
height: root.itemHeight
|
||||
width: root.getButtonWidth(itemCount, parent.width)
|
||||
radius: Theme.cornerRadius
|
||||
color: selectedCategory === modelData ? Theme.primary : Theme.surfaceContainerHigh
|
||||
color: selectedCategory === modelData ? Theme.primary : "transparent"
|
||||
border.color: selectedCategory === modelData ? selectedBorderColor : unselectedBorderColor
|
||||
|
||||
StyledText {
|
||||
@@ -117,7 +118,7 @@ Item {
|
||||
height: root.itemHeight
|
||||
width: root.getButtonWidth(itemCount, parent.width)
|
||||
radius: Theme.cornerRadius
|
||||
color: selectedCategory === modelData ? Theme.primary : Theme.surfaceContainerHigh
|
||||
color: selectedCategory === modelData ? Theme.primary : "transparent"
|
||||
border.color: selectedCategory === modelData ? selectedBorderColor : unselectedBorderColor
|
||||
|
||||
StyledText {
|
||||
|
||||
@@ -7,7 +7,6 @@ Item {
|
||||
|
||||
property string expandedSection: ""
|
||||
property var expandedWidgetData: null
|
||||
property var bluetoothCodecSelector: null
|
||||
|
||||
Loader {
|
||||
width: parent.width
|
||||
@@ -43,17 +42,7 @@ Item {
|
||||
|
||||
Component {
|
||||
id: bluetoothDetailComponent
|
||||
BluetoothDetail {
|
||||
id: bluetoothDetail
|
||||
onShowCodecSelector: function(device) {
|
||||
if (root.bluetoothCodecSelector) {
|
||||
root.bluetoothCodecSelector.show(device)
|
||||
root.bluetoothCodecSelector.codecSelected.connect(function(deviceAddress, codecName) {
|
||||
bluetoothDetail.updateDeviceCodecDisplay(deviceAddress, codecName)
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
BluetoothDetail {}
|
||||
}
|
||||
|
||||
Component {
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Modules.ControlCenter.Details
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property string expandedSection: ""
|
||||
property var expandedWidgetData: null
|
||||
|
||||
height: active ? 250 : 0
|
||||
visible: active
|
||||
|
||||
readonly property bool active: expandedSection !== ""
|
||||
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: Theme.spacingS
|
||||
sourceComponent: {
|
||||
if (!root.active) return null
|
||||
|
||||
if (expandedSection.startsWith("diskUsage_")) {
|
||||
return diskUsageDetailComponent
|
||||
}
|
||||
|
||||
switch (expandedSection) {
|
||||
case "wifi": return networkDetailComponent
|
||||
case "bluetooth": return bluetoothDetailComponent
|
||||
case "audioOutput": return audioOutputDetailComponent
|
||||
case "audioInput": return audioInputDetailComponent
|
||||
case "battery": return batteryDetailComponent
|
||||
default: return null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: networkDetailComponent
|
||||
NetworkDetail {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: bluetoothDetailComponent
|
||||
BluetoothDetail {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: audioOutputDetailComponent
|
||||
AudioOutputDetail {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: audioInputDetailComponent
|
||||
AudioInputDetail {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: batteryDetailComponent
|
||||
BatteryDetail {}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: diskUsageDetailComponent
|
||||
DiskUsageDetail {
|
||||
currentMountPath: root.expandedWidgetData?.mountPath || "/"
|
||||
instanceId: root.expandedWidgetData?.instanceId || ""
|
||||
|
||||
onMountPathChanged: (newMountPath) => {
|
||||
if (root.expandedWidgetData && root.expandedWidgetData.id === "diskUsage") {
|
||||
const widgets = SettingsData.controlCenterWidgets || []
|
||||
const newWidgets = widgets.map(w => {
|
||||
if (w.id === "diskUsage" && w.instanceId === root.expandedWidgetData.instanceId) {
|
||||
const updatedWidget = Object.assign({}, w)
|
||||
updatedWidget.mountPath = newMountPath
|
||||
return updatedWidget
|
||||
}
|
||||
return w
|
||||
})
|
||||
SettingsData.setControlCenterWidgets(newWidgets)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,289 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property bool editMode: false
|
||||
property var widgetData: null
|
||||
property int widgetIndex: -1
|
||||
property bool isSlider: false
|
||||
property Component widgetComponent: null
|
||||
property real gridCellWidth: 100
|
||||
property real gridCellHeight: 60
|
||||
property int gridColumns: 4
|
||||
property var gridLayout: null
|
||||
|
||||
z: dragArea.drag.active ? 10000 : 1
|
||||
|
||||
signal widgetMoved(int fromIndex, int toIndex)
|
||||
signal removeWidget(int index)
|
||||
signal toggleWidgetSize(int index)
|
||||
|
||||
width: {
|
||||
const widgetWidth = widgetData?.width || 50
|
||||
if (widgetWidth <= 25) return gridCellWidth
|
||||
else if (widgetWidth <= 50) return gridCellWidth * 2
|
||||
else if (widgetWidth <= 75) return gridCellWidth * 3
|
||||
else return gridCellWidth * 4
|
||||
}
|
||||
height: isSlider ? 16 : gridCellHeight
|
||||
|
||||
Rectangle {
|
||||
id: dragIndicator
|
||||
anchors.fill: parent
|
||||
color: "transparent"
|
||||
border.color: Theme.primary
|
||||
border.width: dragArea.drag.active ? 2 : 0
|
||||
radius: Theme.cornerRadius
|
||||
opacity: dragArea.drag.active ? 0.8 : 1.0
|
||||
z: dragArea.drag.active ? 10000 : 1
|
||||
|
||||
Behavior on border.width {
|
||||
NumberAnimation { duration: 150 }
|
||||
}
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: 150 }
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: widgetLoader
|
||||
anchors.fill: parent
|
||||
sourceComponent: widgetComponent
|
||||
property var widgetData: root.widgetData
|
||||
property int widgetIndex: root.widgetIndex
|
||||
property int globalWidgetIndex: root.widgetIndex
|
||||
property int widgetWidth: root.widgetData?.width || 50
|
||||
|
||||
|
||||
MouseArea {
|
||||
id: editModeBlocker
|
||||
anchors.fill: parent
|
||||
enabled: root.editMode
|
||||
acceptedButtons: Qt.AllButtons
|
||||
onPressed: function(mouse) { mouse.accepted = true }
|
||||
onWheel: function(wheel) { wheel.accepted = true }
|
||||
z: 100
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: dragArea
|
||||
anchors.fill: parent
|
||||
enabled: editMode
|
||||
cursorShape: editMode ? Qt.OpenHandCursor : Qt.PointingHandCursor
|
||||
drag.target: editMode ? root : null
|
||||
drag.axis: Drag.XAndYAxis
|
||||
drag.smoothed: true
|
||||
|
||||
onPressed: function(mouse) {
|
||||
if (editMode) {
|
||||
cursorShape = Qt.ClosedHandCursor
|
||||
if (root.gridLayout && root.gridLayout.moveToTop) {
|
||||
root.gridLayout.moveToTop(root)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onReleased: function(mouse) {
|
||||
if (editMode) {
|
||||
cursorShape = Qt.OpenHandCursor
|
||||
root.snapToGrid()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Drag.active: dragArea.drag.active
|
||||
Drag.hotSpot.x: width / 2
|
||||
Drag.hotSpot.y: height / 2
|
||||
|
||||
function swapIndices(i, j) {
|
||||
if (i === j) return;
|
||||
const arr = SettingsData.controlCenterWidgets;
|
||||
if (!arr || i < 0 || j < 0 || i >= arr.length || j >= arr.length) return;
|
||||
|
||||
const copy = arr.slice();
|
||||
const tmp = copy[i];
|
||||
copy[i] = copy[j];
|
||||
copy[j] = tmp;
|
||||
|
||||
SettingsData.setControlCenterWidgets(copy);
|
||||
}
|
||||
|
||||
function snapToGrid() {
|
||||
if (!editMode || !gridLayout) return
|
||||
|
||||
const globalPos = root.mapToItem(gridLayout, 0, 0)
|
||||
const cellWidth = gridLayout.width / gridColumns
|
||||
const cellHeight = gridCellHeight + Theme.spacingS
|
||||
|
||||
const centerX = globalPos.x + (root.width / 2)
|
||||
const centerY = globalPos.y + (root.height / 2)
|
||||
|
||||
let targetCol = Math.max(0, Math.floor(centerX / cellWidth))
|
||||
let targetRow = Math.max(0, Math.floor(centerY / cellHeight))
|
||||
|
||||
targetCol = Math.min(targetCol, gridColumns - 1)
|
||||
|
||||
const newIndex = findBestInsertionIndex(targetRow, targetCol)
|
||||
|
||||
if (newIndex !== widgetIndex && newIndex >= 0 && newIndex < (SettingsData.controlCenterWidgets?.length || 0)) {
|
||||
swapIndices(widgetIndex, newIndex)
|
||||
}
|
||||
}
|
||||
|
||||
function findBestInsertionIndex(targetRow, targetCol) {
|
||||
const widgets = SettingsData.controlCenterWidgets || [];
|
||||
const n = widgets.length;
|
||||
if (!n || widgetIndex < 0 || widgetIndex >= n) return -1;
|
||||
|
||||
function spanFor(width) {
|
||||
const w = width ?? 50;
|
||||
if (w <= 25) return 1;
|
||||
if (w <= 50) return 2;
|
||||
if (w <= 75) return 3;
|
||||
return 4;
|
||||
}
|
||||
|
||||
const cols = gridColumns || 4;
|
||||
|
||||
let row = 0, col = 0;
|
||||
let draggedOrigKey = null;
|
||||
|
||||
const pos = [];
|
||||
|
||||
for (let i = 0; i < n; i++) {
|
||||
const span = Math.min(spanFor(widgets[i].width), cols);
|
||||
|
||||
if (col + span > cols) {
|
||||
row++;
|
||||
col = 0;
|
||||
}
|
||||
|
||||
const startCol = col;
|
||||
const centerKey = row * cols + (startCol + (span - 1) / 2);
|
||||
|
||||
if (i === widgetIndex) {
|
||||
draggedOrigKey = centerKey;
|
||||
} else {
|
||||
pos.push({ index: i, row, startCol, span, centerKey });
|
||||
}
|
||||
|
||||
col += span;
|
||||
if (col >= cols) {
|
||||
row++;
|
||||
col = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (pos.length === 0) return -1;
|
||||
|
||||
const centerColCoord = targetCol + 0.5;
|
||||
const targetKey = targetRow * cols + centerColCoord;
|
||||
|
||||
for (let k = 0; k < pos.length; k++) {
|
||||
const p = pos[k];
|
||||
if (p.row === targetRow && centerColCoord >= p.startCol && centerColCoord < (p.startCol + p.span)) {
|
||||
return p.index;
|
||||
}
|
||||
}
|
||||
|
||||
let lo = 0, hi = pos.length - 1;
|
||||
if (targetKey <= pos[0].centerKey) return pos[0].index;
|
||||
if (targetKey >= pos[hi].centerKey) return pos[hi].index;
|
||||
|
||||
while (lo <= hi) {
|
||||
const mid = (lo + hi) >> 1;
|
||||
const mk = pos[mid].centerKey;
|
||||
if (targetKey < mk) hi = mid - 1;
|
||||
else if (targetKey > mk) lo = mid + 1;
|
||||
else return pos[mid].index;
|
||||
}
|
||||
const movingUp = (draggedOrigKey != null) ? (targetKey < draggedOrigKey) : false;
|
||||
return (movingUp ? pos[lo].index : pos[hi].index);
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 16
|
||||
height: 16
|
||||
radius: 8
|
||||
color: Theme.error
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.margins: -4
|
||||
visible: editMode
|
||||
z: 10
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "close"
|
||||
size: 12
|
||||
color: Theme.primaryText
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: removeWidget(widgetIndex)
|
||||
}
|
||||
}
|
||||
|
||||
SizeControls {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.margins: -6
|
||||
visible: editMode
|
||||
z: 10
|
||||
currentSize: root.widgetData?.width || 50
|
||||
isSlider: root.isSlider
|
||||
widgetIndex: root.widgetIndex
|
||||
onSizeChanged: (newSize) => {
|
||||
var widgets = SettingsData.controlCenterWidgets.slice()
|
||||
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
|
||||
widgets[widgetIndex].width = newSize
|
||||
SettingsData.setControlCenterWidgets(widgets)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: dragHandle
|
||||
width: 16
|
||||
height: 12
|
||||
radius: 2
|
||||
color: Theme.primary
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 4
|
||||
visible: editMode
|
||||
z: 15
|
||||
opacity: dragArea.drag.active ? 1.0 : 0.7
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "drag_indicator"
|
||||
size: 10
|
||||
color: Theme.primaryText
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation { duration: 150 }
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: editMode ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
|
||||
radius: Theme.cornerRadius
|
||||
border.color: "transparent"
|
||||
border.width: 0
|
||||
z: -1
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ Row {
|
||||
background: Rectangle {
|
||||
color: Theme.surfaceContainer
|
||||
border.color: Theme.primarySelected
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
radius: Theme.cornerRadius
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ Row {
|
||||
radius: Theme.cornerRadius
|
||||
color: widgetMouseArea.containsMouse ? Theme.primaryHover : Theme.surfaceContainerHigh
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
@@ -138,7 +138,7 @@ Row {
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||
border.color: Theme.primary
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
@@ -172,7 +172,7 @@ Row {
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12)
|
||||
border.color: Theme.warning
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
@@ -206,7 +206,7 @@ Row {
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12)
|
||||
border.color: Theme.error
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
|
||||
241
Modules/ControlCenter/Components/EditModeOverlay.qml
Normal file
241
Modules/ControlCenter/Components/EditModeOverlay.qml
Normal file
@@ -0,0 +1,241 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property bool editMode: false
|
||||
property var widgetData: null
|
||||
property int widgetIndex: -1
|
||||
property bool showSizeControls: true
|
||||
property bool isSlider: false
|
||||
|
||||
signal removeWidget(int index)
|
||||
signal toggleWidgetSize(int index)
|
||||
signal moveWidget(int fromIndex, int toIndex)
|
||||
|
||||
// Delete button in top-right
|
||||
Rectangle {
|
||||
width: 16
|
||||
height: 16
|
||||
radius: 8
|
||||
color: Theme.error
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.margins: -4
|
||||
visible: editMode
|
||||
z: 10
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "close"
|
||||
size: 12
|
||||
color: Theme.primaryText
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: root.removeWidget(widgetIndex)
|
||||
}
|
||||
}
|
||||
|
||||
// Size control buttons in bottom-right
|
||||
Row {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.right: parent.right
|
||||
anchors.margins: -8
|
||||
spacing: 4
|
||||
visible: editMode && showSizeControls
|
||||
z: 10
|
||||
|
||||
Rectangle {
|
||||
width: 24
|
||||
height: 24
|
||||
radius: 12
|
||||
color: (widgetData?.width || 50) === 25 ? Theme.primary : Theme.primaryContainer
|
||||
border.color: Theme.primary
|
||||
border.width: 1
|
||||
visible: !isSlider
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: "25"
|
||||
font.pixelSize: 10
|
||||
font.weight: Font.Medium
|
||||
color: (widgetData?.width || 50) === 25 ? Theme.primaryText : Theme.primary
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
var widgets = SettingsData.controlCenterWidgets.slice()
|
||||
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
|
||||
widgets[widgetIndex].width = 25
|
||||
SettingsData.setControlCenterWidgets(widgets)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 24
|
||||
height: 24
|
||||
radius: 12
|
||||
color: (widgetData?.width || 50) === 50 ? Theme.primary : Theme.primaryContainer
|
||||
border.color: Theme.primary
|
||||
border.width: 1
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: "50"
|
||||
font.pixelSize: 10
|
||||
font.weight: Font.Medium
|
||||
color: (widgetData?.width || 50) === 50 ? Theme.primaryText : Theme.primary
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
var widgets = SettingsData.controlCenterWidgets.slice()
|
||||
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
|
||||
widgets[widgetIndex].width = 50
|
||||
SettingsData.setControlCenterWidgets(widgets)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 24
|
||||
height: 24
|
||||
radius: 12
|
||||
color: (widgetData?.width || 50) === 75 ? Theme.primary : Theme.primaryContainer
|
||||
border.color: Theme.primary
|
||||
border.width: 1
|
||||
visible: !isSlider
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: "75"
|
||||
font.pixelSize: 10
|
||||
font.weight: Font.Medium
|
||||
color: (widgetData?.width || 50) === 75 ? Theme.primaryText : Theme.primary
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
var widgets = SettingsData.controlCenterWidgets.slice()
|
||||
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
|
||||
widgets[widgetIndex].width = 75
|
||||
SettingsData.setControlCenterWidgets(widgets)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 24
|
||||
height: 24
|
||||
radius: 12
|
||||
color: (widgetData?.width || 50) === 100 ? Theme.primary : Theme.primaryContainer
|
||||
border.color: Theme.primary
|
||||
border.width: 1
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: "100"
|
||||
font.pixelSize: 9
|
||||
font.weight: Font.Medium
|
||||
color: (widgetData?.width || 50) === 100 ? Theme.primaryText : Theme.primary
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
var widgets = SettingsData.controlCenterWidgets.slice()
|
||||
if (widgetIndex >= 0 && widgetIndex < widgets.length) {
|
||||
widgets[widgetIndex].width = 100
|
||||
SettingsData.setControlCenterWidgets(widgets)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Arrow buttons for reordering in top-left
|
||||
Row {
|
||||
anchors.top: parent.top
|
||||
anchors.left: parent.left
|
||||
anchors.margins: 4
|
||||
spacing: 2
|
||||
visible: editMode
|
||||
z: 20
|
||||
|
||||
Rectangle {
|
||||
width: 16
|
||||
height: 16
|
||||
radius: 8
|
||||
color: Theme.surfaceContainer
|
||||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "keyboard_arrow_left"
|
||||
size: 12
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
enabled: widgetIndex > 0
|
||||
opacity: enabled ? 1.0 : 0.5
|
||||
onClicked: root.moveWidget(widgetIndex, widgetIndex - 1)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 16
|
||||
height: 16
|
||||
radius: 8
|
||||
color: Theme.surfaceContainer
|
||||
border.color: Theme.outline
|
||||
border.width: 1
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "keyboard_arrow_right"
|
||||
size: 12
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
enabled: widgetIndex < ((SettingsData.controlCenterWidgets?.length ?? 0) - 1)
|
||||
opacity: enabled ? 1.0 : 0.5
|
||||
onClicked: root.moveWidget(widgetIndex, widgetIndex + 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Border highlight
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
|
||||
radius: Theme.cornerRadius
|
||||
border.color: Theme.primary
|
||||
border.width: editMode ? 1 : 0
|
||||
visible: editMode
|
||||
z: -1
|
||||
|
||||
Behavior on border.width {
|
||||
NumberAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,7 @@ Rectangle {
|
||||
color: Theme.surfaceContainerHigh
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.08)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
Row {
|
||||
id: root
|
||||
|
||||
property int currentSize: 50
|
||||
property bool isSlider: false
|
||||
property int widgetIndex: -1
|
||||
|
||||
signal sizeChanged(int newSize)
|
||||
|
||||
readonly property var availableSizes: isSlider ? [50, 100] : [25, 50, 75, 100]
|
||||
|
||||
spacing: 2
|
||||
|
||||
Repeater {
|
||||
model: root.availableSizes
|
||||
|
||||
Rectangle {
|
||||
width: 16
|
||||
height: 16
|
||||
radius: 3
|
||||
color: modelData === root.currentSize ? Theme.primary : Theme.surfaceContainer
|
||||
border.color: modelData === root.currentSize ? Theme.primary : Theme.outline
|
||||
border.width: 1
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: modelData.toString()
|
||||
font.pixelSize: 8
|
||||
font.weight: Font.Medium
|
||||
color: modelData === root.currentSize ? Theme.primaryContainer : Theme.surfaceText
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.currentSize = modelData
|
||||
root.sizeChanged(modelData)
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -13,8 +13,6 @@ Column {
|
||||
property int expandedWidgetIndex: -1
|
||||
property var model: null
|
||||
property var expandedWidgetData: null
|
||||
property var bluetoothCodecSelector: null
|
||||
property bool darkModeTransitionPending: false
|
||||
|
||||
signal expandClicked(var widgetData, int globalIndex)
|
||||
signal removeWidget(int index)
|
||||
@@ -26,7 +24,6 @@ Column {
|
||||
property var currentRowWidgets: []
|
||||
property real currentRowWidth: 0
|
||||
property int expandedRowIndex: -1
|
||||
property var colorPickerModal: null
|
||||
|
||||
function calculateRowsAndWidgets() {
|
||||
return LayoutUtils.calculateRowsAndWidgets(root, expandedSection, expandedWidgetIndex)
|
||||
@@ -41,17 +38,6 @@ Column {
|
||||
expandedRowIndex = layoutResult.expandedRowIndex
|
||||
}
|
||||
|
||||
function moveToTop(item) {
|
||||
const children = root.children
|
||||
for (var i = 0; i < children.length; i++) {
|
||||
if (children[i] === item)
|
||||
continue
|
||||
if (children[i].z)
|
||||
children[i].z = Math.min(children[i].z, 999)
|
||||
}
|
||||
item.z = 1000
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: root.layoutResult.rows
|
||||
|
||||
@@ -65,8 +51,8 @@ Column {
|
||||
if (widgets.length === 0) return false
|
||||
return widgets.every(w => w.id === "volumeSlider" || w.id === "brightnessSlider" || w.id === "inputVolumeSlider")
|
||||
}
|
||||
topPadding: isSliderOnlyRow ? (root.editMode ? 4 : -6) : 0
|
||||
bottomPadding: isSliderOnlyRow ? (root.editMode ? 4 : -6) : 0
|
||||
topPadding: isSliderOnlyRow ? (root.editMode ? 4 : -12) : 0
|
||||
bottomPadding: isSliderOnlyRow ? (root.editMode ? 4 : -12) : 0
|
||||
|
||||
Flow {
|
||||
width: parent.width
|
||||
@@ -75,8 +61,8 @@ Column {
|
||||
Repeater {
|
||||
model: rowWidgets || []
|
||||
|
||||
DragDropWidgetWrapper {
|
||||
widgetData: modelData
|
||||
Item {
|
||||
property var widgetData: modelData
|
||||
property int globalWidgetIndex: {
|
||||
const widgets = SettingsData.controlCenterWidgets || []
|
||||
for (var i = 0; i < widgets.length; i++) {
|
||||
@@ -106,43 +92,36 @@ Column {
|
||||
return baseWidth
|
||||
}
|
||||
}
|
||||
height: isSliderOnlyRow ? 48 : 60
|
||||
height: 60
|
||||
|
||||
editMode: root.editMode
|
||||
widgetIndex: globalWidgetIndex
|
||||
gridCellWidth: width
|
||||
gridCellHeight: height
|
||||
gridColumns: 4
|
||||
gridLayout: root
|
||||
isSlider: {
|
||||
const id = modelData.id || ""
|
||||
return id === "volumeSlider" || id === "brightnessSlider" || id === "inputVolumeSlider"
|
||||
}
|
||||
Loader {
|
||||
id: widgetLoader
|
||||
anchors.fill: parent
|
||||
property var widgetData: parent.widgetData
|
||||
property int widgetIndex: parent.globalWidgetIndex
|
||||
property int globalWidgetIndex: parent.globalWidgetIndex
|
||||
property int widgetWidth: parent.widgetWidth
|
||||
|
||||
widgetComponent: {
|
||||
const id = modelData.id || ""
|
||||
if (id === "wifi" || id === "bluetooth" || id === "audioOutput" || id === "audioInput") {
|
||||
return compoundPillComponent
|
||||
} else if (id === "volumeSlider") {
|
||||
return audioSliderComponent
|
||||
} else if (id === "brightnessSlider") {
|
||||
return brightnessSliderComponent
|
||||
} else if (id === "inputVolumeSlider") {
|
||||
return inputAudioSliderComponent
|
||||
} else if (id === "battery") {
|
||||
return widgetWidth <= 25 ? smallBatteryComponent : batteryPillComponent
|
||||
} else if (id === "diskUsage") {
|
||||
return diskUsagePillComponent
|
||||
} else if (id === "colorPicker") {
|
||||
return colorPickerPillComponent
|
||||
} else {
|
||||
return widgetWidth <= 25 ? smallToggleComponent : toggleButtonComponent
|
||||
sourceComponent: {
|
||||
const id = modelData.id || ""
|
||||
if (id === "wifi" || id === "bluetooth" || id === "audioOutput" || id === "audioInput") {
|
||||
return compoundPillComponent
|
||||
} else if (id === "volumeSlider") {
|
||||
return audioSliderComponent
|
||||
} else if (id === "brightnessSlider") {
|
||||
return brightnessSliderComponent
|
||||
} else if (id === "inputVolumeSlider") {
|
||||
return inputAudioSliderComponent
|
||||
} else if (id === "battery") {
|
||||
return widgetWidth <= 25 ? smallBatteryComponent : batteryPillComponent
|
||||
} else if (id === "diskUsage") {
|
||||
return diskUsagePillComponent
|
||||
} else {
|
||||
return widgetWidth <= 25 ? smallToggleComponent : toggleButtonComponent
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onWidgetMoved: (fromIndex, toIndex) => root.moveWidget(fromIndex, toIndex)
|
||||
onRemoveWidget: index => root.removeWidget(index)
|
||||
onToggleWidgetSize: index => root.toggleWidgetSize(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,7 +142,6 @@ Column {
|
||||
visible: active
|
||||
expandedSection: root.expandedSection
|
||||
expandedWidgetData: root.expandedWidgetData
|
||||
bluetoothCodecSelector: root.bluetoothCodecSelector
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -178,198 +156,201 @@ Column {
|
||||
height: 60
|
||||
iconName: {
|
||||
switch (widgetData.id || "") {
|
||||
case "wifi":
|
||||
{
|
||||
if (NetworkService.wifiToggling)
|
||||
case "wifi": {
|
||||
if (NetworkService.wifiToggling) {
|
||||
return "sync"
|
||||
if (NetworkService.networkStatus === "ethernet")
|
||||
}
|
||||
if (NetworkService.networkStatus === "ethernet") {
|
||||
return "settings_ethernet"
|
||||
if (NetworkService.networkStatus === "wifi")
|
||||
}
|
||||
if (NetworkService.networkStatus === "wifi") {
|
||||
return NetworkService.wifiSignalIcon
|
||||
if (NetworkService.wifiEnabled)
|
||||
}
|
||||
if (NetworkService.wifiEnabled) {
|
||||
return "wifi_off"
|
||||
}
|
||||
return "wifi_off"
|
||||
}
|
||||
case "bluetooth":
|
||||
{
|
||||
if (!BluetoothService.available)
|
||||
case "bluetooth": {
|
||||
if (!BluetoothService.available) {
|
||||
return "bluetooth_disabled"
|
||||
if (!BluetoothService.adapter || !BluetoothService.adapter.enabled)
|
||||
}
|
||||
if (!BluetoothService.adapter || !BluetoothService.adapter.enabled) {
|
||||
return "bluetooth_disabled"
|
||||
}
|
||||
const primaryDevice = (() => {
|
||||
if (!BluetoothService.adapter || !BluetoothService.adapter.devices)
|
||||
return null
|
||||
let devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))]
|
||||
for (let device of devices) {
|
||||
if (device && device.connected)
|
||||
return device
|
||||
}
|
||||
return null
|
||||
})()
|
||||
if (primaryDevice)
|
||||
if (!BluetoothService.adapter || !BluetoothService.adapter.devices) {
|
||||
return null
|
||||
}
|
||||
let devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))]
|
||||
for (let device of devices) {
|
||||
if (device && device.connected) {
|
||||
return device
|
||||
}
|
||||
}
|
||||
return null
|
||||
})()
|
||||
if (primaryDevice) {
|
||||
return BluetoothService.getDeviceIcon(primaryDevice)
|
||||
}
|
||||
return "bluetooth"
|
||||
}
|
||||
case "audioOutput":
|
||||
{
|
||||
if (!AudioService.sink)
|
||||
return "volume_off"
|
||||
case "audioOutput": {
|
||||
if (!AudioService.sink) return "volume_off"
|
||||
let volume = AudioService.sink.audio.volume
|
||||
let muted = AudioService.sink.audio.muted
|
||||
if (muted || volume === 0.0)
|
||||
return "volume_off"
|
||||
if (volume <= 0.33)
|
||||
return "volume_down"
|
||||
if (volume <= 0.66)
|
||||
return "volume_up"
|
||||
if (muted || volume === 0.0) return "volume_off"
|
||||
if (volume <= 0.33) return "volume_down"
|
||||
if (volume <= 0.66) return "volume_up"
|
||||
return "volume_up"
|
||||
}
|
||||
case "audioInput":
|
||||
{
|
||||
if (!AudioService.source)
|
||||
return "mic_off"
|
||||
case "audioInput": {
|
||||
if (!AudioService.source) return "mic_off"
|
||||
let muted = AudioService.source.audio.muted
|
||||
return muted ? "mic_off" : "mic"
|
||||
}
|
||||
default:
|
||||
return widgetDef?.icon || "help"
|
||||
default: return widgetDef?.icon || "help"
|
||||
}
|
||||
}
|
||||
primaryText: {
|
||||
switch (widgetData.id || "") {
|
||||
case "wifi":
|
||||
{
|
||||
if (NetworkService.wifiToggling)
|
||||
case "wifi": {
|
||||
if (NetworkService.wifiToggling) {
|
||||
return NetworkService.wifiEnabled ? "Disabling WiFi..." : "Enabling WiFi..."
|
||||
if (NetworkService.networkStatus === "ethernet")
|
||||
}
|
||||
if (NetworkService.networkStatus === "ethernet") {
|
||||
return "Ethernet"
|
||||
if (NetworkService.networkStatus === "wifi" && NetworkService.currentWifiSSID)
|
||||
}
|
||||
if (NetworkService.networkStatus === "wifi" && NetworkService.currentWifiSSID) {
|
||||
return NetworkService.currentWifiSSID
|
||||
if (NetworkService.wifiEnabled)
|
||||
}
|
||||
if (NetworkService.wifiEnabled) {
|
||||
return "Not connected"
|
||||
}
|
||||
return "WiFi off"
|
||||
}
|
||||
case "bluetooth":
|
||||
{
|
||||
if (!BluetoothService.available)
|
||||
case "bluetooth": {
|
||||
if (!BluetoothService.available) {
|
||||
return "Bluetooth"
|
||||
if (!BluetoothService.adapter)
|
||||
}
|
||||
if (!BluetoothService.adapter) {
|
||||
return "No adapter"
|
||||
if (!BluetoothService.adapter.enabled)
|
||||
}
|
||||
if (!BluetoothService.adapter.enabled) {
|
||||
return "Disabled"
|
||||
}
|
||||
return "Enabled"
|
||||
}
|
||||
case "audioOutput":
|
||||
return AudioService.sink?.description || "No output device"
|
||||
case "audioInput":
|
||||
return AudioService.source?.description || "No input device"
|
||||
default:
|
||||
return widgetDef?.text || "Unknown"
|
||||
case "audioOutput": return AudioService.sink?.description || "No output device"
|
||||
case "audioInput": return AudioService.source?.description || "No input device"
|
||||
default: return widgetDef?.text || "Unknown"
|
||||
}
|
||||
}
|
||||
secondaryText: {
|
||||
switch (widgetData.id || "") {
|
||||
case "wifi":
|
||||
{
|
||||
if (NetworkService.wifiToggling)
|
||||
case "wifi": {
|
||||
if (NetworkService.wifiToggling) {
|
||||
return "Please wait..."
|
||||
if (NetworkService.networkStatus === "ethernet")
|
||||
}
|
||||
if (NetworkService.networkStatus === "ethernet") {
|
||||
return "Connected"
|
||||
if (NetworkService.networkStatus === "wifi")
|
||||
}
|
||||
if (NetworkService.networkStatus === "wifi") {
|
||||
return NetworkService.wifiSignalStrength > 0 ? NetworkService.wifiSignalStrength + "%" : "Connected"
|
||||
if (NetworkService.wifiEnabled)
|
||||
}
|
||||
if (NetworkService.wifiEnabled) {
|
||||
return "Select network"
|
||||
}
|
||||
return ""
|
||||
}
|
||||
case "bluetooth":
|
||||
{
|
||||
if (!BluetoothService.available)
|
||||
case "bluetooth": {
|
||||
if (!BluetoothService.available) {
|
||||
return "No adapters"
|
||||
if (!BluetoothService.adapter || !BluetoothService.adapter.enabled)
|
||||
}
|
||||
if (!BluetoothService.adapter || !BluetoothService.adapter.enabled) {
|
||||
return "Off"
|
||||
}
|
||||
const primaryDevice = (() => {
|
||||
if (!BluetoothService.adapter || !BluetoothService.adapter.devices)
|
||||
return null
|
||||
let devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))]
|
||||
for (let device of devices) {
|
||||
if (device && device.connected)
|
||||
return device
|
||||
}
|
||||
return null
|
||||
})()
|
||||
if (primaryDevice)
|
||||
if (!BluetoothService.adapter || !BluetoothService.adapter.devices) {
|
||||
return null
|
||||
}
|
||||
let devices = [...BluetoothService.adapter.devices.values.filter(dev => dev && (dev.paired || dev.trusted))]
|
||||
for (let device of devices) {
|
||||
if (device && device.connected) {
|
||||
return device
|
||||
}
|
||||
}
|
||||
return null
|
||||
})()
|
||||
if (primaryDevice) {
|
||||
return primaryDevice.name || primaryDevice.alias || primaryDevice.deviceName || "Connected Device"
|
||||
}
|
||||
return "No devices"
|
||||
}
|
||||
case "audioOutput":
|
||||
{
|
||||
if (!AudioService.sink)
|
||||
case "audioOutput": {
|
||||
if (!AudioService.sink) {
|
||||
return "Select device"
|
||||
if (AudioService.sink.audio.muted)
|
||||
}
|
||||
if (AudioService.sink.audio.muted) {
|
||||
return "Muted"
|
||||
}
|
||||
return Math.round(AudioService.sink.audio.volume * 100) + "%"
|
||||
}
|
||||
case "audioInput":
|
||||
{
|
||||
if (!AudioService.source)
|
||||
case "audioInput": {
|
||||
if (!AudioService.source) {
|
||||
return "Select device"
|
||||
if (AudioService.source.audio.muted)
|
||||
}
|
||||
if (AudioService.source.audio.muted) {
|
||||
return "Muted"
|
||||
}
|
||||
return Math.round(AudioService.source.audio.volume * 100) + "%"
|
||||
}
|
||||
default:
|
||||
return widgetDef?.description || ""
|
||||
default: return widgetDef?.description || ""
|
||||
}
|
||||
}
|
||||
isActive: {
|
||||
switch (widgetData.id || "") {
|
||||
case "wifi":
|
||||
{
|
||||
if (NetworkService.wifiToggling)
|
||||
case "wifi": {
|
||||
if (NetworkService.wifiToggling) {
|
||||
return false
|
||||
if (NetworkService.networkStatus === "ethernet")
|
||||
}
|
||||
if (NetworkService.networkStatus === "ethernet") {
|
||||
return true
|
||||
if (NetworkService.networkStatus === "wifi")
|
||||
}
|
||||
if (NetworkService.networkStatus === "wifi") {
|
||||
return true
|
||||
}
|
||||
return NetworkService.wifiEnabled
|
||||
}
|
||||
case "bluetooth":
|
||||
return !!(BluetoothService.available && BluetoothService.adapter && BluetoothService.adapter.enabled)
|
||||
case "audioOutput":
|
||||
return !!(AudioService.sink && !AudioService.sink.audio.muted)
|
||||
case "audioInput":
|
||||
return !!(AudioService.source && !AudioService.source.audio.muted)
|
||||
default:
|
||||
return false
|
||||
case "bluetooth": return !!(BluetoothService.available && BluetoothService.adapter && BluetoothService.adapter.enabled)
|
||||
case "audioOutput": return !!(AudioService.sink && !AudioService.sink.audio.muted)
|
||||
case "audioInput": return !!(AudioService.source && !AudioService.source.audio.muted)
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
enabled: widgetDef?.enabled ?? true
|
||||
enabled: (widgetDef?.enabled ?? true)
|
||||
onToggled: {
|
||||
if (root.editMode) return
|
||||
switch (widgetData.id || "") {
|
||||
case "wifi":
|
||||
{
|
||||
case "wifi": {
|
||||
if (NetworkService.networkStatus !== "ethernet" && !NetworkService.wifiToggling) {
|
||||
NetworkService.toggleWifiRadio()
|
||||
}
|
||||
break
|
||||
}
|
||||
case "bluetooth":
|
||||
{
|
||||
case "bluetooth": {
|
||||
if (BluetoothService.available && BluetoothService.adapter) {
|
||||
BluetoothService.adapter.enabled = !BluetoothService.adapter.enabled
|
||||
}
|
||||
break
|
||||
}
|
||||
case "audioOutput":
|
||||
{
|
||||
case "audioOutput": {
|
||||
if (AudioService.sink && AudioService.sink.audio) {
|
||||
AudioService.sink.audio.muted = !AudioService.sink.audio.muted
|
||||
}
|
||||
break
|
||||
}
|
||||
case "audioInput":
|
||||
{
|
||||
case "audioInput": {
|
||||
if (AudioService.source && AudioService.source.audio) {
|
||||
AudioService.source.audio.muted = !AudioService.source.audio.muted
|
||||
}
|
||||
@@ -382,11 +363,9 @@ Column {
|
||||
root.expandClicked(widgetData, widgetIndex)
|
||||
}
|
||||
onWheelEvent: function (wheelEvent) {
|
||||
if (root.editMode) return
|
||||
const id = widgetData.id || ""
|
||||
if (id === "audioOutput") {
|
||||
if (!AudioService.sink || !AudioService.sink.audio)
|
||||
return
|
||||
if (!AudioService.sink || !AudioService.sink.audio) return
|
||||
let delta = wheelEvent.angleDelta.y
|
||||
let currentVolume = AudioService.sink.audio.volume * 100
|
||||
let newVolume
|
||||
@@ -398,8 +377,7 @@ Column {
|
||||
AudioService.sink.audio.volume = newVolume / 100
|
||||
wheelEvent.accepted = true
|
||||
} else if (id === "audioInput") {
|
||||
if (!AudioService.source || !AudioService.source.audio)
|
||||
return
|
||||
if (!AudioService.source || !AudioService.source.audio) return
|
||||
let delta = wheelEvent.angleDelta.y
|
||||
let currentVolume = AudioService.source.audio.volume * 100
|
||||
let newVolume
|
||||
@@ -412,6 +390,18 @@ Column {
|
||||
wheelEvent.accepted = true
|
||||
}
|
||||
}
|
||||
|
||||
EditModeOverlay {
|
||||
anchors.fill: parent
|
||||
editMode: root.editMode
|
||||
widgetData: parent.widgetData
|
||||
widgetIndex: parent.widgetIndex
|
||||
showSizeControls: true
|
||||
isSlider: false
|
||||
onRemoveWidget: (index) => root.removeWidget(index)
|
||||
onToggleWidgetSize: (index) => root.toggleWidgetSize(index)
|
||||
onMoveWidget: (fromIndex, toIndex) => root.moveWidget(fromIndex, toIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,6 +410,7 @@ Column {
|
||||
Item {
|
||||
property var widgetData: parent.widgetData || {}
|
||||
property int widgetIndex: parent.widgetIndex || 0
|
||||
property var widgetDef: root.model?.getWidgetForId(widgetData.id || "")
|
||||
width: parent.width
|
||||
height: 16
|
||||
|
||||
@@ -429,6 +420,18 @@ Column {
|
||||
height: 14
|
||||
property color sliderTrackColor: Theme.surfaceContainerHigh
|
||||
}
|
||||
|
||||
EditModeOverlay {
|
||||
anchors.fill: parent
|
||||
editMode: root.editMode
|
||||
widgetData: parent.widgetData
|
||||
widgetIndex: parent.widgetIndex
|
||||
showSizeControls: true
|
||||
isSlider: true
|
||||
onRemoveWidget: (index) => root.removeWidget(index)
|
||||
onToggleWidgetSize: (index) => root.toggleWidgetSize(index)
|
||||
onMoveWidget: (fromIndex, toIndex) => root.moveWidget(fromIndex, toIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -446,6 +449,18 @@ Column {
|
||||
height: 14
|
||||
property color sliderTrackColor: Theme.surfaceContainerHigh
|
||||
}
|
||||
|
||||
EditModeOverlay {
|
||||
anchors.fill: parent
|
||||
editMode: root.editMode
|
||||
widgetData: parent.widgetData
|
||||
widgetIndex: parent.widgetIndex
|
||||
showSizeControls: true
|
||||
isSlider: true
|
||||
onRemoveWidget: (index) => root.removeWidget(index)
|
||||
onToggleWidgetSize: (index) => root.toggleWidgetSize(index)
|
||||
onMoveWidget: (fromIndex, toIndex) => root.moveWidget(fromIndex, toIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -463,6 +478,18 @@ Column {
|
||||
height: 14
|
||||
property color sliderTrackColor: Theme.surfaceContainerHigh
|
||||
}
|
||||
|
||||
EditModeOverlay {
|
||||
anchors.fill: parent
|
||||
editMode: root.editMode
|
||||
widgetData: parent.widgetData
|
||||
widgetIndex: parent.widgetIndex
|
||||
showSizeControls: true
|
||||
isSlider: true
|
||||
onRemoveWidget: (index) => root.removeWidget(index)
|
||||
onToggleWidgetSize: (index) => root.toggleWidgetSize(index)
|
||||
onMoveWidget: (fromIndex, toIndex) => root.moveWidget(fromIndex, toIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,6 +506,18 @@ Column {
|
||||
root.expandClicked(widgetData, widgetIndex)
|
||||
}
|
||||
}
|
||||
|
||||
EditModeOverlay {
|
||||
anchors.fill: parent
|
||||
editMode: root.editMode
|
||||
widgetData: parent.widgetData
|
||||
widgetIndex: parent.widgetIndex
|
||||
showSizeControls: true
|
||||
isSlider: false
|
||||
onRemoveWidget: (index) => root.removeWidget(index)
|
||||
onToggleWidgetSize: (index) => root.toggleWidgetSize(index)
|
||||
onMoveWidget: (fromIndex, toIndex) => root.moveWidget(fromIndex, toIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,6 +534,18 @@ Column {
|
||||
root.expandClicked(widgetData, widgetIndex)
|
||||
}
|
||||
}
|
||||
|
||||
EditModeOverlay {
|
||||
anchors.fill: parent
|
||||
editMode: root.editMode
|
||||
widgetData: parent.widgetData
|
||||
widgetIndex: parent.widgetIndex
|
||||
showSizeControls: true
|
||||
isSlider: false
|
||||
onRemoveWidget: (index) => root.removeWidget(index)
|
||||
onToggleWidgetSize: (index) => root.toggleWidgetSize(index)
|
||||
onMoveWidget: (fromIndex, toIndex) => root.moveWidget(fromIndex, toIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -503,99 +554,80 @@ Column {
|
||||
ToggleButton {
|
||||
property var widgetData: parent.widgetData || {}
|
||||
property int widgetIndex: parent.widgetIndex || 0
|
||||
property var widgetDef: root.model?.getWidgetForId(widgetData.id || "")
|
||||
width: parent.width
|
||||
height: 60
|
||||
|
||||
iconName: {
|
||||
switch (widgetData.id || "") {
|
||||
case "nightMode":
|
||||
return DisplayService.nightModeEnabled ? "nightlight" : "dark_mode"
|
||||
case "darkMode":
|
||||
return "contrast"
|
||||
case "doNotDisturb":
|
||||
return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off"
|
||||
case "idleInhibitor":
|
||||
return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"
|
||||
default:
|
||||
return "help"
|
||||
case "nightMode": return DisplayService.nightModeEnabled ? "nightlight" : "dark_mode"
|
||||
case "darkMode": return "contrast"
|
||||
case "doNotDisturb": return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off"
|
||||
case "idleInhibitor": return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"
|
||||
default: return widgetDef?.icon || "help"
|
||||
}
|
||||
}
|
||||
|
||||
text: {
|
||||
switch (widgetData.id || "") {
|
||||
case "nightMode":
|
||||
return "Night Mode"
|
||||
case "darkMode":
|
||||
return SessionData.isLightMode ? "Light Mode" : "Dark Mode"
|
||||
case "doNotDisturb":
|
||||
return "Do Not Disturb"
|
||||
case "idleInhibitor":
|
||||
return SessionService.idleInhibited ? "Keeping Awake" : "Keep Awake"
|
||||
default:
|
||||
return "Unknown"
|
||||
case "nightMode": return "Night Mode"
|
||||
case "darkMode": return SessionData.isLightMode ? "Light Mode" : "Dark Mode"
|
||||
case "doNotDisturb": return "Do Not Disturb"
|
||||
case "idleInhibitor": return SessionService.idleInhibited ? "Keeping Awake" : "Keep Awake"
|
||||
default: return widgetDef?.text || "Unknown"
|
||||
}
|
||||
}
|
||||
|
||||
iconRotation: {
|
||||
if (widgetData.id !== "darkMode") return 0
|
||||
if (darkModeTransitionPending) {
|
||||
return SessionData.isLightMode ? 0 : 180
|
||||
}
|
||||
return SessionData.isLightMode ? 180 : 0
|
||||
}
|
||||
secondaryText: ""
|
||||
|
||||
iconRotation: widgetData.id === "darkMode" && SessionData.isLightMode ? 180 : 0
|
||||
|
||||
isActive: {
|
||||
switch (widgetData.id || "") {
|
||||
case "nightMode":
|
||||
return DisplayService.nightModeEnabled || false
|
||||
case "darkMode":
|
||||
return !SessionData.isLightMode
|
||||
case "doNotDisturb":
|
||||
return SessionData.doNotDisturb || false
|
||||
case "idleInhibitor":
|
||||
return SessionService.idleInhibited || false
|
||||
default:
|
||||
return false
|
||||
case "nightMode": return DisplayService.nightModeEnabled || false
|
||||
case "darkMode": return !SessionData.isLightMode
|
||||
case "doNotDisturb": return SessionData.doNotDisturb || false
|
||||
case "idleInhibitor": return SessionService.idleInhibited || false
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
|
||||
enabled: !root.editMode
|
||||
|
||||
onIconRotationCompleted: {
|
||||
if (root.darkModeTransitionPending && widgetData.id === "darkMode") {
|
||||
root.darkModeTransitionPending = false
|
||||
Theme.screenTransition()
|
||||
Theme.toggleLightMode()
|
||||
}
|
||||
}
|
||||
enabled: (widgetDef?.enabled ?? true) && !root.editMode
|
||||
|
||||
onClicked: {
|
||||
if (root.editMode)
|
||||
return
|
||||
switch (widgetData.id || "") {
|
||||
case "nightMode":
|
||||
{
|
||||
if (DisplayService.automationAvailable)
|
||||
case "nightMode": {
|
||||
if (DisplayService.automationAvailable) {
|
||||
DisplayService.toggleNightMode()
|
||||
}
|
||||
break
|
||||
}
|
||||
case "darkMode":
|
||||
{
|
||||
root.darkModeTransitionPending = true
|
||||
case "darkMode": {
|
||||
Theme.toggleLightMode()
|
||||
break
|
||||
}
|
||||
case "doNotDisturb":
|
||||
{
|
||||
case "doNotDisturb": {
|
||||
SessionData.setDoNotDisturb(!SessionData.doNotDisturb)
|
||||
break
|
||||
}
|
||||
case "idleInhibitor":
|
||||
{
|
||||
case "idleInhibitor": {
|
||||
SessionService.toggleIdleInhibit()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditModeOverlay {
|
||||
anchors.fill: parent
|
||||
editMode: root.editMode
|
||||
widgetData: parent.widgetData
|
||||
widgetIndex: parent.widgetIndex
|
||||
showSizeControls: true
|
||||
isSlider: false
|
||||
onRemoveWidget: (index) => root.removeWidget(index)
|
||||
onToggleWidgetSize: (index) => root.toggleWidgetSize(index)
|
||||
onMoveWidget: (fromIndex, toIndex) => root.moveWidget(fromIndex, toIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -604,84 +636,68 @@ enabled: !root.editMode
|
||||
SmallToggleButton {
|
||||
property var widgetData: parent.widgetData || {}
|
||||
property int widgetIndex: parent.widgetIndex || 0
|
||||
property var widgetDef: root.model?.getWidgetForId(widgetData.id || "")
|
||||
width: parent.width
|
||||
height: 48
|
||||
|
||||
iconName: {
|
||||
switch (widgetData.id || "") {
|
||||
case "nightMode":
|
||||
return DisplayService.nightModeEnabled ? "nightlight" : "dark_mode"
|
||||
case "darkMode":
|
||||
return "contrast"
|
||||
case "doNotDisturb":
|
||||
return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off"
|
||||
case "idleInhibitor":
|
||||
return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"
|
||||
default:
|
||||
return "help"
|
||||
case "nightMode": return DisplayService.nightModeEnabled ? "nightlight" : "dark_mode"
|
||||
case "darkMode": return "contrast"
|
||||
case "doNotDisturb": return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off"
|
||||
case "idleInhibitor": return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle"
|
||||
default: return widgetDef?.icon || "help"
|
||||
}
|
||||
}
|
||||
|
||||
iconRotation: {
|
||||
if (widgetData.id !== "darkMode") return 0
|
||||
if (darkModeTransitionPending) {
|
||||
return SessionData.isLightMode ? 0 : 180
|
||||
}
|
||||
return SessionData.isLightMode ? 180 : 0
|
||||
}
|
||||
iconRotation: widgetData.id === "darkMode" && SessionData.isLightMode ? 180 : 0
|
||||
|
||||
isActive: {
|
||||
switch (widgetData.id || "") {
|
||||
case "nightMode":
|
||||
return DisplayService.nightModeEnabled || false
|
||||
case "darkMode":
|
||||
return !SessionData.isLightMode
|
||||
case "doNotDisturb":
|
||||
return SessionData.doNotDisturb || false
|
||||
case "idleInhibitor":
|
||||
return SessionService.idleInhibited || false
|
||||
default:
|
||||
return false
|
||||
case "nightMode": return DisplayService.nightModeEnabled || false
|
||||
case "darkMode": return !SessionData.isLightMode
|
||||
case "doNotDisturb": return SessionData.doNotDisturb || false
|
||||
case "idleInhibitor": return SessionService.idleInhibited || false
|
||||
default: return false
|
||||
}
|
||||
}
|
||||
|
||||
enabled: !root.editMode
|
||||
|
||||
onIconRotationCompleted: {
|
||||
if (root.darkModeTransitionPending && widgetData.id === "darkMode") {
|
||||
root.darkModeTransitionPending = false
|
||||
Theme.screenTransition()
|
||||
Theme.toggleLightMode()
|
||||
}
|
||||
}
|
||||
enabled: (widgetDef?.enabled ?? true) && !root.editMode
|
||||
|
||||
onClicked: {
|
||||
if (root.editMode)
|
||||
return
|
||||
switch (widgetData.id || "") {
|
||||
case "nightMode":
|
||||
{
|
||||
if (DisplayService.automationAvailable)
|
||||
case "nightMode": {
|
||||
if (DisplayService.automationAvailable) {
|
||||
DisplayService.toggleNightMode()
|
||||
}
|
||||
break
|
||||
}
|
||||
case "darkMode":
|
||||
{
|
||||
root.darkModeTransitionPending = true
|
||||
case "darkMode": {
|
||||
Theme.toggleLightMode()
|
||||
break
|
||||
}
|
||||
case "doNotDisturb":
|
||||
{
|
||||
case "doNotDisturb": {
|
||||
SessionData.setDoNotDisturb(!SessionData.doNotDisturb)
|
||||
break
|
||||
}
|
||||
case "idleInhibitor":
|
||||
{
|
||||
case "idleInhibitor": {
|
||||
SessionService.toggleIdleInhibit()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EditModeOverlay {
|
||||
anchors.fill: parent
|
||||
editMode: root.editMode
|
||||
widgetData: parent.widgetData
|
||||
widgetIndex: parent.widgetIndex
|
||||
showSizeControls: true
|
||||
isSlider: false
|
||||
onRemoveWidget: (index) => root.removeWidget(index)
|
||||
onToggleWidgetSize: (index) => root.toggleWidgetSize(index)
|
||||
onMoveWidget: (fromIndex, toIndex) => root.moveWidget(fromIndex, toIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -701,18 +717,18 @@ enabled: !root.editMode
|
||||
root.expandClicked(widgetData, widgetIndex)
|
||||
}
|
||||
}
|
||||
|
||||
EditModeOverlay {
|
||||
anchors.fill: parent
|
||||
editMode: root.editMode
|
||||
widgetData: parent.widgetData
|
||||
widgetIndex: parent.widgetIndex
|
||||
showSizeControls: true
|
||||
isSlider: false
|
||||
onRemoveWidget: (index) => root.removeWidget(index)
|
||||
onToggleWidgetSize: (index) => root.toggleWidgetSize(index)
|
||||
onMoveWidget: (fromIndex, toIndex) => root.moveWidget(fromIndex, toIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: colorPickerPillComponent
|
||||
ColorPickerPill {
|
||||
property var widgetData: parent.widgetData || {}
|
||||
property int widgetIndex: parent.widgetIndex || 0
|
||||
width: parent.width
|
||||
height: 60
|
||||
|
||||
colorPickerModal: root.colorPickerModal
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import qs.Common
|
||||
import qs.Modules.ControlCenter
|
||||
import qs.Modules.ControlCenter.Widgets
|
||||
import qs.Modules.ControlCenter.Details
|
||||
import qs.Modules.DankBar
|
||||
import qs.Modules.TopBar
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.ControlCenter.Components
|
||||
@@ -22,6 +22,7 @@ DankPopout {
|
||||
|
||||
property string expandedSection: ""
|
||||
property bool powerOptionsExpanded: false
|
||||
property string triggerSection: "right"
|
||||
property var triggerScreen: null
|
||||
property bool editMode: false
|
||||
property int expandedWidgetIndex: -1
|
||||
@@ -65,9 +66,9 @@ DankPopout {
|
||||
popupWidth: 550
|
||||
popupHeight: Math.min((triggerScreen?.height ?? 1080) - 100, contentLoader.item && contentLoader.item.implicitHeight > 0 ? contentLoader.item.implicitHeight + 20 : 400)
|
||||
triggerX: (triggerScreen?.width ?? 1920) - 600 - Theme.spacingL
|
||||
triggerY: Theme.barHeight - 4 + SettingsData.dankBarSpacing
|
||||
triggerY: Theme.barHeight - 4 + SettingsData.topBarSpacing + Theme.spacingXS
|
||||
triggerWidth: 80
|
||||
positioning: ""
|
||||
positioning: "center"
|
||||
screen: triggerScreen
|
||||
shouldBeVisible: false
|
||||
visible: shouldBeVisible
|
||||
@@ -101,14 +102,14 @@ DankPopout {
|
||||
property alias bluetoothCodecSelector: bluetoothCodecSelector
|
||||
|
||||
color: {
|
||||
const transparency = Theme.popupTransparency
|
||||
const transparency = Theme.popupTransparency || 0.92
|
||||
const surface = Theme.surfaceContainer || Qt.rgba(0.1, 0.1, 0.1, 1)
|
||||
return Qt.rgba(surface.r, surface.g, surface.b, transparency)
|
||||
}
|
||||
radius: Theme.cornerRadius
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.08)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
antialiasing: true
|
||||
smooth: true
|
||||
|
||||
@@ -144,7 +145,7 @@ DankPopout {
|
||||
}
|
||||
}
|
||||
|
||||
DragDropGrid {
|
||||
WidgetGrid {
|
||||
id: widgetGrid
|
||||
width: parent.width
|
||||
editMode: root.editMode
|
||||
@@ -152,8 +153,6 @@ DankPopout {
|
||||
expandedWidgetIndex: root.expandedWidgetIndex
|
||||
expandedWidgetData: root.expandedWidgetData
|
||||
model: widgetModel
|
||||
bluetoothCodecSelector: bluetoothCodecSelector
|
||||
colorPickerModal: root.colorPickerModal
|
||||
onExpandClicked: (widgetData, globalIndex) => {
|
||||
root.expandedWidgetIndex = globalIndex
|
||||
root.expandedWidgetData = widgetData
|
||||
@@ -223,6 +222,4 @@ DankPopout {
|
||||
id: batteryDetailComponent
|
||||
BatteryDetail {}
|
||||
}
|
||||
|
||||
property var colorPickerModal: null
|
||||
}
|
||||
@@ -16,7 +16,7 @@ Rectangle {
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHigh
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
id: headerRow
|
||||
@@ -57,6 +57,10 @@ Rectangle {
|
||||
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
|
||||
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: iconArea
|
||||
anchors.fill: parent
|
||||
@@ -134,9 +138,9 @@ Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: deviceMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHighest
|
||||
color: deviceMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHigh
|
||||
border.color: modelData === AudioService.source ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
border.width: 0
|
||||
border.width: modelData === AudioService.source ? 2 : 1
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
@@ -194,6 +198,14 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ Rectangle {
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHigh
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
id: headerRow
|
||||
@@ -57,6 +57,10 @@ Rectangle {
|
||||
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
|
||||
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: iconArea
|
||||
anchors.fill: parent
|
||||
@@ -139,9 +143,9 @@ Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: deviceMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHighest
|
||||
color: deviceMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHigh
|
||||
border.color: modelData === AudioService.sink ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
border.width: 0
|
||||
border.width: modelData === AudioService.sink ? 2 : 1
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
@@ -201,6 +205,14 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ Rectangle {
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHigh
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
|
||||
function isActiveProfile(profile) {
|
||||
if (typeof PowerProfiles === "undefined") {
|
||||
@@ -209,7 +209,7 @@ Rectangle {
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12)
|
||||
border.color: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.3)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
visible: (typeof PowerProfiles !== "undefined") && PowerProfiles.degradationReason !== PerformanceDegradationReason.None
|
||||
|
||||
Column {
|
||||
|
||||
@@ -124,7 +124,7 @@ Item {
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainer
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
opacity: modalVisible ? 1 : 0
|
||||
scale: modalVisible ? 1 : 0.9
|
||||
|
||||
@@ -206,14 +206,14 @@ Item {
|
||||
radius: Theme.cornerRadius
|
||||
color: {
|
||||
if (modelData.name === currentCodec)
|
||||
return Theme.surfaceContainerHighest;
|
||||
return Theme.surfaceContainerHigh;
|
||||
else if (codecMouseArea.containsMouse)
|
||||
return Theme.surfaceHover;
|
||||
else
|
||||
return "transparent";
|
||||
}
|
||||
border.color: "transparent"
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
@@ -272,6 +272,12 @@ Item {
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ Rectangle {
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHigh
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
|
||||
property var bluetoothCodecModalRef: null
|
||||
|
||||
@@ -62,7 +62,7 @@ Rectangle {
|
||||
return scanMouseArea.containsMouse ? Theme.surfaceContainerHigh : "transparent"
|
||||
}
|
||||
border.color: BluetoothService.adapter && BluetoothService.adapter.enabled ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
visible: BluetoothService.adapter && BluetoothService.adapter.enabled
|
||||
|
||||
Row {
|
||||
@@ -96,6 +96,13 @@ Rectangle {
|
||||
BluetoothService.adapter.discovering = !BluetoothService.adapter.discovering
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,7 +159,7 @@ Rectangle {
|
||||
return Qt.rgba(Theme.warning.r, Theme.warning.g, Theme.warning.b, 0.12)
|
||||
if (deviceMouseArea.containsMouse)
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08)
|
||||
return Theme.surfaceContainerHighest
|
||||
return Theme.surfaceContainerHigh
|
||||
}
|
||||
border.color: {
|
||||
if (modelData.state === BluetoothDeviceState.Connecting)
|
||||
@@ -161,7 +168,7 @@ Rectangle {
|
||||
return Theme.primary
|
||||
return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
}
|
||||
border.width: 0
|
||||
border.width: (modelData.connected || modelData.state === BluetoothDeviceState.Connecting) ? 2 : 1
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
@@ -277,6 +284,14 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -332,9 +347,9 @@ Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: availableMouseArea.containsMouse && !isBusy ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHighest
|
||||
color: availableMouseArea.containsMouse && !isBusy ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHigh
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
opacity: canConnect ? 1 : 0.6
|
||||
|
||||
Row {
|
||||
@@ -412,6 +427,9 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,7 +458,7 @@ Rectangle {
|
||||
background: Rectangle {
|
||||
color: Theme.popupBackground()
|
||||
radius: Theme.cornerRadius
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
}
|
||||
|
||||
|
||||
@@ -6,8 +6,6 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property string currentMountPath: "/"
|
||||
property string instanceId: ""
|
||||
|
||||
@@ -17,7 +15,7 @@ Rectangle {
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHigh
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
|
||||
Component.onCompleted: {
|
||||
DgopService.addRef(["diskmounts"])
|
||||
@@ -78,9 +76,9 @@ Rectangle {
|
||||
width: parent.width
|
||||
height: 80
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHighest
|
||||
color: Theme.surfaceContainerHigh
|
||||
border.color: modelData.mount === currentMountPath ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
border.width: modelData.mount === currentMountPath ? 2 : 0
|
||||
border.width: modelData.mount === currentMountPath ? 2 : 1
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
@@ -154,11 +152,16 @@ Rectangle {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
currentMountPath = modelData.mount
|
||||
mountPathChanged(modelData.mount)
|
||||
if (modelData.mount !== currentMountPath) {
|
||||
currentMountPath = modelData.mount
|
||||
mountPathChanged(modelData.mount)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ Rectangle {
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHigh
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
|
||||
Component.onCompleted: {
|
||||
NetworkService.addRef()
|
||||
@@ -27,11 +27,20 @@ Rectangle {
|
||||
NetworkService.scanWifi()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Component.onDestruction: {
|
||||
NetworkService.removeRef()
|
||||
}
|
||||
|
||||
property var wifiPasswordModalRef: {
|
||||
wifiPasswordModalLoader.active = true
|
||||
return wifiPasswordModalLoader.item
|
||||
}
|
||||
property var networkInfoModalRef: {
|
||||
networkInfoModalLoader.active = true
|
||||
return networkInfoModalLoader.item
|
||||
}
|
||||
|
||||
Row {
|
||||
id: headerRow
|
||||
anchors.left: parent.left
|
||||
@@ -149,7 +158,7 @@ Rectangle {
|
||||
height: 36
|
||||
radius: 18
|
||||
color: enableWifiButton.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
border.color: Theme.primary
|
||||
|
||||
StyledText {
|
||||
@@ -168,6 +177,12 @@ Rectangle {
|
||||
onClicked: NetworkService.toggleWifiRadio()
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -227,9 +242,9 @@ Rectangle {
|
||||
width: parent.width
|
||||
height: 50
|
||||
radius: Theme.cornerRadius
|
||||
color: networkMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHighest
|
||||
color: networkMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Theme.surfaceContainerHigh
|
||||
border.color: modelData.ssid === NetworkService.currentWifiSSID ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
border.width: 0
|
||||
border.width: modelData.ssid === NetworkService.currentWifiSSID ? 2 : 1
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
@@ -317,7 +332,9 @@ Rectangle {
|
||||
onClicked: function(event) {
|
||||
if (modelData.ssid !== NetworkService.currentWifiSSID) {
|
||||
if (modelData.secured && !modelData.saved) {
|
||||
wifiPasswordModal.show(modelData.ssid)
|
||||
if (wifiPasswordModalRef) {
|
||||
wifiPasswordModalRef.show(modelData.ssid)
|
||||
}
|
||||
} else {
|
||||
NetworkService.connectToWifi(modelData.ssid)
|
||||
}
|
||||
@@ -326,6 +343,13 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -345,7 +369,7 @@ Rectangle {
|
||||
background: Rectangle {
|
||||
color: Theme.popupBackground()
|
||||
radius: Theme.cornerRadius
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
}
|
||||
|
||||
@@ -371,7 +395,9 @@ Rectangle {
|
||||
NetworkService.disconnectWifi()
|
||||
} else {
|
||||
if (networkContextMenu.currentSecured && !networkContextMenu.currentSaved) {
|
||||
wifiPasswordModal.show(networkContextMenu.currentSSID)
|
||||
if (wifiPasswordModalRef) {
|
||||
wifiPasswordModalRef.show(networkContextMenu.currentSSID)
|
||||
}
|
||||
} else {
|
||||
NetworkService.connectToWifi(networkContextMenu.currentSSID)
|
||||
}
|
||||
@@ -397,8 +423,10 @@ Rectangle {
|
||||
}
|
||||
|
||||
onTriggered: {
|
||||
let networkData = NetworkService.getNetworkInfo(networkContextMenu.currentSSID)
|
||||
networkInfoModal.showNetworkInfo(networkContextMenu.currentSSID, networkData)
|
||||
if (networkInfoModalRef) {
|
||||
let networkData = NetworkService.getNetworkInfo(networkContextMenu.currentSSID)
|
||||
networkInfoModalRef.showNetworkInfo(networkContextMenu.currentSSID, networkData)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -426,12 +454,22 @@ Rectangle {
|
||||
}
|
||||
}
|
||||
|
||||
WifiPasswordModal {
|
||||
id: wifiPasswordModal
|
||||
LazyLoader {
|
||||
id: wifiPasswordModalLoader
|
||||
active: false
|
||||
|
||||
WifiPasswordModal {
|
||||
id: wifiPasswordModal
|
||||
}
|
||||
}
|
||||
|
||||
NetworkInfoModal {
|
||||
id: networkInfoModal
|
||||
|
||||
LazyLoader {
|
||||
id: networkInfoModalLoader
|
||||
active: false
|
||||
|
||||
NetworkInfoModal {
|
||||
id: networkInfoModal
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -116,14 +116,6 @@ QtObject {
|
||||
"enabled": DgopService.dgopAvailable,
|
||||
"warning": !DgopService.dgopAvailable ? "Requires 'dgop' tool" : undefined,
|
||||
"allowMultiple": true
|
||||
},
|
||||
{
|
||||
"id": "colorPicker",
|
||||
"text": "Color Picker",
|
||||
"description": "Choose colors from palette",
|
||||
"icon": "palette",
|
||||
"type": "action",
|
||||
"enabled": true
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
@@ -44,7 +44,7 @@ PanelWindow {
|
||||
radius: Theme.cornerRadius
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
|
||||
Theme.outline.b, 0.08)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
opacity: powerMenuVisible ? 1 : 0
|
||||
scale: powerMenuVisible ? 1 : 0.85
|
||||
|
||||
|
||||
@@ -20,7 +20,11 @@ Row {
|
||||
height: Theme.iconSize + Theme.spacingS * 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
|
||||
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0)
|
||||
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: iconArea
|
||||
@@ -30,9 +34,7 @@ Row {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (defaultSink) {
|
||||
AudioService.suppressOSD = true
|
||||
defaultSink.audio.muted = !defaultSink.audio.muted
|
||||
AudioService.suppressOSD = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -69,9 +71,6 @@ Row {
|
||||
valueOverride: actualVolumePercent
|
||||
thumbOutlineColor: Theme.surfaceContainer
|
||||
trackColor: root.sliderTrackColor.a > 0 ? root.sliderTrackColor : Theme.surfaceContainerHigh
|
||||
onIsDraggingChanged: {
|
||||
AudioService.suppressOSD = isDragging
|
||||
}
|
||||
onSliderValueChanged: function(newValue) {
|
||||
if (defaultSink) {
|
||||
defaultSink.audio.volume = newValue / 100.0
|
||||
|
||||
@@ -30,6 +30,9 @@ CompoundPill {
|
||||
if (!BluetoothService.adapter || !BluetoothService.adapter.enabled) {
|
||||
return "bluetooth_disabled"
|
||||
}
|
||||
if (primaryDevice) {
|
||||
return BluetoothService.getDeviceIcon(primaryDevice)
|
||||
}
|
||||
return "bluetooth"
|
||||
}
|
||||
|
||||
|
||||
@@ -18,13 +18,17 @@ Row {
|
||||
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
|
||||
color: iconArea.containsMouse
|
||||
? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12)
|
||||
: Theme.withAlpha(Theme.primary, 0)
|
||||
: "transparent"
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: iconArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: DisplayService.devices.length > 1 ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: function(event) {
|
||||
if (DisplayService.devices.length > 1) {
|
||||
@@ -37,22 +41,6 @@ Row {
|
||||
}
|
||||
}
|
||||
|
||||
onEntered: {
|
||||
tooltipLoader.active = true
|
||||
if (tooltipLoader.item) {
|
||||
const tooltipText = DisplayService.currentDevice ? "bl device: " + DisplayService.currentDevice : "Backlight Control"
|
||||
const p = iconArea.mapToItem(null, iconArea.width / 2, 0)
|
||||
tooltipLoader.item.show(tooltipText, p.x, p.y - 40, null)
|
||||
}
|
||||
}
|
||||
|
||||
onExited: {
|
||||
if (tooltipLoader.item) {
|
||||
tooltipLoader.item.hide()
|
||||
}
|
||||
tooltipLoader.active = false
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: {
|
||||
@@ -103,7 +91,7 @@ Row {
|
||||
background: Rectangle {
|
||||
color: Theme.popupBackground()
|
||||
radius: Theme.cornerRadius
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
|
||||
}
|
||||
|
||||
@@ -153,10 +141,4 @@ Row {
|
||||
onObjectRemoved: (index, object) => deviceMenu.removeItem(object)
|
||||
}
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: tooltipLoader
|
||||
active: false
|
||||
sourceComponent: DankTooltip {}
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
import qs.Modules.ControlCenter.Widgets
|
||||
|
||||
CompoundPill {
|
||||
id: root
|
||||
|
||||
property var colorPickerModal: null
|
||||
|
||||
isActive: true
|
||||
iconName: "palette"
|
||||
iconColor: Theme.primary
|
||||
primaryText: "Color Picker"
|
||||
secondaryText: "Choose a color"
|
||||
|
||||
onToggled: {
|
||||
console.log("ColorPickerPill toggled, modal:", colorPickerModal)
|
||||
if (colorPickerModal) {
|
||||
colorPickerModal.show()
|
||||
}
|
||||
}
|
||||
|
||||
onExpandClicked: {
|
||||
console.log("ColorPickerPill expandClicked, modal:", colorPickerModal)
|
||||
if (colorPickerModal) {
|
||||
colorPickerModal.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@ Rectangle {
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHigh
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
opacity: enabled ? 1.0 : 0.6
|
||||
|
||||
Row {
|
||||
|
||||
@@ -29,19 +29,16 @@ Rectangle {
|
||||
|
||||
readonly property color _containerBg: Theme.surfaceContainerHigh
|
||||
|
||||
color: {
|
||||
const baseColor = bodyMouse.containsMouse ? Theme.widgetBaseHoverColor : _containerBg
|
||||
return baseColor
|
||||
}
|
||||
color: _containerBg
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.10)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
antialiasing: true
|
||||
|
||||
readonly property color _labelPrimary: Theme.surfaceText
|
||||
readonly property color _labelSecondary: Theme.surfaceVariantText
|
||||
readonly property color _tileBgActive: Theme.primary
|
||||
readonly property color _tileBgInactive: {
|
||||
const transparency = Theme.popupTransparency
|
||||
const transparency = Theme.popupTransparency || 0.92
|
||||
const surface = Theme.surfaceContainer || Qt.rgba(0.1, 0.1, 0.1, 1)
|
||||
return Qt.rgba(surface.r, surface.g, surface.b, transparency)
|
||||
}
|
||||
|
||||
@@ -20,7 +20,11 @@ Row {
|
||||
height: Theme.iconSize + Theme.spacingS * 2
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
radius: (Theme.iconSize + Theme.spacingS * 2) / 2
|
||||
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Theme.withAlpha(Theme.primary, 0)
|
||||
color: iconArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation { duration: Theme.shortDuration }
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: iconArea
|
||||
@@ -30,9 +34,7 @@ Row {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
if (defaultSource) {
|
||||
AudioService.suppressOSD = true
|
||||
defaultSource.audio.muted = !defaultSource.audio.muted
|
||||
AudioService.suppressOSD = false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -67,9 +69,6 @@ Row {
|
||||
valueOverride: actualVolumePercent
|
||||
thumbOutlineColor: Theme.surfaceContainer
|
||||
trackColor: root.sliderTrackColor.a > 0 ? root.sliderTrackColor : Theme.surfaceContainerHigh
|
||||
onIsDraggingChanged: {
|
||||
AudioService.suppressOSD = isDragging
|
||||
}
|
||||
onSliderValueChanged: function(newValue) {
|
||||
if (defaultSource) {
|
||||
defaultSource.audio.volume = newValue / 100.0
|
||||
|
||||
@@ -31,11 +31,7 @@ Rectangle {
|
||||
readonly property color _tileIconActive: Theme.primaryContainer
|
||||
readonly property color _tileIconInactive: Theme.primary
|
||||
|
||||
color: {
|
||||
if (isActive) return _tileBgActive
|
||||
const baseColor = mouseArea.containsMouse ? Theme.widgetBaseHoverColor : _tileBgInactive
|
||||
return baseColor
|
||||
}
|
||||
color: isActive ? _tileBgActive : _tileBgInactive
|
||||
border.color: isActive ? _tileRingActive : "transparent"
|
||||
border.width: isActive ? 1 : 0
|
||||
antialiasing: true
|
||||
@@ -91,6 +87,13 @@ Rectangle {
|
||||
onClicked: root.clicked()
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on radius {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
|
||||
@@ -12,7 +12,6 @@ Rectangle {
|
||||
property real iconRotation: 0
|
||||
|
||||
signal clicked()
|
||||
signal iconRotationCompleted()
|
||||
|
||||
width: parent ? ((parent.width - parent.spacing * 3) / 4) : 48
|
||||
height: 48
|
||||
@@ -33,11 +32,7 @@ Rectangle {
|
||||
readonly property color _tileIconActive: Theme.primaryContainer
|
||||
readonly property color _tileIconInactive: Theme.primary
|
||||
|
||||
color: {
|
||||
if (isActive) return _tileBgActive
|
||||
const baseColor = mouseArea.containsMouse ? Theme.widgetBaseHoverColor : _tileBgInactive
|
||||
return baseColor
|
||||
}
|
||||
color: isActive ? _tileBgActive : _tileBgInactive
|
||||
border.color: isActive ? _tileRingActive : "transparent"
|
||||
border.width: isActive ? 1 : 0
|
||||
antialiasing: true
|
||||
@@ -59,7 +54,6 @@ Rectangle {
|
||||
size: Theme.iconSize
|
||||
color: isActive ? _tileIconActive : _tileIconInactive
|
||||
rotation: iconRotation
|
||||
onRotationCompleted: root.iconRotationCompleted()
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
@@ -71,6 +65,13 @@ Rectangle {
|
||||
onClicked: root.clicked()
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on radius {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
|
||||
@@ -12,9 +12,8 @@ Rectangle {
|
||||
property bool enabled: true
|
||||
property string secondaryText: ""
|
||||
property real iconRotation: 0
|
||||
|
||||
|
||||
signal clicked()
|
||||
signal iconRotationCompleted()
|
||||
|
||||
width: parent ? parent.width : 200
|
||||
height: 60
|
||||
@@ -28,13 +27,9 @@ Rectangle {
|
||||
readonly property color _tileRingActive:
|
||||
Qt.rgba(Theme.primaryText.r, Theme.primaryText.g, Theme.primaryText.b, 0.22)
|
||||
|
||||
color: {
|
||||
if (isActive) return _tileBgActive
|
||||
const baseColor = mouseArea.containsMouse ? Theme.widgetBaseHoverColor : _tileBgInactive
|
||||
return baseColor
|
||||
}
|
||||
color: isActive ? _tileBgActive : _tileBgInactive
|
||||
border.color: isActive ? _tileRingActive : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 0
|
||||
border.width: isActive ? 1 : 1
|
||||
opacity: enabled ? 1.0 : 0.6
|
||||
|
||||
function hoverTint(base) {
|
||||
@@ -47,7 +42,7 @@ Rectangle {
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
color: mouseArea.containsMouse ? hoverTint(_containerBg) : Theme.withAlpha(_containerBg, 0)
|
||||
color: mouseArea.containsMouse ? hoverTint(_containerBg) : "transparent"
|
||||
opacity: mouseArea.containsMouse ? 0.08 : 0.0
|
||||
|
||||
Behavior on opacity {
|
||||
@@ -67,7 +62,6 @@ Rectangle {
|
||||
color: isActive ? Theme.primaryContainer : Theme.primary
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
rotation: root.iconRotation
|
||||
onRotationCompleted: root.iconRotationCompleted()
|
||||
}
|
||||
|
||||
Item {
|
||||
@@ -112,6 +106,13 @@ Rectangle {
|
||||
onClicked: root.clicked()
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on radius {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
|
||||
@@ -1,179 +0,0 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property var barWindow
|
||||
required property var axis
|
||||
required property var appDrawerLoader
|
||||
required property var dankDashPopoutLoader
|
||||
required property var processListPopoutLoader
|
||||
required property var notificationCenterLoader
|
||||
required property var batteryPopoutLoader
|
||||
required property var vpnPopoutLoader
|
||||
required property var controlCenterLoader
|
||||
required property var clipboardHistoryModalPopup
|
||||
required property var systemUpdateLoader
|
||||
required property var notepadInstance
|
||||
|
||||
property alias reveal: core.reveal
|
||||
property alias autoHide: core.autoHide
|
||||
property alias backgroundTransparency: core.backgroundTransparency
|
||||
property alias hasActivePopout: core.hasActivePopout
|
||||
property alias mouseArea: topBarMouseArea
|
||||
|
||||
Item {
|
||||
id: inputMask
|
||||
|
||||
readonly property int barThickness: barWindow.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing)
|
||||
|
||||
readonly property bool showing: SettingsData.dankBarVisible && (core.reveal
|
||||
|| (CompositorService.isNiri && NiriService.inOverview && SettingsData.dankBarOpenOnOverview)
|
||||
|| !core.autoHide)
|
||||
|
||||
readonly property int maskThickness: showing ? barThickness : 1
|
||||
|
||||
x: {
|
||||
if (!axis.isVertical) {
|
||||
return 0
|
||||
} else {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Left: return 0
|
||||
case SettingsData.Position.Right: return parent.width - maskThickness
|
||||
default: return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
y: {
|
||||
if (axis.isVertical) {
|
||||
return 0
|
||||
} else {
|
||||
switch (SettingsData.dankBarPosition) {
|
||||
case SettingsData.Position.Top: return 0
|
||||
case SettingsData.Position.Bottom: return parent.height - maskThickness
|
||||
default: return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
width: axis.isVertical ? maskThickness : parent.width
|
||||
height: axis.isVertical ? parent.height : maskThickness
|
||||
}
|
||||
|
||||
Region {
|
||||
id: mask
|
||||
item: inputMask
|
||||
}
|
||||
|
||||
property alias maskRegion: mask
|
||||
|
||||
QtObject {
|
||||
id: core
|
||||
|
||||
property real backgroundTransparency: SettingsData.dankBarTransparency
|
||||
property bool autoHide: SettingsData.dankBarAutoHide
|
||||
property bool revealSticky: false
|
||||
|
||||
property bool notepadInstanceVisible: notepadInstance?.isVisible ?? false
|
||||
|
||||
readonly property bool hasActivePopout: {
|
||||
const loaders = [{
|
||||
"loader": appDrawerLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": dankDashPopoutLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": processListPopoutLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": notificationCenterLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": batteryPopoutLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": vpnPopoutLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": controlCenterLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}, {
|
||||
"loader": clipboardHistoryModalPopup,
|
||||
"prop": "visible"
|
||||
}, {
|
||||
"loader": systemUpdateLoader,
|
||||
"prop": "shouldBeVisible"
|
||||
}]
|
||||
return notepadInstanceVisible || loaders.some(item => {
|
||||
if (item.loader) {
|
||||
return item.loader?.item?.[item.prop]
|
||||
}
|
||||
return false
|
||||
})
|
||||
}
|
||||
|
||||
property bool reveal: {
|
||||
if (CompositorService.isNiri && NiriService.inOverview) {
|
||||
return SettingsData.dankBarOpenOnOverview
|
||||
}
|
||||
return SettingsData.dankBarVisible && (!autoHide || topBarMouseArea.containsMouse || hasActivePopout || revealSticky)
|
||||
}
|
||||
|
||||
onHasActivePopoutChanged: {
|
||||
if (!hasActivePopout && autoHide && !topBarMouseArea.containsMouse) {
|
||||
revealSticky = true
|
||||
revealHold.restart()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: revealHold
|
||||
interval: 250
|
||||
repeat: false
|
||||
onTriggered: core.revealSticky = false
|
||||
}
|
||||
|
||||
Connections {
|
||||
function onDankBarTransparencyChanged() {
|
||||
core.backgroundTransparency = SettingsData.dankBarTransparency
|
||||
}
|
||||
|
||||
target: SettingsData
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: topBarMouseArea
|
||||
function onContainsMouseChanged() {
|
||||
if (topBarMouseArea.containsMouse) {
|
||||
core.revealSticky = true
|
||||
revealHold.stop()
|
||||
} else {
|
||||
if (core.autoHide && !core.hasActivePopout) {
|
||||
revealHold.restart()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: topBarMouseArea
|
||||
y: !barWindow.isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Bottom ? parent.height - height : 0) : 0
|
||||
x: barWindow.isVertical ? (SettingsData.dankBarPosition === SettingsData.Position.Right ? parent.width - width : 0) : 0
|
||||
height: !barWindow.isVertical ? barWindow.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing) : undefined
|
||||
width: barWindow.isVertical ? barWindow.px(barWindow.effectiveBarThickness + SettingsData.dankBarSpacing) : undefined
|
||||
anchors {
|
||||
left: !barWindow.isVertical ? parent.left : (SettingsData.dankBarPosition === SettingsData.Position.Left ? parent.left : undefined)
|
||||
right: !barWindow.isVertical ? parent.right : (SettingsData.dankBarPosition === SettingsData.Position.Right ? parent.right : undefined)
|
||||
top: barWindow.isVertical ? parent.top : undefined
|
||||
bottom: barWindow.isVertical ? parent.bottom : undefined
|
||||
}
|
||||
hoverEnabled: SettingsData.dankBarAutoHide && !core.reveal
|
||||
acceptedButtons: Qt.NoButton
|
||||
enabled: SettingsData.dankBarAutoHide && !core.reveal
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import QtQuick
|
||||
|
||||
QtObject {
|
||||
id: root
|
||||
|
||||
property string edge: "top"
|
||||
|
||||
readonly property string orientation: isVertical ? "vertical" : "horizontal"
|
||||
readonly property bool isVertical: edge === "left" || edge === "right"
|
||||
readonly property bool isHorizontal: !isVertical
|
||||
|
||||
function primarySize(item) {
|
||||
return isVertical ? item.height : item.width
|
||||
}
|
||||
|
||||
function crossSize(item) {
|
||||
return isVertical ? item.width : item.height
|
||||
}
|
||||
|
||||
function setPrimaryPos(item, value) {
|
||||
if (isVertical) {
|
||||
item.y = value
|
||||
} else {
|
||||
item.x = value
|
||||
}
|
||||
}
|
||||
|
||||
function getPrimaryPos(item) {
|
||||
return isVertical ? item.y : item.x
|
||||
}
|
||||
|
||||
function primaryAnchor(anchors) {
|
||||
return isVertical ? anchors.verticalCenter : anchors.horizontalCenter
|
||||
}
|
||||
|
||||
function crossAnchor(anchors) {
|
||||
return isVertical ? anchors.horizontalCenter : anchors.verticalCenter
|
||||
}
|
||||
|
||||
function outerVisualEdge() {
|
||||
if (edge === "bottom") return "bottom"
|
||||
if (edge === "left") return "right"
|
||||
if (edge === "right") return "left"
|
||||
if (edge === "top") return "top"
|
||||
return "bottom"
|
||||
}
|
||||
|
||||
signal axisEdgeChanged()
|
||||
signal axisOrientationChanged()
|
||||
signal changed() // Single coalesced signal
|
||||
|
||||
onEdgeChanged: {
|
||||
axisEdgeChanged()
|
||||
axisOrientationChanged()
|
||||
changed()
|
||||
}
|
||||
}
|
||||
@@ -1,210 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
required property var barWindow
|
||||
required property var axis
|
||||
|
||||
anchors.fill: parent
|
||||
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.leftMargin: -(SettingsData.dankBarGothCornersEnabled && axis.isVertical && axis.edge === "right" ? barWindow._wingR : 0)
|
||||
anchors.rightMargin: -(SettingsData.dankBarGothCornersEnabled && axis.isVertical && axis.edge === "left" ? barWindow._wingR : 0)
|
||||
anchors.topMargin: -(SettingsData.dankBarGothCornersEnabled && !axis.isVertical && axis.edge === "bottom" ? barWindow._wingR : 0)
|
||||
anchors.bottomMargin: -(SettingsData.dankBarGothCornersEnabled && !axis.isVertical && axis.edge === "top" ? barWindow._wingR : 0)
|
||||
|
||||
Canvas {
|
||||
id: barShape
|
||||
anchors.fill: parent
|
||||
antialiasing: true
|
||||
renderTarget: Canvas.FramebufferObject
|
||||
renderStrategy: Canvas.Cooperative
|
||||
|
||||
readonly property real correctWidth: root.width
|
||||
readonly property real correctHeight: root.height
|
||||
canvasSize: Qt.size(barWindow.px(correctWidth), barWindow.px(correctHeight))
|
||||
|
||||
property real wing: SettingsData.dankBarGothCornersEnabled ? barWindow._wingR : 0
|
||||
property real rt: SettingsData.dankBarSquareCorners ? 0 : Theme.cornerRadius
|
||||
|
||||
onWingChanged: requestPaint()
|
||||
onRtChanged: requestPaint()
|
||||
onCorrectWidthChanged: requestPaint()
|
||||
onCorrectHeightChanged: requestPaint()
|
||||
onVisibleChanged: if (visible) requestPaint()
|
||||
Component.onCompleted: requestPaint()
|
||||
|
||||
Connections {
|
||||
target: barWindow
|
||||
function on_BgColorChanged() { barShape.requestPaint() }
|
||||
function on_DprChanged() { barShape.requestPaint() }
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Theme
|
||||
function onIsLightModeChanged() { barShape.requestPaint() }
|
||||
}
|
||||
|
||||
onPaint: {
|
||||
const ctx = getContext("2d")
|
||||
const scale = barWindow._dpr
|
||||
const W = barWindow.px(barWindow.isVertical ? correctHeight : correctWidth)
|
||||
const H_raw = barWindow.px(barWindow.isVertical ? correctWidth : correctHeight)
|
||||
const R = barWindow.px(wing)
|
||||
const RT = barWindow.px(rt)
|
||||
const H = H_raw - (R > 0 ? R : 0)
|
||||
const isTop = SettingsData.dankBarPosition === SettingsData.Position.Top
|
||||
const isBottom = SettingsData.dankBarPosition === SettingsData.Position.Bottom
|
||||
const isLeft = SettingsData.dankBarPosition === SettingsData.Position.Left
|
||||
const isRight = SettingsData.dankBarPosition === SettingsData.Position.Right
|
||||
|
||||
ctx.scale(scale, scale)
|
||||
|
||||
function drawTopPath() {
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(RT, 0)
|
||||
ctx.lineTo(W - RT, 0)
|
||||
ctx.arcTo(W, 0, W, RT, RT)
|
||||
ctx.lineTo(W, H)
|
||||
|
||||
if (R > 0) {
|
||||
ctx.lineTo(W, H + R)
|
||||
ctx.arc(W - R, H + R, R, 0, -Math.PI / 2, true)
|
||||
ctx.lineTo(R, H)
|
||||
ctx.arc(R, H + R, R, -Math.PI / 2, -Math.PI, true)
|
||||
ctx.lineTo(0, H + R)
|
||||
} else {
|
||||
ctx.lineTo(W, H - RT)
|
||||
ctx.arcTo(W, H, W - RT, H, RT)
|
||||
ctx.lineTo(RT, H)
|
||||
ctx.arcTo(0, H, 0, H - RT, RT)
|
||||
}
|
||||
|
||||
ctx.lineTo(0, RT)
|
||||
ctx.arcTo(0, 0, RT, 0, RT)
|
||||
ctx.closePath()
|
||||
}
|
||||
|
||||
ctx.reset()
|
||||
ctx.clearRect(0, 0, W, H_raw)
|
||||
|
||||
ctx.save()
|
||||
if (isBottom) {
|
||||
ctx.translate(W, H_raw)
|
||||
ctx.rotate(Math.PI)
|
||||
} else if (isLeft) {
|
||||
ctx.translate(0, W)
|
||||
ctx.rotate(-Math.PI / 2)
|
||||
} else if (isRight) {
|
||||
ctx.translate(H_raw, 0)
|
||||
ctx.rotate(Math.PI / 2)
|
||||
}
|
||||
|
||||
drawTopPath()
|
||||
ctx.restore()
|
||||
|
||||
ctx.fillStyle = barWindow._bgColor
|
||||
ctx.fill()
|
||||
}
|
||||
}
|
||||
|
||||
Canvas {
|
||||
id: barTint
|
||||
anchors.fill: parent
|
||||
antialiasing: true
|
||||
renderTarget: Canvas.FramebufferObject
|
||||
renderStrategy: Canvas.Cooperative
|
||||
|
||||
readonly property real correctWidth: root.width
|
||||
readonly property real correctHeight: root.height
|
||||
canvasSize: Qt.size(barWindow.px(correctWidth), barWindow.px(correctHeight))
|
||||
|
||||
property real wing: SettingsData.dankBarGothCornersEnabled ? barWindow._wingR : 0
|
||||
property real rt: SettingsData.dankBarSquareCorners ? 0 : Theme.cornerRadius
|
||||
property real alphaTint: (barWindow._bgColor?.a ?? 1) < 0.99 ? (Theme.stateLayerOpacity ?? 0) : 0
|
||||
|
||||
onWingChanged: requestPaint()
|
||||
onRtChanged: requestPaint()
|
||||
onAlphaTintChanged: requestPaint()
|
||||
onCorrectWidthChanged: requestPaint()
|
||||
onCorrectHeightChanged: requestPaint()
|
||||
onVisibleChanged: if (visible) requestPaint()
|
||||
Component.onCompleted: requestPaint()
|
||||
|
||||
Connections {
|
||||
target: barWindow
|
||||
function on_BgColorChanged() { barTint.requestPaint() }
|
||||
function on_DprChanged() { barTint.requestPaint() }
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: Theme
|
||||
function onIsLightModeChanged() { barTint.requestPaint() }
|
||||
}
|
||||
|
||||
onPaint: {
|
||||
const ctx = getContext("2d")
|
||||
const scale = barWindow._dpr
|
||||
const W = barWindow.px(barWindow.isVertical ? correctHeight : correctWidth)
|
||||
const H_raw = barWindow.px(barWindow.isVertical ? correctWidth : correctHeight)
|
||||
const R = barWindow.px(wing)
|
||||
const RT = barWindow.px(rt)
|
||||
const H = H_raw - (R > 0 ? R : 0)
|
||||
const isTop = SettingsData.dankBarPosition === SettingsData.Position.Top
|
||||
const isBottom = SettingsData.dankBarPosition === SettingsData.Position.Bottom
|
||||
const isLeft = SettingsData.dankBarPosition === SettingsData.Position.Left
|
||||
const isRight = SettingsData.dankBarPosition === SettingsData.Position.Right
|
||||
|
||||
ctx.scale(scale, scale)
|
||||
|
||||
function drawTopPath() {
|
||||
ctx.beginPath()
|
||||
ctx.moveTo(RT, 0)
|
||||
ctx.lineTo(W - RT, 0)
|
||||
ctx.arcTo(W, 0, W, RT, RT)
|
||||
ctx.lineTo(W, H)
|
||||
|
||||
if (R > 0) {
|
||||
ctx.lineTo(W, H + R)
|
||||
ctx.arc(W - R, H + R, R, 0, -Math.PI / 2, true)
|
||||
ctx.lineTo(R, H)
|
||||
ctx.arc(R, H + R, R, -Math.PI / 2, -Math.PI, true)
|
||||
ctx.lineTo(0, H + R)
|
||||
} else {
|
||||
ctx.lineTo(W, H - RT)
|
||||
ctx.arcTo(W, H, W - RT, H, RT)
|
||||
ctx.lineTo(RT, H)
|
||||
ctx.arcTo(0, H, 0, H - RT, RT)
|
||||
}
|
||||
|
||||
ctx.lineTo(0, RT)
|
||||
ctx.arcTo(0, 0, RT, 0, RT)
|
||||
ctx.closePath()
|
||||
}
|
||||
|
||||
ctx.reset()
|
||||
ctx.clearRect(0, 0, W, H_raw)
|
||||
|
||||
ctx.save()
|
||||
if (isBottom) {
|
||||
ctx.translate(W, H_raw)
|
||||
ctx.rotate(Math.PI)
|
||||
} else if (isLeft) {
|
||||
ctx.translate(0, W)
|
||||
ctx.rotate(-Math.PI / 2)
|
||||
} else if (isRight) {
|
||||
ctx.translate(H_raw, 0)
|
||||
ctx.rotate(Math.PI / 2)
|
||||
}
|
||||
|
||||
drawTopPath()
|
||||
ctx.restore()
|
||||
|
||||
ctx.fillStyle = Qt.rgba(Theme.surface.r, Theme.surface.g, Theme.surface.b, alphaTint)
|
||||
ctx.fill()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,444 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var widgetsModel: null
|
||||
property var components: null
|
||||
property bool noBackground: false
|
||||
required property var axis
|
||||
property string section: "center"
|
||||
property var parentScreen: null
|
||||
property real widgetThickness: 30
|
||||
property real barThickness: 48
|
||||
|
||||
readonly property bool isVertical: axis?.isVertical ?? false
|
||||
readonly property real spacing: noBackground ? 2 : Theme.spacingXS
|
||||
|
||||
property var centerWidgets: []
|
||||
property int totalWidgets: 0
|
||||
property real totalSize: 0
|
||||
|
||||
function updateLayout() {
|
||||
const containerSize = isVertical ? height : width
|
||||
if (containerSize <= 0 || !visible) {
|
||||
return
|
||||
}
|
||||
|
||||
centerWidgets = []
|
||||
totalWidgets = 0
|
||||
totalSize = 0
|
||||
|
||||
let configuredWidgets = 0
|
||||
for (var i = 0; i < centerRepeater.count; i++) {
|
||||
const item = centerRepeater.itemAt(i)
|
||||
if (item && getWidgetVisible(item.widgetId)) {
|
||||
configuredWidgets++
|
||||
if (item.active && item.item) {
|
||||
centerWidgets.push(item.item)
|
||||
totalWidgets++
|
||||
totalSize += isVertical ? item.item.height : item.item.width
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (totalWidgets > 1) {
|
||||
totalSize += spacing * (totalWidgets - 1)
|
||||
}
|
||||
|
||||
positionWidgets(configuredWidgets)
|
||||
}
|
||||
|
||||
function positionWidgets(configuredWidgets) {
|
||||
if (totalWidgets === 0 || (isVertical ? height : width) <= 0) {
|
||||
return
|
||||
}
|
||||
|
||||
const parentCenter = (isVertical ? height : width) / 2
|
||||
const isOdd = configuredWidgets % 2 === 1
|
||||
|
||||
centerWidgets.forEach(widget => {
|
||||
if (isVertical) {
|
||||
widget.anchors.verticalCenter = undefined
|
||||
} else {
|
||||
widget.anchors.horizontalCenter = undefined
|
||||
}
|
||||
})
|
||||
|
||||
if (isOdd) {
|
||||
const middleIndex = Math.floor(configuredWidgets / 2)
|
||||
let currentActiveIndex = 0
|
||||
let middleWidget = null
|
||||
|
||||
for (var i = 0; i < centerRepeater.count; i++) {
|
||||
const item = centerRepeater.itemAt(i)
|
||||
if (item && getWidgetVisible(item.widgetId)) {
|
||||
if (currentActiveIndex === middleIndex && item.active && item.item) {
|
||||
middleWidget = item.item
|
||||
break
|
||||
}
|
||||
currentActiveIndex++
|
||||
}
|
||||
}
|
||||
|
||||
if (middleWidget) {
|
||||
const middleSize = isVertical ? middleWidget.height : middleWidget.width
|
||||
if (isVertical) {
|
||||
middleWidget.y = parentCenter - (middleSize / 2)
|
||||
} else {
|
||||
middleWidget.x = parentCenter - (middleSize / 2)
|
||||
}
|
||||
|
||||
let leftWidgets = []
|
||||
let rightWidgets = []
|
||||
let foundMiddle = false
|
||||
|
||||
for (var i = 0; i < centerWidgets.length; i++) {
|
||||
if (centerWidgets[i] === middleWidget) {
|
||||
foundMiddle = true
|
||||
continue
|
||||
}
|
||||
if (!foundMiddle) {
|
||||
leftWidgets.push(centerWidgets[i])
|
||||
} else {
|
||||
rightWidgets.push(centerWidgets[i])
|
||||
}
|
||||
}
|
||||
|
||||
let currentPos = isVertical ? middleWidget.y : middleWidget.x
|
||||
for (var i = leftWidgets.length - 1; i >= 0; i--) {
|
||||
const size = isVertical ? leftWidgets[i].height : leftWidgets[i].width
|
||||
currentPos -= (spacing + size)
|
||||
if (isVertical) {
|
||||
leftWidgets[i].y = currentPos
|
||||
} else {
|
||||
leftWidgets[i].x = currentPos
|
||||
}
|
||||
}
|
||||
|
||||
currentPos = (isVertical ? middleWidget.y : middleWidget.x) + middleSize
|
||||
for (var i = 0; i < rightWidgets.length; i++) {
|
||||
currentPos += spacing
|
||||
if (isVertical) {
|
||||
rightWidgets[i].y = currentPos
|
||||
} else {
|
||||
rightWidgets[i].x = currentPos
|
||||
}
|
||||
currentPos += isVertical ? rightWidgets[i].height : rightWidgets[i].width
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let configuredLeftIndex = (configuredWidgets / 2) - 1
|
||||
let configuredRightIndex = configuredWidgets / 2
|
||||
const halfSpacing = spacing / 2
|
||||
|
||||
let leftWidget = null
|
||||
let rightWidget = null
|
||||
let leftWidgets = []
|
||||
let rightWidgets = []
|
||||
|
||||
let currentConfigIndex = 0
|
||||
for (var i = 0; i < centerRepeater.count; i++) {
|
||||
const item = centerRepeater.itemAt(i)
|
||||
if (item && getWidgetVisible(item.widgetId)) {
|
||||
if (item.active && item.item) {
|
||||
if (currentConfigIndex < configuredLeftIndex) {
|
||||
leftWidgets.push(item.item)
|
||||
} else if (currentConfigIndex === configuredLeftIndex) {
|
||||
leftWidget = item.item
|
||||
} else if (currentConfigIndex === configuredRightIndex) {
|
||||
rightWidget = item.item
|
||||
} else {
|
||||
rightWidgets.push(item.item)
|
||||
}
|
||||
}
|
||||
currentConfigIndex++
|
||||
}
|
||||
}
|
||||
|
||||
if (leftWidget && rightWidget) {
|
||||
const leftSize = isVertical ? leftWidget.height : leftWidget.width
|
||||
if (isVertical) {
|
||||
leftWidget.y = parentCenter - halfSpacing - leftSize
|
||||
rightWidget.y = parentCenter + halfSpacing
|
||||
} else {
|
||||
leftWidget.x = parentCenter - halfSpacing - leftSize
|
||||
rightWidget.x = parentCenter + halfSpacing
|
||||
}
|
||||
|
||||
let currentPos = isVertical ? leftWidget.y : leftWidget.x
|
||||
for (var i = leftWidgets.length - 1; i >= 0; i--) {
|
||||
const size = isVertical ? leftWidgets[i].height : leftWidgets[i].width
|
||||
currentPos -= (spacing + size)
|
||||
if (isVertical) {
|
||||
leftWidgets[i].y = currentPos
|
||||
} else {
|
||||
leftWidgets[i].x = currentPos
|
||||
}
|
||||
}
|
||||
|
||||
currentPos = (isVertical ? rightWidget.y + rightWidget.height : rightWidget.x + rightWidget.width)
|
||||
for (var i = 0; i < rightWidgets.length; i++) {
|
||||
currentPos += spacing
|
||||
if (isVertical) {
|
||||
rightWidgets[i].y = currentPos
|
||||
} else {
|
||||
rightWidgets[i].x = currentPos
|
||||
}
|
||||
currentPos += isVertical ? rightWidgets[i].height : rightWidgets[i].width
|
||||
}
|
||||
} else if (leftWidget && !rightWidget) {
|
||||
const leftSize = isVertical ? leftWidget.height : leftWidget.width
|
||||
if (isVertical) {
|
||||
leftWidget.y = parentCenter - halfSpacing - leftSize
|
||||
} else {
|
||||
leftWidget.x = parentCenter - halfSpacing - leftSize
|
||||
}
|
||||
|
||||
let currentPos = isVertical ? leftWidget.y : leftWidget.x
|
||||
for (var i = leftWidgets.length - 1; i >= 0; i--) {
|
||||
const size = isVertical ? leftWidgets[i].height : leftWidgets[i].width
|
||||
currentPos -= (spacing + size)
|
||||
if (isVertical) {
|
||||
leftWidgets[i].y = currentPos
|
||||
} else {
|
||||
leftWidgets[i].x = currentPos
|
||||
}
|
||||
}
|
||||
|
||||
currentPos = (isVertical ? leftWidget.y + leftWidget.height : leftWidget.x + leftWidget.width) + spacing
|
||||
for (var i = 0; i < rightWidgets.length; i++) {
|
||||
currentPos += spacing
|
||||
if (isVertical) {
|
||||
rightWidgets[i].y = currentPos
|
||||
} else {
|
||||
rightWidgets[i].x = currentPos
|
||||
}
|
||||
currentPos += isVertical ? rightWidgets[i].height : rightWidgets[i].width
|
||||
}
|
||||
} else if (!leftWidget && rightWidget) {
|
||||
if (isVertical) {
|
||||
rightWidget.y = parentCenter + halfSpacing
|
||||
} else {
|
||||
rightWidget.x = parentCenter + halfSpacing
|
||||
}
|
||||
|
||||
let currentPos = (isVertical ? rightWidget.y : rightWidget.x) - spacing
|
||||
for (var i = leftWidgets.length - 1; i >= 0; i--) {
|
||||
const size = isVertical ? leftWidgets[i].height : leftWidgets[i].width
|
||||
currentPos -= size
|
||||
if (isVertical) {
|
||||
leftWidgets[i].y = currentPos
|
||||
} else {
|
||||
leftWidgets[i].x = currentPos
|
||||
}
|
||||
currentPos -= spacing
|
||||
}
|
||||
|
||||
currentPos = (isVertical ? rightWidget.y + rightWidget.height : rightWidget.x + rightWidget.width)
|
||||
for (var i = 0; i < rightWidgets.length; i++) {
|
||||
currentPos += spacing
|
||||
if (isVertical) {
|
||||
rightWidgets[i].y = currentPos
|
||||
} else {
|
||||
rightWidgets[i].x = currentPos
|
||||
}
|
||||
currentPos += isVertical ? rightWidgets[i].height : rightWidgets[i].width
|
||||
}
|
||||
} else if (totalWidgets === 1 && centerWidgets[0]) {
|
||||
const size = isVertical ? centerWidgets[0].height : centerWidgets[0].width
|
||||
if (isVertical) {
|
||||
centerWidgets[0].y = parentCenter - (size / 2)
|
||||
} else {
|
||||
centerWidgets[0].x = parentCenter - (size / 2)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getWidgetVisible(widgetId) {
|
||||
const widgetVisibility = {
|
||||
"cpuUsage": DgopService.dgopAvailable,
|
||||
"memUsage": DgopService.dgopAvailable,
|
||||
"cpuTemp": DgopService.dgopAvailable,
|
||||
"gpuTemp": DgopService.dgopAvailable,
|
||||
"network_speed_monitor": DgopService.dgopAvailable
|
||||
}
|
||||
return widgetVisibility[widgetId] ?? true
|
||||
}
|
||||
|
||||
function getWidgetComponent(widgetId) {
|
||||
// Build dynamic component map including plugins
|
||||
let baseMap = {
|
||||
"launcherButton": "launcherButtonComponent",
|
||||
"workspaceSwitcher": "workspaceSwitcherComponent",
|
||||
"focusedWindow": "focusedWindowComponent",
|
||||
"runningApps": "runningAppsComponent",
|
||||
"clock": "clockComponent",
|
||||
"music": "mediaComponent",
|
||||
"weather": "weatherComponent",
|
||||
"systemTray": "systemTrayComponent",
|
||||
"privacyIndicator": "privacyIndicatorComponent",
|
||||
"clipboard": "clipboardComponent",
|
||||
"cpuUsage": "cpuUsageComponent",
|
||||
"memUsage": "memUsageComponent",
|
||||
"diskUsage": "diskUsageComponent",
|
||||
"cpuTemp": "cpuTempComponent",
|
||||
"gpuTemp": "gpuTempComponent",
|
||||
"notificationButton": "notificationButtonComponent",
|
||||
"battery": "batteryComponent",
|
||||
"controlCenterButton": "controlCenterButtonComponent",
|
||||
"idleInhibitor": "idleInhibitorComponent",
|
||||
"spacer": "spacerComponent",
|
||||
"separator": "separatorComponent",
|
||||
"network_speed_monitor": "networkComponent",
|
||||
"keyboard_layout_name": "keyboardLayoutNameComponent",
|
||||
"vpn": "vpnComponent",
|
||||
"notepadButton": "notepadButtonComponent",
|
||||
"colorPicker": "colorPickerComponent",
|
||||
"systemUpdate": "systemUpdateComponent"
|
||||
}
|
||||
|
||||
// For built-in components, get from components property
|
||||
const componentKey = baseMap[widgetId]
|
||||
if (componentKey && root.components[componentKey]) {
|
||||
return root.components[componentKey]
|
||||
}
|
||||
|
||||
// For plugin components, get from PluginService
|
||||
let pluginMap = PluginService.getWidgetComponents()
|
||||
return pluginMap[widgetId] || null
|
||||
}
|
||||
|
||||
height: parent.height
|
||||
width: parent.width
|
||||
anchors.centerIn: parent
|
||||
|
||||
Timer {
|
||||
id: layoutTimer
|
||||
interval: 0
|
||||
repeat: false
|
||||
onTriggered: root.updateLayout()
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
layoutTimer.restart()
|
||||
}
|
||||
|
||||
onWidthChanged: {
|
||||
if (width > 0) {
|
||||
layoutTimer.restart()
|
||||
}
|
||||
}
|
||||
|
||||
onHeightChanged: {
|
||||
if (height > 0) {
|
||||
layoutTimer.restart()
|
||||
}
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible && (isVertical ? height : width) > 0) {
|
||||
layoutTimer.restart()
|
||||
}
|
||||
}
|
||||
|
||||
Repeater {
|
||||
id: centerRepeater
|
||||
model: root.widgetsModel
|
||||
|
||||
|
||||
Loader {
|
||||
property string widgetId: model.widgetId
|
||||
property var widgetData: model
|
||||
property int spacerSize: model.size || 20
|
||||
|
||||
anchors.verticalCenter: !root.isVertical ? parent.verticalCenter : undefined
|
||||
anchors.horizontalCenter: root.isVertical ? parent.horizontalCenter : undefined
|
||||
active: root.getWidgetVisible(model.widgetId) && (model.widgetId !== "music" || MprisController.activePlayer !== null)
|
||||
sourceComponent: root.getWidgetComponent(model.widgetId)
|
||||
opacity: (model.enabled !== false) ? 1 : 0
|
||||
asynchronous: false
|
||||
|
||||
onLoaded: {
|
||||
if (!item) {
|
||||
return
|
||||
}
|
||||
item.widthChanged.connect(() => layoutTimer.restart())
|
||||
item.heightChanged.connect(() => layoutTimer.restart())
|
||||
if (model.widgetId === "spacer") {
|
||||
item.spacerSize = Qt.binding(() => model.size || 20)
|
||||
}
|
||||
if (root.axis && "axis" in item) {
|
||||
item.axis = root.axis
|
||||
}
|
||||
if (root.axis && "isVertical" in item) {
|
||||
try {
|
||||
item.isVertical = root.axis.isVertical
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
// Inject properties for plugin widgets
|
||||
if ("section" in item) {
|
||||
item.section = root.section
|
||||
}
|
||||
if ("parentScreen" in item) {
|
||||
item.parentScreen = root.parentScreen
|
||||
}
|
||||
if ("widgetThickness" in item) {
|
||||
item.widgetThickness = root.widgetThickness
|
||||
}
|
||||
if ("barThickness" in item) {
|
||||
item.barThickness = root.barThickness
|
||||
}
|
||||
|
||||
// Inject PluginService for plugin widgets
|
||||
if (item.pluginService !== undefined) {
|
||||
if (item.pluginId !== undefined) {
|
||||
item.pluginId = model.widgetId
|
||||
}
|
||||
item.pluginService = PluginService
|
||||
}
|
||||
|
||||
layoutTimer.restart()
|
||||
}
|
||||
|
||||
onActiveChanged: {
|
||||
layoutTimer.restart()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: widgetsModel
|
||||
function onCountChanged() {
|
||||
layoutTimer.restart()
|
||||
}
|
||||
}
|
||||
|
||||
// Listen for plugin changes and refresh components
|
||||
Connections {
|
||||
target: PluginService
|
||||
function onPluginLoaded(pluginId) {
|
||||
// Force refresh of component lookups
|
||||
for (var i = 0; i < centerRepeater.count; i++) {
|
||||
var item = centerRepeater.itemAt(i)
|
||||
if (item && item.widgetId === pluginId) {
|
||||
item.sourceComponent = root.getWidgetComponent(pluginId)
|
||||
}
|
||||
}
|
||||
}
|
||||
function onPluginUnloaded(pluginId) {
|
||||
// Force refresh of component lookups
|
||||
for (var i = 0; i < centerRepeater.count; i++) {
|
||||
var item = centerRepeater.itemAt(i)
|
||||
if (item && item.widgetId === pluginId) {
|
||||
item.sourceComponent = root.getWidgetComponent(pluginId)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,82 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var widgetsModel: null
|
||||
property var components: null
|
||||
property bool noBackground: false
|
||||
required property var axis
|
||||
property var parentScreen: null
|
||||
property real widgetThickness: 30
|
||||
property real barThickness: 48
|
||||
|
||||
readonly property bool isVertical: axis?.isVertical ?? false
|
||||
|
||||
implicitHeight: layoutLoader.item ? (layoutLoader.item.implicitHeight || layoutLoader.item.height) : 0
|
||||
implicitWidth: layoutLoader.item ? (layoutLoader.item.implicitWidth || layoutLoader.item.width) : 0
|
||||
|
||||
Loader {
|
||||
id: layoutLoader
|
||||
anchors.fill: parent
|
||||
sourceComponent: root.isVertical ? columnComp : rowComp
|
||||
}
|
||||
|
||||
Component {
|
||||
id: rowComp
|
||||
Row {
|
||||
spacing: noBackground ? 2 : Theme.spacingXS
|
||||
Repeater {
|
||||
model: root.widgetsModel
|
||||
Item {
|
||||
width: widgetLoader.item ? widgetLoader.item.width : 0
|
||||
height: widgetLoader.item ? widgetLoader.item.height : 0
|
||||
WidgetHost {
|
||||
id: widgetLoader
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
widgetId: model.widgetId
|
||||
widgetData: model
|
||||
spacerSize: model.size || 20
|
||||
components: root.components
|
||||
isInColumn: false
|
||||
axis: root.axis
|
||||
section: "left"
|
||||
parentScreen: root.parentScreen
|
||||
widgetThickness: root.widgetThickness
|
||||
barThickness: root.barThickness
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: columnComp
|
||||
Column {
|
||||
width: Math.max(parent.width, 200)
|
||||
spacing: noBackground ? 2 : Theme.spacingXS
|
||||
Repeater {
|
||||
model: root.widgetsModel
|
||||
Item {
|
||||
width: parent.width
|
||||
height: widgetLoader.item ? widgetLoader.item.height : 0
|
||||
WidgetHost {
|
||||
id: widgetLoader
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
widgetId: model.widgetId
|
||||
widgetData: model
|
||||
spacerSize: model.size || 20
|
||||
components: root.components
|
||||
isInColumn: true
|
||||
axis: root.axis
|
||||
section: "left"
|
||||
parentScreen: root.parentScreen
|
||||
widgetThickness: root.widgetThickness
|
||||
barThickness: root.barThickness
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property var widgetsModel: null
|
||||
property var components: null
|
||||
property bool noBackground: false
|
||||
required property var axis
|
||||
property var parentScreen: null
|
||||
property real widgetThickness: 30
|
||||
property real barThickness: 48
|
||||
|
||||
readonly property bool isVertical: axis?.isVertical ?? false
|
||||
|
||||
implicitHeight: layoutLoader.item ? layoutLoader.item.implicitHeight : 0
|
||||
implicitWidth: layoutLoader.item ? layoutLoader.item.implicitWidth : 0
|
||||
|
||||
Loader {
|
||||
id: layoutLoader
|
||||
width: parent.width
|
||||
height: parent.height
|
||||
sourceComponent: root.isVertical ? columnComp : rowComp
|
||||
}
|
||||
|
||||
Component {
|
||||
id: rowComp
|
||||
Row {
|
||||
spacing: noBackground ? 2 : Theme.spacingXS
|
||||
anchors.right: parent ? parent.right : undefined
|
||||
Repeater {
|
||||
model: root.widgetsModel
|
||||
Item {
|
||||
width: widgetLoader.item ? widgetLoader.item.width : 0
|
||||
height: widgetLoader.item ? widgetLoader.item.height : 0
|
||||
WidgetHost {
|
||||
id: widgetLoader
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
widgetId: model.widgetId
|
||||
widgetData: model
|
||||
spacerSize: model.size || 20
|
||||
components: root.components
|
||||
isInColumn: false
|
||||
axis: root.axis
|
||||
section: "right"
|
||||
parentScreen: root.parentScreen
|
||||
widgetThickness: root.widgetThickness
|
||||
barThickness: root.barThickness
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: columnComp
|
||||
Column {
|
||||
width: parent ? parent.width : 0
|
||||
spacing: noBackground ? 2 : Theme.spacingXS
|
||||
Repeater {
|
||||
model: root.widgetsModel
|
||||
Item {
|
||||
width: parent.width
|
||||
height: widgetLoader.item ? widgetLoader.item.height : 0
|
||||
WidgetHost {
|
||||
id: widgetLoader
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
widgetId: model.widgetId
|
||||
widgetData: model
|
||||
spacerSize: model.size || 20
|
||||
components: root.components
|
||||
isInColumn: true
|
||||
axis: root.axis
|
||||
section: "right"
|
||||
parentScreen: root.parentScreen
|
||||
widgetThickness: root.widgetThickness
|
||||
barThickness: root.barThickness
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,144 +0,0 @@
|
||||
import QtQuick
|
||||
import Quickshell.Services.Mpris
|
||||
import qs.Services
|
||||
|
||||
Loader {
|
||||
id: root
|
||||
|
||||
property string widgetId: ""
|
||||
property var widgetData: null
|
||||
property int spacerSize: 20
|
||||
property var components: null
|
||||
property bool isInColumn: false
|
||||
property var axis: null
|
||||
property string section: "center"
|
||||
property var parentScreen: null
|
||||
property real widgetThickness: 30
|
||||
property real barThickness: 48
|
||||
|
||||
asynchronous: false
|
||||
|
||||
active: getWidgetVisible(widgetId, DgopService.dgopAvailable) &&
|
||||
(widgetId !== "music" || MprisController.activePlayer !== null)
|
||||
sourceComponent: getWidgetComponent(widgetId, components)
|
||||
opacity: getWidgetEnabled(widgetData?.enabled) ? 1 : 0
|
||||
|
||||
signal contentItemReady(var item)
|
||||
|
||||
Binding {
|
||||
target: root.item
|
||||
when: root.item && "parentScreen" in root.item
|
||||
property: "parentScreen"
|
||||
value: root.parentScreen
|
||||
restoreMode: Binding.RestoreNone
|
||||
}
|
||||
|
||||
Binding {
|
||||
target: root.item
|
||||
when: root.item && "section" in root.item
|
||||
property: "section"
|
||||
value: root.section
|
||||
restoreMode: Binding.RestoreNone
|
||||
}
|
||||
|
||||
Binding {
|
||||
target: root.item
|
||||
when: root.item && "widgetThickness" in root.item
|
||||
property: "widgetThickness"
|
||||
value: root.widgetThickness
|
||||
restoreMode: Binding.RestoreNone
|
||||
}
|
||||
|
||||
Binding {
|
||||
target: root.item
|
||||
when: root.item && "barThickness" in root.item
|
||||
property: "barThickness"
|
||||
value: root.barThickness
|
||||
restoreMode: Binding.RestoreNone
|
||||
}
|
||||
|
||||
Binding {
|
||||
target: root.item
|
||||
when: root.item && "axis" in root.item
|
||||
property: "axis"
|
||||
value: root.axis
|
||||
restoreMode: Binding.RestoreNone
|
||||
}
|
||||
|
||||
onLoaded: {
|
||||
if (item) {
|
||||
contentItemReady(item)
|
||||
if (widgetId === "spacer") {
|
||||
item.spacerSize = Qt.binding(() => spacerSize)
|
||||
}
|
||||
if (axis && "isVertical" in item) {
|
||||
try {
|
||||
item.isVertical = axis.isVertical
|
||||
} catch (e) {
|
||||
}
|
||||
}
|
||||
|
||||
if (item.pluginService !== undefined) {
|
||||
if (item.pluginId !== undefined) {
|
||||
item.pluginId = widgetId
|
||||
}
|
||||
item.pluginService = PluginService
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function getWidgetComponent(widgetId, components) {
|
||||
const componentMap = {
|
||||
"launcherButton": components.launcherButtonComponent,
|
||||
"workspaceSwitcher": components.workspaceSwitcherComponent,
|
||||
"focusedWindow": components.focusedWindowComponent,
|
||||
"runningApps": components.runningAppsComponent,
|
||||
"clock": components.clockComponent,
|
||||
"music": components.mediaComponent,
|
||||
"weather": components.weatherComponent,
|
||||
"systemTray": components.systemTrayComponent,
|
||||
"privacyIndicator": components.privacyIndicatorComponent,
|
||||
"clipboard": components.clipboardComponent,
|
||||
"cpuUsage": components.cpuUsageComponent,
|
||||
"memUsage": components.memUsageComponent,
|
||||
"diskUsage": components.diskUsageComponent,
|
||||
"cpuTemp": components.cpuTempComponent,
|
||||
"gpuTemp": components.gpuTempComponent,
|
||||
"notificationButton": components.notificationButtonComponent,
|
||||
"battery": components.batteryComponent,
|
||||
"controlCenterButton": components.controlCenterButtonComponent,
|
||||
"idleInhibitor": components.idleInhibitorComponent,
|
||||
"spacer": components.spacerComponent,
|
||||
"separator": components.separatorComponent,
|
||||
"network_speed_monitor": components.networkComponent,
|
||||
"keyboard_layout_name": components.keyboardLayoutNameComponent,
|
||||
"vpn": components.vpnComponent,
|
||||
"notepadButton": components.notepadButtonComponent,
|
||||
"colorPicker": components.colorPickerComponent,
|
||||
"systemUpdate": components.systemUpdateComponent
|
||||
}
|
||||
|
||||
if (componentMap[widgetId]) {
|
||||
return componentMap[widgetId]
|
||||
}
|
||||
|
||||
let pluginMap = PluginService.getWidgetComponents()
|
||||
return pluginMap[widgetId] || null
|
||||
}
|
||||
|
||||
function getWidgetVisible(widgetId, dgopAvailable) {
|
||||
const widgetVisibility = {
|
||||
"cpuUsage": dgopAvailable,
|
||||
"memUsage": dgopAvailable,
|
||||
"cpuTemp": dgopAvailable,
|
||||
"gpuTemp": dgopAvailable,
|
||||
"network_speed_monitor": dgopAvailable
|
||||
}
|
||||
|
||||
return widgetVisibility[widgetId] ?? true
|
||||
}
|
||||
|
||||
function getWidgetEnabled(enabled) {
|
||||
return enabled !== false
|
||||
}
|
||||
}
|
||||
@@ -1,126 +0,0 @@
|
||||
import QtQuick
|
||||
import Quickshell.Services.UPower
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: battery
|
||||
|
||||
property bool isVertical: axis?.isVertical ?? false
|
||||
property var axis: null
|
||||
property bool batteryPopupVisible: false
|
||||
property string section: "right"
|
||||
property var popupTarget: null
|
||||
property var parentScreen: null
|
||||
property real widgetThickness: 30
|
||||
property real barThickness: 48
|
||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||
|
||||
signal toggleBatteryPopup()
|
||||
|
||||
width: isVertical ? widgetThickness : (batteryContent.implicitWidth + horizontalPadding * 2)
|
||||
height: isVertical ? (batteryColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
|
||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||
color: {
|
||||
if (SettingsData.dankBarNoBackground) {
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
const baseColor = batteryArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
|
||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
|
||||
}
|
||||
visible: true
|
||||
|
||||
Column {
|
||||
id: batteryColumn
|
||||
visible: battery.isVertical
|
||||
anchors.centerIn: parent
|
||||
spacing: 1
|
||||
|
||||
DankIcon {
|
||||
name: BatteryService.getBatteryIcon()
|
||||
size: Theme.iconSize - 8
|
||||
color: {
|
||||
if (!BatteryService.batteryAvailable) {
|
||||
return Theme.surfaceText
|
||||
}
|
||||
|
||||
if (BatteryService.isLowBattery && !BatteryService.isCharging) {
|
||||
return Theme.error
|
||||
}
|
||||
|
||||
if (BatteryService.isCharging || BatteryService.isPluggedIn) {
|
||||
return Theme.primary
|
||||
}
|
||||
|
||||
return Theme.surfaceText
|
||||
}
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: BatteryService.batteryLevel.toString()
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
visible: BatteryService.batteryAvailable
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: batteryContent
|
||||
visible: !battery.isVertical
|
||||
anchors.centerIn: parent
|
||||
spacing: SettingsData.dankBarNoBackground ? 1 : 2
|
||||
|
||||
DankIcon {
|
||||
name: BatteryService.getBatteryIcon()
|
||||
size: Theme.iconSize - 6
|
||||
color: {
|
||||
if (!BatteryService.batteryAvailable) {
|
||||
return Theme.surfaceText;
|
||||
}
|
||||
|
||||
if (BatteryService.isLowBattery && !BatteryService.isCharging) {
|
||||
return Theme.error;
|
||||
}
|
||||
|
||||
if (BatteryService.isCharging || BatteryService.isPluggedIn) {
|
||||
return Theme.primary;
|
||||
}
|
||||
|
||||
return Theme.surfaceText;
|
||||
}
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: `${BatteryService.batteryLevel}%`
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: BatteryService.batteryAvailable
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: batteryArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: {
|
||||
if (popupTarget && popupTarget.setTriggerPosition) {
|
||||
const globalPos = mapToGlobal(0, 0)
|
||||
const currentScreen = parentScreen || Screen
|
||||
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
|
||||
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
|
||||
}
|
||||
toggleBatteryPopup();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property bool isActive: false
|
||||
property bool isVertical: axis?.isVertical ?? false
|
||||
property var axis: null
|
||||
property string section: "right"
|
||||
property var clipboardHistoryModal: null
|
||||
property var parentScreen: null
|
||||
property real widgetThickness: 30
|
||||
property real barThickness: 48
|
||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||
|
||||
signal clicked()
|
||||
|
||||
width: widgetThickness
|
||||
height: widgetThickness
|
||||
|
||||
MouseArea {
|
||||
id: clipboardArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onPressed: {
|
||||
root.clicked()
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: clipboardContent
|
||||
|
||||
anchors.fill: parent
|
||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||
color: {
|
||||
if (SettingsData.dankBarNoBackground) {
|
||||
return "transparent"
|
||||
}
|
||||
|
||||
const baseColor = clipboardArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor
|
||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency)
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
name: "content_paste"
|
||||
size: widgetThickness - 8
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property bool isVertical: axis?.isVertical ?? false
|
||||
property var axis: null
|
||||
property bool compactMode: false
|
||||
property string section: "center"
|
||||
property var popupTarget: null
|
||||
property var parentScreen: null
|
||||
property real barThickness: 48
|
||||
property real widgetThickness: 30
|
||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
|
||||
|
||||
signal clockClicked
|
||||
|
||||
width: isVertical ? widgetThickness : (clockRow.implicitWidth + horizontalPadding * 2)
|
||||
height: isVertical ? (clockColumn.implicitHeight + horizontalPadding * 2) : widgetThickness
|
||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||
color: {
|
||||
if (SettingsData.dankBarNoBackground) {
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
const baseColor = clockMouseArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
|
||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
|
||||
}
|
||||
|
||||
Column {
|
||||
id: clockColumn
|
||||
visible: root.isVertical
|
||||
anchors.centerIn: parent
|
||||
spacing: -2
|
||||
|
||||
Row {
|
||||
spacing: 0
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (SettingsData.use24HourClock) {
|
||||
return String(systemClock?.date?.getHours()).padStart(2, '0').charAt(0)
|
||||
} else {
|
||||
const hours = systemClock?.date?.getHours()
|
||||
const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours
|
||||
return String(display).padStart(2, '0').charAt(0)
|
||||
}
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.primary
|
||||
font.weight: Font.Normal
|
||||
width: 9
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (SettingsData.use24HourClock) {
|
||||
return String(systemClock?.date?.getHours()).padStart(2, '0').charAt(1)
|
||||
} else {
|
||||
const hours = systemClock?.date?.getHours()
|
||||
const display = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours
|
||||
return String(display).padStart(2, '0').charAt(1)
|
||||
}
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.primary
|
||||
font.weight: Font.Normal
|
||||
width: 9
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: 0
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
StyledText {
|
||||
text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(0)
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.primary
|
||||
font.weight: Font.Normal
|
||||
width: 9
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: String(systemClock?.date?.getMinutes()).padStart(2, '0').charAt(1)
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.primary
|
||||
font.weight: Font.Normal
|
||||
width: 9
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 12
|
||||
height: Theme.spacingM
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
Rectangle {
|
||||
width: 12
|
||||
height: 1
|
||||
color: Theme.outlineButton
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: 0
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
const locale = Qt.locale()
|
||||
const dateFormatShort = locale.dateFormat(Locale.ShortFormat)
|
||||
const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M')
|
||||
const value = dayFirst ? String(systemClock?.date?.getDate()).padStart(2, '0') : String(systemClock?.date?.getMonth() + 1).padStart(2, '0')
|
||||
return value.charAt(0)
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: {
|
||||
const locale = Qt.locale()
|
||||
const dateFormatShort = locale.dateFormat(Locale.ShortFormat)
|
||||
const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M')
|
||||
return dayFirst ? Font.Normal : Font.Light
|
||||
}
|
||||
width: 9
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
const locale = Qt.locale()
|
||||
const dateFormatShort = locale.dateFormat(Locale.ShortFormat)
|
||||
const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M')
|
||||
const value = dayFirst ? String(systemClock?.date?.getDate()).padStart(2, '0') : String(systemClock?.date?.getMonth() + 1).padStart(2, '0')
|
||||
return value.charAt(1)
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: {
|
||||
const locale = Qt.locale()
|
||||
const dateFormatShort = locale.dateFormat(Locale.ShortFormat)
|
||||
const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M')
|
||||
return dayFirst ? Font.Normal : Font.Light
|
||||
}
|
||||
width: 9
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: 0
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
const locale = Qt.locale()
|
||||
const dateFormatShort = locale.dateFormat(Locale.ShortFormat)
|
||||
const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M')
|
||||
const value = dayFirst ? String(systemClock?.date?.getMonth() + 1).padStart(2, '0') : String(systemClock?.date?.getDate()).padStart(2, '0')
|
||||
return value.charAt(0)
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: {
|
||||
const locale = Qt.locale()
|
||||
const dateFormatShort = locale.dateFormat(Locale.ShortFormat)
|
||||
const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M')
|
||||
return dayFirst ? Font.Light : Font.Normal
|
||||
}
|
||||
width: 9
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
const locale = Qt.locale()
|
||||
const dateFormatShort = locale.dateFormat(Locale.ShortFormat)
|
||||
const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M')
|
||||
const value = dayFirst ? String(systemClock?.date?.getMonth() + 1).padStart(2, '0') : String(systemClock?.date?.getDate()).padStart(2, '0')
|
||||
return value.charAt(1)
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
font.weight: {
|
||||
const locale = Qt.locale()
|
||||
const dateFormatShort = locale.dateFormat(Locale.ShortFormat)
|
||||
const dayFirst = dateFormatShort.indexOf('d') < dateFormatShort.indexOf('M')
|
||||
return dayFirst ? Font.Light : Font.Normal
|
||||
}
|
||||
width: 9
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
id: clockRow
|
||||
|
||||
visible: !root.isVertical
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingS
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
const format = SettingsData.use24HourClock ? "HH:mm" : "h:mm AP"
|
||||
return systemClock?.date?.toLocaleTimeString(Qt.locale(), format)
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeMedium - 1
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "•"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.outlineButton
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: !SettingsData.clockCompactMode
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (SettingsData.clockDateFormat && SettingsData.clockDateFormat.length > 0) {
|
||||
return systemClock?.date?.toLocaleDateString(Qt.locale(), SettingsData.clockDateFormat)
|
||||
}
|
||||
|
||||
return systemClock?.date?.toLocaleDateString(Qt.locale(), "ddd d")
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeMedium - 1
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: !SettingsData.clockCompactMode
|
||||
}
|
||||
}
|
||||
|
||||
SystemClock {
|
||||
id: systemClock
|
||||
precision: SystemClock.Seconds
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: clockMouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: {
|
||||
if (popupTarget && popupTarget.setTriggerPosition) {
|
||||
const globalPos = mapToGlobal(0, 0)
|
||||
const currentScreen = parentScreen || Screen
|
||||
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
|
||||
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
|
||||
}
|
||||
root.clockClicked()
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,96 +0,0 @@
|
||||
import QtQuick
|
||||
import Quickshell.Hyprland
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property bool isVertical: axis?.isVertical ?? false
|
||||
property var axis: null
|
||||
property string section: "right"
|
||||
property var parentScreen: null
|
||||
property real widgetThickness: 30
|
||||
property real barThickness: 48
|
||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||
|
||||
signal clicked()
|
||||
|
||||
readonly property string focusedScreenName: (
|
||||
CompositorService.isHyprland && typeof Hyprland !== "undefined" && Hyprland.focusedWorkspace && Hyprland.focusedWorkspace.monitor ? (Hyprland.focusedWorkspace.monitor.name || "") :
|
||||
CompositorService.isNiri && typeof NiriService !== "undefined" && NiriService.currentOutput ? NiriService.currentOutput : ""
|
||||
)
|
||||
|
||||
function resolveNotepadInstance() {
|
||||
if (typeof notepadSlideoutVariants === "undefined" || !notepadSlideoutVariants || !notepadSlideoutVariants.instances) {
|
||||
return null
|
||||
}
|
||||
|
||||
const targetScreen = focusedScreenName
|
||||
if (targetScreen) {
|
||||
for (var i = 0; i < notepadSlideoutVariants.instances.length; i++) {
|
||||
var slideout = notepadSlideoutVariants.instances[i]
|
||||
if (slideout.modelData && slideout.modelData.name === targetScreen) {
|
||||
return slideout
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return notepadSlideoutVariants.instances.length > 0 ? notepadSlideoutVariants.instances[0] : null
|
||||
}
|
||||
|
||||
readonly property var notepadInstance: resolveNotepadInstance()
|
||||
readonly property bool isActive: notepadInstance?.isVisible ?? false
|
||||
|
||||
width: isVertical ? widgetThickness : (notepadIcon.width + horizontalPadding * 2)
|
||||
height: isVertical ? (notepadIcon.height + horizontalPadding * 2) : widgetThickness
|
||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||
color: {
|
||||
if (SettingsData.dankBarNoBackground) {
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
const baseColor = notepadArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
|
||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
id: notepadIcon
|
||||
|
||||
anchors.centerIn: parent
|
||||
name: "assignment"
|
||||
size: Theme.iconSize - 6
|
||||
color: notepadArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 6
|
||||
height: 6
|
||||
radius: 3
|
||||
color: Theme.primary
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.rightMargin: SettingsData.dankBarNoBackground ? 0 : 4
|
||||
anchors.topMargin: SettingsData.dankBarNoBackground ? 0 : 4
|
||||
visible: NotepadStorageService.tabs && NotepadStorageService.tabs.length > 0
|
||||
opacity: 0.8
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: notepadArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: {
|
||||
const inst = root.notepadInstance
|
||||
if (inst) {
|
||||
inst.toggle()
|
||||
}
|
||||
root.clicked()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
Item {
|
||||
id: root
|
||||
|
||||
property bool hasUnread: false
|
||||
property bool isActive: false
|
||||
property bool isVertical: axis?.isVertical ?? false
|
||||
property var axis: null
|
||||
property string section: "right"
|
||||
property var popupTarget: null
|
||||
property var parentScreen: null
|
||||
property real widgetThickness: 30
|
||||
property real barThickness: 48
|
||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||
|
||||
signal clicked()
|
||||
|
||||
width: widgetThickness
|
||||
height: widgetThickness
|
||||
|
||||
MouseArea {
|
||||
id: notificationArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton
|
||||
onPressed: {
|
||||
if (popupTarget && popupTarget.setTriggerPosition) {
|
||||
const globalPos = mapToGlobal(0, 0)
|
||||
const currentScreen = parentScreen || Screen
|
||||
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
|
||||
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
|
||||
}
|
||||
root.clicked()
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: notificationContent
|
||||
|
||||
anchors.fill: parent
|
||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||
color: {
|
||||
if (SettingsData.dankBarNoBackground) {
|
||||
return "transparent"
|
||||
}
|
||||
|
||||
const baseColor = notificationArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor
|
||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency)
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
name: SessionData.doNotDisturb ? "notifications_off" : "notifications"
|
||||
size: widgetThickness - 8
|
||||
color: SessionData.doNotDisturb ? Theme.error : (notificationArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText)
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 8
|
||||
height: 8
|
||||
radius: 4
|
||||
color: Theme.error
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.rightMargin: SettingsData.dankBarNoBackground ? 0 : 6
|
||||
anchors.topMargin: SettingsData.dankBarNoBackground ? 0 : 6
|
||||
visible: root.hasUnread
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,630 +0,0 @@
|
||||
import QtQuick
|
||||
import QtQuick.Controls
|
||||
import Quickshell
|
||||
import Quickshell.Services.SystemTray
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Widgets
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property bool isVertical: axis?.isVertical ?? false
|
||||
property var axis: null
|
||||
property var parentWindow: null
|
||||
property var parentScreen: null
|
||||
property real widgetThickness: 30
|
||||
property bool isAtBottom: false
|
||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 2 : Theme.spacingS
|
||||
readonly property int calculatedSize: SystemTray.items.values.length > 0 ? SystemTray.items.values.length * 24 + horizontalPadding * 2 : 0
|
||||
|
||||
width: isVertical ? widgetThickness : calculatedSize
|
||||
height: isVertical ? calculatedSize : widgetThickness
|
||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||
color: {
|
||||
if (SystemTray.items.values.length === 0) {
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
if (SettingsData.dankBarNoBackground) {
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
const baseColor = Theme.widgetBaseBackgroundColor;
|
||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
|
||||
}
|
||||
visible: SystemTray.items.values.length > 0
|
||||
|
||||
Loader {
|
||||
id: layoutLoader
|
||||
anchors.centerIn: parent
|
||||
sourceComponent: root.isVertical ? columnComp : rowComp
|
||||
}
|
||||
|
||||
Component {
|
||||
id: rowComp
|
||||
Row {
|
||||
spacing: 0
|
||||
|
||||
Repeater {
|
||||
model: SystemTray.items.values
|
||||
|
||||
delegate: Item {
|
||||
property var trayItem: modelData
|
||||
property string iconSource: {
|
||||
let icon = trayItem && trayItem.icon;
|
||||
if (typeof icon === 'string' || icon instanceof String) {
|
||||
if (icon === "") {
|
||||
return "";
|
||||
}
|
||||
if (icon.includes("?path=")) {
|
||||
const split = icon.split("?path=");
|
||||
if (split.length !== 2) {
|
||||
return icon;
|
||||
}
|
||||
|
||||
const name = split[0];
|
||||
const path = split[1];
|
||||
const fileName = name.substring(name.lastIndexOf("/") + 1);
|
||||
return `file://${path}/${fileName}`;
|
||||
}
|
||||
if (icon.startsWith("/") && !icon.startsWith("file://")) {
|
||||
return `file://${icon}`;
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
width: 24
|
||||
height: 24
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
color: trayItemArea.containsMouse ? Theme.primaryHover : "transparent"
|
||||
|
||||
|
||||
}
|
||||
|
||||
IconImage {
|
||||
anchors.centerIn: parent
|
||||
width: 16
|
||||
height: 16
|
||||
source: parent.iconSource
|
||||
asynchronous: true
|
||||
smooth: true
|
||||
mipmap: true
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: trayItemArea
|
||||
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: (mouse) => {
|
||||
if (!trayItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mouse.button === Qt.LeftButton && !trayItem.onlyMenu) {
|
||||
trayItem.activate();
|
||||
return ;
|
||||
}
|
||||
if (trayItem.hasMenu) {
|
||||
root.showForTrayItem(trayItem, parent, parentScreen, root.isAtBottom, root.isVertical, root.axis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: columnComp
|
||||
Column {
|
||||
spacing: 0
|
||||
|
||||
Repeater {
|
||||
model: SystemTray.items.values
|
||||
|
||||
delegate: Item {
|
||||
property var trayItem: modelData
|
||||
property string iconSource: {
|
||||
let icon = trayItem && trayItem.icon;
|
||||
if (typeof icon === 'string' || icon instanceof String) {
|
||||
if (icon === "") {
|
||||
return "";
|
||||
}
|
||||
if (icon.includes("?path=")) {
|
||||
const split = icon.split("?path=");
|
||||
if (split.length !== 2) {
|
||||
return icon;
|
||||
}
|
||||
|
||||
const name = split[0];
|
||||
const path = split[1];
|
||||
const fileName = name.substring(name.lastIndexOf("/") + 1);
|
||||
return `file://${path}/${fileName}`;
|
||||
}
|
||||
if (icon.startsWith("/") && !icon.startsWith("file://")) {
|
||||
return `file://${icon}`;
|
||||
}
|
||||
return icon;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
width: 24
|
||||
height: 24
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: Theme.cornerRadius
|
||||
color: trayItemArea.containsMouse ? Theme.primaryHover : "transparent"
|
||||
}
|
||||
|
||||
IconImage {
|
||||
anchors.centerIn: parent
|
||||
width: 16
|
||||
height: 16
|
||||
source: parent.iconSource
|
||||
asynchronous: true
|
||||
smooth: true
|
||||
mipmap: true
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: trayItemArea
|
||||
|
||||
anchors.fill: parent
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: (mouse) => {
|
||||
if (!trayItem) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mouse.button === Qt.LeftButton && !trayItem.onlyMenu) {
|
||||
trayItem.activate();
|
||||
return ;
|
||||
}
|
||||
if (trayItem.hasMenu) {
|
||||
root.showForTrayItem(trayItem, parent, parentScreen, root.isAtBottom, root.isVertical, root.axis);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: trayMenuComponent
|
||||
|
||||
Rectangle {
|
||||
id: menuRoot
|
||||
|
||||
property var trayItem: null
|
||||
property var anchorItem: null
|
||||
property var parentScreen: null
|
||||
property bool isAtBottom: false
|
||||
property bool isVertical: false
|
||||
property var axis: null
|
||||
property bool showMenu: false
|
||||
property var menuHandle: null
|
||||
|
||||
ListModel { id: entryStack }
|
||||
function topEntry() {
|
||||
return entryStack.count ? entryStack.get(entryStack.count - 1).handle : null
|
||||
}
|
||||
|
||||
function showForTrayItem(item, anchor, screen, atBottom, vertical, axisObj) {
|
||||
trayItem = item
|
||||
anchorItem = anchor
|
||||
parentScreen = screen
|
||||
isAtBottom = atBottom
|
||||
isVertical = vertical
|
||||
axis = axisObj
|
||||
menuHandle = item?.menu
|
||||
|
||||
if (parentScreen) {
|
||||
for (var i = 0; i < Quickshell.screens.length; i++) {
|
||||
const s = Quickshell.screens[i]
|
||||
if (s === parentScreen) {
|
||||
menuWindow.screen = s
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
showMenu = true
|
||||
}
|
||||
|
||||
function close() {
|
||||
showMenu = false
|
||||
}
|
||||
|
||||
function showSubMenu(entry) {
|
||||
if (!entry || !entry.hasChildren) return;
|
||||
|
||||
entryStack.append({ handle: entry });
|
||||
|
||||
const h = entry.menu || entry;
|
||||
if (h && typeof h.updateLayout === "function") h.updateLayout();
|
||||
|
||||
submenuHydrator.menu = h;
|
||||
submenuHydrator.open();
|
||||
Qt.callLater(() => submenuHydrator.close());
|
||||
}
|
||||
|
||||
function goBack() {
|
||||
if (!entryStack.count) return;
|
||||
entryStack.remove(entryStack.count - 1);
|
||||
}
|
||||
|
||||
width: 0
|
||||
height: 0
|
||||
color: "transparent"
|
||||
|
||||
PanelWindow {
|
||||
id: menuWindow
|
||||
visible: menuRoot.showMenu && (menuRoot.trayItem?.hasMenu ?? false)
|
||||
WlrLayershell.layer: WlrLayershell.Overlay
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
color: "transparent"
|
||||
|
||||
anchors {
|
||||
top: true
|
||||
left: true
|
||||
right: true
|
||||
bottom: true
|
||||
}
|
||||
|
||||
property point anchorPos: Qt.point(screen.width / 2, screen.height / 2)
|
||||
|
||||
onVisibleChanged: {
|
||||
if (visible) {
|
||||
updatePosition()
|
||||
}
|
||||
}
|
||||
|
||||
function updatePosition() {
|
||||
if (!menuRoot.anchorItem || !menuRoot.trayItem) {
|
||||
anchorPos = Qt.point(screen.width / 2, screen.height / 2)
|
||||
return
|
||||
}
|
||||
|
||||
const globalPos = menuRoot.anchorItem.mapToGlobal(0, 0)
|
||||
const screenX = screen.x || 0
|
||||
const screenY = screen.y || 0
|
||||
const relativeX = globalPos.x - screenX
|
||||
const relativeY = globalPos.y - screenY
|
||||
|
||||
const widgetThickness = Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6)
|
||||
const effectiveBarThickness = Math.max(widgetThickness + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
|
||||
|
||||
if (menuRoot.isVertical) {
|
||||
const edge = menuRoot.axis?.edge
|
||||
let targetX
|
||||
if (edge === "left") {
|
||||
targetX = effectiveBarThickness + SettingsData.dankBarSpacing + Theme.popupDistance
|
||||
} else {
|
||||
const popupX = effectiveBarThickness + SettingsData.dankBarSpacing + Theme.popupDistance
|
||||
targetX = screen.width - popupX
|
||||
}
|
||||
anchorPos = Qt.point(targetX, relativeY + menuRoot.anchorItem.height / 2)
|
||||
} else {
|
||||
let targetY
|
||||
if (menuRoot.isAtBottom) {
|
||||
const popupY = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap + Theme.popupDistance
|
||||
targetY = screen.height - popupY
|
||||
} else {
|
||||
targetY = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap + Theme.popupDistance
|
||||
}
|
||||
anchorPos = Qt.point(relativeX + menuRoot.anchorItem.width / 2, targetY)
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: menuContainer
|
||||
|
||||
width: Math.min(500, Math.max(250, menuColumn.implicitWidth + Theme.spacingS * 2))
|
||||
height: Math.max(40, menuColumn.implicitHeight + Theme.spacingS * 2)
|
||||
|
||||
x: {
|
||||
if (menuRoot.isVertical) {
|
||||
const edge = menuRoot.axis?.edge
|
||||
if (edge === "left") {
|
||||
const targetX = menuWindow.anchorPos.x
|
||||
return Math.min(menuWindow.screen.width - width - 10, targetX)
|
||||
} else {
|
||||
const targetX = menuWindow.anchorPos.x - width
|
||||
return Math.max(10, targetX)
|
||||
}
|
||||
} else {
|
||||
const left = 10
|
||||
const right = menuWindow.width - width - 10
|
||||
const want = menuWindow.anchorPos.x - width / 2
|
||||
return Math.max(left, Math.min(right, want))
|
||||
}
|
||||
}
|
||||
|
||||
y: {
|
||||
if (menuRoot.isVertical) {
|
||||
const top = 10
|
||||
const bottom = menuWindow.height - height - 10
|
||||
const want = menuWindow.anchorPos.y - height / 2
|
||||
return Math.max(top, Math.min(bottom, want))
|
||||
} else {
|
||||
if (menuRoot.isAtBottom) {
|
||||
const targetY = menuWindow.anchorPos.y - height
|
||||
return Math.max(10, targetY)
|
||||
} else {
|
||||
const targetY = menuWindow.anchorPos.y
|
||||
return Math.min(menuWindow.screen.height - height - 10, targetY)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
color: Theme.popupBackground()
|
||||
radius: Theme.cornerRadius
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
|
||||
opacity: menuRoot.showMenu ? 1 : 0
|
||||
scale: menuRoot.showMenu ? 1 : 0.85
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
anchors.topMargin: 4
|
||||
anchors.leftMargin: 2
|
||||
anchors.rightMargin: -2
|
||||
anchors.bottomMargin: -4
|
||||
radius: parent.radius
|
||||
color: Qt.rgba(0, 0, 0, 0.15)
|
||||
z: parent.z - 1
|
||||
}
|
||||
|
||||
QsMenuAnchor {
|
||||
id: submenuHydrator
|
||||
anchor.window: menuWindow
|
||||
}
|
||||
|
||||
QsMenuOpener {
|
||||
id: rootOpener
|
||||
menu: menuRoot.menuHandle
|
||||
}
|
||||
|
||||
QsMenuOpener {
|
||||
id: subOpener
|
||||
menu: {
|
||||
const e = menuRoot.topEntry();
|
||||
return e ? (e.menu || e) : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Column {
|
||||
id: menuColumn
|
||||
|
||||
width: parent.width - Theme.spacingS * 2
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: Theme.spacingS
|
||||
spacing: 1
|
||||
|
||||
Rectangle {
|
||||
visible: entryStack.count > 0
|
||||
width: parent.width
|
||||
height: 28
|
||||
radius: Theme.cornerRadius
|
||||
color: backArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
DankIcon {
|
||||
name: "arrow_back"
|
||||
size: 16
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Back"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: backArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: menuRoot.goBack()
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
visible: entryStack.count > 0
|
||||
width: parent.width
|
||||
height: 1
|
||||
color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
}
|
||||
|
||||
Repeater {
|
||||
model: entryStack.count
|
||||
? (subOpener.children ? subOpener.children
|
||||
: (menuRoot.topEntry()?.children || []))
|
||||
: rootOpener.children
|
||||
|
||||
Rectangle {
|
||||
property var menuEntry: modelData
|
||||
|
||||
width: menuColumn.width
|
||||
height: menuEntry?.isSeparator ? 1 : 28
|
||||
radius: menuEntry?.isSeparator ? 0 : Theme.cornerRadius
|
||||
color: {
|
||||
if (menuEntry?.isSeparator) {
|
||||
return Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.2)
|
||||
}
|
||||
return itemArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: itemArea
|
||||
anchors.fill: parent
|
||||
enabled: !menuEntry?.isSeparator && (menuEntry?.enabled !== false)
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
|
||||
onClicked: {
|
||||
if (!menuEntry || menuEntry.isSeparator) return;
|
||||
|
||||
if (menuEntry.hasChildren) {
|
||||
menuRoot.showSubMenu(menuEntry);
|
||||
} else {
|
||||
if (typeof menuEntry.activate === "function") {
|
||||
menuEntry.activate();
|
||||
} else if (typeof menuEntry.triggered === "function") {
|
||||
menuEntry.triggered();
|
||||
}
|
||||
Qt.createQmlObject('import QtQuick; Timer { interval: 80; running: true; repeat: false; onTriggered: menuRoot.close() }', menuRoot);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingS
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingXS
|
||||
visible: !menuEntry?.isSeparator
|
||||
|
||||
Rectangle {
|
||||
width: 16
|
||||
height: 16
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: menuEntry?.buttonType !== undefined && menuEntry.buttonType !== 0
|
||||
radius: menuEntry?.buttonType === 2 ? 8 : 2
|
||||
border.width: 1
|
||||
border.color: Theme.outline
|
||||
color: "transparent"
|
||||
|
||||
Rectangle {
|
||||
anchors.centerIn: parent
|
||||
width: parent.width - 6
|
||||
height: parent.height - 6
|
||||
radius: parent.radius - 3
|
||||
color: Theme.primary
|
||||
visible: menuEntry?.checkState === 2
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "check"
|
||||
size: 10
|
||||
color: Theme.primaryText
|
||||
visible: menuEntry?.buttonType === 1 && menuEntry?.checkState === 2
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 16
|
||||
height: 16
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: menuEntry?.icon && menuEntry.icon !== ""
|
||||
|
||||
Image {
|
||||
anchors.fill: parent
|
||||
source: menuEntry?.icon || ""
|
||||
sourceSize.width: 16
|
||||
sourceSize.height: 16
|
||||
fillMode: Image.PreserveAspectFit
|
||||
smooth: true
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: menuEntry?.text || ""
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: (menuEntry?.enabled !== false) ? Theme.surfaceText : Theme.surfaceTextMedium
|
||||
elide: Text.ElideRight
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: Math.max(150, parent.width - 64)
|
||||
wrapMode: Text.NoWrap
|
||||
}
|
||||
|
||||
Item {
|
||||
width: 16
|
||||
height: 16
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "chevron_right"
|
||||
size: 14
|
||||
color: Theme.surfaceText
|
||||
visible: menuEntry?.hasChildren ?? false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
duration: Theme.mediumDuration
|
||||
easing.type: Theme.emphasizedEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
z: -1
|
||||
onClicked: menuRoot.close()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property var currentTrayMenu: null
|
||||
|
||||
function showForTrayItem(item, anchor, screen, atBottom, vertical, axisObj) {
|
||||
if (currentTrayMenu) {
|
||||
currentTrayMenu.destroy()
|
||||
}
|
||||
currentTrayMenu = trayMenuComponent.createObject(null)
|
||||
if (currentTrayMenu) {
|
||||
currentTrayMenu.showForTrayItem(item, anchor, screen, atBottom, vertical ?? false, axisObj)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,154 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property bool isVertical: axis?.isVertical ?? false
|
||||
property var axis: null
|
||||
property bool isActive: false
|
||||
property string section: "right"
|
||||
property var popupTarget: null
|
||||
property var parentScreen: null
|
||||
property real widgetThickness: 30
|
||||
property real barThickness: 48
|
||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||
readonly property bool hasUpdates: SystemUpdateService.updateCount > 0
|
||||
readonly property bool isChecking: SystemUpdateService.isChecking
|
||||
|
||||
signal clicked()
|
||||
|
||||
width: isVertical ? widgetThickness : (updaterIcon.width + horizontalPadding * 2)
|
||||
height: isVertical ? widgetThickness : widgetThickness
|
||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||
color: {
|
||||
if (SettingsData.dankBarNoBackground) {
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
const baseColor = updaterArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
|
||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
id: statusIcon
|
||||
|
||||
anchors.centerIn: parent
|
||||
visible: root.isVertical
|
||||
name: {
|
||||
if (isChecking) return "refresh";
|
||||
if (SystemUpdateService.hasError) return "error";
|
||||
if (hasUpdates) return "system_update_alt";
|
||||
return "check_circle";
|
||||
}
|
||||
size: Theme.iconSize - 6
|
||||
color: {
|
||||
if (SystemUpdateService.hasError) return Theme.error;
|
||||
if (hasUpdates) return Theme.primary;
|
||||
return (updaterArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText);
|
||||
}
|
||||
|
||||
RotationAnimation {
|
||||
id: rotationAnimation
|
||||
target: statusIcon
|
||||
property: "rotation"
|
||||
from: 0
|
||||
to: 360
|
||||
duration: 1000
|
||||
running: isChecking
|
||||
loops: Animation.Infinite
|
||||
|
||||
onRunningChanged: {
|
||||
if (!running) {
|
||||
statusIcon.rotation = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 8
|
||||
height: 8
|
||||
radius: 4
|
||||
color: Theme.error
|
||||
anchors.right: parent.right
|
||||
anchors.top: parent.top
|
||||
anchors.rightMargin: SettingsData.dankBarNoBackground ? 0 : 6
|
||||
anchors.topMargin: SettingsData.dankBarNoBackground ? 0 : 6
|
||||
visible: root.isVertical && root.hasUpdates && !root.isChecking
|
||||
}
|
||||
|
||||
Row {
|
||||
id: updaterIcon
|
||||
|
||||
anchors.centerIn: parent
|
||||
spacing: Theme.spacingXS
|
||||
visible: !root.isVertical
|
||||
|
||||
DankIcon {
|
||||
id: statusIconHorizontal
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
name: {
|
||||
if (isChecking) return "refresh";
|
||||
if (SystemUpdateService.hasError) return "error";
|
||||
if (hasUpdates) return "system_update_alt";
|
||||
return "check_circle";
|
||||
}
|
||||
size: Theme.iconSize - 6
|
||||
color: {
|
||||
if (SystemUpdateService.hasError) return Theme.error;
|
||||
if (hasUpdates) return Theme.primary;
|
||||
return (updaterArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText);
|
||||
}
|
||||
|
||||
RotationAnimation {
|
||||
id: rotationAnimationHorizontal
|
||||
target: statusIconHorizontal
|
||||
property: "rotation"
|
||||
from: 0
|
||||
to: 360
|
||||
duration: 1000
|
||||
running: isChecking
|
||||
loops: Animation.Infinite
|
||||
|
||||
onRunningChanged: {
|
||||
if (!running) {
|
||||
statusIconHorizontal.rotation = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: countText
|
||||
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: SystemUpdateService.updateCount.toString()
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
visible: hasUpdates && !isChecking
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: updaterArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: {
|
||||
if (popupTarget && popupTarget.setTriggerPosition) {
|
||||
const globalPos = mapToGlobal(0, 0)
|
||||
const currentScreen = parentScreen || Screen
|
||||
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
|
||||
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
|
||||
}
|
||||
root.clicked();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property bool isVertical: axis?.isVertical ?? false
|
||||
property var axis: null
|
||||
property int widgetThickness: 28
|
||||
property int barThickness: 32
|
||||
property string section: "right"
|
||||
property var popupTarget: null
|
||||
property var parentScreen: null
|
||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||
|
||||
signal toggleVpnPopup()
|
||||
|
||||
width: isVertical ? widgetThickness : (Theme.iconSize + horizontalPadding * 2)
|
||||
height: isVertical ? (Theme.iconSize + horizontalPadding * 2) : widgetThickness
|
||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||
color: {
|
||||
if (SettingsData.dankBarNoBackground) {
|
||||
return "transparent";
|
||||
}
|
||||
|
||||
const baseColor = clickArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor;
|
||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency);
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
id: icon
|
||||
|
||||
name: VpnService.isBusy ? "sync" : (VpnService.connected ? "vpn_lock" : "vpn_key_off")
|
||||
size: Theme.iconSize - 6
|
||||
color: VpnService.connected ? Theme.primary : Theme.surfaceText
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: tooltipLoader
|
||||
active: false
|
||||
sourceComponent: DankTooltip {}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: clickArea
|
||||
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: {
|
||||
if (popupTarget && popupTarget.setTriggerPosition) {
|
||||
const globalPos = mapToGlobal(0, 0)
|
||||
const currentScreen = parentScreen || Screen
|
||||
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
|
||||
popupTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
|
||||
}
|
||||
root.toggleVpnPopup();
|
||||
}
|
||||
onEntered: {
|
||||
if (root.parentScreen && !(popupTarget && popupTarget.shouldBeVisible)) {
|
||||
tooltipLoader.active = true
|
||||
if (tooltipLoader.item) {
|
||||
let tooltipText = ""
|
||||
if (!VpnService.connected) {
|
||||
tooltipText = "VPN Disconnected"
|
||||
} else {
|
||||
const names = VpnService.activeNames || []
|
||||
if (names.length <= 1) {
|
||||
tooltipText = "VPN Connected • " + (names[0] || "")
|
||||
} else {
|
||||
tooltipText = "VPN Connected • " + names[0] + " +" + (names.length - 1)
|
||||
}
|
||||
}
|
||||
|
||||
if (root.isVertical) {
|
||||
const globalPos = mapToGlobal(width / 2, height / 2)
|
||||
const screenX = root.parentScreen ? root.parentScreen.x : 0
|
||||
const screenY = root.parentScreen ? root.parentScreen.y : 0
|
||||
const relativeY = globalPos.y - screenY
|
||||
const tooltipX = root.axis?.edge === "left" ? (Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS) : (root.parentScreen.width - Theme.barHeight - SettingsData.dankBarSpacing - Theme.spacingXS)
|
||||
const isLeft = root.axis?.edge === "left"
|
||||
tooltipLoader.item.show(tooltipText, screenX + tooltipX, relativeY, root.parentScreen, isLeft, !isLeft)
|
||||
} else {
|
||||
const globalPos = mapToGlobal(width / 2, height)
|
||||
const tooltipY = Theme.barHeight + SettingsData.dankBarSpacing + Theme.spacingXS
|
||||
tooltipLoader.item.show(tooltipText, globalPos.x, tooltipY, root.parentScreen, false, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
onExited: {
|
||||
if (tooltipLoader.item) {
|
||||
tooltipLoader.item.hide()
|
||||
}
|
||||
tooltipLoader.active = false
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,33 +13,30 @@ DankPopout {
|
||||
id: root
|
||||
|
||||
property bool dashVisible: false
|
||||
property string triggerSection: "center"
|
||||
property var triggerScreen: null
|
||||
property int currentTabIndex: 0
|
||||
|
||||
function setTriggerPosition(x, y, width, section, screen) {
|
||||
triggerSection = section
|
||||
triggerScreen = screen
|
||||
triggerY = y
|
||||
|
||||
if (section === "center" && (SettingsData.dankBarPosition === SettingsData.Position.Top || SettingsData.dankBarPosition === SettingsData.Position.Bottom)) {
|
||||
if (section === "center") {
|
||||
const screenWidth = screen ? screen.width : Screen.width
|
||||
triggerX = (screenWidth - popupWidth) / 2
|
||||
triggerWidth = popupWidth
|
||||
} else if (section === "center" && (SettingsData.dankBarPosition === SettingsData.Position.Left || SettingsData.dankBarPosition === SettingsData.Position.Right)) {
|
||||
const screenHeight = screen ? screen.height : Screen.height
|
||||
triggerX = (screenHeight - popupHeight) / 2
|
||||
triggerWidth = popupHeight
|
||||
} else {
|
||||
triggerX = x
|
||||
triggerWidth = width
|
||||
}
|
||||
triggerY = y
|
||||
triggerSection = section
|
||||
triggerScreen = screen
|
||||
}
|
||||
|
||||
popupWidth: 700
|
||||
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 500
|
||||
triggerX: Screen.width - 620 - Theme.spacingL
|
||||
triggerY: Math.max(26 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding)) + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap - 2
|
||||
triggerY: Theme.barHeight - 4 + SettingsData.topBarSpacing + Theme.spacingS
|
||||
triggerWidth: 80
|
||||
positioning: "center"
|
||||
shouldBeVisible: dashVisible
|
||||
visible: shouldBeVisible
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -13,22 +13,83 @@ Card {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankCircularImage {
|
||||
Item {
|
||||
id: avatarContainer
|
||||
|
||||
|
||||
property bool hasImage: profileImageLoader.status === Image.Ready
|
||||
|
||||
width: 77
|
||||
height: 77
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
imageSource: {
|
||||
if (PortalService.profileImage === "")
|
||||
return ""
|
||||
|
||||
if (PortalService.profileImage.startsWith("/"))
|
||||
return "file://" + PortalService.profileImage
|
||||
|
||||
return PortalService.profileImage
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: 36
|
||||
color: Theme.primary
|
||||
visible: !avatarContainer.hasImage
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: UserInfoService.username.length > 0 ? UserInfoService.username.charAt(0).toUpperCase() : "b"
|
||||
font.pixelSize: Theme.fontSizeXLarge + 4
|
||||
font.weight: Font.Bold
|
||||
color: Theme.background
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: profileImageLoader
|
||||
|
||||
source: {
|
||||
if (PortalService.profileImage === "")
|
||||
return ""
|
||||
|
||||
if (PortalService.profileImage.startsWith("/"))
|
||||
return "file://" + PortalService.profileImage
|
||||
|
||||
return PortalService.profileImage
|
||||
}
|
||||
smooth: true
|
||||
asynchronous: true
|
||||
mipmap: true
|
||||
cache: true
|
||||
visible: false
|
||||
}
|
||||
|
||||
MultiEffect {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 2
|
||||
source: profileImageLoader
|
||||
maskEnabled: true
|
||||
maskSource: circularMask
|
||||
visible: avatarContainer.hasImage
|
||||
maskThresholdMin: 0.5
|
||||
maskSpreadAtMin: 1
|
||||
}
|
||||
|
||||
Item {
|
||||
id: circularMask
|
||||
width: 77 - 4
|
||||
height: 77 - 4
|
||||
layer.enabled: true
|
||||
layer.smooth: true
|
||||
visible: false
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: width / 2
|
||||
color: "black"
|
||||
antialiasing: true
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "person"
|
||||
size: Theme.iconSize + 8
|
||||
color: Theme.error
|
||||
visible: PortalService.profileImage !== "" && profileImageLoader.status === Image.Error
|
||||
}
|
||||
fallbackIcon: "person"
|
||||
}
|
||||
|
||||
Column {
|
||||
@@ -43,7 +104,7 @@ Card {
|
||||
elide: Text.ElideRight
|
||||
width: parent.parent.parent.width - avatarContainer.width - Theme.spacingM * 3
|
||||
}
|
||||
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
@@ -67,7 +128,7 @@ Card {
|
||||
width: parent.parent.parent.parent.width - avatarContainer.width - Theme.spacingM * 3 - 16 - Theme.spacingS
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingS
|
||||
|
||||
@@ -80,7 +141,7 @@ Card {
|
||||
|
||||
StyledText {
|
||||
id: uptimeText
|
||||
|
||||
|
||||
property real availableWidth: parent.parent.parent.parent.width - avatarContainer.width - Theme.spacingM * 3 - 16 - Theme.spacingS
|
||||
property real longTextWidth: {
|
||||
const fontSize = Math.round(Theme.fontSizeSmall || 12)
|
||||
|
||||
@@ -7,59 +7,22 @@ import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
pragma ComponentBehavior: Bound
|
||||
PanelWindow {
|
||||
id: dock
|
||||
|
||||
Variants {
|
||||
id: dockVariants
|
||||
model: SettingsData.getFilteredScreens("dock")
|
||||
WlrLayershell.namespace: "quickshell:dock"
|
||||
|
||||
WlrLayershell.layer: WlrLayershell.Top
|
||||
WlrLayershell.exclusiveZone: -1
|
||||
WlrLayershell.keyboardFocus: WlrKeyboardFocus.None
|
||||
|
||||
property var modelData
|
||||
property var contextMenu
|
||||
|
||||
delegate: PanelWindow {
|
||||
id: dock
|
||||
|
||||
WlrLayershell.namespace: "quickshell:dock"
|
||||
|
||||
readonly property bool isVertical: SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right
|
||||
|
||||
anchors {
|
||||
top: !isVertical ? (SettingsData.dockPosition === SettingsData.Position.Top) : true
|
||||
bottom: !isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom) : true
|
||||
left: !isVertical ? true : (SettingsData.dockPosition === SettingsData.Position.Left)
|
||||
right: !isVertical ? true : (SettingsData.dockPosition === SettingsData.Position.Right)
|
||||
}
|
||||
|
||||
property var modelData: item
|
||||
property bool autoHide: SettingsData.dockAutoHide
|
||||
property real backgroundTransparency: SettingsData.dockTransparency
|
||||
property bool groupByApp: SettingsData.dockGroupByApp
|
||||
|
||||
readonly property real widgetHeight: Math.max(20, 26 + SettingsData.dankBarInnerPadding * 0.6)
|
||||
readonly property real effectiveBarHeight: Math.max(widgetHeight + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
|
||||
readonly property real barSpacing: {
|
||||
const barIsHorizontal = (SettingsData.dankBarPosition === SettingsData.Position.Top || SettingsData.dankBarPosition === SettingsData.Position.Bottom)
|
||||
const barIsVertical = (SettingsData.dankBarPosition === SettingsData.Position.Left || SettingsData.dankBarPosition === SettingsData.Position.Right)
|
||||
const samePosition = (SettingsData.dockPosition === SettingsData.dankBarPosition)
|
||||
const dockIsHorizontal = !isVertical
|
||||
const dockIsVertical = isVertical
|
||||
|
||||
if (!SettingsData.dankBarVisible) return 0
|
||||
if (dockIsHorizontal && barIsHorizontal && samePosition) {
|
||||
return SettingsData.dankBarSpacing + effectiveBarHeight + SettingsData.dankBarBottomGap
|
||||
}
|
||||
if (dockIsVertical && barIsVertical && samePosition) {
|
||||
return SettingsData.dankBarSpacing + effectiveBarHeight + SettingsData.dankBarBottomGap
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
readonly property real dockMargin: SettingsData.dockSpacing
|
||||
readonly property real positionSpacing: barSpacing + SettingsData.dockBottomGap
|
||||
readonly property real _dpr: (dock.screen && dock.screen.devicePixelRatio) ? dock.screen.devicePixelRatio : 1
|
||||
function px(v) { return Math.round(v * _dpr) / _dpr }
|
||||
|
||||
|
||||
property bool contextMenuOpen: (dockVariants.contextMenu && dockVariants.contextMenu.visible && dockVariants.contextMenu.screen === modelData)
|
||||
property bool contextMenuOpen: (contextMenu && contextMenu.visible && contextMenu.screen === modelData)
|
||||
property bool windowIsFullscreen: {
|
||||
if (!ToplevelManager.activeToplevel) {
|
||||
return false
|
||||
@@ -68,28 +31,7 @@ Variants {
|
||||
const fullscreenApps = ["vlc", "mpv", "kodi", "steam", "lutris", "wine", "dosbox"]
|
||||
return fullscreenApps.some(app => activeWindow.appId && activeWindow.appId.toLowerCase().includes(app))
|
||||
}
|
||||
property bool revealSticky: false
|
||||
|
||||
Timer {
|
||||
id: revealHold
|
||||
interval: 250
|
||||
repeat: false
|
||||
onTriggered: dock.revealSticky = false
|
||||
}
|
||||
|
||||
property bool reveal: {
|
||||
if (CompositorService.isNiri && NiriService.inOverview) {
|
||||
return SettingsData.dockOpenOnOverview
|
||||
}
|
||||
return (!autoHide || dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen || revealSticky) && !windowIsFullscreen
|
||||
}
|
||||
|
||||
onContextMenuOpenChanged: {
|
||||
if (!contextMenuOpen && autoHide && !dockMouseArea.containsMouse) {
|
||||
revealSticky = true
|
||||
revealHold.restart()
|
||||
}
|
||||
}
|
||||
property bool reveal: (!autoHide || dockMouseArea.containsMouse || dockApps.requestDockShow || contextMenuOpen) && !windowIsFullscreen
|
||||
|
||||
Connections {
|
||||
target: SettingsData
|
||||
@@ -102,253 +44,152 @@ Variants {
|
||||
visible: SettingsData.showDock
|
||||
color: "transparent"
|
||||
|
||||
|
||||
exclusiveZone: {
|
||||
if (!SettingsData.showDock || autoHide) return -1
|
||||
if (barSpacing > 0) return -1
|
||||
return px(58 + SettingsData.dockSpacing + SettingsData.dockBottomGap)
|
||||
anchors {
|
||||
bottom: true
|
||||
left: true
|
||||
right: true
|
||||
}
|
||||
|
||||
margins {
|
||||
left: 0
|
||||
right: 0
|
||||
}
|
||||
|
||||
implicitHeight: 100
|
||||
exclusiveZone: autoHide ? -1 : 65 - 16
|
||||
|
||||
mask: Region {
|
||||
item: dockMouseArea
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: appTooltip
|
||||
z: 1000
|
||||
MouseArea {
|
||||
id: dockMouseArea
|
||||
property real currentScreen: modelData ? modelData : dock.screen
|
||||
property real screenWidth: currentScreen ? currentScreen.geometry.width : 1920
|
||||
property real maxDockWidth: Math.min(screenWidth * 0.8, 1200)
|
||||
|
||||
property var hoveredButton: {
|
||||
if (!dockApps.children[0]) {
|
||||
return null
|
||||
}
|
||||
const layoutItem = dockApps.children[0]
|
||||
const flowLayout = layoutItem.children[0]
|
||||
let repeater = null
|
||||
for (var i = 0; i < flowLayout.children.length; i++) {
|
||||
const child = flowLayout.children[i]
|
||||
if (child && typeof child.count !== "undefined" && typeof child.itemAt === "function") {
|
||||
repeater = child
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!repeater || !repeater.itemAt) {
|
||||
return null
|
||||
}
|
||||
for (var i = 0; i < repeater.count; i++) {
|
||||
const item = repeater.itemAt(i)
|
||||
if (item && item.dockButton && item.dockButton.showTooltip) {
|
||||
return item.dockButton
|
||||
}
|
||||
}
|
||||
return null
|
||||
height: dock.reveal ? 65 : 20
|
||||
width: dock.reveal ? Math.min(dockBackground.width + 32, maxDockWidth) : Math.min(Math.max(dockBackground.width + 64, 200), screenWidth * 0.5)
|
||||
anchors {
|
||||
bottom: parent.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
hoverEnabled: true
|
||||
|
||||
property string tooltipText: hoveredButton ? hoveredButton.tooltipText : ""
|
||||
|
||||
visible: hoveredButton !== null && tooltipText !== ""
|
||||
width: px(tooltipLabel.implicitWidth + 24)
|
||||
height: px(tooltipLabel.implicitHeight + 12)
|
||||
|
||||
color: Theme.surfaceContainer
|
||||
radius: Theme.cornerRadius
|
||||
border.width: 1
|
||||
border.color: Theme.outlineMedium
|
||||
|
||||
x: {
|
||||
if (!hoveredButton) return 0
|
||||
const buttonPos = hoveredButton.mapToItem(dock.contentItem, 0, 0)
|
||||
if (!dock.isVertical) {
|
||||
return buttonPos.x + hoveredButton.width / 2 - width / 2
|
||||
} else {
|
||||
if (SettingsData.dockPosition === SettingsData.Position.Right) {
|
||||
return buttonPos.x - width - Theme.spacingS
|
||||
} else {
|
||||
return buttonPos.x + hoveredButton.width + Theme.spacingS
|
||||
}
|
||||
}
|
||||
}
|
||||
y: {
|
||||
if (!hoveredButton) return 0
|
||||
const buttonPos = hoveredButton.mapToItem(dock.contentItem, 0, 0)
|
||||
if (!dock.isVertical) {
|
||||
if (SettingsData.dockPosition === SettingsData.Position.Bottom) {
|
||||
return buttonPos.y - height - Theme.spacingS
|
||||
} else {
|
||||
return buttonPos.y + hoveredButton.height + Theme.spacingS
|
||||
}
|
||||
} else {
|
||||
return buttonPos.y + hoveredButton.height / 2 - height / 2
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
id: tooltipLabel
|
||||
anchors.centerIn: parent
|
||||
text: appTooltip.tooltipText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
}
|
||||
Item {
|
||||
id: dockContainer
|
||||
anchors.fill: parent
|
||||
|
||||
Item {
|
||||
id: dockCore
|
||||
anchors.fill: parent
|
||||
transform: Translate {
|
||||
id: dockSlide
|
||||
y: dock.reveal ? 0 : 60
|
||||
|
||||
Connections {
|
||||
target: dockMouseArea
|
||||
function onContainsMouseChanged() {
|
||||
if (dockMouseArea.containsMouse) {
|
||||
dock.revealSticky = true
|
||||
revealHold.stop()
|
||||
} else {
|
||||
if (dock.autoHide && !dock.contextMenuOpen) {
|
||||
revealHold.restart()
|
||||
Behavior on y {
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: dockMouseArea
|
||||
property real currentScreen: modelData ? modelData : dock.screen
|
||||
property real screenWidth: currentScreen ? currentScreen.geometry.width : 1920
|
||||
property real screenHeight: currentScreen ? currentScreen.geometry.height : 1080
|
||||
property real maxDockWidth: Math.min(screenWidth * 0.8, 1200)
|
||||
property real maxDockHeight: Math.min(screenHeight * 0.8, 1200)
|
||||
|
||||
height: {
|
||||
if (dock.isVertical) {
|
||||
return dock.reveal ? Math.min(dockBackground.implicitHeight + 32, maxDockHeight) : Math.min(Math.max(dockBackground.implicitHeight + 64, 200), screenHeight * 0.5)
|
||||
} else {
|
||||
return dock.reveal ? px(58 + SettingsData.dockSpacing + SettingsData.dockBottomGap) : 1
|
||||
Rectangle {
|
||||
id: dockBackground
|
||||
objectName: "dockBackground"
|
||||
anchors {
|
||||
top: parent.top
|
||||
bottom: parent.bottom
|
||||
horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
}
|
||||
width: {
|
||||
if (dock.isVertical) {
|
||||
return dock.reveal ? px(58 + SettingsData.dockSpacing + SettingsData.dockBottomGap) : 1
|
||||
} else {
|
||||
return dock.reveal ? Math.min(dockBackground.implicitWidth + 32, maxDockWidth) : Math.min(Math.max(dockBackground.implicitWidth + 64, 200), screenWidth * 0.5)
|
||||
}
|
||||
}
|
||||
anchors {
|
||||
top: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? undefined : parent.top) : undefined
|
||||
bottom: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? parent.bottom : undefined) : undefined
|
||||
horizontalCenter: !dock.isVertical ? parent.horizontalCenter : undefined
|
||||
left: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? undefined : parent.left) : undefined
|
||||
right: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined) : undefined
|
||||
verticalCenter: dock.isVertical ? parent.verticalCenter : undefined
|
||||
}
|
||||
hoverEnabled: true
|
||||
acceptedButtons: Qt.NoButton
|
||||
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
width: dockApps.implicitWidth + 12
|
||||
height: parent.height - 8
|
||||
|
||||
Behavior on width {
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
anchors.topMargin: 4
|
||||
anchors.bottomMargin: 1
|
||||
|
||||
Item {
|
||||
id: dockContainer
|
||||
anchors.fill: parent
|
||||
|
||||
transform: Translate {
|
||||
id: dockSlide
|
||||
x: {
|
||||
if (!dock.isVertical) return 0
|
||||
if (dock.reveal) return 0
|
||||
if (SettingsData.dockPosition === SettingsData.Position.Right) {
|
||||
return 60
|
||||
} else {
|
||||
return -60
|
||||
}
|
||||
}
|
||||
y: {
|
||||
if (dock.isVertical) return 0
|
||||
if (dock.reveal) return 0
|
||||
if (SettingsData.dockPosition === SettingsData.Position.Bottom) {
|
||||
return 60
|
||||
} else {
|
||||
return -60
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on x {
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on y {
|
||||
NumberAnimation {
|
||||
duration: 200
|
||||
easing.type: Easing.OutCubic
|
||||
}
|
||||
}
|
||||
}
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, backgroundTransparency)
|
||||
radius: Theme.cornerRadius
|
||||
border.width: 1
|
||||
border.color: Theme.outlineMedium
|
||||
layer.enabled: true
|
||||
|
||||
Rectangle {
|
||||
id: dockBackground
|
||||
objectName: "dockBackground"
|
||||
anchors {
|
||||
top: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? undefined : parent.top) : undefined
|
||||
bottom: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? parent.bottom : undefined) : undefined
|
||||
horizontalCenter: !dock.isVertical ? parent.horizontalCenter : undefined
|
||||
left: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? undefined : parent.left) : undefined
|
||||
right: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? parent.right : undefined) : undefined
|
||||
verticalCenter: dock.isVertical ? parent.verticalCenter : undefined
|
||||
}
|
||||
anchors.topMargin: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? 0 : barSpacing + 4) : 0
|
||||
anchors.bottomMargin: !dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Bottom ? barSpacing + 1 : 0) : 0
|
||||
anchors.leftMargin: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? 0 : barSpacing + 4) : 0
|
||||
anchors.rightMargin: dock.isVertical ? (SettingsData.dockPosition === SettingsData.Position.Right ? barSpacing + 1 : 0) : 0
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g, Theme.surfaceTint.b, 0.04)
|
||||
radius: parent.radius
|
||||
}
|
||||
|
||||
implicitWidth: dock.isVertical ? (dockApps.implicitHeight + SettingsData.dockSpacing * 2) : (dockApps.implicitWidth + SettingsData.dockSpacing * 2)
|
||||
implicitHeight: dock.isVertical ? (dockApps.implicitWidth + SettingsData.dockSpacing * 2) : (dockApps.implicitHeight + SettingsData.dockSpacing * 2)
|
||||
width: implicitWidth
|
||||
height: implicitHeight
|
||||
DockApps {
|
||||
id: dockApps
|
||||
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, backgroundTransparency)
|
||||
radius: Theme.cornerRadius
|
||||
border.width: 1
|
||||
border.color: Theme.outlineMedium
|
||||
layer.enabled: true
|
||||
anchors.top: parent.top
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
anchors.topMargin: 4
|
||||
anchors.bottomMargin: 4
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
color: Qt.rgba(Theme.surfaceTint.r, Theme.surfaceTint.g, Theme.surfaceTint.b, 0.04)
|
||||
radius: parent.radius
|
||||
}
|
||||
|
||||
DockApps {
|
||||
id: dockApps
|
||||
|
||||
anchors.top: !dock.isVertical ? parent.top : undefined
|
||||
anchors.bottom: !dock.isVertical ? parent.bottom : undefined
|
||||
anchors.horizontalCenter: !dock.isVertical ? parent.horizontalCenter : undefined
|
||||
anchors.left: dock.isVertical ? parent.left : undefined
|
||||
anchors.right: dock.isVertical ? parent.right : undefined
|
||||
anchors.verticalCenter: dock.isVertical ? parent.verticalCenter : undefined
|
||||
anchors.topMargin: !dock.isVertical ? SettingsData.dockSpacing : 0
|
||||
anchors.bottomMargin: !dock.isVertical ? SettingsData.dockSpacing : 0
|
||||
anchors.leftMargin: dock.isVertical ? SettingsData.dockSpacing : 0
|
||||
anchors.rightMargin: dock.isVertical ? SettingsData.dockSpacing : 0
|
||||
|
||||
contextMenu: dockVariants.contextMenu
|
||||
groupByApp: dock.groupByApp
|
||||
isVertical: dock.isVertical
|
||||
}
|
||||
contextMenu: dock.contextMenu
|
||||
groupByApp: dock.groupByApp
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
id: appTooltip
|
||||
|
||||
property var hoveredButton: {
|
||||
if (!dockApps.children[0]) {
|
||||
return null
|
||||
}
|
||||
const row = dockApps.children[0]
|
||||
let repeater = null
|
||||
for (var i = 0; i < row.children.length; i++) {
|
||||
const child = row.children[i]
|
||||
if (child && typeof child.count !== "undefined" && typeof child.itemAt === "function") {
|
||||
repeater = child
|
||||
break
|
||||
}
|
||||
}
|
||||
if (!repeater || !repeater.itemAt) {
|
||||
return null
|
||||
}
|
||||
for (var i = 0; i < repeater.count; i++) {
|
||||
const item = repeater.itemAt(i)
|
||||
if (item && item.dockButton && item.dockButton.showTooltip) {
|
||||
return item.dockButton
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
property string tooltipText: hoveredButton ? hoveredButton.tooltipText : ""
|
||||
|
||||
visible: hoveredButton !== null && tooltipText !== ""
|
||||
width: tooltipLabel.implicitWidth + 24
|
||||
height: tooltipLabel.implicitHeight + 12
|
||||
|
||||
color: Theme.surfaceContainer
|
||||
radius: Theme.cornerRadius
|
||||
border.width: 1
|
||||
border.color: Theme.outlineMedium
|
||||
|
||||
y: -height - 8
|
||||
x: hoveredButton ? hoveredButton.mapToItem(dockContainer, hoveredButton.width / 2, 0).x - width / 2 : 0
|
||||
|
||||
StyledText {
|
||||
id: tooltipLabel
|
||||
anchors.centerIn: parent
|
||||
text: appTooltip.tooltipText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,27 +25,6 @@ Item {
|
||||
property string windowTitle: ""
|
||||
property bool isHovered: mouseArea.containsMouse && !dragging
|
||||
property bool showTooltip: mouseArea.containsMouse && !dragging
|
||||
property var cachedDesktopEntry: null
|
||||
|
||||
function updateDesktopEntry() {
|
||||
if (!appData || appData.appId === "__SEPARATOR__") {
|
||||
cachedDesktopEntry = null
|
||||
return
|
||||
}
|
||||
const moddedId = Paths.moddedAppId(appData.appId)
|
||||
cachedDesktopEntry = DesktopEntries.heuristicLookup(moddedId)
|
||||
}
|
||||
|
||||
Component.onCompleted: updateDesktopEntry()
|
||||
|
||||
onAppDataChanged: updateDesktopEntry()
|
||||
|
||||
Connections {
|
||||
target: DesktopEntries
|
||||
function onApplicationsChanged() {
|
||||
updateDesktopEntry()
|
||||
}
|
||||
}
|
||||
property bool isWindowFocused: {
|
||||
if (!appData) {
|
||||
return false
|
||||
@@ -76,7 +55,8 @@ Item {
|
||||
}
|
||||
|
||||
if ((appData.type === "window" && showWindowTitle) || (appData.type === "grouped" && appData.windowTitle)) {
|
||||
const appName = cachedDesktopEntry && cachedDesktopEntry.name ? cachedDesktopEntry.name : appData.appId
|
||||
const desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
|
||||
const appName = desktopEntry && desktopEntry.name ? desktopEntry.name : appData.appId
|
||||
const title = appData.type === "window" ? windowTitle : appData.windowTitle
|
||||
return appName + (title ? " • " + title : "")
|
||||
}
|
||||
@@ -85,7 +65,8 @@ Item {
|
||||
return ""
|
||||
}
|
||||
|
||||
return cachedDesktopEntry && cachedDesktopEntry.name ? cachedDesktopEntry.name : appData.appId
|
||||
const desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
|
||||
return desktopEntry && desktopEntry.name ? desktopEntry.name : appData.appId
|
||||
}
|
||||
|
||||
width: 40
|
||||
@@ -274,7 +255,7 @@ Item {
|
||||
if (mouse.button === Qt.LeftButton) {
|
||||
if (appData.type === "pinned") {
|
||||
if (appData && appData.appId) {
|
||||
const desktopEntry = cachedDesktopEntry
|
||||
const desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
|
||||
if (desktopEntry) {
|
||||
AppUsageHistoryData.addAppUsage({
|
||||
"id": appData.appId,
|
||||
@@ -294,7 +275,7 @@ Item {
|
||||
} else if (appData.type === "grouped") {
|
||||
if (appData.windowCount === 0) {
|
||||
if (appData && appData.appId) {
|
||||
const desktopEntry = cachedDesktopEntry
|
||||
const desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
|
||||
if (desktopEntry) {
|
||||
AppUsageHistoryData.addAppUsage({
|
||||
"id": appData.appId,
|
||||
@@ -324,7 +305,7 @@ Item {
|
||||
}
|
||||
} else if (mouse.button === Qt.MiddleButton) {
|
||||
if (appData && appData.appId) {
|
||||
const desktopEntry = cachedDesktopEntry
|
||||
const desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
|
||||
if (desktopEntry) {
|
||||
AppUsageHistoryData.addAppUsage({
|
||||
"id": appData.appId,
|
||||
@@ -360,7 +341,8 @@ Item {
|
||||
if (moddedId.toLowerCase().includes("steam_app")) {
|
||||
return ""
|
||||
}
|
||||
return cachedDesktopEntry && cachedDesktopEntry.icon ? Quickshell.iconPath(cachedDesktopEntry.icon, true) : ""
|
||||
const desktopEntry = DesktopEntries.heuristicLookup(moddedId)
|
||||
return desktopEntry && desktopEntry.icon ? Quickshell.iconPath(desktopEntry.icon, true) : ""
|
||||
}
|
||||
mipmap: true
|
||||
smooth: true
|
||||
@@ -399,7 +381,7 @@ Item {
|
||||
return "?"
|
||||
}
|
||||
|
||||
const desktopEntry = cachedDesktopEntry
|
||||
const desktopEntry = DesktopEntries.heuristicLookup(appData.appId)
|
||||
if (desktopEntry && desktopEntry.name) {
|
||||
return desktopEntry.name.charAt(0).toUpperCase()
|
||||
}
|
||||
|
||||
@@ -13,10 +13,9 @@ Item {
|
||||
property bool requestDockShow: false
|
||||
property int pinnedAppCount: 0
|
||||
property bool groupByApp: false
|
||||
property bool isVertical: false
|
||||
|
||||
implicitWidth: isVertical ? appLayout.height : appLayout.width
|
||||
implicitHeight: isVertical ? appLayout.width : appLayout.height
|
||||
implicitWidth: row.width
|
||||
implicitHeight: row.height
|
||||
|
||||
function movePinnedApp(fromIndex, toIndex) {
|
||||
if (fromIndex === toIndex) {
|
||||
@@ -34,16 +33,11 @@ Item {
|
||||
SessionData.setPinnedApps(currentPinned)
|
||||
}
|
||||
|
||||
Item {
|
||||
id: appLayout
|
||||
Row {
|
||||
id: row
|
||||
spacing: 2
|
||||
anchors.centerIn: parent
|
||||
width: layoutFlow.width
|
||||
height: layoutFlow.height
|
||||
|
||||
Flow {
|
||||
id: layoutFlow
|
||||
flow: root.isVertical ? Flow.TopToBottom : Flow.LeftToRight
|
||||
spacing: 8
|
||||
height: 40
|
||||
|
||||
Repeater {
|
||||
id: repeater
|
||||
@@ -224,7 +218,6 @@ Item {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
|
||||
@@ -92,41 +92,17 @@ PanelWindow {
|
||||
}
|
||||
|
||||
const dockBackground = findDockBackground(dockWindow.contentItem)
|
||||
let actualDockWidth = dockWindow.width
|
||||
if (dockBackground) {
|
||||
actualDockHeight = dockBackground.height
|
||||
actualDockWidth = dockBackground.width
|
||||
}
|
||||
|
||||
const isVertical = SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right
|
||||
const dockMargin = 16
|
||||
let buttonScreenX, buttonScreenY
|
||||
const dockBottomMargin = 16
|
||||
const buttonScreenY = root.screen.height - actualDockHeight - dockBottomMargin - 20
|
||||
|
||||
if (isVertical) {
|
||||
const dockContentHeight = dockWindow.height
|
||||
const screenHeight = root.screen.height
|
||||
const dockTopMargin = Math.round((screenHeight - dockContentHeight) / 2)
|
||||
buttonScreenY = dockTopMargin + buttonPosInDock.y + anchorItem.height / 2
|
||||
|
||||
if (SettingsData.dockPosition === SettingsData.Position.Right) {
|
||||
buttonScreenX = root.screen.width - actualDockWidth - dockMargin - 20
|
||||
} else {
|
||||
buttonScreenX = actualDockWidth + dockMargin + 20
|
||||
}
|
||||
} else {
|
||||
const isDockAtBottom = SettingsData.dockPosition === SettingsData.Position.Bottom
|
||||
|
||||
if (isDockAtBottom) {
|
||||
buttonScreenY = root.screen.height - actualDockHeight - dockMargin - 20
|
||||
} else {
|
||||
buttonScreenY = actualDockHeight + dockMargin + 20
|
||||
}
|
||||
|
||||
const dockContentWidth = dockWindow.width
|
||||
const screenWidth = root.screen.width
|
||||
const dockLeftMargin = Math.round((screenWidth - dockContentWidth) / 2)
|
||||
buttonScreenX = dockLeftMargin + buttonPosInDock.x + anchorItem.width / 2
|
||||
}
|
||||
const dockContentWidth = dockWindow.width
|
||||
const screenWidth = root.screen.width
|
||||
const dockLeftMargin = Math.round((screenWidth - dockContentWidth) / 2)
|
||||
const buttonScreenX = dockLeftMargin + buttonPosInDock.x + anchorItem.width / 2
|
||||
|
||||
anchorPos = Qt.point(buttonScreenX, buttonScreenY)
|
||||
}
|
||||
@@ -138,37 +114,12 @@ PanelWindow {
|
||||
height: Math.max(60, menuColumn.implicitHeight + Theme.spacingS * 2)
|
||||
|
||||
x: {
|
||||
const isVertical = SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right
|
||||
if (isVertical) {
|
||||
const isDockAtRight = SettingsData.dockPosition === SettingsData.Position.Right
|
||||
if (isDockAtRight) {
|
||||
return Math.max(10, root.anchorPos.x - width + 30)
|
||||
} else {
|
||||
return Math.min(root.width - width - 10, root.anchorPos.x - 30)
|
||||
}
|
||||
} else {
|
||||
const left = 10
|
||||
const right = root.width - width - 10
|
||||
const want = root.anchorPos.x - width / 2
|
||||
return Math.max(left, Math.min(right, want))
|
||||
}
|
||||
}
|
||||
y: {
|
||||
const isVertical = SettingsData.dockPosition === SettingsData.Position.Left || SettingsData.dockPosition === SettingsData.Position.Right
|
||||
if (isVertical) {
|
||||
const top = 10
|
||||
const bottom = root.height - height - 10
|
||||
const want = root.anchorPos.y - height / 2
|
||||
return Math.max(top, Math.min(bottom, want))
|
||||
} else {
|
||||
const isDockAtBottom = SettingsData.dockPosition === SettingsData.Position.Bottom
|
||||
if (isDockAtBottom) {
|
||||
return Math.max(10, root.anchorPos.y - height + 30)
|
||||
} else {
|
||||
return Math.min(root.height - height - 10, root.anchorPos.y - 30)
|
||||
}
|
||||
}
|
||||
const left = 10
|
||||
const right = root.width - width - 10
|
||||
const want = root.anchorPos.x - width / 2
|
||||
return Math.max(left, Math.min(right, want))
|
||||
}
|
||||
y: Math.max(10, root.anchorPos.y - height + 30)
|
||||
color: Theme.popupBackground()
|
||||
radius: Theme.cornerRadius
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtCore
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property string greetCfgDir: Quickshell.env("DMS_GREET_CFG_DIR") || "/etc/greetd/.dms"
|
||||
readonly property string sessionConfigPath: greetCfgDir + "/session.json"
|
||||
readonly property string memoryFile: greetCfgDir + "/memory.json"
|
||||
|
||||
property string lastSessionId: ""
|
||||
property string lastSuccessfulUser: ""
|
||||
property bool isLightMode: false
|
||||
property bool nightModeEnabled: false
|
||||
|
||||
Component.onCompleted: {
|
||||
Quickshell.execDetached(["mkdir", "-p", greetCfgDir])
|
||||
loadMemory()
|
||||
loadSessionConfig()
|
||||
}
|
||||
|
||||
function loadMemory() {
|
||||
parseMemory(memoryFileView.text())
|
||||
}
|
||||
|
||||
function loadSessionConfig() {
|
||||
parseSessionConfig(sessionConfigFileView.text())
|
||||
}
|
||||
|
||||
function parseSessionConfig(content) {
|
||||
try {
|
||||
if (content && content.trim()) {
|
||||
const config = JSON.parse(content)
|
||||
isLightMode = config.isLightMode !== undefined ? config.isLightMode : false
|
||||
nightModeEnabled = config.nightModeEnabled !== undefined ? config.nightModeEnabled : false
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Failed to parse greeter session config:", e)
|
||||
}
|
||||
}
|
||||
|
||||
function parseMemory(content) {
|
||||
try {
|
||||
if (content && content.trim()) {
|
||||
const memory = JSON.parse(content)
|
||||
lastSessionId = memory.lastSessionId !== undefined ? memory.lastSessionId : ""
|
||||
lastSuccessfulUser = memory.lastSuccessfulUser !== undefined ? memory.lastSuccessfulUser : ""
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Failed to parse greetd memory:", e)
|
||||
}
|
||||
}
|
||||
|
||||
function saveMemory() {
|
||||
memoryFileView.setText(JSON.stringify({
|
||||
"lastSessionId": lastSessionId,
|
||||
"lastSuccessfulUser": lastSuccessfulUser
|
||||
}, null, 2))
|
||||
}
|
||||
|
||||
function setLastSessionId(id) {
|
||||
lastSessionId = id || ""
|
||||
saveMemory()
|
||||
}
|
||||
|
||||
function setLastSuccessfulUser(username) {
|
||||
lastSuccessfulUser = username || ""
|
||||
saveMemory()
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: memoryFileView
|
||||
path: root.memoryFile
|
||||
blockLoading: false
|
||||
blockWrites: false
|
||||
atomicWrites: true
|
||||
watchChanges: false
|
||||
printErrors: false
|
||||
onLoaded: {
|
||||
parseMemory(memoryFileView.text())
|
||||
}
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: sessionConfigFileView
|
||||
path: root.sessionConfigPath
|
||||
blockLoading: false
|
||||
blockWrites: true
|
||||
atomicWrites: false
|
||||
watchChanges: false
|
||||
printErrors: true
|
||||
onLoaded: {
|
||||
parseSessionConfig(sessionConfigFileView.text())
|
||||
}
|
||||
onLoadFailed: error => {
|
||||
console.warn("Could not load greeter session config from", root.sessionConfigPath, "error:", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
import QtCore
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Io
|
||||
import qs.Common
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
readonly property string configPath: {
|
||||
const greetCfgDir = Quickshell.env("DMS_GREET_CFG_DIR") || "/etc/greetd/.dms"
|
||||
return greetCfgDir + "/settings.json"
|
||||
}
|
||||
|
||||
property string currentThemeName: "blue"
|
||||
property bool settingsLoaded: false
|
||||
property string customThemeFile: ""
|
||||
property string matugenScheme: "scheme-tonal-spot"
|
||||
property bool use24HourClock: true
|
||||
property bool useFahrenheit: false
|
||||
property bool nightModeEnabled: false
|
||||
property string weatherLocation: "New York, NY"
|
||||
property string weatherCoordinates: "40.7128,-74.0060"
|
||||
property bool useAutoLocation: false
|
||||
property bool weatherEnabled: true
|
||||
property string iconTheme: "System Default"
|
||||
property bool useOSLogo: false
|
||||
property string osLogoColorOverride: ""
|
||||
property real osLogoBrightness: 0.5
|
||||
property real osLogoContrast: 1
|
||||
property string fontFamily: "Inter Variable"
|
||||
property string monoFontFamily: "Fira Code"
|
||||
property int fontWeight: Font.Normal
|
||||
property real fontScale: 1.0
|
||||
property real cornerRadius: 12
|
||||
property string widgetBackgroundColor: "sch"
|
||||
property string surfaceBase: "s"
|
||||
property string lockDateFormat: ""
|
||||
property bool lockScreenShowPowerActions: true
|
||||
property var screenPreferences: ({})
|
||||
property int animationSpeed: 2
|
||||
|
||||
readonly property string defaultFontFamily: "Inter Variable"
|
||||
readonly property string defaultMonoFontFamily: "Fira Code"
|
||||
|
||||
function parseSettings(content) {
|
||||
try {
|
||||
if (content && content.trim()) {
|
||||
const settings = JSON.parse(content)
|
||||
currentThemeName = settings.currentThemeName !== undefined ? settings.currentThemeName : "blue"
|
||||
customThemeFile = settings.customThemeFile !== undefined ? settings.customThemeFile : ""
|
||||
matugenScheme = settings.matugenScheme !== undefined ? settings.matugenScheme : "scheme-tonal-spot"
|
||||
use24HourClock = settings.use24HourClock !== undefined ? settings.use24HourClock : true
|
||||
useFahrenheit = settings.useFahrenheit !== undefined ? settings.useFahrenheit : false
|
||||
nightModeEnabled = settings.nightModeEnabled !== undefined ? settings.nightModeEnabled : false
|
||||
weatherLocation = settings.weatherLocation !== undefined ? settings.weatherLocation : "New York, NY"
|
||||
weatherCoordinates = settings.weatherCoordinates !== undefined ? settings.weatherCoordinates : "40.7128,-74.0060"
|
||||
useAutoLocation = settings.useAutoLocation !== undefined ? settings.useAutoLocation : false
|
||||
weatherEnabled = settings.weatherEnabled !== undefined ? settings.weatherEnabled : true
|
||||
iconTheme = settings.iconTheme !== undefined ? settings.iconTheme : "System Default"
|
||||
useOSLogo = settings.useOSLogo !== undefined ? settings.useOSLogo : false
|
||||
osLogoColorOverride = settings.osLogoColorOverride !== undefined ? settings.osLogoColorOverride : ""
|
||||
osLogoBrightness = settings.osLogoBrightness !== undefined ? settings.osLogoBrightness : 0.5
|
||||
osLogoContrast = settings.osLogoContrast !== undefined ? settings.osLogoContrast : 1
|
||||
fontFamily = settings.fontFamily !== undefined ? settings.fontFamily : defaultFontFamily
|
||||
monoFontFamily = settings.monoFontFamily !== undefined ? settings.monoFontFamily : defaultMonoFontFamily
|
||||
fontWeight = settings.fontWeight !== undefined ? settings.fontWeight : Font.Normal
|
||||
fontScale = settings.fontScale !== undefined ? settings.fontScale : 1.0
|
||||
cornerRadius = settings.cornerRadius !== undefined ? settings.cornerRadius : 12
|
||||
widgetBackgroundColor = settings.widgetBackgroundColor !== undefined ? settings.widgetBackgroundColor : "sch"
|
||||
surfaceBase = settings.surfaceBase !== undefined ? settings.surfaceBase : "s"
|
||||
lockDateFormat = settings.lockDateFormat !== undefined ? settings.lockDateFormat : ""
|
||||
lockScreenShowPowerActions = settings.lockScreenShowPowerActions !== undefined ? settings.lockScreenShowPowerActions : true
|
||||
screenPreferences = settings.screenPreferences !== undefined ? settings.screenPreferences : ({})
|
||||
animationSpeed = settings.animationSpeed !== undefined ? settings.animationSpeed : 2
|
||||
settingsLoaded = true
|
||||
|
||||
if (typeof Theme !== "undefined") {
|
||||
Theme.applyGreeterTheme(currentThemeName)
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn("Failed to parse greetd settings:", e)
|
||||
}
|
||||
}
|
||||
|
||||
function getEffectiveLockDateFormat() {
|
||||
return lockDateFormat && lockDateFormat.length > 0 ? lockDateFormat : Locale.LongFormat
|
||||
}
|
||||
|
||||
function getFilteredScreens(componentId) {
|
||||
const prefs = screenPreferences && screenPreferences[componentId] || ["all"]
|
||||
if (prefs.includes("all")) {
|
||||
return Quickshell.screens
|
||||
}
|
||||
return Quickshell.screens.filter(screen => prefs.includes(screen.name))
|
||||
}
|
||||
|
||||
FileView {
|
||||
id: settingsFile
|
||||
path: root.configPath
|
||||
blockLoading: false
|
||||
blockWrites: true
|
||||
atomicWrites: false
|
||||
watchChanges: false
|
||||
printErrors: true
|
||||
onLoaded: {
|
||||
parseSettings(settingsFile.text())
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,29 +0,0 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
pragma Singleton
|
||||
pragma ComponentBehavior: Bound
|
||||
|
||||
Singleton {
|
||||
id: root
|
||||
|
||||
property string passwordBuffer: ""
|
||||
property string username: ""
|
||||
property string usernameInput: ""
|
||||
property bool showPasswordInput: false
|
||||
property string selectedSession: ""
|
||||
property string pamState: ""
|
||||
property bool unlocking: false
|
||||
|
||||
property var sessionList: []
|
||||
property var sessionExecs: []
|
||||
property var sessionPaths: []
|
||||
property int currentSessionIndex: 0
|
||||
|
||||
function reset() {
|
||||
showPasswordInput = false
|
||||
username = ""
|
||||
usernameInput = ""
|
||||
passwordBuffer = ""
|
||||
pamState = ""
|
||||
}
|
||||
}
|
||||
@@ -1,18 +0,0 @@
|
||||
import QtQuick
|
||||
import Quickshell
|
||||
import Quickshell.Wayland
|
||||
import Quickshell.Services.Greetd
|
||||
|
||||
WlSessionLockSurface {
|
||||
id: root
|
||||
|
||||
required property WlSessionLock lock
|
||||
|
||||
color: "transparent"
|
||||
|
||||
GreeterContent {
|
||||
anchors.fill: parent
|
||||
screenName: root.screen?.name ?? ""
|
||||
sessionLock: root.lock
|
||||
}
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
# Dank (dms) Greeter
|
||||
|
||||
A greeter for [greetd](https://github.com/kennylevinsen/greetd) that follows the aesthetics of the dms lock screen.
|
||||
|
||||
## Features
|
||||
|
||||
- **Multi user**: Login with any system user
|
||||
- **dms sync**: Sync settings with dms for consistent styling between shell and greeter
|
||||
- **niri or Hyprland**: Use either niri or Hyprland for the greeter's compositor.
|
||||
- **Custom PAM**: Supports custom PAM configuration in `/etc/pam.d/dankshell`
|
||||
- **Session Memory**: Remembers last selected session and user
|
||||
|
||||
## Installation
|
||||
|
||||
The easiest thing is to run `dms greeter install` or `dms` for interactive installation.
|
||||
|
||||
Manual installation:
|
||||
1. Install `greetd` (in most distro's standard repositories)
|
||||
2. Copy `assets/dms-niri.kdl` or `assets/dms-hypr.conf` to `/etc/greetd`
|
||||
- niri if you want to run the greeter under niri, hypr if you want to run the greeter under Hyprland
|
||||
3. Copy `assets/greet-niri.sh` or `assets/greet-hyprland.sh` to `/usr/local/bin/start-dms-greetd.sh`
|
||||
4. Edit `/etc/greetd/dms-niri.kdl` or `/etc/greetd/dms-hypr.conf` and replace `_DMS_PATH_` with the absolute path to dms, e.g. `/home/joecool/.config/quickshell/dms`
|
||||
5. Edit or create `/etc/greetd/config.toml`
|
||||
```toml
|
||||
[terminal]
|
||||
# The VT to run the greeter on. Can be "next", "current" or a number
|
||||
# designating the VT.
|
||||
vt = 1
|
||||
|
||||
# The default session, also known as the greeter.
|
||||
[default_session]
|
||||
|
||||
# `agreety` is the bundled agetty/login-lookalike. You can replace `/bin/sh`
|
||||
# with whatever you want started, such as `sway`.
|
||||
|
||||
# The user to run the command as. The privileges this user must have depends
|
||||
# on the greeter. A graphical greeter may for example require the user to be
|
||||
# in the `video` group.
|
||||
user = "greeter"
|
||||
|
||||
command = "/usr/local/bin/start-dms-greetd.sh"
|
||||
```
|
||||
|
||||
Enable the greeter with `sudo systemctl enable greetd`
|
||||
|
||||
## Usage
|
||||
|
||||
To run dms in greeter mode you just need to set `DMS_RUN_GREETER=1` in the environment.
|
||||
|
||||
```bash
|
||||
DMS_RUN_GREETER=1 qs -p /path/to/dms
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
#### Compositor
|
||||
|
||||
You can configure compositor specific settings such as outputs/displays the same as you would in niri or Hyprland.
|
||||
|
||||
Simply edit `/etc/greetd/dms-niri.kdl` or `/etc/greetd/dms-hypr.conf` to change compositor settings for the greeter
|
||||
|
||||
#### Personalization
|
||||
|
||||
Wallpapers and themes and weather and clock formats and things are a TODO on the documentation, but it's configured exactly the same as dms.
|
||||
|
||||
You can synchronize those configurations with a specific user if you want greeter settings to always mirror the shell.
|
||||
|
||||
```bash
|
||||
# For core settings (theme, clock formats, etc)
|
||||
sudo ln -sf ~/.config/DankMaterialShell/settings.json /etc/greetd/.dms/settings.json
|
||||
# For state (mainly you would configure wallpaper in this file)
|
||||
sudo ln -sf ~/.local/state/DankMaterialShell/session.json /etc/greetd/.dms/session.json
|
||||
# For wallpaper based theming
|
||||
sudo ln -sf ~/.cache/quickshell/dankshell/dms-colors.json /etc/greetd/.dms/dms-colors.json
|
||||
```
|
||||
|
||||
You can override the configuration path with the `DMS_GREET_CFG_DIR` environment variable, the default is `/etc/greetd/.dms`
|
||||
|
||||
It should be writable by the greeter user.
|
||||
@@ -1,3 +0,0 @@
|
||||
env = DMS_RUN_GREETER,1
|
||||
|
||||
exec = sh -c "qs -p _DMS_PATH_; hyprctl dispatch exit"
|
||||
@@ -1,19 +0,0 @@
|
||||
hotkey-overlay {
|
||||
skip-at-startup
|
||||
}
|
||||
|
||||
environment {
|
||||
DMS_RUN_GREETER "1"
|
||||
}
|
||||
|
||||
spawn-at-startup "sh" "-c" "qs -p _DMS_PATH_; niri msg action quit --skip-confirmation"
|
||||
|
||||
debug {
|
||||
keep-max-bpc-unchanged
|
||||
}
|
||||
|
||||
gestures {
|
||||
hot-corners {
|
||||
off
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export XDG_SESSION_TYPE=wayland
|
||||
export QT_QPA_PLATFORM=wayland
|
||||
export QT_WAYLAND_DISABLE_WINDOWDECORATION=1
|
||||
export EGL_PLATFORM=gbm
|
||||
|
||||
exec Hyprland -c /etc/greetd/dms-hypr.conf
|
||||
@@ -1,8 +0,0 @@
|
||||
#!/bin/sh
|
||||
|
||||
export XDG_SESSION_TYPE=wayland
|
||||
export QT_QPA_PLATFORM=wayland
|
||||
export QT_WAYLAND_DISABLE_WINDOWDECORATION=1
|
||||
export EGL_PLATFORM=gbm
|
||||
|
||||
exec niri -c /etc/greetd/dms-niri.kdl
|
||||
@@ -20,9 +20,6 @@ Item {
|
||||
property bool unlocking: false
|
||||
property string pamState: ""
|
||||
property string randomFact: ""
|
||||
property string hyprlandCurrentLayout: ""
|
||||
property string hyprlandKeyboard: ""
|
||||
property int hyprlandLayoutCount: 0
|
||||
|
||||
signal unlockRequested
|
||||
|
||||
@@ -47,8 +44,10 @@ Item {
|
||||
powerDialogVisible = false
|
||||
}
|
||||
|
||||
property var facts: ["A photon takes 100,000 to 200,000 years bouncing through the Sun's dense core, then races to Earth in just 8 minutes 20 seconds.", "A teaspoon of neutron star matter would weigh a billion metric tons here on Earth.", "Right now, 100 trillion solar neutrinos are passing through your body every second.", "The Sun converts 4 million metric tons of matter into pure energy every second—enough to power Earth for 500,000 years.", "The universe still glows with leftover heat from the Big Bang—just 2.7 degrees above absolute zero.", "There's a nebula out there that's actually colder than empty space itself.", "We've detected black holes crashing together by measuring spacetime stretch by less than 1/10,000th the width of a proton.", "Fast radio bursts can release more energy in 5 milliseconds than our Sun produces in 3 days.", "Our galaxy might be crawling with billions of rogue planets drifting alone in the dark.", "Distant galaxies can move away from us faster than light because space itself is stretching.", "The edge of what we can see is 46.5 billion light-years away, even though the universe is only 13.8 billion years old.", "The universe is mostly invisible: 5% regular matter, 27% dark matter, 68% dark energy.", "A day on Venus lasts longer than its entire year around the Sun.", "On Mercury, the time between sunrises is 176 Earth days long.", "In about 4.5 billion years, our galaxy will smash into Andromeda.", "Most of the gold in your jewelry was forged when neutron stars collided somewhere in space.", "PSR J1748-2446ad, the fastest spinning star, rotates 716 times per second—its equator moves at 24% the speed of light.", "Cosmic rays create particles that shouldn't make it to Earth's surface, but time dilation lets them sneak through.", "Jupiter's magnetic field is so huge that if we could see it, it would look bigger than the Moon in our sky.", "Interstellar space is so empty it's like a cube 32 kilometers wide containing just a single grain of sand.", "Voyager 1 is 24 billion kilometers away but won't leave the Sun's gravitational influence for another 30,000 years.", "Counting to a billion at one number per second would take over 31 years.", "Space is so vast, even speeding at light-speed, you'd never return past the cosmic horizon.", "Astronauts on the ISS age about 0.01 seconds less each year than people on Earth.", "Sagittarius B2, a dust cloud near our galaxy's center, contains ethyl formate—the compound that gives raspberries their flavor and rum its smell.", "Beyond 16 billion light-years, the cosmic event horizon marks where space expands too fast for light to ever reach us again.", "Even at light-speed, you'd never catch up to most galaxies—space expands faster.", "Only around 5% of galaxies are ever reachable—even at light-speed.", "If the Sun vanished, we'd still orbit it for 8 minutes before drifting away.", "If a planet 65 million light-years away looked at Earth now, it'd see dinosaurs.", "Our oldest radio signals will reach the Milky Way's center in 26,000 years.", "Every atom in your body heavier than hydrogen was forged in the nuclear furnace of a dying star.", "The Moon moves 3.8 centimeters farther from Earth every year.", "The universe creates 275 million new stars every single day.", "Jupiter's Great Red Spot is a storm twice the size of Earth that has been raging for at least 350 years.", "If you watched someone fall into a black hole, they'd appear frozen at the event horizon forever—time effectively stops from your perspective.", "The Boötes Supervoid is a cosmic desert 1.8 billion light-years across with 60% fewer galaxies than it should have."]
|
||||
|
||||
function pickRandomFact() {
|
||||
randomFact = Facts.getRandomFact()
|
||||
randomFact = facts[Math.floor(Math.random() * facts.length)]
|
||||
}
|
||||
|
||||
Component.onCompleted: {
|
||||
@@ -58,11 +57,6 @@ Item {
|
||||
|
||||
WeatherService.addRef()
|
||||
UserInfoService.refreshUserInfo()
|
||||
|
||||
if (CompositorService.isHyprland) {
|
||||
updateHyprlandLayout()
|
||||
hyprlandLayoutUpdateTimer.start()
|
||||
}
|
||||
}
|
||||
onDemoModeChanged: {
|
||||
if (demoMode) {
|
||||
@@ -71,56 +65,6 @@ Item {
|
||||
}
|
||||
Component.onDestruction: {
|
||||
WeatherService.removeRef()
|
||||
if (CompositorService.isHyprland) {
|
||||
hyprlandLayoutUpdateTimer.stop()
|
||||
}
|
||||
}
|
||||
|
||||
function updateHyprlandLayout() {
|
||||
if (CompositorService.isHyprland) {
|
||||
hyprlandLayoutProcess.running = true
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: hyprlandLayoutProcess
|
||||
running: false
|
||||
command: ["hyprctl", "-j", "devices"]
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
try {
|
||||
const data = JSON.parse(text)
|
||||
const mainKeyboard = data.keyboards.find(kb => kb.main === true)
|
||||
hyprlandKeyboard = mainKeyboard.name
|
||||
if (mainKeyboard && mainKeyboard.active_keymap) {
|
||||
const parts = mainKeyboard.active_keymap.split(" ")
|
||||
if (parts.length > 0) {
|
||||
hyprlandCurrentLayout = parts[0].substring(0, 2).toUpperCase()
|
||||
} else {
|
||||
hyprlandCurrentLayout = mainKeyboard.active_keymap.substring(0, 2).toUpperCase()
|
||||
}
|
||||
} else {
|
||||
hyprlandCurrentLayout = ""
|
||||
}
|
||||
if (mainKeyboard && mainKeyboard.layout_names) {
|
||||
hyprlandLayoutCount = mainKeyboard.layout_names.length
|
||||
} else {
|
||||
hyprlandLayoutCount = 0
|
||||
}
|
||||
} catch (e) {
|
||||
hyprlandCurrentLayout = ""
|
||||
hyprlandLayoutCount = 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Timer {
|
||||
id: hyprlandLayoutUpdateTimer
|
||||
interval: 1000
|
||||
running: false
|
||||
repeat: true
|
||||
onTriggered: updateHyprlandLayout()
|
||||
}
|
||||
|
||||
Loader {
|
||||
@@ -236,21 +180,93 @@ Item {
|
||||
spacing: Theme.spacingL
|
||||
Layout.fillWidth: true
|
||||
|
||||
DankCircularImage {
|
||||
Item {
|
||||
id: avatarContainer
|
||||
|
||||
property bool hasImage: profileImageLoader.status === Image.Ready
|
||||
|
||||
Layout.preferredWidth: 60
|
||||
Layout.preferredHeight: 60
|
||||
imageSource: {
|
||||
if (PortalService.profileImage === "") {
|
||||
return ""
|
||||
}
|
||||
|
||||
if (PortalService.profileImage.startsWith("/")) {
|
||||
return "file://" + PortalService.profileImage
|
||||
}
|
||||
|
||||
return PortalService.profileImage
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: width / 2
|
||||
color: "transparent"
|
||||
border.color: Theme.primary
|
||||
border.width: 1
|
||||
visible: parent.hasImage
|
||||
}
|
||||
|
||||
Image {
|
||||
id: profileImageLoader
|
||||
|
||||
source: {
|
||||
if (PortalService.profileImage === "") {
|
||||
return ""
|
||||
}
|
||||
|
||||
if (PortalService.profileImage.startsWith("/")) {
|
||||
return "file://" + PortalService.profileImage
|
||||
}
|
||||
|
||||
return PortalService.profileImage
|
||||
}
|
||||
smooth: true
|
||||
asynchronous: true
|
||||
mipmap: true
|
||||
cache: true
|
||||
visible: false
|
||||
}
|
||||
|
||||
MultiEffect {
|
||||
anchors.fill: parent
|
||||
anchors.margins: 5
|
||||
source: profileImageLoader
|
||||
maskEnabled: true
|
||||
maskSource: circularMask
|
||||
visible: avatarContainer.hasImage
|
||||
maskThresholdMin: 0.5
|
||||
maskSpreadAtMin: 1
|
||||
}
|
||||
|
||||
Item {
|
||||
id: circularMask
|
||||
|
||||
width: 60 - 10
|
||||
height: 60 - 10
|
||||
layer.enabled: true
|
||||
layer.smooth: true
|
||||
visible: false
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: width / 2
|
||||
color: "black"
|
||||
antialiasing: true
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: width / 2
|
||||
color: Theme.primary
|
||||
visible: !parent.hasImage
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "person"
|
||||
size: Theme.iconSize + 4
|
||||
color: Theme.primaryText
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "warning"
|
||||
size: Theme.iconSize + 4
|
||||
color: Theme.primaryText
|
||||
visible: PortalService.profileImage !== "" && profileImageLoader.status === Image.Error
|
||||
}
|
||||
fallbackIcon: "person"
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -578,7 +594,7 @@ Item {
|
||||
|
||||
StyledText {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: 20
|
||||
Layout.preferredHeight: root.pamState ? 20 : 0
|
||||
text: {
|
||||
if (root.pamState === "error") {
|
||||
return "Authentication error - try again"
|
||||
@@ -594,6 +610,7 @@ Item {
|
||||
color: Theme.error
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
visible: root.pamState !== ""
|
||||
opacity: root.pamState !== "" ? 1 : 0
|
||||
|
||||
Behavior on opacity {
|
||||
@@ -602,6 +619,13 @@ Item {
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on Layout.preferredHeight {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -622,92 +646,6 @@ Item {
|
||||
anchors.margins: Theme.spacingXL
|
||||
spacing: Theme.spacingL
|
||||
|
||||
Item {
|
||||
width: keyboardLayoutRow.width
|
||||
height: keyboardLayoutRow.height
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: {
|
||||
if (CompositorService.isNiri) {
|
||||
return NiriService.keyboardLayoutNames.length > 1
|
||||
} else if (CompositorService.isHyprland) {
|
||||
return hyprlandLayoutCount > 1
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
Row {
|
||||
id: keyboardLayoutRow
|
||||
spacing: 4
|
||||
|
||||
Item {
|
||||
width: Theme.iconSize
|
||||
height: Theme.iconSize
|
||||
|
||||
DankIcon {
|
||||
name: "keyboard"
|
||||
size: Theme.iconSize
|
||||
color: "white"
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
width: childrenRect.width
|
||||
height: Theme.iconSize
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
if (CompositorService.isNiri) {
|
||||
const layout = NiriService.getCurrentKeyboardLayoutName()
|
||||
if (!layout) return ""
|
||||
const parts = layout.split(" ")
|
||||
if (parts.length > 0) {
|
||||
return parts[0].substring(0, 2).toUpperCase()
|
||||
}
|
||||
return layout.substring(0, 2).toUpperCase()
|
||||
} else if (CompositorService.isHyprland) {
|
||||
return hyprlandCurrentLayout
|
||||
}
|
||||
return ""
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Light
|
||||
color: "white"
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: keyboardLayoutArea
|
||||
anchors.fill: parent
|
||||
enabled: !demoMode
|
||||
hoverEnabled: enabled
|
||||
cursorShape: enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||
onClicked: {
|
||||
if (CompositorService.isNiri) {
|
||||
NiriService.cycleKeyboardLayout()
|
||||
} else if (CompositorService.isHyprland) {
|
||||
Quickshell.execDetached([
|
||||
"hyprctl",
|
||||
"switchxkblayout",
|
||||
hyprlandKeyboard,
|
||||
"next"
|
||||
])
|
||||
updateHyprlandLayout()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
width: 1
|
||||
height: 24
|
||||
color: Qt.rgba(255, 255, 255, 0.2)
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
visible: MprisController.activePlayer
|
||||
}
|
||||
|
||||
Row {
|
||||
spacing: Theme.spacingS
|
||||
visible: MprisController.activePlayer
|
||||
@@ -1172,8 +1110,6 @@ Item {
|
||||
return
|
||||
}
|
||||
console.log("Authentication failed:", res)
|
||||
passwordField.text = ""
|
||||
root.passwordBuffer = ""
|
||||
if (res === PamResult.Error)
|
||||
root.pamState = "error"
|
||||
else if (res === PamResult.MaxTries)
|
||||
|
||||
@@ -163,7 +163,7 @@ Item {
|
||||
|
||||
DankDropdown {
|
||||
id: fontDropdown
|
||||
anchors.left: parent.left
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: -Theme.spacingM
|
||||
width: parent.width + Theme.spacingM
|
||||
text: "Font Family"
|
||||
|
||||
@@ -63,7 +63,7 @@ Column {
|
||||
width: calculatedWidth
|
||||
height: 32
|
||||
radius: Theme.cornerRadius
|
||||
color: isActive ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : Theme.withAlpha(Theme.primaryPressed, 0)
|
||||
color: isActive ? Theme.primaryPressed : isHovered ? Theme.primaryHoverLight : "transparent"
|
||||
border.width: isActive ? 0 : 1
|
||||
border.color: Theme.outlineMedium
|
||||
|
||||
@@ -104,7 +104,7 @@ Column {
|
||||
width: 20
|
||||
height: 20
|
||||
radius: 10
|
||||
color: closeMouseArea.containsMouse ? Theme.surfaceTextHover : Theme.withAlpha(Theme.surfaceTextHover, 0)
|
||||
color: closeMouseArea.containsMouse ? Theme.surfaceTextHover : "transparent"
|
||||
visible: NotepadStorageService.tabs.length > 1
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
|
||||
@@ -34,6 +34,12 @@ Rectangle {
|
||||
}
|
||||
radius: Theme.cornerRadius
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
ColorAnimation {
|
||||
@@ -44,12 +50,12 @@ Rectangle {
|
||||
|
||||
color: {
|
||||
if (isGroupSelected && keyboardNavigationActive) {
|
||||
return Theme.primaryPressed
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.2)
|
||||
}
|
||||
if (keyboardNavigationActive && expanded && selectedNotificationIndex >= 0) {
|
||||
return Theme.primaryHoverLight
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.12)
|
||||
}
|
||||
return Theme.surfaceContainerHigh
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.1)
|
||||
}
|
||||
border.color: {
|
||||
if (isGroupSelected && keyboardNavigationActive) {
|
||||
@@ -344,10 +350,16 @@ Rectangle {
|
||||
return baseHeight
|
||||
}
|
||||
radius: Theme.cornerRadius
|
||||
color: isSelected ? Theme.primaryPressed : Theme.surfaceContainerHigh
|
||||
color: isSelected ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.25) : "transparent"
|
||||
border.color: isSelected ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.4) : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.05)
|
||||
border.width: isSelected ? 1 : 1
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
ColorAnimation {
|
||||
|
||||
@@ -13,6 +13,7 @@ DankPopout {
|
||||
id: root
|
||||
|
||||
property bool notificationHistoryVisible: false
|
||||
property string triggerSection: "right"
|
||||
property var triggerScreen: null
|
||||
|
||||
NotificationKeyboardController {
|
||||
@@ -34,10 +35,10 @@ DankPopout {
|
||||
|
||||
popupWidth: 400
|
||||
popupHeight: contentLoader.item ? contentLoader.item.implicitHeight : 400
|
||||
triggerX: 0
|
||||
triggerY: 0
|
||||
triggerX: Screen.width - 400 - Theme.spacingL
|
||||
triggerY: Theme.barHeight - 4 + SettingsData.topBarSpacing + Theme.spacingXS
|
||||
triggerWidth: 40
|
||||
positioning: ""
|
||||
positioning: "center"
|
||||
screen: triggerScreen
|
||||
shouldBeVisible: notificationHistoryVisible
|
||||
visible: shouldBeVisible
|
||||
@@ -116,7 +117,7 @@ DankPopout {
|
||||
color: Theme.popupBackground()
|
||||
radius: Theme.cornerRadius
|
||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 0
|
||||
border.width: 1
|
||||
focus: true
|
||||
|
||||
Component.onCompleted: {
|
||||
|
||||
@@ -106,7 +106,9 @@ Item {
|
||||
height: 28
|
||||
radius: Theme.cornerRadius
|
||||
visible: NotificationService.notifications.length > 0
|
||||
color: clearArea.containsMouse ? Theme.primaryHoverLight : Theme.surfaceContainerHigh
|
||||
color: clearArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
||||
border.color: clearArea.containsMouse ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: 1
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
@@ -137,6 +139,19 @@ Item {
|
||||
onClicked: NotificationService.clearAllNotifications()
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on border.color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -411,78 +411,6 @@ QtObject {
|
||||
selectPrevious()
|
||||
event.accepted = true
|
||||
}
|
||||
} else if (event.key === Qt.Key_N && event.modifiers & Qt.ControlModifier) {
|
||||
if (!keyboardNavigationActive) {
|
||||
keyboardNavigationActive = true
|
||||
rebuildFlatNavigation()
|
||||
selectedFlatIndex = 0
|
||||
updateSelectedIdFromIndex()
|
||||
if (listView) {
|
||||
listView.keyboardActive = true
|
||||
}
|
||||
selectionVersion++
|
||||
ensureVisible()
|
||||
} else {
|
||||
selectNext()
|
||||
}
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_P && event.modifiers & Qt.ControlModifier) {
|
||||
if (!keyboardNavigationActive) {
|
||||
keyboardNavigationActive = true
|
||||
rebuildFlatNavigation()
|
||||
selectedFlatIndex = 0
|
||||
updateSelectedIdFromIndex()
|
||||
if (listView) {
|
||||
listView.keyboardActive = true
|
||||
}
|
||||
selectionVersion++
|
||||
ensureVisible()
|
||||
} else if (selectedFlatIndex === 0) {
|
||||
keyboardNavigationActive = false
|
||||
if (listView) {
|
||||
listView.keyboardActive = false
|
||||
}
|
||||
selectionVersion++
|
||||
} else {
|
||||
selectPrevious()
|
||||
}
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_J && event.modifiers & Qt.ControlModifier) {
|
||||
if (!keyboardNavigationActive) {
|
||||
keyboardNavigationActive = true
|
||||
rebuildFlatNavigation()
|
||||
selectedFlatIndex = 0
|
||||
updateSelectedIdFromIndex()
|
||||
if (listView) {
|
||||
listView.keyboardActive = true
|
||||
}
|
||||
selectionVersion++
|
||||
ensureVisible()
|
||||
} else {
|
||||
selectNext()
|
||||
}
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_K && event.modifiers & Qt.ControlModifier) {
|
||||
if (!keyboardNavigationActive) {
|
||||
keyboardNavigationActive = true
|
||||
rebuildFlatNavigation()
|
||||
selectedFlatIndex = 0
|
||||
updateSelectedIdFromIndex()
|
||||
if (listView) {
|
||||
listView.keyboardActive = true
|
||||
}
|
||||
selectionVersion++
|
||||
ensureVisible()
|
||||
} else if (selectedFlatIndex === 0) {
|
||||
keyboardNavigationActive = false
|
||||
if (listView) {
|
||||
listView.keyboardActive = false
|
||||
}
|
||||
selectionVersion++
|
||||
} else {
|
||||
selectPrevious()
|
||||
}
|
||||
event.accepted = true
|
||||
} else if (keyboardNavigationActive) {
|
||||
if (event.key === Qt.Key_Space) {
|
||||
toggleGroupExpanded()
|
||||
@@ -497,10 +425,7 @@ QtObject {
|
||||
clearSelected()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_Tab) {
|
||||
selectNext()
|
||||
event.accepted = true
|
||||
} else if (event.key === Qt.Key_Backtab) {
|
||||
selectPrevious()
|
||||
selectNextWrapping()
|
||||
event.accepted = true
|
||||
} else if (event.key >= Qt.Key_1 && event.key <= Qt.Key_9) {
|
||||
const actionIndex = event.key - Qt.Key_1
|
||||
|
||||
@@ -157,6 +157,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
width: parent.width
|
||||
text: "Low Priority"
|
||||
description: "Timeout for low priority notifications"
|
||||
currentValue: getTimeoutText(SettingsData.notificationTimeoutLow)
|
||||
@@ -172,6 +173,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
width: parent.width
|
||||
text: "Normal Priority"
|
||||
description: "Timeout for normal priority notifications"
|
||||
currentValue: getTimeoutText(SettingsData.notificationTimeoutNormal)
|
||||
@@ -187,6 +189,7 @@ Rectangle {
|
||||
}
|
||||
|
||||
DankDropdown {
|
||||
width: parent.width
|
||||
text: "Critical Priority"
|
||||
description: "Timeout for critical priority notifications"
|
||||
currentValue: getTimeoutText(SettingsData.notificationTimeoutCritical)
|
||||
|
||||
@@ -76,6 +76,7 @@ PanelWindow {
|
||||
color: "transparent"
|
||||
implicitWidth: 400
|
||||
implicitHeight: 122
|
||||
onScreenYChanged: margins.top = Theme.barHeight - 4 + SettingsData.topBarSpacing + 4 + screenY
|
||||
onHasValidDataChanged: {
|
||||
if (!hasValidData && !exiting && !_isDestroying) {
|
||||
forceExit()
|
||||
@@ -107,94 +108,14 @@ PanelWindow {
|
||||
}
|
||||
}
|
||||
|
||||
property bool isTopCenter: SettingsData.notificationPopupPosition === -1
|
||||
|
||||
anchors.top: isTopCenter || SettingsData.notificationPopupPosition === SettingsData.Position.Top || SettingsData.notificationPopupPosition === SettingsData.Position.Left
|
||||
anchors.bottom: SettingsData.notificationPopupPosition === SettingsData.Position.Bottom || SettingsData.notificationPopupPosition === SettingsData.Position.Right
|
||||
anchors.left: SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom
|
||||
anchors.right: SettingsData.notificationPopupPosition === SettingsData.Position.Top || SettingsData.notificationPopupPosition === SettingsData.Position.Right
|
||||
anchors {
|
||||
top: true
|
||||
right: true
|
||||
}
|
||||
|
||||
margins {
|
||||
top: getTopMargin()
|
||||
bottom: getBottomMargin()
|
||||
left: getLeftMargin()
|
||||
right: getRightMargin()
|
||||
}
|
||||
|
||||
function getTopMargin() {
|
||||
const popupPos = SettingsData.notificationPopupPosition
|
||||
const barPos = SettingsData.dankBarPosition
|
||||
const isTop = isTopCenter || popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Left
|
||||
|
||||
if (!isTop) return 0
|
||||
|
||||
const effectiveBarThickness = Math.max(26 + SettingsData.dankBarInnerPadding * 0.6 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
|
||||
const exclusiveZone = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap
|
||||
|
||||
let base = Theme.popupDistance
|
||||
if (barPos === SettingsData.Position.Top) {
|
||||
base = exclusiveZone
|
||||
}
|
||||
|
||||
return base + screenY
|
||||
}
|
||||
|
||||
function getBottomMargin() {
|
||||
const popupPos = SettingsData.notificationPopupPosition
|
||||
const barPos = SettingsData.dankBarPosition
|
||||
const isBottom = popupPos === SettingsData.Position.Bottom || popupPos === SettingsData.Position.Right
|
||||
|
||||
if (!isBottom) return 0
|
||||
|
||||
const effectiveBarThickness = Math.max(26 + SettingsData.dankBarInnerPadding * 0.6 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
|
||||
const exclusiveZone = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap
|
||||
|
||||
let base = Theme.popupDistance
|
||||
if (barPos === SettingsData.Position.Bottom) {
|
||||
base = exclusiveZone
|
||||
}
|
||||
|
||||
return base + screenY
|
||||
}
|
||||
|
||||
function getLeftMargin() {
|
||||
if (isTopCenter) {
|
||||
return (screen.width - implicitWidth) / 2
|
||||
}
|
||||
|
||||
const popupPos = SettingsData.notificationPopupPosition
|
||||
const barPos = SettingsData.dankBarPosition
|
||||
const isLeft = popupPos === SettingsData.Position.Left || popupPos === SettingsData.Position.Bottom
|
||||
|
||||
if (!isLeft) return 0
|
||||
|
||||
const effectiveBarThickness = Math.max(26 + SettingsData.dankBarInnerPadding * 0.6 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
|
||||
const exclusiveZone = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap
|
||||
|
||||
if (barPos === SettingsData.Position.Left) {
|
||||
return exclusiveZone
|
||||
}
|
||||
|
||||
return Theme.popupDistance
|
||||
}
|
||||
|
||||
function getRightMargin() {
|
||||
if (isTopCenter) return 0
|
||||
|
||||
const popupPos = SettingsData.notificationPopupPosition
|
||||
const barPos = SettingsData.dankBarPosition
|
||||
const isRight = popupPos === SettingsData.Position.Top || popupPos === SettingsData.Position.Right
|
||||
|
||||
if (!isRight) return 0
|
||||
|
||||
const effectiveBarThickness = Math.max(26 + SettingsData.dankBarInnerPadding * 0.6 + SettingsData.dankBarInnerPadding + 4, Theme.barHeight - 4 - (8 - SettingsData.dankBarInnerPadding))
|
||||
const exclusiveZone = effectiveBarThickness + SettingsData.dankBarSpacing + SettingsData.dankBarBottomGap
|
||||
|
||||
if (barPos === SettingsData.Position.Right) {
|
||||
return exclusiveZone
|
||||
}
|
||||
|
||||
return Theme.popupDistance
|
||||
top: Theme.barHeight - 4 + SettingsData.topBarSpacing + 4
|
||||
right: 12
|
||||
}
|
||||
|
||||
Item {
|
||||
@@ -202,7 +123,7 @@ PanelWindow {
|
||||
|
||||
anchors.fill: parent
|
||||
visible: win.hasValidData
|
||||
layer.enabled: true
|
||||
layer.enabled: (enterX.running || exitAnim.running)
|
||||
layer.smooth: true
|
||||
|
||||
Rectangle {
|
||||
@@ -213,7 +134,7 @@ PanelWindow {
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.popupBackground()
|
||||
border.color: notificationData && notificationData.urgency === NotificationUrgency.Critical ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
||||
border.width: notificationData && notificationData.urgency === NotificationUrgency.Critical ? 2 : 0
|
||||
border.width: notificationData && notificationData.urgency === NotificationUrgency.Critical ? 2 : 1
|
||||
clip: true
|
||||
|
||||
Rectangle {
|
||||
@@ -534,12 +455,7 @@ PanelWindow {
|
||||
transform: Translate {
|
||||
id: tx
|
||||
|
||||
x: {
|
||||
if (isTopCenter) return 0
|
||||
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom
|
||||
return isLeft ? -Anims.slidePx : Anims.slidePx
|
||||
}
|
||||
y: isTopCenter ? -Anims.slidePx : 0
|
||||
x: Anims.slidePx
|
||||
}
|
||||
}
|
||||
|
||||
@@ -547,23 +463,15 @@ PanelWindow {
|
||||
id: enterX
|
||||
|
||||
target: tx
|
||||
property: isTopCenter ? "y" : "x"
|
||||
from: {
|
||||
if (isTopCenter) return -Anims.slidePx
|
||||
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom
|
||||
return isLeft ? -Anims.slidePx : Anims.slidePx
|
||||
}
|
||||
property: "x"
|
||||
from: Anims.slidePx
|
||||
to: 0
|
||||
duration: Anims.durMed
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: isTopCenter ? Anims.standardDecel : Anims.emphasizedDecel
|
||||
easing.bezierCurve: Anims.emphasizedDecel
|
||||
onStopped: {
|
||||
if (!win.exiting && !win._isDestroying) {
|
||||
if (isTopCenter) {
|
||||
if (Math.abs(tx.y) < 0.5) win.entered()
|
||||
} else {
|
||||
if (Math.abs(tx.x) < 0.5) win.entered()
|
||||
}
|
||||
if (!win.exiting && !win._isDestroying && Math.abs(tx.x) < 0.5) {
|
||||
win.entered()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -575,13 +483,9 @@ PanelWindow {
|
||||
|
||||
PropertyAnimation {
|
||||
target: tx
|
||||
property: isTopCenter ? "y" : "x"
|
||||
property: "x"
|
||||
from: 0
|
||||
to: {
|
||||
if (isTopCenter) return -Anims.slidePx
|
||||
const isLeft = SettingsData.notificationPopupPosition === SettingsData.Position.Left || SettingsData.notificationPopupPosition === SettingsData.Position.Bottom
|
||||
return isLeft ? -Anims.slidePx : Anims.slidePx
|
||||
}
|
||||
to: Anims.slidePx
|
||||
duration: Anims.durShort
|
||||
easing.type: Easing.BezierSpline
|
||||
easing.bezierCurve: Anims.emphasizedAccel
|
||||
|
||||
@@ -12,24 +12,12 @@ DankOSD {
|
||||
enableMouseInteraction: true
|
||||
|
||||
Connections {
|
||||
target: AudioService.sink && AudioService.sink.audio ? AudioService.sink.audio : null
|
||||
target: AudioService
|
||||
|
||||
function onVolumeChanged() {
|
||||
if (!AudioService.suppressOSD) {
|
||||
root.show()
|
||||
}
|
||||
root.show()
|
||||
}
|
||||
|
||||
function onMutedChanged() {
|
||||
if (!AudioService.suppressOSD) {
|
||||
root.show()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: AudioService
|
||||
|
||||
function onSinkChanged() {
|
||||
if (root.shouldBeVisible) {
|
||||
root.show()
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property var axis: null
|
||||
property string section: "center"
|
||||
property var popoutTarget: null
|
||||
property var parentScreen: null
|
||||
property real widgetThickness: 30
|
||||
property real barThickness: 48
|
||||
property alias content: contentLoader.sourceComponent
|
||||
|
||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||
|
||||
signal clicked()
|
||||
|
||||
width: contentLoader.item ? (contentLoader.item.implicitWidth + horizontalPadding * 2) : 0
|
||||
height: widgetThickness
|
||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||
color: {
|
||||
if (SettingsData.dankBarNoBackground) {
|
||||
return "transparent"
|
||||
}
|
||||
|
||||
const baseColor = mouseArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor
|
||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency)
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: contentLoader
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: {
|
||||
if (popoutTarget && popoutTarget.setTriggerPosition) {
|
||||
const globalPos = mapToGlobal(0, 0)
|
||||
const currentScreen = parentScreen || Screen
|
||||
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, width)
|
||||
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
|
||||
}
|
||||
root.clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
property var axis: null
|
||||
property string section: "center"
|
||||
property var popoutTarget: null
|
||||
property var parentScreen: null
|
||||
property real widgetThickness: 30
|
||||
property real barThickness: 48
|
||||
property alias content: contentLoader.sourceComponent
|
||||
|
||||
readonly property real horizontalPadding: SettingsData.dankBarNoBackground ? 0 : Math.max(Theme.spacingXS, Theme.spacingS * (widgetThickness / 30))
|
||||
|
||||
signal clicked()
|
||||
|
||||
width: widgetThickness
|
||||
height: contentLoader.item ? (contentLoader.item.implicitHeight + horizontalPadding * 2) : 0
|
||||
radius: SettingsData.dankBarNoBackground ? 0 : Theme.cornerRadius
|
||||
color: {
|
||||
if (SettingsData.dankBarNoBackground) {
|
||||
return "transparent"
|
||||
}
|
||||
|
||||
const baseColor = mouseArea.containsMouse ? Theme.widgetBaseHoverColor : Theme.widgetBaseBackgroundColor
|
||||
return Qt.rgba(baseColor.r, baseColor.g, baseColor.b, baseColor.a * Theme.widgetTransparency)
|
||||
}
|
||||
|
||||
Loader {
|
||||
id: contentLoader
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onPressed: {
|
||||
if (popoutTarget && popoutTarget.setTriggerPosition) {
|
||||
const globalPos = mapToGlobal(0, 0)
|
||||
const currentScreen = parentScreen || Screen
|
||||
const pos = SettingsData.getPopupTriggerPosition(globalPos, currentScreen, barThickness, height)
|
||||
popoutTarget.setTriggerPosition(pos.x, pos.y, pos.width, section, currentScreen)
|
||||
}
|
||||
root.clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,132 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
Column {
|
||||
id: root
|
||||
|
||||
required property string settingKey
|
||||
required property string label
|
||||
property string description: ""
|
||||
property var defaultValue: []
|
||||
property var items: defaultValue
|
||||
property Component delegate: null
|
||||
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Component.onCompleted: {
|
||||
const settings = findSettings()
|
||||
if (settings) {
|
||||
items = settings.loadValue(settingKey, defaultValue)
|
||||
}
|
||||
}
|
||||
|
||||
onItemsChanged: {
|
||||
const settings = findSettings()
|
||||
if (settings) {
|
||||
settings.saveValue(settingKey, items)
|
||||
}
|
||||
}
|
||||
|
||||
function findSettings() {
|
||||
let item = parent
|
||||
while (item) {
|
||||
if (item.saveValue !== undefined && item.loadValue !== undefined) {
|
||||
return item
|
||||
}
|
||||
item = item.parent
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function addItem(item) {
|
||||
items = items.concat([item])
|
||||
}
|
||||
|
||||
function removeItem(index) {
|
||||
const newItems = items.slice()
|
||||
newItems.splice(index, 1)
|
||||
items = newItems
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: root.label
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: root.description
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
visible: root.description !== ""
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Repeater {
|
||||
model: root.items
|
||||
delegate: root.delegate ? root.delegate : defaultDelegate
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "No items added yet"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
visible: root.items.length === 0
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: defaultDelegate
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: 40
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHigh
|
||||
border.width: 0
|
||||
|
||||
StyledText {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
text: modelData
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 60
|
||||
height: 28
|
||||
color: removeArea.containsMouse ? Theme.errorHover : Theme.error
|
||||
radius: Theme.cornerRadius
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: "Remove"
|
||||
color: Theme.errorText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: removeArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.removeItem(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,231 +0,0 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
Column {
|
||||
id: root
|
||||
|
||||
required property string settingKey
|
||||
required property string label
|
||||
property string description: ""
|
||||
property var fields: []
|
||||
property var defaultValue: []
|
||||
property var items: defaultValue
|
||||
|
||||
width: parent.width
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Component.onCompleted: {
|
||||
const settings = findSettings()
|
||||
if (settings) {
|
||||
items = settings.loadValue(settingKey, defaultValue)
|
||||
}
|
||||
}
|
||||
|
||||
onItemsChanged: {
|
||||
const settings = findSettings()
|
||||
if (settings) {
|
||||
settings.saveValue(settingKey, items)
|
||||
}
|
||||
}
|
||||
|
||||
function findSettings() {
|
||||
let item = parent
|
||||
while (item) {
|
||||
if (item.saveValue !== undefined && item.loadValue !== undefined) {
|
||||
return item
|
||||
}
|
||||
item = item.parent
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
function addItem(item) {
|
||||
items = items.concat([item])
|
||||
}
|
||||
|
||||
function removeItem(index) {
|
||||
const newItems = items.slice()
|
||||
newItems.splice(index, 1)
|
||||
items = newItems
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: root.label
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: root.description
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
visible: root.description !== ""
|
||||
}
|
||||
|
||||
Flow {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Repeater {
|
||||
model: root.fields
|
||||
|
||||
StyledText {
|
||||
text: modelData.label
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
width: modelData.width || 200
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Flow {
|
||||
id: inputRow
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
property var inputFields: []
|
||||
|
||||
Repeater {
|
||||
id: inputRepeater
|
||||
model: root.fields
|
||||
|
||||
DankTextField {
|
||||
width: modelData.width || 200
|
||||
placeholderText: modelData.placeholder || ""
|
||||
|
||||
Component.onCompleted: {
|
||||
inputRow.inputFields.push(this)
|
||||
}
|
||||
|
||||
Keys.onReturnPressed: {
|
||||
addButton.clicked()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankButton {
|
||||
id: addButton
|
||||
width: 50
|
||||
height: 36
|
||||
text: "Add"
|
||||
|
||||
onClicked: {
|
||||
let newItem = {}
|
||||
let hasValue = false
|
||||
|
||||
for (let i = 0; i < root.fields.length; i++) {
|
||||
const field = root.fields[i]
|
||||
const input = inputRow.inputFields[i]
|
||||
const value = input.text.trim()
|
||||
|
||||
if (value !== "") {
|
||||
hasValue = true
|
||||
}
|
||||
|
||||
if (field.required && value === "") {
|
||||
return
|
||||
}
|
||||
|
||||
newItem[field.id] = value || (field.default || "")
|
||||
}
|
||||
|
||||
if (hasValue) {
|
||||
root.addItem(newItem)
|
||||
for (let i = 0; i < inputRow.inputFields.length; i++) {
|
||||
inputRow.inputFields[i].text = ""
|
||||
}
|
||||
if (inputRow.inputFields.length > 0) {
|
||||
inputRow.inputFields[0].forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Current Items"
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surfaceText
|
||||
visible: root.items.length > 0
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
Repeater {
|
||||
model: root.items
|
||||
|
||||
StyledRect {
|
||||
width: parent.width
|
||||
height: 40
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.surfaceContainerHigh
|
||||
border.width: 0
|
||||
|
||||
Row {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Repeater {
|
||||
model: root.fields
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
const value = root.items[index][modelData.id]
|
||||
return value || ""
|
||||
}
|
||||
color: Theme.surfaceText
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
width: modelData.width || 200
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: Theme.spacingM
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 60
|
||||
height: 28
|
||||
color: removeArea.containsMouse ? Theme.errorHover : Theme.error
|
||||
radius: Theme.cornerRadius
|
||||
|
||||
StyledText {
|
||||
anchors.centerIn: parent
|
||||
text: "Remove"
|
||||
color: Theme.errorText
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: removeArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
root.removeItem(index)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "No items added yet"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
visible: root.items.length === 0
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user