mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-01-28 23:42:51 -05:00
initial structure refactor
This commit is contained in:
116
CLAUDE.md
116
CLAUDE.md
@@ -40,7 +40,7 @@ When asked to backup Memory Bank System files, you will copy the core context fi
|
|||||||
|
|
||||||
This is a Quickshell-based desktop shell implementation with Material Design 3 dark theme. The shell provides a complete desktop environment experience with panels, widgets, and system integration services.
|
This is a Quickshell-based desktop shell implementation with Material Design 3 dark theme. The shell provides a complete desktop environment experience with panels, widgets, and system integration services.
|
||||||
|
|
||||||
**Architecture**: Modular design with clean separation between UI components (Widgets), system services (Services), and shared utilities (Common).
|
**Architecture**: Modular design with clean separation between UI components (Modules), system services (Services), and shared utilities (Common).
|
||||||
|
|
||||||
## Technology Stack
|
## Technology Stack
|
||||||
|
|
||||||
@@ -81,11 +81,19 @@ shell.qml # Main entry point (minimal orchestration)
|
|||||||
│ ├── NetworkService.qml
|
│ ├── NetworkService.qml
|
||||||
│ ├── BrightnessService.qml
|
│ ├── BrightnessService.qml
|
||||||
│ └── [9 total services]
|
│ └── [9 total services]
|
||||||
└── Widgets/ # UI components
|
├── Modules/ # UI components
|
||||||
├── TopBar.qml
|
│ ├── TopBar.qml
|
||||||
├── AppLauncher.qml
|
│ ├── AppLauncher.qml
|
||||||
├── ControlCenterPopup.qml
|
│ ├── ControlCenterPopup.qml
|
||||||
└── [18 total widgets]
|
│ └── [18 total modules]
|
||||||
|
└── Widgets/ # Reusable UI controls
|
||||||
|
├── DankIcon.qml
|
||||||
|
├── DankSlider.qml
|
||||||
|
├── DankToggle.qml
|
||||||
|
├── DankTabBar.qml
|
||||||
|
├── DankGridView.qml
|
||||||
|
├── DankListView.qml
|
||||||
|
└── [6 total widgets]
|
||||||
```
|
```
|
||||||
|
|
||||||
### Component Organization
|
### Component Organization
|
||||||
@@ -106,10 +114,18 @@ shell.qml # Main entry point (minimal orchestration)
|
|||||||
- **Examples**: AudioService, NetworkService, BrightnessService, WeatherService
|
- **Examples**: AudioService, NetworkService, BrightnessService, WeatherService
|
||||||
- Services handle system commands, state management, and hardware integration
|
- Services handle system commands, state management, and hardware integration
|
||||||
|
|
||||||
4. **Widgets/** - Reusable UI components
|
4. **Modules/** - UI components
|
||||||
- **Full-screen components**: AppLauncher, ClipboardHistory, ControlCenterPopup
|
- **Full-screen components**: AppLauncher, ClipboardHistory, ControlCenterPopup
|
||||||
- **Panel components**: TopBar, SystemTrayWidget, NotificationPopup
|
- **Panel components**: TopBar, SystemTrayWidget, NotificationPopup
|
||||||
- **Reusable controls**: CustomSlider, WorkspaceSwitcher
|
- **Layout components**: WorkspaceSwitcher
|
||||||
|
|
||||||
|
5. **Widgets/** - Reusable UI controls
|
||||||
|
- **DankIcon**: Centralized icon component with Material Design font integration
|
||||||
|
- **DankSlider**: Enhanced slider with animations and smart detection
|
||||||
|
- **DankToggle**: Consistent toggle switch component
|
||||||
|
- **DankTabBar**: Unified tab bar implementation
|
||||||
|
- **DankGridView**: Reusable grid view with adaptive columns
|
||||||
|
- **DankListView**: Reusable list view with configurable styling
|
||||||
|
|
||||||
### Key Architectural Patterns
|
### Key Architectural Patterns
|
||||||
|
|
||||||
@@ -146,7 +162,15 @@ shell.qml # Main entry point (minimal orchestration)
|
|||||||
- **AppLauncher**: Full-featured app grid/list with 93+ applications, search, categories
|
- **AppLauncher**: Full-featured app grid/list with 93+ applications, search, categories
|
||||||
- **ClipboardHistory**: Complete clipboard management with cliphist integration
|
- **ClipboardHistory**: Complete clipboard management with cliphist integration
|
||||||
- **TopBar**: Per-monitor panels with workspace switching, clock, system tray
|
- **TopBar**: Per-monitor panels with workspace switching, clock, system tray
|
||||||
- **CustomSlider**: Reusable enhanced slider with animations and smart detection
|
|
||||||
|
#### Key Widgets
|
||||||
|
|
||||||
|
- **DankIcon**: Centralized icon component with automatic Material Design font detection
|
||||||
|
- **DankSlider**: Enhanced slider with animations and smart detection
|
||||||
|
- **DankToggle**: Consistent toggle switch component
|
||||||
|
- **DankTabBar**: Unified tab bar implementation
|
||||||
|
- **DankGridView**: Reusable grid view with adaptive columns
|
||||||
|
- **DankListView**: Reusable list view with configurable styling
|
||||||
|
|
||||||
## Code Conventions
|
## Code Conventions
|
||||||
|
|
||||||
@@ -161,7 +185,7 @@ shell.qml # Main entry point (minimal orchestration)
|
|||||||
|
|
||||||
2. **Naming Conventions**:
|
2. **Naming Conventions**:
|
||||||
- **Services**: Use `Singleton` type with `id: root`
|
- **Services**: Use `Singleton` type with `id: root`
|
||||||
- **Components**: Use descriptive names (e.g., `CustomSlider`, `TopBar`)
|
- **Components**: Use descriptive names (e.g., `DankSlider`, `TopBar`)
|
||||||
- **Properties**: camelCase for properties, PascalCase for types
|
- **Properties**: camelCase for properties, PascalCase for types
|
||||||
|
|
||||||
3. **Null-Safe Operations**:
|
3. **Null-Safe Operations**:
|
||||||
@@ -204,14 +228,16 @@ shell.qml # Main entry point (minimal orchestration)
|
|||||||
import Quickshell
|
import Quickshell
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import Quickshell.Io // For Process, FileView
|
import Quickshell.Io // For Process, FileView
|
||||||
import "../Common" // For Theme, utilities
|
import qs.Common // For Theme, utilities
|
||||||
import "../Services" // For service access
|
import qs.Services // For service access
|
||||||
|
import qs.Widgets // For reusable widgets (DankIcon, etc.)
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Service Dependencies**:
|
2. **Service Dependencies**:
|
||||||
- Services should NOT import other services
|
- Services should NOT import other services
|
||||||
- Widgets can import and use services via property bindings
|
- Modules and Widgets can import and use services via property bindings
|
||||||
- Use `Theme.propertyName` for consistent styling
|
- Use `Theme.propertyName` for consistent styling
|
||||||
|
- Use `DankIcon { name: "icon_name" }` for all icons instead of manual Text components
|
||||||
|
|
||||||
### Component Development Patterns
|
### Component Development Patterns
|
||||||
|
|
||||||
@@ -220,8 +246,8 @@ shell.qml # Main entry point (minimal orchestration)
|
|||||||
// In services - detect capabilities
|
// In services - detect capabilities
|
||||||
property bool brightnessAvailable: false
|
property bool brightnessAvailable: false
|
||||||
|
|
||||||
// In widgets - adapt UI accordingly
|
// In modules - adapt UI accordingly
|
||||||
CustomSlider {
|
DankSlider {
|
||||||
visible: BrightnessService.brightnessAvailable
|
visible: BrightnessService.brightnessAvailable
|
||||||
enabled: BrightnessService.brightnessAvailable
|
enabled: BrightnessService.brightnessAvailable
|
||||||
value: BrightnessService.brightnessLevel
|
value: BrightnessService.brightnessLevel
|
||||||
@@ -229,13 +255,13 @@ shell.qml # Main entry point (minimal orchestration)
|
|||||||
```
|
```
|
||||||
|
|
||||||
2. **Reusable Components**:
|
2. **Reusable Components**:
|
||||||
- Create reusable widgets for common patterns (like CustomSlider)
|
- Create reusable widgets for common patterns (like DankSlider)
|
||||||
- Use configurable properties for different use cases
|
- Use configurable properties for different use cases
|
||||||
- Include proper signal handling with unique names (avoid `valueChanged`)
|
- Include proper signal handling with unique names (avoid `valueChanged`)
|
||||||
|
|
||||||
3. **Service Integration**:
|
3. **Service Integration**:
|
||||||
- Services expose properties and functions
|
- Services expose properties and functions
|
||||||
- Widgets bind to service properties for reactive updates
|
- Modules and Widgets bind to service properties for reactive updates
|
||||||
- Use service functions for actions: `ServiceName.performAction(value)`
|
- Use service functions for actions: `ServiceName.performAction(value)`
|
||||||
- **CRITICAL**: DO NOT create wrapper functions for everything - bind directly to underlying APIs when possible
|
- **CRITICAL**: DO NOT create wrapper functions for everything - bind directly to underlying APIs when possible
|
||||||
- Example: Use `BluetoothService.adapter.discovering = true` instead of `BluetoothService.startScan()`
|
- Example: Use `BluetoothService.adapter.discovering = true` instead of `BluetoothService.startScan()`
|
||||||
@@ -284,6 +310,30 @@ When modifying the shell:
|
|||||||
6. **Multi-monitor**: Verify behavior with multiple displays
|
6. **Multi-monitor**: Verify behavior with multiple displays
|
||||||
7. **Feature detection**: Test on systems with/without required tools
|
7. **Feature detection**: Test on systems with/without required tools
|
||||||
|
|
||||||
|
### Adding New Modules
|
||||||
|
|
||||||
|
1. **Create component**:
|
||||||
|
```bash
|
||||||
|
# Create new module file
|
||||||
|
touch Modules/NewModule.qml
|
||||||
|
```
|
||||||
|
|
||||||
|
2. **Follow module patterns**:
|
||||||
|
- Use `Theme.propertyName` for styling
|
||||||
|
- Import `qs.Common` and `qs.Services` as needed
|
||||||
|
- Import `qs.Widgets` for reusable components
|
||||||
|
- Bind to service properties for reactive updates
|
||||||
|
- Consider per-screen vs global behavior
|
||||||
|
- Use `DankIcon` for icons instead of manual Text components
|
||||||
|
|
||||||
|
3. **Integration in shell.qml**:
|
||||||
|
```qml
|
||||||
|
NewModule {
|
||||||
|
id: newModule
|
||||||
|
// Configure properties
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Adding New Widgets
|
### Adding New Widgets
|
||||||
|
|
||||||
1. **Create component**:
|
1. **Create component**:
|
||||||
@@ -294,17 +344,10 @@ When modifying the shell:
|
|||||||
|
|
||||||
2. **Follow widget patterns**:
|
2. **Follow widget patterns**:
|
||||||
- Use `Theme.propertyName` for styling
|
- Use `Theme.propertyName` for styling
|
||||||
- Import `"../Common"` and `"../Services"` as needed
|
- Import `qs.Common` for theming
|
||||||
- Bind to service properties for reactive updates
|
- Focus on reusability and composition
|
||||||
- Consider per-screen vs global behavior
|
- Keep widgets simple and focused
|
||||||
|
- Use `DankIcon` for icons instead of manual Text components
|
||||||
3. **Integration in shell.qml**:
|
|
||||||
```qml
|
|
||||||
NewWidget {
|
|
||||||
id: newWidget
|
|
||||||
// Configure properties
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Adding New Services
|
### Adding New Services
|
||||||
|
|
||||||
@@ -329,9 +372,9 @@ When modifying the shell:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
2. **Use in widgets**:
|
2. **Use in modules**:
|
||||||
```qml
|
```qml
|
||||||
// In widget files
|
// In module files
|
||||||
property alias serviceValue: NewService.currentValue
|
property alias serviceValue: NewService.currentValue
|
||||||
|
|
||||||
SomeControl {
|
SomeControl {
|
||||||
@@ -352,9 +395,20 @@ When modifying the shell:
|
|||||||
### Best Practices Summary
|
### Best Practices Summary
|
||||||
|
|
||||||
- **Modularity**: Keep components focused and independent
|
- **Modularity**: Keep components focused and independent
|
||||||
- **Reusability**: Create reusable components for common patterns
|
- **Reusability**: Create reusable components for common patterns using Widgets/
|
||||||
- **Responsiveness**: Use property bindings for reactive UI
|
- **Responsiveness**: Use property bindings for reactive UI
|
||||||
- **Robustness**: Implement feature detection and graceful degradation
|
- **Robustness**: Implement feature detection and graceful degradation
|
||||||
- **Consistency**: Follow Material Design 3 principles via Theme singleton
|
- **Consistency**: Follow Material Design 3 principles via Theme singleton
|
||||||
- **Performance**: Minimize expensive operations and use appropriate data structures
|
- **Performance**: Minimize expensive operations and use appropriate data structures
|
||||||
|
- **Icon Management**: Use `DankIcon` for all icons instead of manual Text components
|
||||||
|
- **Widget System**: Leverage existing widgets (DankSlider, DankToggle, etc.) for consistency
|
||||||
- **NO WRAPPER HELL**: Avoid creating unnecessary wrapper functions - bind directly to underlying APIs for better reactivity and performance
|
- **NO WRAPPER HELL**: Avoid creating unnecessary wrapper functions - bind directly to underlying APIs for better reactivity and performance
|
||||||
|
|
||||||
|
### Common Widget Patterns
|
||||||
|
|
||||||
|
1. **Icons**: Always use `DankIcon { name: "icon_name" }` instead of `Text { font.family: Theme.iconFont }`
|
||||||
|
2. **Sliders**: Use `DankSlider` for consistent styling and behavior
|
||||||
|
3. **Toggles**: Use `DankToggle` for switches and checkboxes
|
||||||
|
4. **Tab Bars**: Use `DankTabBar` for tabbed interfaces
|
||||||
|
5. **Lists**: Use `DankListView` for scrollable lists
|
||||||
|
6. **Grids**: Use `DankGridView` for grid layouts
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ import Quickshell.Io
|
|||||||
import qs.Services
|
import qs.Services
|
||||||
|
|
||||||
Singleton {
|
Singleton {
|
||||||
// This dependency forces re-evaluation when colorUpdateTrigger changes
|
|
||||||
// Just check if matugen is available
|
|
||||||
|
|
||||||
id: root
|
id: root
|
||||||
|
|
||||||
@@ -22,47 +20,38 @@ Singleton {
|
|||||||
property var matugenColors: ({
|
property var matugenColors: ({
|
||||||
})
|
})
|
||||||
property bool extractionRequested: false
|
property bool extractionRequested: false
|
||||||
property int colorUpdateTrigger: 0 // Force property re-evaluation
|
property int colorUpdateTrigger: 0
|
||||||
// ──────────────── wallpaper change monitor ────────────────
|
|
||||||
property string lastWallpaperTimestamp: ""
|
property string lastWallpaperTimestamp: ""
|
||||||
// ──────────────── color properties (MD3) ────────────────
|
|
||||||
property color primary: getMatugenColor("primary", "#42a5f5")
|
property color primary: getMatugenColor("primary", "#42a5f5")
|
||||||
property color secondary: getMatugenColor("secondary", "#8ab4f8")
|
property color secondary: getMatugenColor("secondary", "#8ab4f8")
|
||||||
property color tertiary: getMatugenColor("tertiary", "#bb86fc")
|
property color tertiary: getMatugenColor("tertiary", "#bb86fc")
|
||||||
property color tertiaryContainer: getMatugenColor("tertiary_container", "#3700b3")
|
property color tertiaryContainer: getMatugenColor("tertiary_container", "#3700b3")
|
||||||
property color error: getMatugenColor("error", "#cf6679")
|
property color error: getMatugenColor("error", "#cf6679")
|
||||||
property color inversePrimary: getMatugenColor("inverse_primary", "#6200ea")
|
property color inversePrimary: getMatugenColor("inverse_primary", "#6200ea")
|
||||||
// backgrounds
|
|
||||||
property color bg: getMatugenColor("background", "#1a1c1e")
|
property color bg: getMatugenColor("background", "#1a1c1e")
|
||||||
property color surface: getMatugenColor("surface", "#1a1c1e")
|
property color surface: getMatugenColor("surface", "#1a1c1e")
|
||||||
property color surfaceContainer: getMatugenColor("surface_container", "#1e2023")
|
property color surfaceContainer: getMatugenColor("surface_container", "#1e2023")
|
||||||
property color surfaceContainerHigh: getMatugenColor("surface_container_high", "#292b2f")
|
property color surfaceContainerHigh: getMatugenColor("surface_container_high", "#292b2f")
|
||||||
property color surfaceVariant: getMatugenColor("surface_variant", "#44464f")
|
property color surfaceVariant: getMatugenColor("surface_variant", "#44464f")
|
||||||
// text
|
|
||||||
property color surfaceText: getMatugenColor("on_background", "#e3e8ef")
|
property color surfaceText: getMatugenColor("on_background", "#e3e8ef")
|
||||||
property color primaryText: getMatugenColor("on_primary", "#ffffff")
|
property color primaryText: getMatugenColor("on_primary", "#ffffff")
|
||||||
property color surfaceVariantText: getMatugenColor("on_surface_variant", "#c4c7c5")
|
property color surfaceVariantText: getMatugenColor("on_surface_variant", "#c4c7c5")
|
||||||
// containers & misc
|
|
||||||
property color primaryContainer: getMatugenColor("primary_container", "#1976d2")
|
property color primaryContainer: getMatugenColor("primary_container", "#1976d2")
|
||||||
property color surfaceTint: getMatugenColor("surface_tint", "#8ab4f8")
|
property color surfaceTint: getMatugenColor("surface_tint", "#8ab4f8")
|
||||||
property color outline: getMatugenColor("outline", "#8e918f")
|
property color outline: getMatugenColor("outline", "#8e918f")
|
||||||
// legacy aliases
|
|
||||||
property color accentHi: primary
|
property color accentHi: primary
|
||||||
property color accentLo: secondary
|
property color accentLo: secondary
|
||||||
|
|
||||||
// ──────────────── basic state ────────────────
|
|
||||||
signal colorsUpdated()
|
signal colorsUpdated()
|
||||||
|
|
||||||
function onLightModeChanged() {
|
function onLightModeChanged() {
|
||||||
// Force color properties to update when light mode changes
|
|
||||||
if (matugenColors && Object.keys(matugenColors).length > 0) {
|
if (matugenColors && Object.keys(matugenColors).length > 0) {
|
||||||
console.log("Light mode changed - updating dynamic colors");
|
console.log("Light mode changed - updating dynamic colors");
|
||||||
colorUpdateTrigger++; // This will trigger re-evaluation of all color properties
|
colorUpdateTrigger++;
|
||||||
colorsUpdated();
|
colorsUpdated();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ──────────────── public helper ────────────────
|
|
||||||
function extractColors() {
|
function extractColors() {
|
||||||
console.log("Colors.extractColors() called, matugenAvailable:", matugenAvailable);
|
console.log("Colors.extractColors() called, matugenAvailable:", matugenAvailable);
|
||||||
extractionRequested = true;
|
extractionRequested = true;
|
||||||
@@ -73,9 +62,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function getMatugenColor(path, fallback) {
|
function getMatugenColor(path, fallback) {
|
||||||
// Include colorUpdateTrigger in the function to make properties reactive to changes
|
|
||||||
colorUpdateTrigger;
|
colorUpdateTrigger;
|
||||||
// Use light or dark colors based on Theme.isLightMode
|
|
||||||
const colorMode = (typeof Theme !== "undefined" && Theme.isLightMode) ? "light" : "dark";
|
const colorMode = (typeof Theme !== "undefined" && Theme.isLightMode) ? "light" : "dark";
|
||||||
let cur = matugenColors && matugenColors.colors && matugenColors.colors[colorMode];
|
let cur = matugenColors && matugenColors.colors && matugenColors.colors[colorMode];
|
||||||
for (const part of path.split(".")) {
|
for (const part of path.split(".")) {
|
||||||
@@ -93,15 +80,11 @@ Singleton {
|
|||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
console.log("Colors.qml → home =", homeDir);
|
console.log("Colors.qml → home =", homeDir);
|
||||||
// Don't automatically run color extraction - only when requested
|
|
||||||
matugenCheck.running = true;
|
matugenCheck.running = true;
|
||||||
// Connect to Theme light mode changes to update colors
|
|
||||||
if (typeof Theme !== "undefined")
|
if (typeof Theme !== "undefined")
|
||||||
Theme.isLightModeChanged.connect(root.onLightModeChanged);
|
Theme.isLightModeChanged.connect(root.onLightModeChanged);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// ──────────────── availability checks ────────────────
|
|
||||||
Process {
|
Process {
|
||||||
id: matugenCheck
|
id: matugenCheck
|
||||||
|
|
||||||
@@ -115,7 +98,6 @@ Singleton {
|
|||||||
ToastService.showWarning("matugen not found - dynamic theming disabled");
|
ToastService.showWarning("matugen not found - dynamic theming disabled");
|
||||||
return ;
|
return ;
|
||||||
}
|
}
|
||||||
// If extraction was requested, continue the process
|
|
||||||
if (extractionRequested) {
|
if (extractionRequested) {
|
||||||
console.log("Continuing with color extraction");
|
console.log("Continuing with color extraction");
|
||||||
fileChecker.running = true;
|
fileChecker.running = true;
|
||||||
@@ -124,7 +106,7 @@ Singleton {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Process {
|
Process {
|
||||||
id: fileChecker // exists & readable?
|
id: fileChecker
|
||||||
|
|
||||||
command: ["test", "-r", wallpaperPath]
|
command: ["test", "-r", wallpaperPath]
|
||||||
onExited: (code) => {
|
onExited: (code) => {
|
||||||
@@ -139,13 +121,11 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ──────────────── matugen invocation ────────────────
|
|
||||||
Process {
|
Process {
|
||||||
id: matugenProcess
|
id: matugenProcess
|
||||||
|
|
||||||
command: ["matugen", "-v", "image", wallpaperPath, "--json", "hex"]
|
command: ["matugen", "-v", "image", wallpaperPath, "--json", "hex"]
|
||||||
|
|
||||||
// ── grab stdout as a stream ──
|
|
||||||
stdout: StdioCollector {
|
stdout: StdioCollector {
|
||||||
id: matugenCollector
|
id: matugenCollector
|
||||||
|
|
||||||
@@ -162,7 +142,6 @@ Singleton {
|
|||||||
root.matugenColors = JSON.parse(out);
|
root.matugenColors = JSON.parse(out);
|
||||||
root.colorsUpdated();
|
root.colorsUpdated();
|
||||||
ToastService.clearWallpaperError();
|
ToastService.clearWallpaperError();
|
||||||
ToastService.showInfo("Loaded Dynamic Theme Colors");
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.error("JSON parse failed:", e);
|
console.error("JSON parse failed:", e);
|
||||||
ToastService.wallpaperErrorStatus = "error";
|
ToastService.wallpaperErrorStatus = "error";
|
||||||
@@ -171,7 +150,6 @@ Singleton {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// grab stderr too, so we can print it above
|
|
||||||
stderr: StdioCollector {
|
stderr: StdioCollector {
|
||||||
id: matugenErr
|
id: matugenErr
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -388,12 +388,6 @@ Singleton {
|
|||||||
// Transparency system - can be overridden by Prefs
|
// Transparency system - can be overridden by Prefs
|
||||||
property real panelTransparency: 0.85
|
property real panelTransparency: 0.85
|
||||||
property real popupTransparency: 0.92
|
property real popupTransparency: 0.92
|
||||||
property string iconFont: { Qt.fontFamilies()
|
|
||||||
.indexOf("Material Symbols Rounded") !== -1 ? "Material Symbols Rounded" : "Material Icons Round" }
|
|
||||||
property string iconFontFilled: { Qt.fontFamilies()
|
|
||||||
.indexOf("Material Symbols Rounded") !== -1 ? "Material Symbols Rounded" : "Material Icons Rounded" }
|
|
||||||
property int iconFontWeight: Font.Normal
|
|
||||||
property int iconFontFilledWeight: Font.Medium
|
|
||||||
|
|
||||||
// Handle successful color extraction
|
// Handle successful color extraction
|
||||||
function onColorsUpdated() {
|
function onColorsUpdated() {
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import Quickshell.Wayland
|
|||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
// For recents, use the recent apps from Prefs and filter out non-existent ones
|
// For recents, use the recent apps from Prefs and filter out non-existent ones
|
||||||
@@ -74,7 +75,7 @@ PanelWindow {
|
|||||||
if (filteredModel.count > 0) {
|
if (filteredModel.count > 0) {
|
||||||
if (viewMode === "grid") {
|
if (viewMode === "grid") {
|
||||||
// Grid navigation: move by columns
|
// Grid navigation: move by columns
|
||||||
var columnsCount = appGrid.columnsCount || 8;
|
var columnsCount = appGrid.columns || 4;
|
||||||
selectedIndex = Math.min(selectedIndex + columnsCount, filteredModel.count - 1);
|
selectedIndex = Math.min(selectedIndex + columnsCount, filteredModel.count - 1);
|
||||||
} else {
|
} else {
|
||||||
// List navigation: next item
|
// List navigation: next item
|
||||||
@@ -87,7 +88,7 @@ PanelWindow {
|
|||||||
if (filteredModel.count > 0) {
|
if (filteredModel.count > 0) {
|
||||||
if (viewMode === "grid") {
|
if (viewMode === "grid") {
|
||||||
// Grid navigation: move by columns
|
// Grid navigation: move by columns
|
||||||
var columnsCount = appGrid.columnsCount || 8;
|
var columnsCount = appGrid.columns || 4;
|
||||||
selectedIndex = Math.max(selectedIndex - columnsCount, 0);
|
selectedIndex = Math.max(selectedIndex - columnsCount, 0);
|
||||||
} else {
|
} else {
|
||||||
// List navigation: previous item
|
// List navigation: previous item
|
||||||
@@ -459,13 +460,11 @@ PanelWindow {
|
|||||||
anchors.rightMargin: Theme.spacingL
|
anchors.rightMargin: Theme.spacingL
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: "search"
|
name: "search"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: searchField.activeFocus ? Theme.primary : Theme.surfaceVariantText
|
color: searchField.activeFocus ? Theme.primary : Theme.surfaceVariantText
|
||||||
font.weight: Theme.iconFontWeight
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TextInput {
|
TextInput {
|
||||||
@@ -526,11 +525,10 @@ PanelWindow {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: searchField.text.length > 0
|
visible: searchField.text.length > 0
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "close"
|
name: "close"
|
||||||
font.family: Theme.iconFont
|
size: 16
|
||||||
font.pixelSize: 16
|
|
||||||
color: clearSearchArea.containsMouse ? Theme.outline : Theme.surfaceVariantText
|
color: clearSearchArea.containsMouse ? Theme.outline : Theme.surfaceVariantText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -581,10 +579,9 @@ PanelWindow {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "category"
|
name: "category"
|
||||||
font.family: Theme.iconFont
|
size: 18
|
||||||
font.pixelSize: 18
|
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -599,13 +596,12 @@ PanelWindow {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: Theme.spacingM
|
anchors.rightMargin: Theme.spacingM
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: showCategories ? "expand_less" : "expand_more"
|
name: showCategories ? "expand_less" : "expand_more"
|
||||||
font.family: Theme.iconFont
|
size: 18
|
||||||
font.pixelSize: 18
|
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -635,11 +631,10 @@ PanelWindow {
|
|||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: viewMode === "list" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : listViewArea.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08) : "transparent"
|
color: viewMode === "list" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : listViewArea.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08) : "transparent"
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "view_list"
|
name: "view_list"
|
||||||
font.family: Theme.iconFont
|
size: 20
|
||||||
font.pixelSize: 20
|
|
||||||
color: viewMode === "list" ? Theme.primary : Theme.surfaceText
|
color: viewMode === "list" ? Theme.primary : Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -664,11 +659,10 @@ PanelWindow {
|
|||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: viewMode === "grid" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : gridViewArea.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08) : "transparent"
|
color: viewMode === "grid" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : gridViewArea.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.08) : "transparent"
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "grid_view"
|
name: "grid_view"
|
||||||
font.family: Theme.iconFont
|
size: 20
|
||||||
font.pixelSize: 20
|
|
||||||
color: viewMode === "grid" ? Theme.primary : Theme.surfaceText
|
color: viewMode === "grid" ? Theme.primary : Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -705,96 +699,51 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
// List view scroll container
|
// List view
|
||||||
ScrollView {
|
DankListView {
|
||||||
|
id: appList
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
clip: true
|
|
||||||
visible: viewMode === "list"
|
visible: viewMode === "list"
|
||||||
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
|
model: filteredModel
|
||||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
currentIndex: selectedIndex
|
||||||
|
itemHeight: 72
|
||||||
ListView {
|
iconSize: 56
|
||||||
id: appList
|
showDescription: true
|
||||||
|
onItemClicked: function(index, modelData) {
|
||||||
// Make mouse wheel scrolling more responsive
|
if (modelData.desktopEntry) {
|
||||||
property real wheelStepSize: 60
|
Prefs.addRecentApp(modelData.desktopEntry);
|
||||||
|
modelData.desktopEntry.execute();
|
||||||
width: parent.width
|
} else {
|
||||||
anchors.margins: Theme.spacingS
|
launcher.launchApp(modelData.exec);
|
||||||
spacing: Theme.spacingS
|
|
||||||
model: filteredModel
|
|
||||||
delegate: listDelegate
|
|
||||||
currentIndex: selectedIndex
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
acceptedButtons: Qt.NoButton
|
|
||||||
propagateComposedEvents: true
|
|
||||||
z: -1
|
|
||||||
onWheel: (wheel) => {
|
|
||||||
var delta = wheel.angleDelta.y;
|
|
||||||
var steps = delta / 120; // Standard wheel step
|
|
||||||
appList.contentY -= steps * appList.wheelStepSize;
|
|
||||||
// Ensure we stay within bounds
|
|
||||||
if (appList.contentY < 0)
|
|
||||||
appList.contentY = 0;
|
|
||||||
else if (appList.contentY > appList.contentHeight - appList.height)
|
|
||||||
appList.contentY = Math.max(0, appList.contentHeight - appList.height);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
launcher.hide();
|
||||||
|
}
|
||||||
|
onItemHovered: function(index) {
|
||||||
|
selectedIndex = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grid view scroll container
|
// Grid view
|
||||||
ScrollView {
|
DankGridView {
|
||||||
|
id: appGrid
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
clip: true
|
|
||||||
visible: viewMode === "grid"
|
visible: viewMode === "grid"
|
||||||
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
model: filteredModel
|
||||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
columns: 4
|
||||||
|
adaptiveColumns: false
|
||||||
GridView {
|
currentIndex: selectedIndex
|
||||||
id: appGrid
|
onItemClicked: function(index, modelData) {
|
||||||
|
if (modelData.desktopEntry) {
|
||||||
// Responsive cell sizes based on screen width - 4 columns
|
Prefs.addRecentApp(modelData.desktopEntry);
|
||||||
property int columnsCount: 4
|
modelData.desktopEntry.execute();
|
||||||
property int baseCellWidth: (width - Theme.spacingS * 2) / columnsCount
|
} else {
|
||||||
property int baseCellHeight: baseCellWidth + 20
|
launcher.launchApp(modelData.exec);
|
||||||
// Center the grid content
|
|
||||||
property int remainingSpace: width - (columnsCount * cellWidth)
|
|
||||||
// Make mouse wheel scrolling more responsive
|
|
||||||
property real wheelStepSize: 60
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Theme.spacingS
|
|
||||||
cellWidth: baseCellWidth
|
|
||||||
cellHeight: baseCellHeight
|
|
||||||
leftMargin: Math.max(Theme.spacingS, remainingSpace / 2)
|
|
||||||
rightMargin: leftMargin
|
|
||||||
model: filteredModel
|
|
||||||
delegate: gridDelegate
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
acceptedButtons: Qt.NoButton
|
|
||||||
propagateComposedEvents: true
|
|
||||||
z: -1
|
|
||||||
onWheel: (wheel) => {
|
|
||||||
var delta = wheel.angleDelta.y;
|
|
||||||
var steps = delta / 120; // Standard wheel step
|
|
||||||
appGrid.contentY -= steps * appGrid.wheelStepSize;
|
|
||||||
// Ensure we stay within bounds
|
|
||||||
if (appGrid.contentY < 0)
|
|
||||||
appGrid.contentY = 0;
|
|
||||||
else if (appGrid.contentY > appGrid.contentHeight - appGrid.height)
|
|
||||||
appGrid.contentY = Math.max(0, appGrid.contentHeight - appGrid.height);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
launcher.hide();
|
||||||
|
}
|
||||||
|
onItemHovered: function(index) {
|
||||||
|
selectedIndex = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -918,163 +867,6 @@ PanelWindow {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// List delegate with new loader
|
|
||||||
Component {
|
|
||||||
id: listDelegate
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: appList.width
|
|
||||||
height: 72
|
|
||||||
radius: Theme.cornerRadiusLarge
|
|
||||||
color: ListView.isCurrentItem ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) : appMouseArea.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.03)
|
|
||||||
border.color: ListView.isCurrentItem ? 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: ListView.isCurrentItem ? 2 : 1
|
|
||||||
|
|
||||||
Row {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Theme.spacingM
|
|
||||||
spacing: Theme.spacingL
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: 56
|
|
||||||
height: 56
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: listIconLoader
|
|
||||||
|
|
||||||
property var modelData: model
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
sourceComponent: iconComponent
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
width: parent.width - 56 - Theme.spacingL
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
|
|
||||||
Text {
|
|
||||||
width: parent.width
|
|
||||||
text: model.name
|
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
|
||||||
color: Theme.surfaceText
|
|
||||||
font.weight: Font.Medium
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
width: parent.width
|
|
||||||
text: model.comment || "Application"
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
elide: Text.ElideRight
|
|
||||||
visible: model.comment && model.comment.length > 0
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: appMouseArea
|
|
||||||
|
|
||||||
property bool hovered: containsMouse
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
z: 10
|
|
||||||
onEntered: selectedIndex = index
|
|
||||||
onClicked: {
|
|
||||||
if (model.desktopEntry) {
|
|
||||||
Prefs.addRecentApp(model.desktopEntry);
|
|
||||||
model.desktopEntry.execute();
|
|
||||||
} else {
|
|
||||||
launcher.launchApp(model.exec);
|
|
||||||
}
|
|
||||||
launcher.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Grid delegate with new loader (uses dynamic icon size)
|
|
||||||
Component {
|
|
||||||
id: gridDelegate
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: appGrid.cellWidth - 8
|
|
||||||
height: appGrid.cellHeight - 8
|
|
||||||
radius: Theme.cornerRadiusLarge
|
|
||||||
color: selectedIndex === index ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) : gridAppArea.hovered ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.03)
|
|
||||||
border.color: selectedIndex === index ? 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: selectedIndex === index ? 2 : 1
|
|
||||||
|
|
||||||
Column {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
|
|
||||||
Item {
|
|
||||||
property int iconSize: Math.min(56, Math.max(32, appGrid.cellWidth * 0.6))
|
|
||||||
|
|
||||||
width: iconSize
|
|
||||||
height: iconSize
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
|
|
||||||
Loader {
|
|
||||||
id: gridIconLoader
|
|
||||||
|
|
||||||
property var modelData: model
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
sourceComponent: iconComponent
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
width: appGrid.cellWidth - 12
|
|
||||||
text: model.name
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceText
|
|
||||||
font.weight: Font.Medium
|
|
||||||
elide: Text.ElideRight
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
maximumLineCount: 2
|
|
||||||
wrapMode: Text.WordWrap
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: gridAppArea
|
|
||||||
|
|
||||||
property bool hovered: containsMouse
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
z: 10
|
|
||||||
onEntered: selectedIndex = index
|
|
||||||
onClicked: {
|
|
||||||
if (model.desktopEntry) {
|
|
||||||
Prefs.addRecentApp(model.desktopEntry);
|
|
||||||
model.desktopEntry.execute();
|
|
||||||
} else {
|
|
||||||
launcher.launchApp(model.exec);
|
|
||||||
}
|
|
||||||
launcher.hide();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ import Quickshell.Wayland
|
|||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: root
|
id: root
|
||||||
@@ -105,11 +106,10 @@ PanelWindow {
|
|||||||
radius: 16
|
radius: 16
|
||||||
color: closeBatteryArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) : "transparent"
|
color: closeBatteryArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) : "transparent"
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "close"
|
name: "close"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 4
|
||||||
font.pixelSize: Theme.iconSize - 4
|
|
||||||
color: closeBatteryArea.containsMouse ? Theme.error : Theme.surfaceText
|
color: closeBatteryArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,10 +143,9 @@ PanelWindow {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingL
|
spacing: Theme.spacingL
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: Theme.getBatteryIcon(BatteryService.batteryLevel, BatteryService.isCharging, BatteryService.batteryAvailable)
|
name: Theme.getBatteryIcon(BatteryService.batteryLevel, BatteryService.isCharging, BatteryService.batteryAvailable)
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSizeLarge
|
||||||
font.pixelSize: Theme.iconSizeLarge
|
|
||||||
color: {
|
color: {
|
||||||
if (BatteryService.isLowBattery && !BatteryService.isCharging)
|
if (BatteryService.isLowBattery && !BatteryService.isCharging)
|
||||||
return Theme.error;
|
return Theme.error;
|
||||||
@@ -232,10 +231,9 @@ PanelWindow {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingL
|
spacing: Theme.spacingL
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: Theme.getBatteryIcon(0, false, false)
|
name: Theme.getBatteryIcon(0, false, false)
|
||||||
font.family: Theme.iconFont
|
size: 36
|
||||||
font.pixelSize: 36
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -364,10 +362,9 @@ PanelWindow {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: Theme.getPowerProfileIcon(modelData)
|
name: Theme.getPowerProfileIcon(modelData)
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: batteryControlPopup.isActiveProfile(modelData) ? Theme.primary : Theme.surfaceText
|
color: batteryControlPopup.isActiveProfile(modelData) ? Theme.primary : Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -428,10 +425,9 @@ PanelWindow {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "warning"
|
name: "warning"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: Theme.error
|
color: Theme.error
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@ import QtQuick
|
|||||||
import Quickshell.Services.UPower
|
import Quickshell.Services.UPower
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: batteryWidget
|
id: batteryWidget
|
||||||
@@ -20,10 +21,9 @@ Rectangle {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: 4
|
spacing: 4
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: Theme.getBatteryIcon(BatteryService.batteryLevel, BatteryService.isCharging, BatteryService.batteryAvailable)
|
name: Theme.getBatteryIcon(BatteryService.batteryLevel, BatteryService.isCharging, BatteryService.batteryAvailable)
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 6
|
||||||
font.pixelSize: Theme.iconSize - 6
|
|
||||||
color: {
|
color: {
|
||||||
if (!BatteryService.batteryAvailable)
|
if (!BatteryService.batteryAvailable)
|
||||||
return Theme.surfaceText;
|
return Theme.surfaceText;
|
||||||
@@ -3,6 +3,7 @@ import QtQuick.Controls
|
|||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
Column {
|
Column {
|
||||||
id: calendarWidget
|
id: calendarWidget
|
||||||
@@ -57,13 +58,11 @@ Column {
|
|||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: prevMonthArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
color: prevMonthArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "chevron_left"
|
name: "chevron_left"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: Theme.primary
|
color: Theme.primary
|
||||||
font.weight: Theme.iconFontWeight
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
@@ -98,13 +97,11 @@ Column {
|
|||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: nextMonthArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
color: nextMonthArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : "transparent"
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "chevron_right"
|
name: "chevron_right"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: Theme.primary
|
color: Theme.primary
|
||||||
font.weight: Theme.iconFontWeight
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
@@ -3,6 +3,7 @@ import QtQuick.Controls
|
|||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
// Events widget for selected date - Material Design 3 style
|
// Events widget for selected date - Material Design 3 style
|
||||||
Rectangle {
|
Rectangle {
|
||||||
@@ -67,10 +68,9 @@ Rectangle {
|
|||||||
anchors.margins: Theme.spacingL
|
anchors.margins: Theme.spacingL
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "event"
|
name: "event"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 2
|
||||||
font.pixelSize: Theme.iconSize - 2
|
|
||||||
color: Theme.primary
|
color: Theme.primary
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -91,10 +91,9 @@ Rectangle {
|
|||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
visible: !hasEvents
|
visible: !hasEvents
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "event_busy"
|
name: "event_busy"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize + 8
|
||||||
font.pixelSize: Theme.iconSize + 8
|
|
||||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3)
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3)
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
@@ -202,10 +201,9 @@ Rectangle {
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "schedule"
|
name: "schedule"
|
||||||
font.family: Theme.iconFont
|
size: Theme.fontSizeSmall
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -239,10 +237,9 @@ Rectangle {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: modelData.location !== ""
|
visible: modelData.location !== ""
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "location_on"
|
name: "location_on"
|
||||||
font.family: Theme.iconFont
|
size: Theme.fontSizeSmall
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,7 @@ import Quickshell
|
|||||||
import Quickshell.Services.Mpris
|
import Quickshell.Services.Mpris
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: mediaPlayerWidget
|
id: mediaPlayerWidget
|
||||||
@@ -90,10 +91,9 @@ Rectangle {
|
|||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
visible: (!activePlayer && !lastValidTitle) || (activePlayer && activePlayer.trackTitle === "" && lastValidTitle === "")
|
visible: (!activePlayer && !lastValidTitle) || (activePlayer && activePlayer.trackTitle === "" && lastValidTitle === "")
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "music_note"
|
name: "music_note"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize + 8
|
||||||
font.pixelSize: Theme.iconSize + 8
|
|
||||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
@@ -149,11 +149,10 @@ Rectangle {
|
|||||||
visible: albumArt.status !== Image.Ready
|
visible: albumArt.status !== Image.Ready
|
||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "album"
|
name: "album"
|
||||||
font.family: Theme.iconFont
|
size: 28
|
||||||
font.pixelSize: 28
|
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -356,11 +355,10 @@ Rectangle {
|
|||||||
radius: 14
|
radius: 14
|
||||||
color: prevBtnArea.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.12) : "transparent"
|
color: prevBtnArea.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.12) : "transparent"
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "skip_previous"
|
name: "skip_previous"
|
||||||
font.family: Theme.iconFont
|
size: 16
|
||||||
font.pixelSize: 16
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,11 +391,10 @@ Rectangle {
|
|||||||
radius: 16
|
radius: 16
|
||||||
color: Theme.primary
|
color: Theme.primary
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: activePlayer && activePlayer.playbackState === MprisPlaybackState.Playing ? "pause" : "play_arrow"
|
name: activePlayer && activePlayer.playbackState === MprisPlaybackState.Playing ? "pause" : "play_arrow"
|
||||||
font.family: Theme.iconFont
|
size: 20
|
||||||
font.pixelSize: 20
|
|
||||||
color: Theme.background
|
color: Theme.background
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -417,11 +414,10 @@ Rectangle {
|
|||||||
radius: 14
|
radius: 14
|
||||||
color: nextBtnArea.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.12) : "transparent"
|
color: nextBtnArea.containsMouse ? Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.12) : "transparent"
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "skip_next"
|
name: "skip_next"
|
||||||
font.family: Theme.iconFont
|
size: 16
|
||||||
font.pixelSize: 16
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3,6 +3,7 @@ import QtQuick.Controls
|
|||||||
import QtQuick.Effects
|
import QtQuick.Effects
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: weatherWidget
|
id: weatherWidget
|
||||||
@@ -21,10 +22,9 @@ Rectangle {
|
|||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
visible: !WeatherService.weather.available || WeatherService.weather.temp === 0
|
visible: !WeatherService.weather.available || WeatherService.weather.temp === 0
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "cloud_off"
|
name: "cloud_off"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize + 8
|
||||||
font.pixelSize: Theme.iconSize + 8
|
|
||||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
@@ -55,10 +55,9 @@ Rectangle {
|
|||||||
spacing: Theme.spacingL
|
spacing: Theme.spacingL
|
||||||
|
|
||||||
// Weather icon
|
// Weather icon
|
||||||
Text {
|
DankIcon {
|
||||||
text: WeatherService.getWeatherIcon(WeatherService.weather.wCode)
|
name: WeatherService.getWeatherIcon(WeatherService.weather.wCode)
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize + 8
|
||||||
font.pixelSize: Theme.iconSize + 8
|
|
||||||
color: Theme.primary
|
color: Theme.primary
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -109,10 +108,9 @@ Rectangle {
|
|||||||
Row {
|
Row {
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "humidity_low"
|
name: "humidity_low"
|
||||||
font.family: Theme.iconFont
|
size: Theme.fontSizeSmall
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -129,10 +127,9 @@ Rectangle {
|
|||||||
Row {
|
Row {
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "air"
|
name: "air"
|
||||||
font.family: Theme.iconFont
|
size: Theme.fontSizeSmall
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -149,10 +146,9 @@ Rectangle {
|
|||||||
Row {
|
Row {
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "wb_twilight"
|
name: "wb_twilight"
|
||||||
font.family: Theme.iconFont
|
size: Theme.fontSizeSmall
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -169,10 +165,9 @@ Rectangle {
|
|||||||
Row {
|
Row {
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "bedtime"
|
name: "bedtime"
|
||||||
font.family: Theme.iconFont
|
size: Theme.fontSizeSmall
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,8 @@ import Quickshell.Services.Pipewire
|
|||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
import "../../Widgets"
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: audioTab
|
id: audioTab
|
||||||
@@ -23,57 +25,22 @@ Item {
|
|||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
// Audio Sub-tabs
|
// Audio Sub-tabs
|
||||||
Row {
|
DankTabBar {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
height: 40
|
tabHeight: 40
|
||||||
spacing: 2
|
currentIndex: audioTab.audioSubTab
|
||||||
|
showIcons: false
|
||||||
Rectangle {
|
model: [
|
||||||
width: parent.width / 2 - 1
|
{
|
||||||
height: parent.height
|
"text": "Output"
|
||||||
radius: Theme.cornerRadius
|
},
|
||||||
color: audioTab.audioSubTab === 0 ? Theme.primary : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
{
|
||||||
|
"text": "Input"
|
||||||
Text {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: "Output"
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
color: audioTab.audioSubTab === 0 ? Theme.primaryText : Theme.surfaceText
|
|
||||||
font.weight: Font.Medium
|
|
||||||
}
|
}
|
||||||
|
]
|
||||||
MouseArea {
|
onTabClicked: function(index) {
|
||||||
anchors.fill: parent
|
audioTab.audioSubTab = index;
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: audioTab.audioSubTab = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: parent.width / 2 - 1
|
|
||||||
height: parent.height
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: audioTab.audioSubTab === 1 ? Theme.primary : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
|
||||||
|
|
||||||
Text {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: "Input"
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
color: audioTab.audioSubTab === 1 ? Theme.primaryText : Theme.surfaceText
|
|
||||||
font.weight: Font.Medium
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: audioTab.audioSubTab = 1
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Output Tab Content
|
// Output Tab Content
|
||||||
@@ -103,10 +70,9 @@ Item {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: audioTab.volumeMuted ? "volume_off" : "volume_down"
|
name: audioTab.volumeMuted ? "volume_off" : "volume_down"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: audioTab.volumeMuted ? Theme.error : Theme.surfaceText
|
color: audioTab.volumeMuted ? Theme.error : Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
@@ -248,10 +214,9 @@ Item {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "volume_up"
|
name: "volume_up"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -288,10 +253,9 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "check_circle"
|
name: "check_circle"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 4
|
||||||
font.pixelSize: Theme.iconSize - 4
|
|
||||||
color: Theme.primary
|
color: Theme.primary
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -335,8 +299,8 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: {
|
name: {
|
||||||
if (modelData.name.includes("bluez"))
|
if (modelData.name.includes("bluez"))
|
||||||
return "headset";
|
return "headset";
|
||||||
else if (modelData.name.includes("hdmi"))
|
else if (modelData.name.includes("hdmi"))
|
||||||
@@ -346,8 +310,7 @@ Item {
|
|||||||
else
|
else
|
||||||
return "speaker";
|
return "speaker";
|
||||||
}
|
}
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: modelData === AudioService.sink ? Theme.primary : Theme.surfaceText
|
color: modelData === AudioService.sink ? Theme.primary : Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -429,10 +392,9 @@ Item {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: audioTab.micMuted ? "mic_off" : "mic"
|
name: audioTab.micMuted ? "mic_off" : "mic"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: audioTab.micMuted ? Theme.error : Theme.surfaceText
|
color: audioTab.micMuted ? Theme.error : Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
@@ -574,10 +536,9 @@ Item {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "mic"
|
name: "mic"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -614,10 +575,9 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "check_circle"
|
name: "check_circle"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 4
|
||||||
font.pixelSize: Theme.iconSize - 4
|
|
||||||
color: Theme.primary
|
color: Theme.primary
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -661,8 +621,8 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: {
|
name: {
|
||||||
if (modelData.name.includes("bluez"))
|
if (modelData.name.includes("bluez"))
|
||||||
return "headset_mic";
|
return "headset_mic";
|
||||||
else if (modelData.name.includes("usb"))
|
else if (modelData.name.includes("usb"))
|
||||||
@@ -670,8 +630,7 @@ Item {
|
|||||||
else
|
else
|
||||||
return "mic";
|
return "mic";
|
||||||
}
|
}
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: modelData === AudioService.source ? Theme.primary : Theme.surfaceText
|
color: modelData === AudioService.source ? Theme.primary : Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -6,6 +6,7 @@ import Quickshell.Io
|
|||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: bluetoothTab
|
id: bluetoothTab
|
||||||
@@ -34,10 +35,9 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "bluetooth"
|
name: "bluetooth"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSizeLarge
|
||||||
font.pixelSize: Theme.iconSizeLarge
|
|
||||||
color: BluetoothService.adapter && BluetoothService.adapter.enabled ? Theme.primary : Theme.surfaceText
|
color: BluetoothService.adapter && BluetoothService.adapter.enabled ? Theme.primary : Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -109,10 +109,9 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: BluetoothService.getDeviceIcon(modelData)
|
name: BluetoothService.getDeviceIcon(modelData)
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: modelData.connected ? Theme.primary : Theme.surfaceText
|
color: modelData.connected ? Theme.primary : Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -169,11 +168,9 @@ Item {
|
|||||||
anchors.rightMargin: Theme.spacingM
|
anchors.rightMargin: Theme.spacingM
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "more_vert"
|
name: "more_vert"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.weight: Theme.iconFontWeight
|
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
opacity: 0.6
|
opacity: 0.6
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
@@ -258,10 +255,9 @@ Item {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: BluetoothService.adapter && BluetoothService.adapter.discovering ? "stop" : "bluetooth_searching"
|
name: BluetoothService.adapter && BluetoothService.adapter.discovering ? "stop" : "bluetooth_searching"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 4
|
||||||
font.pixelSize: Theme.iconSize - 4
|
|
||||||
color: Theme.primary
|
color: Theme.primary
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -341,10 +337,9 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: BluetoothService.getDeviceIcon(modelData)
|
name: BluetoothService.getDeviceIcon(modelData)
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: {
|
color: {
|
||||||
if (modelData.pairing)
|
if (modelData.pairing)
|
||||||
return Theme.warning;
|
return Theme.warning;
|
||||||
@@ -402,10 +397,9 @@ Item {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: BluetoothService.getSignalIcon(modelData)
|
name: BluetoothService.getSignalIcon(modelData)
|
||||||
font.family: Theme.iconFont
|
size: Theme.fontSizeSmall
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.7)
|
||||||
visible: modelData.signalStrength !== undefined && modelData.signalStrength > 0 && !modelData.pairing && !modelData.blocked
|
visible: modelData.signalStrength !== undefined && modelData.signalStrength > 0 && !modelData.pairing && !modelData.blocked
|
||||||
}
|
}
|
||||||
@@ -510,10 +504,9 @@ Item {
|
|||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "sync"
|
name: "sync"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSizeLarge
|
||||||
font.pixelSize: Theme.iconSizeLarge
|
|
||||||
color: Theme.primary
|
color: Theme.primary
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
@@ -638,10 +631,9 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: bluetoothContextMenuWindow.deviceData && bluetoothContextMenuWindow.deviceData.connected ? "link_off" : "link"
|
name: bluetoothContextMenuWindow.deviceData && bluetoothContextMenuWindow.deviceData.connected ? "link_off" : "link"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 2
|
||||||
font.pixelSize: Theme.iconSize - 2
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
opacity: 0.7
|
opacity: 0.7
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -712,10 +704,9 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "delete"
|
name: "delete"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 2
|
||||||
font.pixelSize: Theme.iconSize - 2
|
|
||||||
color: forgetArea.containsMouse ? Theme.error : Theme.surfaceText
|
color: forgetArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||||
opacity: 0.7
|
opacity: 0.7
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -8,6 +8,8 @@ import Quickshell.Wayland
|
|||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
import "../../Widgets"
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: root
|
id: root
|
||||||
@@ -225,22 +227,20 @@ PanelWindow {
|
|||||||
color: Theme.primary
|
color: Theme.primary
|
||||||
visible: !parent.hasImage
|
visible: !parent.hasImage
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "person"
|
name: "person"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize + 8
|
||||||
font.pixelSize: Theme.iconSize + 8
|
|
||||||
color: Theme.primaryText
|
color: Theme.primaryText
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error icon for when the image fails to load.
|
// Error icon for when the image fails to load.
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "warning"
|
name: "warning"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize + 8
|
||||||
font.pixelSize: Theme.iconSize + 8
|
|
||||||
color: Theme.primaryText
|
color: Theme.primaryText
|
||||||
visible: Prefs.profileImage !== "" && profileImageLoader.status === Image.Error
|
visible: Prefs.profileImage !== "" && profileImageLoader.status === Image.Error
|
||||||
}
|
}
|
||||||
@@ -292,14 +292,13 @@ PanelWindow {
|
|||||||
color: "transparent"
|
color: "transparent"
|
||||||
clip: true
|
clip: true
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: root.powerOptionsExpanded ? "expand_less" : "power_settings_new"
|
name: root.powerOptionsExpanded ? "expand_less" : "power_settings_new"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 2
|
||||||
font.pixelSize: Theme.iconSize - 2
|
|
||||||
color: powerButton.containsMouse || root.powerOptionsExpanded ? Theme.error : Theme.surfaceText
|
color: powerButton.containsMouse || root.powerOptionsExpanded ? Theme.error : Theme.surfaceText
|
||||||
|
|
||||||
Behavior on text {
|
Behavior on name {
|
||||||
// Smooth icon transition
|
// Smooth icon transition
|
||||||
SequentialAnimation {
|
SequentialAnimation {
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
@@ -312,7 +311,7 @@ PanelWindow {
|
|||||||
|
|
||||||
PropertyAction {
|
PropertyAction {
|
||||||
target: parent
|
target: parent
|
||||||
property: "text"
|
property: "name"
|
||||||
}
|
}
|
||||||
|
|
||||||
NumberAnimation {
|
NumberAnimation {
|
||||||
@@ -359,11 +358,10 @@ PanelWindow {
|
|||||||
radius: 20
|
radius: 20
|
||||||
color: settingsButton.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.5)
|
color: settingsButton.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.5)
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "settings"
|
name: "settings"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 2
|
||||||
font.pixelSize: Theme.iconSize - 2
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -420,10 +418,9 @@ PanelWindow {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "logout"
|
name: "logout"
|
||||||
font.family: Theme.iconFont
|
size: Theme.fontSizeSmall
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: logoutButton.containsMouse ? Theme.warning : Theme.surfaceText
|
color: logoutButton.containsMouse ? Theme.warning : Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -476,10 +473,9 @@ PanelWindow {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "restart_alt"
|
name: "restart_alt"
|
||||||
font.family: Theme.iconFont
|
size: Theme.fontSizeSmall
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: rebootButton.containsMouse ? Theme.warning : Theme.surfaceText
|
color: rebootButton.containsMouse ? Theme.warning : Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -532,10 +528,9 @@ PanelWindow {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "power_settings_new"
|
name: "power_settings_new"
|
||||||
font.family: Theme.iconFont
|
size: Theme.fontSizeSmall
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: shutdownButton.containsMouse ? Theme.error : Theme.surfaceText
|
color: shutdownButton.containsMouse ? Theme.error : Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -599,105 +594,54 @@ PanelWindow {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Tab buttons
|
// Tab buttons
|
||||||
Row {
|
DankTabBar {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.spacingXS
|
tabHeight: 40
|
||||||
|
currentIndex: {
|
||||||
Repeater {
|
let tabs = ["network", "audio"];
|
||||||
model: {
|
if (BluetoothService.available)
|
||||||
|
tabs.push("bluetooth");
|
||||||
|
tabs.push("display");
|
||||||
|
return tabs.indexOf(root.currentTab);
|
||||||
|
}
|
||||||
|
model: {
|
||||||
let tabs = [{
|
let tabs = [{
|
||||||
"name": "Network",
|
"text": "Network",
|
||||||
"icon": "wifi",
|
"icon": "wifi",
|
||||||
"id": "network",
|
"id": "network"
|
||||||
"available": true
|
|
||||||
}];
|
}];
|
||||||
// Always show audio
|
// Always show audio
|
||||||
tabs.push({
|
tabs.push({
|
||||||
"name": "Audio",
|
"text": "Audio",
|
||||||
"icon": "volume_up",
|
"icon": "volume_up",
|
||||||
"id": "audio",
|
"id": "audio"
|
||||||
"available": true
|
|
||||||
});
|
});
|
||||||
// Show Bluetooth only if available
|
// Show Bluetooth only if available
|
||||||
if (BluetoothService.available)
|
if (BluetoothService.available)
|
||||||
tabs.push({
|
tabs.push({
|
||||||
"name": "Bluetooth",
|
"text": "Bluetooth",
|
||||||
"icon": "bluetooth",
|
"icon": "bluetooth",
|
||||||
"id": "bluetooth",
|
"id": "bluetooth"
|
||||||
"available": true
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Always show display
|
// Always show display
|
||||||
tabs.push({
|
tabs.push({
|
||||||
"name": "Display",
|
"text": "Display",
|
||||||
"icon": "brightness_6",
|
"icon": "brightness_6",
|
||||||
"id": "display",
|
"id": "display"
|
||||||
"available": true
|
|
||||||
});
|
});
|
||||||
return tabs;
|
return tabs;
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
property int tabCount: {
|
|
||||||
let count = 3; // Network + Audio + Display (always visible)
|
|
||||||
if (BluetoothService.available)
|
|
||||||
count++;
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
width: (parent.width - Theme.spacingXS * (tabCount - 1)) / tabCount
|
|
||||||
height: 40
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: root.currentTab === modelData.id ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) : tabArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
|
|
||||||
|
|
||||||
Row {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: modelData.icon
|
|
||||||
font.family: Theme.iconFont
|
|
||||||
font.pixelSize: Theme.iconSize - 4
|
|
||||||
color: root.currentTab === modelData.id ? Theme.primary : Theme.surfaceText
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: modelData.name
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: root.currentTab === modelData.id ? Theme.primary : Theme.surfaceText
|
|
||||||
font.weight: root.currentTab === modelData.id ? Font.Medium : Font.Normal
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: tabArea
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
root.currentTab = modelData.id;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: Theme.shortDuration
|
|
||||||
easing.type: Theme.standardEasing
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
onTabClicked: function(index) {
|
||||||
|
let tabs = ["network", "audio"];
|
||||||
|
if (BluetoothService.available)
|
||||||
|
tabs.push("bluetooth");
|
||||||
|
tabs.push("display");
|
||||||
|
root.currentTab = tabs[index];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tab content area
|
// Tab content area
|
||||||
@@ -5,6 +5,7 @@ import Quickshell.Io
|
|||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Modules
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
ScrollView {
|
ScrollView {
|
||||||
@@ -39,7 +40,7 @@ ScrollView {
|
|||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomSlider {
|
DankSlider {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
value: BrightnessService.brightnessLevel
|
value: BrightnessService.brightnessLevel
|
||||||
leftIcon: "brightness_low"
|
leftIcon: "brightness_low"
|
||||||
@@ -97,10 +98,9 @@ ScrollView {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: Prefs.nightModeEnabled ? "nightlight" : "dark_mode"
|
name: Prefs.nightModeEnabled ? "nightlight" : "dark_mode"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSizeLarge
|
||||||
font.pixelSize: Theme.iconSizeLarge
|
|
||||||
color: Prefs.nightModeEnabled ? Theme.primary : Theme.surfaceText
|
color: Prefs.nightModeEnabled ? Theme.primary : Theme.surfaceText
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
@@ -149,10 +149,9 @@ ScrollView {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: Theme.isLightMode ? "light_mode" : "palette"
|
name: Theme.isLightMode ? "light_mode" : "palette"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSizeLarge
|
||||||
font.pixelSize: Theme.iconSizeLarge
|
|
||||||
color: Theme.isLightMode ? Theme.primary : Theme.surfaceText
|
color: Theme.isLightMode ? Theme.primary : Theme.surfaceText
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
}
|
}
|
||||||
@@ -5,6 +5,8 @@ import Quickshell.Io
|
|||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
import "../../Widgets"
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
// Default to WiFi when nothing is connected
|
// Default to WiFi when nothing is connected
|
||||||
@@ -26,97 +28,29 @@ Item {
|
|||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
// Network sub-tabs
|
// Network sub-tabs
|
||||||
Row {
|
DankTabBar {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.spacingXS
|
currentIndex: networkTab.networkSubTab
|
||||||
|
model: [
|
||||||
Rectangle {
|
{
|
||||||
width: (parent.width - Theme.spacingXS) / 2
|
"icon": "lan",
|
||||||
height: 36
|
"text": "Ethernet"
|
||||||
radius: Theme.cornerRadiusSmall
|
},
|
||||||
color: networkTab.networkSubTab === 0 ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) : ethernetTabArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
|
{
|
||||||
|
"icon": NetworkService.wifiEnabled ? "wifi" : "wifi_off",
|
||||||
Row {
|
"text": "Wi-Fi"
|
||||||
anchors.centerIn: parent
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: "lan"
|
|
||||||
font.family: Theme.iconFont
|
|
||||||
font.pixelSize: Theme.iconSize - 4
|
|
||||||
color: networkTab.networkSubTab === 0 ? Theme.primary : Theme.surfaceText
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: "Ethernet"
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
color: networkTab.networkSubTab === 0 ? Theme.primary : Theme.surfaceText
|
|
||||||
font.weight: networkTab.networkSubTab === 0 ? Font.Medium : Font.Normal
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
]
|
||||||
MouseArea {
|
onTabClicked: function(index) {
|
||||||
id: ethernetTabArea
|
networkTab.networkSubTab = index;
|
||||||
|
if (index === 0) {
|
||||||
anchors.fill: parent
|
WifiService.autoRefreshEnabled = false;
|
||||||
hoverEnabled: true
|
} else {
|
||||||
cursorShape: Qt.PointingHandCursor
|
WifiService.autoRefreshEnabled = true;
|
||||||
onClicked: {
|
if (NetworkService.wifiEnabled)
|
||||||
networkTab.networkSubTab = 0;
|
WifiService.scanWifi();
|
||||||
WifiService.autoRefreshEnabled = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
width: (parent.width - Theme.spacingXS) / 2
|
|
||||||
height: 36
|
|
||||||
radius: Theme.cornerRadiusSmall
|
|
||||||
color: networkTab.networkSubTab === 1 ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) : wifiTabArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) : "transparent"
|
|
||||||
|
|
||||||
Row {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
spacing: Theme.spacingXS
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: NetworkService.wifiEnabled ? "wifi" : "wifi_off"
|
|
||||||
font.family: Theme.iconFont
|
|
||||||
font.pixelSize: Theme.iconSize - 4
|
|
||||||
color: networkTab.networkSubTab === 1 ? Theme.primary : Theme.surfaceText
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: "Wi-Fi"
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
color: networkTab.networkSubTab === 1 ? Theme.primary : Theme.surfaceText
|
|
||||||
font.weight: networkTab.networkSubTab === 1 ? Font.Medium : Font.Normal
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: wifiTabArea
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
networkTab.networkSubTab = 1;
|
|
||||||
WifiService.autoRefreshEnabled = true;
|
|
||||||
if (NetworkService.wifiEnabled)
|
|
||||||
WifiService.scanWifi();
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ethernet Tab Content
|
// Ethernet Tab Content
|
||||||
@@ -153,10 +87,9 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "lan"
|
name: "lan"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSizeLarge - 4
|
||||||
font.pixelSize: Theme.iconSizeLarge - 4
|
|
||||||
color: networkTab.networkStatus === "ethernet" ? Theme.primary : Theme.surfaceText
|
color: networkTab.networkStatus === "ethernet" ? Theme.primary : Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -197,12 +130,11 @@ Item {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
id: ethernetPreferenceIcon
|
id: ethernetPreferenceIcon
|
||||||
|
|
||||||
text: networkTab.changingNetworkPreference ? "sync" : ""
|
name: networkTab.changingNetworkPreference ? "sync" : ""
|
||||||
font.family: Theme.iconFont
|
size: Theme.fontSizeSmall
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: networkTab.networkStatus === "ethernet" ? Theme.background : Theme.primary
|
color: networkTab.networkStatus === "ethernet" ? Theme.background : Theme.primary
|
||||||
visible: networkTab.changingNetworkPreference
|
visible: networkTab.changingNetworkPreference
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -275,10 +207,9 @@ Item {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: networkTab.ethernetConnected ? "link_off" : "link"
|
name: networkTab.ethernetConnected ? "link_off" : "link"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: networkTab.ethernetConnected ? Theme.error : Theme.primary
|
color: networkTab.ethernetConnected ? Theme.error : Theme.primary
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -344,11 +275,11 @@ Item {
|
|||||||
visible: NetworkService.wifiAvailable
|
visible: NetworkService.wifiAvailable
|
||||||
|
|
||||||
// WiFi icon
|
// WiFi icon
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.leftMargin: Theme.spacingL
|
anchors.leftMargin: Theme.spacingL
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: {
|
name: {
|
||||||
if (!NetworkService.wifiEnabled) {
|
if (!NetworkService.wifiEnabled) {
|
||||||
return "wifi_off";
|
return "wifi_off";
|
||||||
} else if (NetworkService.networkStatus === "wifi") {
|
} else if (NetworkService.networkStatus === "wifi") {
|
||||||
@@ -357,8 +288,7 @@ Item {
|
|||||||
return "wifi";
|
return "wifi";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: NetworkService.networkStatus === "wifi" ? Theme.primary : Theme.surfaceText
|
color: NetworkService.networkStatus === "wifi" ? Theme.primary : Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -402,70 +332,16 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WiFi toggle switch
|
// WiFi toggle switch
|
||||||
Rectangle {
|
DankToggle {
|
||||||
width: 48
|
checked: NetworkService.wifiEnabled
|
||||||
height: 24
|
enabled: true
|
||||||
radius: 12
|
toggling: NetworkService.wifiToggling
|
||||||
color: NetworkService.wifiEnabled ? Theme.primary : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
|
||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
anchors.rightMargin: Theme.spacingL
|
anchors.rightMargin: Theme.spacingL
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
opacity: NetworkService.wifiToggling ? 0.6 : 1
|
onClicked: {
|
||||||
|
NetworkService.toggleWifiRadio();
|
||||||
Rectangle {
|
refreshTimer.triggered = true;
|
||||||
id: toggleHandle
|
|
||||||
width: 20
|
|
||||||
height: 20
|
|
||||||
radius: 10
|
|
||||||
color: Theme.surface
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
x: NetworkService.wifiEnabled ? parent.width - width - 2 : 2
|
|
||||||
|
|
||||||
Behavior on x {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: Theme.shortDuration
|
|
||||||
easing.type: Theme.emphasizedEasing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subtle shadow/glow effect
|
|
||||||
Rectangle {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
width: parent.width + 2
|
|
||||||
height: parent.height + 2
|
|
||||||
radius: (parent.width + 2) / 2
|
|
||||||
color: "transparent"
|
|
||||||
border.color: Qt.rgba(0, 0, 0, 0.1)
|
|
||||||
border.width: 1
|
|
||||||
z: -1
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: wifiToggleArea
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
onClicked: {
|
|
||||||
NetworkService.toggleWifiRadio();
|
|
||||||
// Refresh network status and WiFi info after toggle with delay
|
|
||||||
refreshTimer.triggered = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on color {
|
|
||||||
ColorAnimation {
|
|
||||||
duration: Theme.shortDuration
|
|
||||||
easing.type: Theme.standardEasing
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Behavior on opacity {
|
|
||||||
NumberAnimation {
|
|
||||||
duration: Theme.shortDuration
|
|
||||||
easing.type: Theme.standardEasing
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,12 +363,11 @@ Item {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
id: wifiPreferenceIcon
|
id: wifiPreferenceIcon
|
||||||
|
|
||||||
text: networkTab.changingNetworkPreference ? "sync" : ""
|
name: networkTab.changingNetworkPreference ? "sync" : ""
|
||||||
font.family: Theme.iconFont
|
size: Theme.fontSizeSmall
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: networkTab.networkStatus === "wifi" ? Theme.background : Theme.primary
|
color: networkTab.networkStatus === "wifi" ? Theme.background : Theme.primary
|
||||||
visible: networkTab.changingNetworkPreference
|
visible: networkTab.changingNetworkPreference
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -574,13 +449,12 @@ Item {
|
|||||||
radius: 16
|
radius: 16
|
||||||
color: refreshArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : WifiService.isScanning ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.06) : "transparent"
|
color: refreshArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : WifiService.isScanning ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.06) : "transparent"
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
id: refreshIcon
|
id: refreshIcon
|
||||||
|
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: WifiService.isScanning ? "sync" : "refresh"
|
name: WifiService.isScanning ? "sync" : "refresh"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 4
|
||||||
font.pixelSize: Theme.iconSize - 4
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
rotation: WifiService.isScanning ? refreshIcon.rotation : 0
|
rotation: WifiService.isScanning ? refreshIcon.rotation : 0
|
||||||
|
|
||||||
@@ -652,10 +526,10 @@ Item {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
id: connectionIcon
|
id: connectionIcon
|
||||||
|
|
||||||
text: {
|
name: {
|
||||||
if (WifiService.connectionStatus === "connecting")
|
if (WifiService.connectionStatus === "connecting")
|
||||||
return "sync";
|
return "sync";
|
||||||
|
|
||||||
@@ -667,8 +541,7 @@ Item {
|
|||||||
|
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 6
|
||||||
font.pixelSize: Theme.iconSize - 6
|
|
||||||
color: {
|
color: {
|
||||||
if (WifiService.connectionStatus === "connecting")
|
if (WifiService.connectionStatus === "connecting")
|
||||||
return Theme.warning;
|
return Theme.warning;
|
||||||
@@ -762,14 +635,13 @@ Item {
|
|||||||
anchors.margins: Theme.spacingS
|
anchors.margins: Theme.spacingS
|
||||||
|
|
||||||
// Signal strength icon
|
// Signal strength icon
|
||||||
Text {
|
DankIcon {
|
||||||
id: signalIcon
|
id: signalIcon
|
||||||
|
|
||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: modelData.signalStrength === "excellent" ? "wifi" : modelData.signalStrength === "good" ? "wifi_2_bar" : modelData.signalStrength === "fair" ? "wifi_1_bar" : modelData.signalStrength === "poor" ? "wifi_calling_3" : "wifi"
|
name: modelData.signalStrength === "excellent" ? "wifi" : modelData.signalStrength === "good" ? "wifi_2_bar" : modelData.signalStrength === "fair" ? "wifi_1_bar" : modelData.signalStrength === "poor" ? "wifi_calling_3" : "wifi"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: modelData.connected ? Theme.primary : Theme.surfaceText
|
color: modelData.connected ? Theme.primary : Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -818,10 +690,9 @@ Item {
|
|||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
// Lock icon (if secured)
|
// Lock icon (if secured)
|
||||||
Text {
|
DankIcon {
|
||||||
text: "lock"
|
name: "lock"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 6
|
||||||
font.pixelSize: Theme.iconSize - 6
|
|
||||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.6)
|
||||||
visible: modelData.secured
|
visible: modelData.secured
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
@@ -835,11 +706,10 @@ Item {
|
|||||||
color: forgetArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) : "transparent"
|
color: forgetArea.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) : "transparent"
|
||||||
visible: modelData.saved || modelData.connected
|
visible: modelData.saved || modelData.connected
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "delete"
|
name: "delete"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 6
|
||||||
font.pixelSize: Theme.iconSize - 6
|
|
||||||
color: forgetArea.containsMouse ? Theme.error : Theme.surfaceText
|
color: forgetArea.containsMouse ? Theme.error : Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -900,11 +770,10 @@ Item {
|
|||||||
visible: !NetworkService.wifiEnabled
|
visible: !NetworkService.wifiEnabled
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
text: "wifi_off"
|
name: "wifi_off"
|
||||||
font.family: Theme.iconFont
|
size: 48
|
||||||
font.pixelSize: 48
|
|
||||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3)
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3,6 +3,7 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: cpuWidget
|
id: cpuWidget
|
||||||
@@ -32,11 +33,9 @@ Rectangle {
|
|||||||
spacing: 3
|
spacing: 3
|
||||||
|
|
||||||
// CPU icon
|
// CPU icon
|
||||||
Text {
|
DankIcon {
|
||||||
text: "memory" // Material Design memory icon (swapped from RAM widget)
|
name: "memory" // Material Design memory icon (swapped from RAM widget)
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 8
|
||||||
font.pixelSize: Theme.iconSize - 8
|
|
||||||
font.weight: Theme.iconFontWeight
|
|
||||||
color: {
|
color: {
|
||||||
if (SystemMonitorService.cpuUsage > 80)
|
if (SystemMonitorService.cpuUsage > 80)
|
||||||
return Theme.error;
|
return Theme.error;
|
||||||
@@ -6,6 +6,7 @@ import Quickshell.Wayland
|
|||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: root
|
id: root
|
||||||
@@ -160,10 +161,9 @@ PanelWindow {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "delete_sweep"
|
name: "delete_sweep"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSizeSmall
|
||||||
font.pixelSize: Theme.iconSizeSmall
|
|
||||||
color: clearArea.containsMouse ? Theme.primary : Theme.surfaceText
|
color: clearArea.containsMouse ? Theme.primary : Theme.surfaceText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -496,11 +496,10 @@ PanelWindow {
|
|||||||
color: expandArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
color: expandArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
||||||
visible: modelData.count > 1
|
visible: modelData.count > 1
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "expand_more"
|
name: "expand_more"
|
||||||
font.family: Theme.iconFont
|
size: 18
|
||||||
font.pixelSize: 18
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
rotation: expanded ? 180 : 0
|
rotation: expanded ? 180 : 0
|
||||||
|
|
||||||
@@ -532,11 +531,10 @@ PanelWindow {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
color: dismissArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
color: dismissArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "close"
|
name: "close"
|
||||||
font.family: Theme.iconFont
|
size: 16
|
||||||
font.pixelSize: 16
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -599,11 +597,10 @@ PanelWindow {
|
|||||||
border.color: quickReplyField.text.length > 0 ? "transparent" : Theme.outline
|
border.color: quickReplyField.text.length > 0 ? "transparent" : Theme.outline
|
||||||
border.width: quickReplyField.text.length > 0 ? 0 : 1
|
border.width: quickReplyField.text.length > 0 ? 0 : 1
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "send"
|
name: "send"
|
||||||
font.family: Theme.iconFont
|
size: 16
|
||||||
font.pixelSize: 16
|
|
||||||
color: quickReplyField.text.length > 0 ? Theme.primaryText : Theme.surfaceVariantText
|
color: quickReplyField.text.length > 0 ? Theme.primaryText : Theme.surfaceVariantText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -702,11 +699,10 @@ PanelWindow {
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
color: collapseArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
color: collapseArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "expand_less"
|
name: "expand_less"
|
||||||
font.family: Theme.iconFont
|
size: 18
|
||||||
font.pixelSize: 18
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -728,11 +724,10 @@ PanelWindow {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
color: dismissAllArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
color: dismissAllArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "close"
|
name: "close"
|
||||||
font.family: Theme.iconFont
|
size: 16
|
||||||
font.pixelSize: 16
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -810,11 +805,10 @@ PanelWindow {
|
|||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
color: individualDismissArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
color: individualDismissArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "close"
|
name: "close"
|
||||||
font.family: Theme.iconFont
|
size: 12
|
||||||
font.pixelSize: 12
|
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -901,11 +895,10 @@ PanelWindow {
|
|||||||
radius: 14
|
radius: 14
|
||||||
color: replyField.text.length > 0 ? Theme.primary : Theme.surfaceContainer
|
color: replyField.text.length > 0 ? Theme.primary : Theme.surfaceContainer
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "send"
|
name: "send"
|
||||||
font.family: Theme.iconFont
|
size: 12
|
||||||
font.pixelSize: 12
|
|
||||||
color: replyField.text.length > 0 ? Theme.primaryText : Theme.surfaceVariantText
|
color: replyField.text.length > 0 ? Theme.primaryText : Theme.surfaceVariantText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -974,11 +967,10 @@ PanelWindow {
|
|||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
width: parent.width * 0.8
|
width: parent.width * 0.8
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
text: "notifications_none"
|
name: "notifications_none"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSizeLarge + 16
|
||||||
font.pixelSize: Theme.iconSizeLarge + 16
|
|
||||||
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3)
|
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.3)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5,6 +5,7 @@ import Quickshell.Wayland
|
|||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: notificationPopup
|
id: notificationPopup
|
||||||
@@ -268,11 +269,10 @@ PanelWindow {
|
|||||||
color: expandArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
color: expandArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
||||||
visible: modelData.count > 1
|
visible: modelData.count > 1
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "expand_more"
|
name: "expand_more"
|
||||||
font.family: Theme.iconFont
|
size: 18
|
||||||
font.pixelSize: 18
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
rotation: expanded ? 180 : 0
|
rotation: expanded ? 180 : 0
|
||||||
|
|
||||||
@@ -309,11 +309,10 @@ PanelWindow {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
color: dismissArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
color: dismissArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "close"
|
name: "close"
|
||||||
font.family: Theme.iconFont
|
size: 16
|
||||||
font.pixelSize: 16
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -376,11 +375,10 @@ PanelWindow {
|
|||||||
border.color: quickReplyField.text.length > 0 ? "transparent" : Theme.outline
|
border.color: quickReplyField.text.length > 0 ? "transparent" : Theme.outline
|
||||||
border.width: quickReplyField.text.length > 0 ? 0 : 1
|
border.width: quickReplyField.text.length > 0 ? 0 : 1
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "send"
|
name: "send"
|
||||||
font.family: Theme.iconFont
|
size: 16
|
||||||
font.pixelSize: 16
|
|
||||||
color: quickReplyField.text.length > 0 ? Theme.primaryText : Theme.surfaceVariantText
|
color: quickReplyField.text.length > 0 ? Theme.primaryText : Theme.surfaceVariantText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -487,11 +485,10 @@ PanelWindow {
|
|||||||
anchors.left: parent.left
|
anchors.left: parent.left
|
||||||
color: collapseArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
color: collapseArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "expand_less"
|
name: "expand_less"
|
||||||
font.family: Theme.iconFont
|
size: 18
|
||||||
font.pixelSize: 18
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,11 +514,10 @@ PanelWindow {
|
|||||||
anchors.right: parent.right
|
anchors.right: parent.right
|
||||||
color: dismissAllArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
color: dismissAllArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "close"
|
name: "close"
|
||||||
font.family: Theme.iconFont
|
size: 16
|
||||||
font.pixelSize: 16
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -612,11 +608,10 @@ PanelWindow {
|
|||||||
anchors.top: parent.top
|
anchors.top: parent.top
|
||||||
color: individualDismissArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
color: individualDismissArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "close"
|
name: "close"
|
||||||
font.family: Theme.iconFont
|
size: 12
|
||||||
font.pixelSize: 12
|
|
||||||
color: Theme.surfaceVariantText
|
color: Theme.surfaceVariantText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -706,11 +701,10 @@ PanelWindow {
|
|||||||
radius: 14
|
radius: 14
|
||||||
color: replyField.text.length > 0 ? Theme.primary : Theme.surfaceContainer
|
color: replyField.text.length > 0 ? Theme.primary : Theme.surfaceContainer
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "send"
|
name: "send"
|
||||||
font.family: Theme.iconFont
|
size: 12
|
||||||
font.pixelSize: 12
|
|
||||||
color: replyField.text.length > 0 ? Theme.primaryText : Theme.surfaceVariantText
|
color: replyField.text.length > 0 ? Theme.primaryText : Theme.surfaceVariantText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8,6 +8,7 @@ import Quickshell.Wayland
|
|||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: processListWidget
|
id: processListWidget
|
||||||
@@ -213,8 +214,8 @@ PanelWindow {
|
|||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
// Tab icons for visual hierarchy
|
// Tab icons for visual hierarchy
|
||||||
Text {
|
DankIcon {
|
||||||
text: {
|
name: {
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0:
|
case 0:
|
||||||
return "list_alt";
|
return "list_alt";
|
||||||
@@ -226,8 +227,7 @@ PanelWindow {
|
|||||||
return "tab";
|
return "tab";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 2
|
||||||
font.pixelSize: Theme.iconSize - 2
|
|
||||||
color: currentTab === index ? Theme.primary : Theme.surfaceText
|
color: currentTab === index ? Theme.primary : Theme.surfaceText
|
||||||
opacity: currentTab === index ? 1 : 0.7
|
opacity: currentTab === index ? 1 : 0.7
|
||||||
|
|
||||||
@@ -706,10 +706,9 @@ PanelWindow {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
spacing: 8
|
spacing: 8
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: ProcessMonitorService.getProcessIcon(modelData ? modelData.command : "")
|
name: ProcessMonitorService.getProcessIcon(modelData ? modelData.command : "")
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 4
|
||||||
font.pixelSize: Theme.iconSize - 4
|
|
||||||
color: {
|
color: {
|
||||||
if (modelData && modelData.cpu > 80)
|
if (modelData && modelData.cpu > 80)
|
||||||
return Theme.error;
|
return Theme.error;
|
||||||
@@ -822,11 +821,9 @@ PanelWindow {
|
|||||||
color: menuButtonArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
color: menuButtonArea.containsMouse ? Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.08) : "transparent"
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "more_vert"
|
name: "more_vert"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 2
|
||||||
font.weight: Theme.iconFontWeight
|
|
||||||
font.pixelSize: Theme.iconSize - 2
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
opacity: 0.6
|
opacity: 0.6
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
@@ -1310,10 +1307,9 @@ PanelWindow {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "computer"
|
name: "computer"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: Theme.primary
|
color: Theme.primary
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -1382,10 +1378,9 @@ PanelWindow {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "developer_board"
|
name: "developer_board"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: Theme.secondary
|
color: Theme.secondary
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -1461,10 +1456,9 @@ PanelWindow {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "timer"
|
name: "timer"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: Theme.warning
|
color: Theme.warning
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -1526,10 +1520,9 @@ PanelWindow {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "list_alt"
|
name: "list_alt"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: Theme.info
|
color: Theme.info
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -1583,10 +1576,9 @@ PanelWindow {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.spacingS
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "storage"
|
name: "storage"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: Theme.success
|
color: Theme.success
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,7 @@ import QtQuick
|
|||||||
import QtQuick.Controls
|
import QtQuick.Controls
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: ramWidget
|
id: ramWidget
|
||||||
@@ -32,11 +33,9 @@ Rectangle {
|
|||||||
spacing: 3
|
spacing: 3
|
||||||
|
|
||||||
// RAM icon
|
// RAM icon
|
||||||
Text {
|
DankIcon {
|
||||||
text: "developer_board" // Material Design CPU/processor icon (swapped from CPU widget)
|
name: "developer_board" // Material Design CPU/processor icon (swapped from CPU widget)
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 8
|
||||||
font.pixelSize: Theme.iconSize - 8
|
|
||||||
font.weight: Theme.iconFontWeight
|
|
||||||
color: {
|
color: {
|
||||||
if (SystemMonitorService.memoryUsage > 90)
|
if (SystemMonitorService.memoryUsage > 90)
|
||||||
return Theme.error;
|
return Theme.error;
|
||||||
@@ -6,6 +6,7 @@ import Quickshell.Io
|
|||||||
import Quickshell.Wayland
|
import Quickshell.Wayland
|
||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Common
|
import qs.Common
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: settingsPopup
|
id: settingsPopup
|
||||||
@@ -74,10 +75,9 @@ PanelWindow {
|
|||||||
width: parent.width
|
width: parent.width
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "settings"
|
name: "settings"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: Theme.primary
|
color: Theme.primary
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
@@ -102,10 +102,9 @@ PanelWindow {
|
|||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: closeButton.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) : "transparent"
|
color: closeButton.containsMouse ? Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) : "transparent"
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: "close"
|
name: "close"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 4
|
||||||
font.pixelSize: Theme.iconSize - 4
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
}
|
}
|
||||||
@@ -234,22 +233,20 @@ PanelWindow {
|
|||||||
color: Theme.primary
|
color: Theme.primary
|
||||||
visible: !parent.hasImage
|
visible: !parent.hasImage
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "person"
|
name: "person"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize + 8
|
||||||
font.pixelSize: Theme.iconSize + 8
|
|
||||||
color: Theme.primaryText
|
color: Theme.primaryText
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Error icon for when the image fails to load.
|
// Error icon for when the image fails to load.
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "warning"
|
name: "warning"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize + 8
|
||||||
font.pixelSize: Theme.iconSize + 8
|
|
||||||
color: Theme.primaryText
|
color: Theme.primaryText
|
||||||
visible: profileImageInput.text !== "" && avatarImageSource.status === Image.Error
|
visible: profileImageInput.text !== "" && avatarImageSource.status === Image.Error
|
||||||
}
|
}
|
||||||
@@ -540,7 +537,7 @@ PanelWindow {
|
|||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomSlider {
|
DankSlider {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
value: Math.round(Prefs.topBarTransparency * 100)
|
value: Math.round(Prefs.topBarTransparency * 100)
|
||||||
minimum: 0
|
minimum: 0
|
||||||
@@ -577,7 +574,7 @@ PanelWindow {
|
|||||||
font.weight: Font.Medium
|
font.weight: Font.Medium
|
||||||
}
|
}
|
||||||
|
|
||||||
CustomSlider {
|
DankSlider {
|
||||||
width: parent.width
|
width: parent.width
|
||||||
value: Math.round(Prefs.popupTransparency * 100)
|
value: Math.round(Prefs.popupTransparency * 100)
|
||||||
minimum: 0
|
minimum: 0
|
||||||
@@ -7,6 +7,7 @@ import Quickshell.Wayland
|
|||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
id: spotlightLauncher
|
id: spotlightLauncher
|
||||||
@@ -155,8 +156,8 @@ PanelWindow {
|
|||||||
function selectNext() {
|
function selectNext() {
|
||||||
if (filteredApps.length > 0) {
|
if (filteredApps.length > 0) {
|
||||||
if (viewMode === "grid") {
|
if (viewMode === "grid") {
|
||||||
// Grid navigation: move by columns (6 columns)
|
// Grid navigation: move by columns
|
||||||
var columnsCount = 6;
|
var columnsCount = resultsGrid.columns || 6;
|
||||||
selectedIndex = Math.min(selectedIndex + columnsCount, filteredApps.length - 1);
|
selectedIndex = Math.min(selectedIndex + columnsCount, filteredApps.length - 1);
|
||||||
} else {
|
} else {
|
||||||
// List navigation: next item
|
// List navigation: next item
|
||||||
@@ -168,8 +169,8 @@ PanelWindow {
|
|||||||
function selectPrevious() {
|
function selectPrevious() {
|
||||||
if (filteredApps.length > 0) {
|
if (filteredApps.length > 0) {
|
||||||
if (viewMode === "grid") {
|
if (viewMode === "grid") {
|
||||||
// Grid navigation: move by columns (6 columns)
|
// Grid navigation: move by columns
|
||||||
var columnsCount = 6;
|
var columnsCount = resultsGrid.columns || 6;
|
||||||
selectedIndex = Math.max(selectedIndex - columnsCount, 0);
|
selectedIndex = Math.max(selectedIndex - columnsCount, 0);
|
||||||
} else {
|
} else {
|
||||||
// List navigation: previous item
|
// List navigation: previous item
|
||||||
@@ -465,11 +466,10 @@ PanelWindow {
|
|||||||
anchors.rightMargin: Theme.spacingL
|
anchors.rightMargin: Theme.spacingL
|
||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
text: "search"
|
name: "search"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: searchField.activeFocus ? Theme.primary : Theme.surfaceVariantText
|
color: searchField.activeFocus ? Theme.primary : Theme.surfaceVariantText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -553,11 +553,10 @@ PanelWindow {
|
|||||||
border.color: viewMode === "list" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) : "transparent"
|
border.color: viewMode === "list" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) : "transparent"
|
||||||
border.width: 1
|
border.width: 1
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "view_list"
|
name: "view_list"
|
||||||
font.family: Theme.iconFont
|
size: 18
|
||||||
font.pixelSize: 18
|
|
||||||
color: viewMode === "list" ? Theme.primary : Theme.surfaceText
|
color: viewMode === "list" ? Theme.primary : Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -584,11 +583,10 @@ PanelWindow {
|
|||||||
border.color: viewMode === "grid" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) : "transparent"
|
border.color: viewMode === "grid" ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.3) : "transparent"
|
||||||
border.width: 1
|
border.width: 1
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "grid_view"
|
name: "grid_view"
|
||||||
font.family: Theme.iconFont
|
size: 18
|
||||||
font.pixelSize: 18
|
|
||||||
color: viewMode === "grid" ? Theme.primary : Theme.surfaceText
|
color: viewMode === "grid" ? Theme.primary : Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -619,256 +617,42 @@ PanelWindow {
|
|||||||
color: "transparent"
|
color: "transparent"
|
||||||
|
|
||||||
// List view
|
// List view
|
||||||
ListView {
|
DankListView {
|
||||||
id: resultsList
|
id: resultsList
|
||||||
|
|
||||||
// Make mouse wheel scrolling more responsive
|
|
||||||
property real wheelStepSize: 60
|
|
||||||
|
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
visible: viewMode === "list"
|
visible: viewMode === "list"
|
||||||
model: filteredModel
|
model: filteredModel
|
||||||
currentIndex: selectedIndex
|
currentIndex: selectedIndex
|
||||||
clip: true
|
itemHeight: 60
|
||||||
focus: spotlightOpen
|
iconSize: 40
|
||||||
interactive: true
|
showDescription: true
|
||||||
flickDeceleration: 8000
|
onItemClicked: function(index, modelData) {
|
||||||
maximumFlickVelocity: 15000
|
launchApp(modelData);
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
acceptedButtons: Qt.NoButton
|
|
||||||
propagateComposedEvents: true
|
|
||||||
z: -1
|
|
||||||
onWheel: (wheel) => {
|
|
||||||
var delta = wheel.angleDelta.y;
|
|
||||||
var steps = delta / 120; // Standard wheel step
|
|
||||||
resultsList.contentY -= steps * resultsList.wheelStepSize;
|
|
||||||
// Ensure we stay within bounds
|
|
||||||
if (resultsList.contentY < 0)
|
|
||||||
resultsList.contentY = 0;
|
|
||||||
else if (resultsList.contentY > resultsList.contentHeight - resultsList.height)
|
|
||||||
resultsList.contentY = Math.max(0, resultsList.contentHeight - resultsList.height);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
onItemHovered: function(index) {
|
||||||
delegate: Rectangle {
|
selectedIndex = index;
|
||||||
width: resultsList.width
|
|
||||||
height: 60
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: ListView.isCurrentItem ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : listMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.06) : "transparent"
|
|
||||||
|
|
||||||
Row {
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Theme.spacingM
|
|
||||||
spacing: Theme.spacingL
|
|
||||||
|
|
||||||
Item {
|
|
||||||
width: 40
|
|
||||||
height: 40
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
|
|
||||||
IconImage {
|
|
||||||
id: listIconImg
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
source: model.icon ? Quickshell.iconPath(model.icon, "") : ""
|
|
||||||
smooth: true
|
|
||||||
asynchronous: true
|
|
||||||
visible: status === Image.Ready
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
visible: !listIconImg.visible
|
|
||||||
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
|
|
||||||
radius: Theme.cornerRadiusLarge
|
|
||||||
border.width: 1
|
|
||||||
border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2)
|
|
||||||
|
|
||||||
Text {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: (model.name && model.name.length > 0) ? model.name.charAt(0).toUpperCase() : "A"
|
|
||||||
font.pixelSize: 20
|
|
||||||
color: Theme.primary
|
|
||||||
font.weight: Font.Bold
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Column {
|
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
|
||||||
spacing: 2
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: model.name
|
|
||||||
font.pixelSize: Theme.fontSizeLarge
|
|
||||||
color: Theme.surfaceText
|
|
||||||
font.weight: Font.Medium
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
text: model.comment
|
|
||||||
font.pixelSize: Theme.fontSizeMedium
|
|
||||||
color: Theme.surfaceVariantText
|
|
||||||
visible: model.comment && model.comment.length > 0
|
|
||||||
elide: Text.ElideRight
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: listMouseArea
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
z: 10
|
|
||||||
onEntered: selectedIndex = index
|
|
||||||
onClicked: launchApp(model)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScrollBar.vertical: ScrollBar {
|
|
||||||
policy: ScrollBar.AlwaysOn
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Grid view scroll container
|
// Grid view
|
||||||
ScrollView {
|
DankGridView {
|
||||||
|
id: resultsGrid
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
clip: true
|
|
||||||
visible: viewMode === "grid"
|
visible: viewMode === "grid"
|
||||||
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
model: filteredModel
|
||||||
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
columns: 6
|
||||||
|
adaptiveColumns: true
|
||||||
GridView {
|
minCellWidth: 120
|
||||||
id: resultsGrid
|
maxCellWidth: 160
|
||||||
|
iconSizeRatio: 0.55
|
||||||
// Responsive cell sizes based on screen width - wider cells for better fill
|
maxIconSize: 48
|
||||||
property int baseCellWidth: Math.max(120, Math.min(160, width / 6))
|
currentIndex: selectedIndex
|
||||||
property int baseCellHeight: baseCellWidth + 20
|
onItemClicked: function(index, modelData) {
|
||||||
// Center the grid content with better fill
|
launchApp(modelData);
|
||||||
property int columnsCount: Math.floor(width / cellWidth)
|
}
|
||||||
property int remainingSpace: width - (columnsCount * cellWidth)
|
onItemHovered: function(index) {
|
||||||
// Make mouse wheel scrolling more responsive
|
selectedIndex = index;
|
||||||
property real wheelStepSize: 60
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
anchors.margins: Theme.spacingS
|
|
||||||
model: filteredModel
|
|
||||||
focus: spotlightOpen
|
|
||||||
interactive: true
|
|
||||||
flickDeceleration: 8000
|
|
||||||
maximumFlickVelocity: 15000
|
|
||||||
cellWidth: baseCellWidth
|
|
||||||
cellHeight: baseCellHeight
|
|
||||||
leftMargin: Math.max(Theme.spacingXS, remainingSpace / 2)
|
|
||||||
rightMargin: leftMargin
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
anchors.fill: parent
|
|
||||||
acceptedButtons: Qt.NoButton
|
|
||||||
propagateComposedEvents: true
|
|
||||||
z: -1
|
|
||||||
onWheel: (wheel) => {
|
|
||||||
var delta = wheel.angleDelta.y;
|
|
||||||
var steps = delta / 120; // Standard wheel step
|
|
||||||
resultsGrid.contentY -= steps * resultsGrid.wheelStepSize;
|
|
||||||
// Ensure we stay within bounds
|
|
||||||
if (resultsGrid.contentY < 0)
|
|
||||||
resultsGrid.contentY = 0;
|
|
||||||
else if (resultsGrid.contentY > resultsGrid.contentHeight - resultsGrid.height)
|
|
||||||
resultsGrid.contentY = Math.max(0, resultsGrid.contentHeight - resultsGrid.height);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
delegate: Rectangle {
|
|
||||||
width: resultsGrid.cellWidth - 8
|
|
||||||
height: resultsGrid.cellHeight - 8
|
|
||||||
radius: Theme.cornerRadius
|
|
||||||
color: selectedIndex === index ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.12) : gridMouseArea.containsMouse ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.06) : "transparent"
|
|
||||||
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
|
|
||||||
border.width: 1
|
|
||||||
|
|
||||||
Column {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
spacing: Theme.spacingS
|
|
||||||
|
|
||||||
Item {
|
|
||||||
property int iconSize: Math.min(48, Math.max(32, resultsGrid.cellWidth * 0.55))
|
|
||||||
|
|
||||||
width: iconSize
|
|
||||||
height: iconSize
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
|
|
||||||
IconImage {
|
|
||||||
id: iconImg
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
source: model.icon ? Quickshell.iconPath(model.icon, "") : ""
|
|
||||||
smooth: true
|
|
||||||
asynchronous: true
|
|
||||||
visible: status === Image.Ready
|
|
||||||
}
|
|
||||||
|
|
||||||
Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
visible: !iconImg.visible
|
|
||||||
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
|
|
||||||
radius: Theme.cornerRadiusLarge
|
|
||||||
border.width: 1
|
|
||||||
border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2)
|
|
||||||
|
|
||||||
Text {
|
|
||||||
anchors.centerIn: parent
|
|
||||||
text: (model.name && model.name.length > 0) ? model.name.charAt(0).toUpperCase() : "A"
|
|
||||||
font.pixelSize: Math.min(24, parent.width * 0.5)
|
|
||||||
color: Theme.primary
|
|
||||||
font.weight: Font.Bold
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
Text {
|
|
||||||
anchors.horizontalCenter: parent.horizontalCenter
|
|
||||||
width: resultsGrid.cellWidth - 12
|
|
||||||
text: model.name
|
|
||||||
font.pixelSize: Theme.fontSizeSmall
|
|
||||||
color: Theme.surfaceText
|
|
||||||
font.weight: Font.Medium
|
|
||||||
elide: Text.ElideRight
|
|
||||||
wrapMode: Text.Wrap
|
|
||||||
maximumLineCount: 2
|
|
||||||
horizontalAlignment: Text.AlignHCenter
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
MouseArea {
|
|
||||||
id: gridMouseArea
|
|
||||||
|
|
||||||
anchors.fill: parent
|
|
||||||
hoverEnabled: true
|
|
||||||
cursorShape: Qt.PointingHandCursor
|
|
||||||
z: 10
|
|
||||||
onEntered: selectedIndex = index
|
|
||||||
onClicked: launchApp(model)
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
@@ -21,8 +22,8 @@ Rectangle {
|
|||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
// Network Status Icon
|
// Network Status Icon
|
||||||
Text {
|
DankIcon {
|
||||||
text: {
|
name: {
|
||||||
if (NetworkService.networkStatus === "ethernet") {
|
if (NetworkService.networkStatus === "ethernet") {
|
||||||
return "lan";
|
return "lan";
|
||||||
} else if (NetworkService.networkStatus === "wifi") {
|
} else if (NetworkService.networkStatus === "wifi") {
|
||||||
@@ -42,20 +43,16 @@ Rectangle {
|
|||||||
return "wifi_off";
|
return "wifi_off";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 8
|
||||||
font.pixelSize: Theme.iconSize - 8
|
|
||||||
font.weight: Theme.iconFontWeight
|
|
||||||
color: NetworkService.networkStatus !== "disconnected" ? Theme.primary : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
|
color: NetworkService.networkStatus !== "disconnected" ? Theme.primary : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: true
|
visible: true
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bluetooth Icon (when available and enabled) - moved next to network
|
// Bluetooth Icon (when available and enabled) - moved next to network
|
||||||
Text {
|
DankIcon {
|
||||||
text: "bluetooth"
|
name: "bluetooth"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 8
|
||||||
font.pixelSize: Theme.iconSize - 8
|
|
||||||
font.weight: Theme.iconFontWeight
|
|
||||||
color: BluetoothService.enabled ? Theme.primary : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
|
color: BluetoothService.enabled ? Theme.primary : Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: BluetoothService.available && BluetoothService.enabled
|
visible: BluetoothService.available && BluetoothService.enabled
|
||||||
@@ -68,13 +65,11 @@ Rectangle {
|
|||||||
color: "transparent"
|
color: "transparent"
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
id: audioIcon
|
id: audioIcon
|
||||||
|
|
||||||
text: AudioService.sinkMuted ? "volume_off" : AudioService.volumeLevel < 33 ? "volume_down" : "volume_up"
|
name: AudioService.sinkMuted ? "volume_off" : AudioService.volumeLevel < 33 ? "volume_down" : "volume_up"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 8
|
||||||
font.pixelSize: Theme.iconSize - 8
|
|
||||||
font.weight: Theme.iconFontWeight
|
|
||||||
color: audioWheelArea.containsMouse || controlCenterArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText
|
color: audioWheelArea.containsMouse || controlCenterArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
}
|
}
|
||||||
@@ -107,11 +102,9 @@ Rectangle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Microphone Icon (when active)
|
// Microphone Icon (when active)
|
||||||
Text {
|
DankIcon {
|
||||||
text: "mic"
|
name: "mic"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 8
|
||||||
font.pixelSize: Theme.iconSize - 8
|
|
||||||
font.weight: Theme.iconFontWeight
|
|
||||||
color: Theme.primary
|
color: Theme.primary
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: false // TODO: Add mic detection
|
visible: false // TODO: Add mic detection
|
||||||
@@ -2,6 +2,7 @@ import QtQuick
|
|||||||
import Quickshell.Services.Mpris
|
import Quickshell.Services.Mpris
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
@@ -148,11 +149,10 @@ Rectangle {
|
|||||||
visible: root.playerAvailable
|
visible: root.playerAvailable
|
||||||
opacity: (activePlayer && activePlayer.canGoPrevious) ? 1 : 0.3
|
opacity: (activePlayer && activePlayer.canGoPrevious) ? 1 : 0.3
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "skip_previous"
|
name: "skip_previous"
|
||||||
font.family: Theme.iconFont
|
size: 12
|
||||||
font.pixelSize: 12
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -181,11 +181,10 @@ Rectangle {
|
|||||||
visible: root.playerAvailable
|
visible: root.playerAvailable
|
||||||
opacity: activePlayer ? 1 : 0.3
|
opacity: activePlayer ? 1 : 0.3
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: activePlayer && activePlayer.playbackState === 1 ? "pause" : "play_arrow"
|
name: activePlayer && activePlayer.playbackState === 1 ? "pause" : "play_arrow"
|
||||||
font.family: Theme.iconFont
|
size: 14
|
||||||
font.pixelSize: 14
|
|
||||||
color: activePlayer && activePlayer.playbackState === 1 ? Theme.background : Theme.primary
|
color: activePlayer && activePlayer.playbackState === 1 ? Theme.background : Theme.primary
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,11 +211,10 @@ Rectangle {
|
|||||||
visible: playerAvailable
|
visible: playerAvailable
|
||||||
opacity: (activePlayer && activePlayer.canGoNext) ? 1 : 0.3
|
opacity: (activePlayer && activePlayer.canGoNext) ? 1 : 0.3
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "skip_next"
|
name: "skip_next"
|
||||||
font.family: Theme.iconFont
|
size: 12
|
||||||
font.pixelSize: 12
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import qs.Common
|
import qs.Common
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
@@ -14,12 +15,10 @@ Rectangle {
|
|||||||
radius: Theme.cornerRadius
|
radius: Theme.cornerRadius
|
||||||
color: notificationArea.containsMouse || root.isActive ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) : Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.08)
|
color: notificationArea.containsMouse || root.isActive ? Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) : Qt.rgba(Theme.secondary.r, Theme.secondary.g, Theme.secondary.b, 0.08)
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "notifications"
|
name: "notifications"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 6
|
||||||
font.pixelSize: Theme.iconSize - 6
|
|
||||||
font.weight: Theme.iconFontWeight
|
|
||||||
color: notificationArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText
|
color: notificationArea.containsMouse || root.isActive ? Theme.primary : Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -11,6 +11,7 @@ import Quickshell.Wayland
|
|||||||
import Quickshell.Widgets
|
import Quickshell.Widgets
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Modules
|
||||||
import qs.Widgets
|
import qs.Widgets
|
||||||
|
|
||||||
PanelWindow {
|
PanelWindow {
|
||||||
@@ -204,12 +205,10 @@ PanelWindow {
|
|||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: Prefs.showClipboard
|
visible: Prefs.showClipboard
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
text: "content_paste"
|
name: "content_paste"
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 6
|
||||||
font.pixelSize: Theme.iconSize - 6
|
|
||||||
font.weight: Theme.iconFontWeight
|
|
||||||
color: Theme.surfaceText
|
color: Theme.surfaceText
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import qs.Common
|
import qs.Common
|
||||||
import qs.Services
|
import qs.Services
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
Rectangle {
|
Rectangle {
|
||||||
id: root
|
id: root
|
||||||
@@ -19,10 +20,9 @@ Rectangle {
|
|||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
spacing: Theme.spacingXS
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
Text {
|
DankIcon {
|
||||||
text: WeatherService.getWeatherIcon(WeatherService.weather.wCode)
|
name: WeatherService.getWeatherIcon(WeatherService.weather.wCode)
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize - 4
|
||||||
font.pixelSize: Theme.iconSize - 4
|
|
||||||
color: Theme.primary
|
color: Theme.primary
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
}
|
}
|
||||||
148
Widgets/DankGridView.qml
Normal file
148
Widgets/DankGridView.qml
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import qs.Common
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
id: gridView
|
||||||
|
|
||||||
|
property alias model: grid.model
|
||||||
|
property int currentIndex: 0
|
||||||
|
property int columns: 4
|
||||||
|
property bool adaptiveColumns: false
|
||||||
|
property int minCellWidth: 120
|
||||||
|
property int maxCellWidth: 160
|
||||||
|
property int cellPadding: 8
|
||||||
|
property real iconSizeRatio: 0.6
|
||||||
|
property int maxIconSize: 56
|
||||||
|
property int minIconSize: 32
|
||||||
|
property real wheelStepSize: 60
|
||||||
|
|
||||||
|
signal itemClicked(int index, var modelData)
|
||||||
|
signal itemHovered(int index)
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
ScrollBar.vertical.policy: ScrollBar.AsNeeded
|
||||||
|
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||||
|
|
||||||
|
GridView {
|
||||||
|
id: grid
|
||||||
|
|
||||||
|
property int baseCellWidth: adaptiveColumns ?
|
||||||
|
Math.max(minCellWidth, Math.min(maxCellWidth, width / columns)) :
|
||||||
|
(width - Theme.spacingS * 2) / columns
|
||||||
|
property int baseCellHeight: baseCellWidth + 20
|
||||||
|
property int actualColumns: adaptiveColumns ? Math.floor(width / cellWidth) : columns
|
||||||
|
property int remainingSpace: width - (actualColumns * cellWidth)
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingS
|
||||||
|
cellWidth: baseCellWidth
|
||||||
|
cellHeight: baseCellHeight
|
||||||
|
leftMargin: Math.max(Theme.spacingS, remainingSpace / 2)
|
||||||
|
rightMargin: leftMargin
|
||||||
|
focus: true
|
||||||
|
interactive: true
|
||||||
|
flickDeceleration: 8000
|
||||||
|
maximumFlickVelocity: 15000
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.NoButton
|
||||||
|
propagateComposedEvents: true
|
||||||
|
z: -1
|
||||||
|
onWheel: function(wheel) {
|
||||||
|
var delta = wheel.angleDelta.y;
|
||||||
|
var steps = delta / 120;
|
||||||
|
grid.contentY -= steps * wheelStepSize;
|
||||||
|
if (grid.contentY < 0)
|
||||||
|
grid.contentY = 0;
|
||||||
|
else if (grid.contentY > grid.contentHeight - grid.height)
|
||||||
|
grid.contentY = Math.max(0, grid.contentHeight - grid.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
width: grid.cellWidth - cellPadding
|
||||||
|
height: grid.cellHeight - cellPadding
|
||||||
|
radius: Theme.cornerRadiusLarge
|
||||||
|
color: currentIndex === index ?
|
||||||
|
Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) :
|
||||||
|
mouseArea.containsMouse ?
|
||||||
|
Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) :
|
||||||
|
Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.03)
|
||||||
|
border.color: currentIndex === index ?
|
||||||
|
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: currentIndex === index ? 2 : 1
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Theme.spacingS
|
||||||
|
|
||||||
|
Item {
|
||||||
|
property int iconSize: Math.min(maxIconSize, Math.max(minIconSize, grid.cellWidth * iconSizeRatio))
|
||||||
|
|
||||||
|
width: iconSize
|
||||||
|
height: iconSize
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
|
||||||
|
IconImage {
|
||||||
|
id: iconImg
|
||||||
|
anchors.fill: parent
|
||||||
|
source: (model.icon) ? Quickshell.iconPath(model.icon, "") : ""
|
||||||
|
smooth: true
|
||||||
|
asynchronous: true
|
||||||
|
visible: status === Image.Ready
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: !iconImg.visible
|
||||||
|
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
|
||||||
|
radius: Theme.cornerRadiusLarge
|
||||||
|
border.width: 1
|
||||||
|
border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2)
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: (model.name && model.name.length > 0) ? model.name.charAt(0).toUpperCase() : "A"
|
||||||
|
font.pixelSize: Math.min(28, parent.width * 0.5)
|
||||||
|
color: Theme.primary
|
||||||
|
font.weight: Font.Bold
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.horizontalCenter: parent.horizontalCenter
|
||||||
|
width: grid.cellWidth - 12
|
||||||
|
text: model.name || ""
|
||||||
|
font.pixelSize: Theme.fontSizeSmall
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Medium
|
||||||
|
elide: Text.ElideRight
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
maximumLineCount: 2
|
||||||
|
wrapMode: Text.WordWrap
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
z: 10
|
||||||
|
onEntered: {
|
||||||
|
currentIndex = index;
|
||||||
|
itemHovered(index);
|
||||||
|
}
|
||||||
|
onClicked: {
|
||||||
|
itemClicked(index, model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
Widgets/DankIcon.qml
Normal file
26
Widgets/DankIcon.qml
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
|
||||||
|
Text {
|
||||||
|
id: icon
|
||||||
|
|
||||||
|
property alias name: icon.text
|
||||||
|
property alias size: icon.font.pixelSize
|
||||||
|
property alias color: icon.color
|
||||||
|
property bool filled: false
|
||||||
|
readonly property string iconFont : {
|
||||||
|
var families = Qt.fontFamilies();
|
||||||
|
if (families.indexOf("Material Symbols Rounded") !== -1) {
|
||||||
|
return "Material Symbols Rounded";
|
||||||
|
} else {
|
||||||
|
return "Material Icons Round";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
font.family: iconFont
|
||||||
|
font.pixelSize: Theme.iconSize
|
||||||
|
font.weight: filled ? Font.Medium : Font.Normal
|
||||||
|
color: Theme.surfaceText
|
||||||
|
verticalAlignment: Text.AlignVCenter
|
||||||
|
horizontalAlignment: Text.AlignHCenter
|
||||||
|
}
|
||||||
145
Widgets/DankListView.qml
Normal file
145
Widgets/DankListView.qml
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
import QtQuick
|
||||||
|
import QtQuick.Controls
|
||||||
|
import Quickshell
|
||||||
|
import Quickshell.Widgets
|
||||||
|
import qs.Common
|
||||||
|
|
||||||
|
ScrollView {
|
||||||
|
id: listView
|
||||||
|
|
||||||
|
property alias model: list.model
|
||||||
|
property int currentIndex: 0
|
||||||
|
property int itemHeight: 72
|
||||||
|
property int iconSize: 56
|
||||||
|
property real wheelStepSize: 60
|
||||||
|
property bool showDescription: true
|
||||||
|
property int itemSpacing: Theme.spacingS
|
||||||
|
|
||||||
|
signal itemClicked(int index, var modelData)
|
||||||
|
signal itemHovered(int index)
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
ScrollBar.vertical.policy: ScrollBar.AlwaysOn
|
||||||
|
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
|
||||||
|
|
||||||
|
ListView {
|
||||||
|
id: list
|
||||||
|
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: itemSpacing
|
||||||
|
spacing: listView.itemSpacing
|
||||||
|
focus: true
|
||||||
|
interactive: true
|
||||||
|
currentIndex: listView.currentIndex
|
||||||
|
flickDeceleration: 8000
|
||||||
|
maximumFlickVelocity: 15000
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.NoButton
|
||||||
|
propagateComposedEvents: true
|
||||||
|
z: -1
|
||||||
|
onWheel: function(wheel) {
|
||||||
|
var delta = wheel.angleDelta.y;
|
||||||
|
var steps = delta / 120;
|
||||||
|
list.contentY -= steps * wheelStepSize;
|
||||||
|
if (list.contentY < 0)
|
||||||
|
list.contentY = 0;
|
||||||
|
else if (list.contentY > list.contentHeight - list.height)
|
||||||
|
list.contentY = Math.max(0, list.contentHeight - list.height);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
delegate: Rectangle {
|
||||||
|
width: list.width
|
||||||
|
height: itemHeight
|
||||||
|
radius: Theme.cornerRadiusLarge
|
||||||
|
color: ListView.isCurrentItem ?
|
||||||
|
Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) :
|
||||||
|
mouseArea.containsMouse ?
|
||||||
|
Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) :
|
||||||
|
Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.03)
|
||||||
|
border.color: ListView.isCurrentItem ?
|
||||||
|
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: ListView.isCurrentItem ? 2 : 1
|
||||||
|
|
||||||
|
Row {
|
||||||
|
anchors.fill: parent
|
||||||
|
anchors.margins: Theme.spacingM
|
||||||
|
spacing: Theme.spacingL
|
||||||
|
|
||||||
|
Item {
|
||||||
|
width: iconSize
|
||||||
|
height: iconSize
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
|
||||||
|
IconImage {
|
||||||
|
id: iconImg
|
||||||
|
anchors.fill: parent
|
||||||
|
source: (model.icon) ? Quickshell.iconPath(model.icon, "") : ""
|
||||||
|
smooth: true
|
||||||
|
asynchronous: true
|
||||||
|
visible: status === Image.Ready
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
visible: !iconImg.visible
|
||||||
|
color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.1)
|
||||||
|
radius: Theme.cornerRadiusLarge
|
||||||
|
border.width: 1
|
||||||
|
border.color: Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.2)
|
||||||
|
|
||||||
|
Text {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
text: (model.name && model.name.length > 0) ? model.name.charAt(0).toUpperCase() : "A"
|
||||||
|
font.pixelSize: iconSize * 0.4
|
||||||
|
color: Theme.primary
|
||||||
|
font.weight: Font.Bold
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Column {
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
width: parent.width - iconSize - Theme.spacingL
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
Text {
|
||||||
|
width: parent.width
|
||||||
|
text: model.name || ""
|
||||||
|
font.pixelSize: Theme.fontSizeLarge
|
||||||
|
color: Theme.surfaceText
|
||||||
|
font.weight: Font.Medium
|
||||||
|
elide: Text.ElideRight
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
width: parent.width
|
||||||
|
text: model.comment || "Application"
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: Theme.surfaceVariantText
|
||||||
|
elide: Text.ElideRight
|
||||||
|
visible: showDescription && model.comment && model.comment.length > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
z: 10
|
||||||
|
onEntered: {
|
||||||
|
listView.currentIndex = index;
|
||||||
|
itemHovered(index);
|
||||||
|
}
|
||||||
|
onClicked: {
|
||||||
|
itemClicked(index, model);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
import QtQuick
|
import QtQuick
|
||||||
import qs.Common
|
import qs.Common
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
Item {
|
Item {
|
||||||
id: slider
|
id: slider
|
||||||
@@ -40,10 +41,9 @@ Item {
|
|||||||
spacing: Theme.spacingM
|
spacing: Theme.spacingM
|
||||||
|
|
||||||
// Left icon
|
// Left icon
|
||||||
Text {
|
DankIcon {
|
||||||
text: slider.leftIcon
|
name: slider.leftIcon
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: slider.enabled ? Theme.surfaceText : Theme.surfaceVariantText
|
color: slider.enabled ? Theme.surfaceText : Theme.surfaceVariantText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: slider.leftIcon.length > 0
|
visible: slider.leftIcon.length > 0
|
||||||
@@ -205,10 +205,9 @@ Item {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Right icon
|
// Right icon
|
||||||
Text {
|
DankIcon {
|
||||||
text: slider.rightIcon
|
name: slider.rightIcon
|
||||||
font.family: Theme.iconFont
|
size: Theme.iconSize
|
||||||
font.pixelSize: Theme.iconSize
|
|
||||||
color: slider.enabled ? Theme.surfaceText : Theme.surfaceVariantText
|
color: slider.enabled ? Theme.surfaceText : Theme.surfaceVariantText
|
||||||
anchors.verticalCenter: parent.verticalCenter
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
visible: slider.rightIcon.length > 0
|
visible: slider.rightIcon.length > 0
|
||||||
87
Widgets/DankTabBar.qml
Normal file
87
Widgets/DankTabBar.qml
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
import qs.Widgets
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: tabBar
|
||||||
|
|
||||||
|
property alias model: tabRepeater.model
|
||||||
|
property int currentIndex: 0
|
||||||
|
property int spacing: Theme.spacingXS
|
||||||
|
property int tabHeight: 36
|
||||||
|
property bool showIcons: true
|
||||||
|
property bool equalWidthTabs: true
|
||||||
|
|
||||||
|
signal tabClicked(int index)
|
||||||
|
|
||||||
|
height: tabHeight
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: tabRow
|
||||||
|
anchors.fill: parent
|
||||||
|
spacing: tabBar.spacing
|
||||||
|
|
||||||
|
Repeater {
|
||||||
|
id: tabRepeater
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
property int tabCount: tabRepeater.count
|
||||||
|
property bool isActive: tabBar.currentIndex === index
|
||||||
|
property bool hasIcon: tabBar.showIcons && modelData.icon && modelData.icon.length > 0
|
||||||
|
property bool hasText: modelData.text && modelData.text.length > 0
|
||||||
|
|
||||||
|
width: tabBar.equalWidthTabs ?
|
||||||
|
(tabBar.width - tabBar.spacing * (tabCount - 1)) / tabCount :
|
||||||
|
contentRow.implicitWidth + Theme.spacingM * 2
|
||||||
|
height: tabBar.tabHeight
|
||||||
|
radius: Theme.cornerRadiusSmall
|
||||||
|
color: isActive ?
|
||||||
|
Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.16) :
|
||||||
|
tabArea.containsMouse ?
|
||||||
|
Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.08) :
|
||||||
|
"transparent"
|
||||||
|
|
||||||
|
Row {
|
||||||
|
id: contentRow
|
||||||
|
anchors.centerIn: parent
|
||||||
|
spacing: Theme.spacingXS
|
||||||
|
|
||||||
|
DankIcon {
|
||||||
|
name: modelData.icon || ""
|
||||||
|
size: Theme.iconSize - 4
|
||||||
|
color: parent.parent.isActive ? Theme.primary : Theme.surfaceText
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
visible: parent.parent.hasIcon
|
||||||
|
}
|
||||||
|
|
||||||
|
Text {
|
||||||
|
text: modelData.text || ""
|
||||||
|
font.pixelSize: Theme.fontSizeMedium
|
||||||
|
color: parent.parent.isActive ? Theme.primary : Theme.surfaceText
|
||||||
|
font.weight: parent.parent.isActive ? Font.Medium : Font.Normal
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
visible: parent.parent.hasText
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: tabArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: Qt.PointingHandCursor
|
||||||
|
onClicked: {
|
||||||
|
tabBar.currentIndex = index
|
||||||
|
tabBar.tabClicked(index)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
75
Widgets/DankToggle.qml
Normal file
75
Widgets/DankToggle.qml
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
import QtQuick
|
||||||
|
import qs.Common
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: toggle
|
||||||
|
|
||||||
|
property bool checked: false
|
||||||
|
property bool enabled: true
|
||||||
|
property bool toggling: false
|
||||||
|
|
||||||
|
signal clicked()
|
||||||
|
|
||||||
|
width: 48
|
||||||
|
height: 24
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: toggleTrack
|
||||||
|
width: parent.width
|
||||||
|
height: parent.height
|
||||||
|
radius: height / 2
|
||||||
|
color: toggle.checked ? Theme.primary : Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.3)
|
||||||
|
opacity: toggle.toggling ? 0.6 : 1
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
id: toggleHandle
|
||||||
|
width: 20
|
||||||
|
height: 20
|
||||||
|
radius: 10
|
||||||
|
color: Theme.surface
|
||||||
|
anchors.verticalCenter: parent.verticalCenter
|
||||||
|
x: toggle.checked ? parent.width - width - 2 : 2
|
||||||
|
|
||||||
|
Behavior on x {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.emphasizedEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Rectangle {
|
||||||
|
anchors.centerIn: parent
|
||||||
|
width: parent.width + 2
|
||||||
|
height: parent.height + 2
|
||||||
|
radius: (parent.width + 2) / 2
|
||||||
|
color: "transparent"
|
||||||
|
border.color: Qt.rgba(0, 0, 0, 0.1)
|
||||||
|
border.width: 1
|
||||||
|
z: -1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: toggleArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
cursorShape: toggle.enabled ? Qt.PointingHandCursor : Qt.ArrowCursor
|
||||||
|
enabled: toggle.enabled
|
||||||
|
onClicked: toggle.clicked()
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on color {
|
||||||
|
ColorAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Behavior on opacity {
|
||||||
|
NumberAnimation {
|
||||||
|
duration: Theme.shortDuration
|
||||||
|
easing.type: Theme.standardEasing
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
10
shell.qml
10
shell.qml
@@ -1,10 +1,10 @@
|
|||||||
//@ pragma UseQApplication
|
//@ pragma UseQApplication
|
||||||
|
|
||||||
import Quickshell
|
import Quickshell
|
||||||
import qs.Widgets
|
import qs.Modules
|
||||||
import qs.Widgets.CenterCommandCenter
|
import qs.Modules.CenterCommandCenter
|
||||||
import qs.Widgets.ControlCenter
|
import qs.Modules.ControlCenter
|
||||||
import qs.Widgets.TopBar
|
import qs.Modules.TopBar
|
||||||
|
|
||||||
ShellRoot {
|
ShellRoot {
|
||||||
id: root
|
id: root
|
||||||
@@ -85,7 +85,7 @@ ShellRoot {
|
|||||||
id: clipboardHistoryPopup
|
id: clipboardHistoryPopup
|
||||||
}
|
}
|
||||||
|
|
||||||
ToastWidget {
|
Toast {
|
||||||
id: toastWidget
|
id: toastWidget
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user