1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-29 16:02:51 -05:00

Compare commits

...

11 Commits

Author SHA1 Message Date
Lucas
09cf8c9641 niri: add spotlight on overview typing functionality (#774) 2025-11-20 13:48:30 -05:00
Pi Home Server
f1bed4d6a3 Feature/privacy widget fix (#772)
* Fix active camera icon

* Fix active camera icon
2025-11-20 12:30:23 -05:00
bbedward
2ed6c33c83 missing import 2025-11-19 19:14:47 -05:00
bbedward
7ad532ed17 dankinstall: add ultramarine 2025-11-19 18:53:41 -05:00
bbedward
92fe8c5b14 hyprland: restore focus grab to tray menus 2025-11-19 17:24:14 -05:00
bbedward
8e95572589 modals: move HyprFocusGrab out of common Modal 2025-11-19 17:16:51 -05:00
bbedward
62da862a66 modal: round textureSize pixels 2025-11-19 14:36:08 -05:00
bbedward
993e34f548 dankinstall: weakdeps for niri/system 2025-11-19 09:35:22 -05:00
github-actions[bot]
e39465aece chore: bump version to v0.6.2 2025-11-19 13:54:50 +00:00
bbedward
8fd616b680 osd: suppression fix from cc 2025-11-19 08:52:37 -05:00
bbedward
cc054b27de filebrowser: fix auto closing from ddash 2025-11-19 08:33:07 -05:00
30 changed files with 353 additions and 19 deletions

View File

@@ -19,10 +19,12 @@ func init() {
Register("fedora-asahi-remix", "#0B57A4", FamilyFedora, func(config DistroConfig, logChan chan<- string) Distribution {
return NewFedoraDistribution(config, logChan)
})
Register("bluefin", "#0B57A4", FamilyFedora, func(config DistroConfig, logChan chan<- string) Distribution {
return NewFedoraDistribution(config, logChan)
})
Register("ultramarine", "#00078b", FamilyFedora, func(config DistroConfig, logChan chan<- string) Distribution {
return NewFedoraDistribution(config, logChan)
})
}
type FedoraDistribution struct {
@@ -506,6 +508,14 @@ func (f *FedoraDistribution) installDNFPackages(ctx context.Context, packages []
f.log(fmt.Sprintf("Installing DNF packages: %s", strings.Join(packages, ", ")))
args := []string{"dnf", "install", "-y"}
for _, pkg := range packages {
if pkg == "niri" || pkg == "niri-git" {
args = append(args, "--setopt=install_weak_deps=False")
break
}
}
args = append(args, packages...)
progressChan <- InstallProgressMsg{

View File

@@ -171,6 +171,7 @@ Singleton {
property string spotlightModalViewMode: "list"
property bool sortAppsAlphabetically: false
property int appLauncherGridColumns: 4
property bool spotlightCloseNiriOverview: true
property string weatherLocation: "New York, NY"
property string weatherCoordinates: "40.7128,-74.0060"

View File

@@ -97,6 +97,7 @@ var SPEC = {
spotlightModalViewMode: { def: "list" },
sortAppsAlphabetically: { def: false },
appLauncherGridColumns: { def: 4 },
spotlightCloseNiriOverview: { def: true },
weatherLocation: { def: "New York, NY" },
weatherCoordinates: { def: "40.7128,-74.0060" },

View File

@@ -22,7 +22,7 @@ import qs.Modules.ProcessList
import qs.Modules.Settings
import qs.Modules.DankBar
import qs.Modules.DankBar.Popouts
import qs.Modules.HyprWorkspaces
import qs.Modules.WorkspaceOverlays
import qs.Modules.Plugins
import qs.Services
@@ -581,4 +581,12 @@ Item {
id: hyprlandOverview
}
}
LazyLoader {
id: niriOverviewOverlayLoader
active: CompositorService.isNiri
component: NiriOverviewOverlay {
id: niriOverviewOverlay
}
}
}

View File

@@ -1,4 +1,6 @@
import QtQuick
import Quickshell
import Quickshell.Hyprland
import qs.Common
import qs.Modals.Common
import qs.Services
@@ -9,6 +11,11 @@ DankModal {
layerNamespace: "dms:bluetooth-pairing"
HyprlandFocusGrab {
windows: [root]
active: CompositorService.isHyprland && root.shouldHaveFocus
}
property string deviceName: ""
property string deviceAddress: ""
property string requestType: ""

View File

@@ -3,6 +3,7 @@ pragma ComponentBehavior: Bound
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Hyprland
import Quickshell.Io
import qs.Common
import qs.Modals.Common
@@ -14,6 +15,11 @@ DankModal {
layerNamespace: "dms:clipboard"
HyprlandFocusGrab {
windows: [clipboardHistoryModal]
active: CompositorService.isHyprland && clipboardHistoryModal.shouldHaveFocus
}
property int totalCount: 0
property var clipboardEntries: []
property string searchText: ""

View File

@@ -95,11 +95,6 @@ PanelWindow {
return WlrKeyboardFocus.Exclusive
}
HyprlandFocusGrab {
windows: [root]
active: CompositorService.isHyprland && shouldHaveFocus
}
onVisibleChanged: {
if (root.visible) {
opened()
@@ -245,7 +240,7 @@ PanelWindow {
clip: false
layer.enabled: true
layer.smooth: false
layer.textureSize: Qt.size(width * root.dpr, height * root.dpr)
layer.textureSize: Qt.size(Math.round(width * root.dpr), Math.round(height * root.dpr))
opacity: root.shouldBeVisible ? 1 : 0
scale: modalContainer.scaleValue
x: Theme.snap(modalContainer.animX + (parent.width - width) * (1 - modalContainer.scaleValue) * 0.5, root.dpr)

View File

@@ -1,6 +1,7 @@
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Hyprland
import Quickshell.Io
import qs.Common
import qs.Modals.Common
@@ -12,6 +13,11 @@ DankModal {
layerNamespace: "dms:color-picker"
HyprlandFocusGrab {
windows: [root]
active: CompositorService.isHyprland && root.shouldHaveFocus
}
property string pickerTitle: "Choose Color"
property color selectedColor: SessionData.recentColors.length > 0 ? SessionData.recentColors[0] : Theme.primary
property var onColorSelectedCallback: null

View File

@@ -2,10 +2,13 @@ import Qt.labs.folderlistmodel
import QtCore
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Hyprland
import Quickshell.Io
import qs.Common
import qs.Modals.Common
import qs.Modals.FileBrowser
import qs.Services
import qs.Widgets
DankModal {
@@ -13,6 +16,13 @@ DankModal {
layerNamespace: "dms:file-browser"
HyprlandFocusGrab {
windows: [fileBrowserModal]
active: CompositorService.isHyprland && fileBrowserModal.shouldHaveFocus
}
keepPopoutsOpen: true
property string homeDir: StandardPaths.writableLocation(StandardPaths.HomeLocation)
property string docsDir: StandardPaths.writableLocation(StandardPaths.DocumentsLocation)
property string musicDir: StandardPaths.writableLocation(StandardPaths.MusicLocation)

View File

@@ -1,4 +1,6 @@
import QtQuick
import Quickshell
import Quickshell.Hyprland
import Quickshell.Io
import qs.Common
import qs.Modals.Common
@@ -11,6 +13,11 @@ DankModal {
layerNamespace: "dms:notification-center-modal"
HyprlandFocusGrab {
windows: [notificationModal]
active: CompositorService.isHyprland && notificationModal.shouldHaveFocus
}
property bool notificationModalOpen: false
property var notificationListRef: null

View File

@@ -1,4 +1,6 @@
import QtQuick
import Quickshell
import Quickshell.Hyprland
import qs.Common
import qs.Modals.Common
import qs.Services
@@ -9,6 +11,11 @@ DankModal {
layerNamespace: "dms:polkit"
HyprlandFocusGrab {
windows: [root]
active: CompositorService.isHyprland && root.shouldHaveFocus
}
property string passwordInput: ""
property var currentFlow: PolkitService.agent?.flow
property bool isLoading: false

View File

@@ -1,5 +1,6 @@
import QtQuick
import Quickshell
import Quickshell.Hyprland
import qs.Common
import qs.Modals.Common
import qs.Services
@@ -10,6 +11,11 @@ DankModal {
layerNamespace: "dms:power-menu"
HyprlandFocusGrab {
windows: [root]
active: CompositorService.isHyprland && root.shouldHaveFocus
}
property int selectedIndex: 0
property int selectedRow: 0
property int selectedCol: 0

View File

@@ -1,5 +1,7 @@
import QtQuick
import QtQuick.Effects
import Quickshell
import Quickshell.Hyprland
import Quickshell.Io
import qs.Common
import qs.Modals.Common
@@ -13,6 +15,11 @@ DankModal {
layerNamespace: "dms:settings"
HyprlandFocusGrab {
windows: [settingsModal]
active: CompositorService.isHyprland && settingsModal.shouldHaveFocus
}
property Component settingsContent
property alias profileBrowser: profileBrowser
property int currentTabIndex: 0

View File

@@ -158,6 +158,10 @@ Item {
onAppLaunched: () => {
if (parentModal)
parentModal.hide()
if (SettingsData.spotlightCloseNiriOverview && NiriService.inOverview) {
NiriService.toggleOverview()
}
}
onViewModeSelected: mode => {
SettingsData.set("spotlightModalViewMode", mode)
@@ -170,6 +174,10 @@ Item {
onFileOpened: () => {
if (parentModal)
parentModal.hide()
if (SettingsData.spotlightCloseNiriOverview && NiriService.inOverview) {
NiriService.toggleOverview()
}
}
}

View File

@@ -1,6 +1,7 @@
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Hyprland
import Quickshell.Io
import Quickshell.Widgets
import qs.Common
@@ -14,6 +15,11 @@ DankModal {
layerNamespace: "dms:spotlight"
HyprlandFocusGrab {
windows: [spotlightModal]
active: CompositorService.isHyprland && spotlightModal.shouldHaveFocus
}
property bool spotlightOpen: false
property alias spotlightContent: spotlightContentInstance

View File

@@ -1,4 +1,6 @@
import QtQuick
import Quickshell
import Quickshell.Hyprland
import qs.Common
import qs.Modals.Common
import qs.Services
@@ -9,6 +11,11 @@ DankModal {
layerNamespace: "dms:wifi-password"
HyprlandFocusGrab {
windows: [root]
active: CompositorService.isHyprland && root.shouldHaveFocus
}
property string wifiPasswordSSID: ""
property string wifiPasswordInput: ""
property string wifiUsernameInput: ""

View File

@@ -593,13 +593,13 @@ Column {
text: {
switch (widgetData.id || "") {
case "nightMode":
return "Night Mode"
return I18n.tr("Night Mode")
case "darkMode":
return SessionData.isLightMode ? "Light Mode" : "Dark Mode"
return I18n.tr("Dark Mode")
case "doNotDisturb":
return "Do Not Disturb"
return I18n.tr("Do Not Disturb")
case "idleInhibitor":
return SessionService.idleInhibited ? "Keeping Awake" : "Keep Awake"
return SessionService.idleInhibited ? I18n.tr("Keeping Awake") : I18n.tr("Keep Awake")
default:
return "Unknown"
}
@@ -619,7 +619,7 @@ Column {
case "nightMode":
return DisplayService.nightModeEnabled || false
case "darkMode":
return SessionData.isLightMode
return !SessionData.isLightMode
case "doNotDisturb":
return SessionData.doNotDisturb || false
case "idleInhibitor":
@@ -700,7 +700,7 @@ Column {
case "nightMode":
return DisplayService.nightModeEnabled || false
case "darkMode":
return SessionData.isLightMode
return !SessionData.isLightMode
case "doNotDisturb":
return SessionData.doNotDisturb || false
case "idleInhibitor":

View File

@@ -69,6 +69,15 @@ Row {
valueOverride: actualVolumePercent
thumbOutlineColor: Theme.surfaceContainer
trackColor: root.sliderTrackColor.a > 0 ? root.sliderTrackColor : Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
onIsDraggingChanged: {
if (isDragging) {
AudioService.suppressOSD = true
} else {
Qt.callLater(() => { AudioService.suppressOSD = false })
}
}
onSliderValueChanged: function(newValue) {
if (defaultSink) {
defaultSink.audio.volume = newValue / 100.0

View File

@@ -143,6 +143,8 @@ Row {
}
DankSlider {
id: brightnessSlider
anchors.verticalCenter: parent.verticalCenter
width: parent.width - (Theme.iconSize + Theme.spacingS * 2)
enabled: DisplayService.brightnessAvailable && targetDeviceName.length > 0
@@ -162,7 +164,7 @@ Row {
}
return targetDevice.displayMax || 100
}
value: targetBrightness
value: !isDragging ? targetBrightness : value
showValue: true
unit: {
if (!targetDevice) return "%"

View File

@@ -292,6 +292,7 @@ DankPopout {
tabBarItem: tabBar
keyForwardTarget: mainContainer
targetScreen: root.triggerScreen
parentPopout: root
}
WeatherTab {

View File

@@ -5,6 +5,7 @@ import QtQuick.Controls
import QtQuick.Effects
import QtQuick.Layouts
import Quickshell
import Quickshell.Wayland
import qs.Common
import qs.Modals.FileBrowser
import qs.Services
@@ -25,6 +26,7 @@ Item {
property Item tabBarItem: null
property int gridIndex: 0
property Item keyForwardTarget: null
property var parentPopout: null
property int lastPage: 0
property bool enableAnimation: false
property string homeDir: StandardPaths.writableLocation(StandardPaths.HomeLocation)
@@ -293,6 +295,12 @@ Item {
active: false
asynchronous: true
onActiveChanged: {
if (active && parentPopout) {
parentPopout.WlrLayershell.keyboardFocus = WlrKeyboardFocus.None
}
}
sourceComponent: FileBrowserModal {
Component.onCompleted: {
open()
@@ -318,6 +326,13 @@ Item {
}
onDialogClosed: {
if (parentPopout) {
if (CompositorService.isHyprland) {
parentPopout.WlrLayershell.keyboardFocus = WlrKeyboardFocus.OnDemand
} else {
parentPopout.WlrLayershell.keyboardFocus = WlrKeyboardFocus.Exclusive
}
}
Qt.callLater(() => wallpaperBrowserLoader.active = false)
}
}

View File

@@ -591,6 +591,72 @@ Item {
}
}
StyledRect {
width: parent.width
height: niriOverviewSection.implicitHeight + Theme.spacingL * 2
radius: Theme.cornerRadius
color: Theme.withAlpha(Theme.surfaceContainerHigh, Theme.popupTransparency)
border.color: Qt.rgba(Theme.outline.r, Theme.outline.g,
Theme.outline.b, 0.2)
border.width: 0
visible: CompositorService.isNiri
Column {
id: niriOverviewSection
anchors.fill: parent
anchors.margins: Theme.spacingL
spacing: Theme.spacingM
Row {
width: parent.width
spacing: Theme.spacingM
DankIcon {
name: "open_in_new"
size: Theme.iconSize
color: Theme.primary
anchors.verticalCenter: parent.verticalCenter
}
StyledText {
text: I18n.tr("Close Overview on Launch")
font.pixelSize: Theme.fontSizeLarge
font.weight: Font.Medium
color: Theme.surfaceText
anchors.verticalCenter: parent.verticalCenter
}
Item {
width: parent.width - parent.children[0].width
- parent.children[1].width
- niriOverviewToggle.width - Theme.spacingM * 3
height: 1
}
DankToggle {
id: niriOverviewToggle
width: 32
height: 18
checked: SettingsData.spotlightCloseNiriOverview
anchors.verticalCenter: parent.verticalCenter
onToggled: checked => {
SettingsData.set("spotlightCloseNiriOverview", checked)
}
}
}
StyledText {
width: parent.width
text: I18n.tr("When enabled, launching an app from the launcher will automatically close the Niri overview if it's open.")
font.pixelSize: Theme.fontSizeSmall
color: Theme.surfaceVariantText
wrapMode: Text.WordWrap
}
}
}
StyledRect {
width: parent.width
height: recentlyUsedSection.implicitHeight + Theme.spacingL * 2

View File

@@ -0,0 +1,117 @@
import QtQuick
import QtQuick.Controls
import Quickshell
import Quickshell.Wayland
import qs.Common
import qs.Services
Scope {
id: niriOverviewScope
// Only show overlay when in overview and spotlight is not open
property bool overlayActive: NiriService.inOverview && !(PopoutService.spotlightModal?.spotlightOpen ?? false)
Loader {
id: niriOverlayLoader
active: NiriService.inOverview
asynchronous: false
sourceComponent: Variants {
id: overlayVariants
model: Quickshell.screens
PanelWindow {
id: overlayWindow
required property var modelData
screen: modelData
visible: niriOverviewScope.overlayActive
color: "transparent"
WlrLayershell.namespace: "dms:niri-overview-overlay"
WlrLayershell.layer: WlrLayer.Overlay
WlrLayershell.exclusiveZone: -1
WlrLayershell.keyboardFocus: niriOverviewScope.overlayActive ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
implicitWidth: 0
implicitHeight: 0
anchors {
top: true
left: true
right: false
bottom: false
}
FocusScope {
id: keyboardFocusScope
anchors.fill: parent
visible: niriOverviewScope.overlayActive
focus: niriOverviewScope.overlayActive
Keys.onPressed: event => {
// Handle arrow keys and escape for navigation, mimicking niri's harcoded keybinds
if ([Qt.Key_Escape, Qt.Key_Return].includes(event.key)) {
NiriService.toggleOverview()
event.accepted = true
return
}
if (event.key === Qt.Key_Left) {
NiriService.moveColumnLeft()
event.accepted = true
return
}
if (event.key === Qt.Key_Right) {
NiriService.moveColumnRight()
event.accepted = true
return
}
if (event.key === Qt.Key_Up) {
NiriService.moveWorkspaceUp()
event.accepted = true
return
}
if (event.key === Qt.Key_Down) {
NiriService.moveWorkspaceDown()
event.accepted = true
return
}
// Allowing delete and backspace will produce a broken text
if (event.modifiers & (Qt.ControlModifier | Qt.MetaModifier) || [Qt.Key_Delete, Qt.Key_Backspace].includes(event.key)) {
event.accepted = false
return
}
// For any other key (printable characters), open spotlight
if (!event.isAutoRepeat) {
Qt.callLater(() => {
if (PopoutService.spotlightModal) {
if (event.text) {
PopoutService.spotlightModal.showWithQuery(event.text.trim())
}
}
})
event.accepted = true
}
}
Connections {
target: niriOverviewScope
function onOverlayActiveChanged() {
if (niriOverviewScope.overlayActive) {
Qt.callLater(() => keyboardFocusScope.forceActiveFocus())
}
}
}
}
}
}
}
}

View File

@@ -412,7 +412,7 @@ Singleton {
interval: 50
repeat: false
onTriggered: {
if (!root.suppressOSD && SettingsData.soundsEnabled && SettingsData.soundVolumeChanged) {
if (SettingsData.soundsEnabled && SettingsData.soundVolumeChanged) {
root.playVolumeChangeSound()
}
}

View File

@@ -606,6 +606,38 @@ Singleton {
})
}
function moveColumnLeft() {
return send({
"Action": {
"FocusColumnLeft": {}
}
})
}
function moveColumnRight() {
return send({
"Action": {
"FocusColumnRight": {}
}
})
}
function moveWorkspaceDown() {
return send({
"Action": {
"FocusWorkspaceDown": {}
}
})
}
function moveWorkspaceUp() {
return send({
"Action": {
"FocusWorkspaceUp": {}
}
})
}
function switchToWorkspace(workspaceIndex) {
return send({
"Action": {

View File

@@ -34,7 +34,7 @@ Singleton {
}
PwObjectTracker {
objects: Pipewire.nodes.values.filter(node => node.audio && !node.isStream)
objects: Pipewire.nodes.values.filter(node => !node.isStream)
}
readonly property bool cameraActive: {
@@ -47,7 +47,7 @@ Singleton {
if (!node || !node.ready) {
continue
}
if (node.properties && node.properties["media.class"] === "Stream/Input/Video") {
if (node.properties["stream.is-live"] === "true") {
return true

View File

@@ -1 +1 @@
v0.6.1
v0.6.2