mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-06-28 05:55:21 -04:00
Compare commits
6 Commits
e50ac208e3
...
e7ccb702a3
| Author | SHA1 | Date | |
|---|---|---|---|
| e7ccb702a3 | |||
| bf3ce6deb2 | |||
| f5295fb35d | |||
| 6c5836722a | |||
| 5716249bd9 | |||
| 4d0aab773b |
@@ -75,7 +75,7 @@ var greeterSyncCmd = &cobra.Command{
|
||||
auth, _ := cmd.Flags().GetBool("auth")
|
||||
local, _ := cmd.Flags().GetBool("local")
|
||||
profile, _ := cmd.Flags().GetBool("profile")
|
||||
autologinOnly, _ := cmd.Flags().GetBool("autologin-only")
|
||||
autologinOnly, _ := cmd.Flags().GetBool("autologin")
|
||||
term, _ := cmd.Flags().GetBool("terminal")
|
||||
if term {
|
||||
if err := syncInTerminal(yes, auth, local, profile, autologinOnly); err != nil {
|
||||
@@ -101,7 +101,7 @@ func init() {
|
||||
greeterSyncCmd.Flags().BoolP("auth", "a", false, "Configure PAM for fingerprint and U2F (adds both if modules exist); overrides UI toggles")
|
||||
greeterSyncCmd.Flags().BoolP("local", "l", false, "Developer mode: force greetd config to use a local DMS checkout path")
|
||||
greeterSyncCmd.Flags().BoolP("profile", "p", false, "Sync only your per-user greeter slot (no sudo; for secondary accounts)")
|
||||
greeterSyncCmd.Flags().Bool("autologin-only", false, "Apply only greeter auto-login on startup settings to greetd (no theme or auth sync)")
|
||||
greeterSyncCmd.Flags().Bool("autologin", false, "Apply only greeter auto-login on startup settings to greetd (no theme or auth sync)")
|
||||
}
|
||||
|
||||
var greeterEnableCmd = &cobra.Command{
|
||||
@@ -544,7 +544,7 @@ func syncInTerminal(nonInteractive bool, forceAuth bool, local bool, profileOnly
|
||||
syncFlags = append(syncFlags, "--profile")
|
||||
}
|
||||
if autologinOnly {
|
||||
syncFlags = append(syncFlags, "--autologin-only")
|
||||
syncFlags = append(syncFlags, "--autologin")
|
||||
}
|
||||
shellSyncCmd := "dms greeter sync"
|
||||
if len(syncFlags) > 0 {
|
||||
|
||||
@@ -2153,18 +2153,6 @@ vt = 1
|
||||
commandLine := fmt.Sprintf(`command = "%s"`, commandValue)
|
||||
newConfig := upsertDefaultSession(configContent, greeterUser, commandLine)
|
||||
|
||||
homeDir, homeErr := os.UserHomeDir()
|
||||
if homeErr == nil {
|
||||
enabled, loginUser, sessionExec, resolveErr := resolveGreeterAutoLoginState(GreeterCacheDir, homeDir)
|
||||
if resolveErr != nil {
|
||||
logFunc(fmt.Sprintf("⚠ Warning: Failed to resolve greeter auto-login state: %v", resolveErr))
|
||||
} else if enabled && loginUser != "" && sessionExec != "" {
|
||||
newConfig = upsertInitialSession(newConfig, loginUser, sessionExec, true)
|
||||
} else {
|
||||
newConfig = upsertInitialSession(newConfig, "", "", false)
|
||||
}
|
||||
}
|
||||
|
||||
if err := writeGreetdConfig(configPath, newConfig, logFunc, sudoPassword, fmt.Sprintf("✓ Updated greetd configuration (user: %s, command: %s)", greeterUser, commandValue)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -2241,6 +2241,9 @@ Singleton {
|
||||
|
||||
function getFilteredScreens(componentId) {
|
||||
var prefs = screenPreferences && screenPreferences[componentId] || ["all"];
|
||||
if (componentId === "wallpaper" && Array.isArray(prefs) && prefs.length === 0) {
|
||||
return [];
|
||||
}
|
||||
if (!prefs || prefs.length === 0 || prefs.includes("all") || (typeof prefs[0] === "string" && prefs[0] === "all")) {
|
||||
return Quickshell.screens;
|
||||
}
|
||||
|
||||
@@ -361,7 +361,7 @@ Singleton {
|
||||
}
|
||||
|
||||
function launchGreeterAutoLoginSyncTerminalFallback(details) {
|
||||
ToastService.showWarning(I18n.tr("Opening terminal to update greetd"), I18n.tr("DMS needs administrator access. The terminal closes automatically when done.") + (details ? "\n\n" + details : ""), "dms greeter sync --autologin-only", "greeter-autologin-sync");
|
||||
ToastService.showWarning(I18n.tr("Opening terminal to update greetd"), I18n.tr("DMS needs administrator access. The terminal closes automatically when done.") + (details ? "\n\n" + details : ""), "dms greeter sync --autologin", "greeter-autologin-sync");
|
||||
greeterAutoLoginSyncTerminalFallbackStderr = "";
|
||||
greeterAutoLoginSyncTerminalFallbackProcess.running = true;
|
||||
}
|
||||
@@ -530,7 +530,7 @@ Singleton {
|
||||
}
|
||||
|
||||
property var greeterAutoLoginSyncProcess: Process {
|
||||
command: ["dms", "greeter", "sync", "--yes", "--autologin-only"]
|
||||
command: ["dms", "greeter", "sync", "--yes", "--autologin"]
|
||||
running: false
|
||||
|
||||
stdout: StdioCollector {
|
||||
@@ -570,7 +570,7 @@ Singleton {
|
||||
onExited: exitCode => {
|
||||
const enabling = root.settingsRoot && root.settingsRoot.greeterAutoLogin;
|
||||
if (exitCode === 0) {
|
||||
ToastService.showWarning(enabling ? I18n.tr("Applying auto-login on startup…") : I18n.tr("Disabling auto-login on startup…"), "", "dms greeter sync --autologin-only", "greeter-autologin-sync");
|
||||
ToastService.showWarning(enabling ? I18n.tr("Applying auto-login on startup…") : I18n.tr("Disabling auto-login on startup…"), "", "dms greeter sync --autologin", "greeter-autologin-sync");
|
||||
root.greeterAutoLoginSyncProcess.running = true;
|
||||
return;
|
||||
}
|
||||
@@ -580,7 +580,7 @@ Singleton {
|
||||
}
|
||||
|
||||
property var greeterAutoLoginSyncTerminalFallbackProcess: Process {
|
||||
command: ["dms", "greeter", "sync", "--terminal", "--yes", "--autologin-only"]
|
||||
command: ["dms", "greeter", "sync", "--terminal", "--yes", "--autologin"]
|
||||
running: false
|
||||
|
||||
stderr: StdioCollector {
|
||||
@@ -592,7 +592,7 @@ Singleton {
|
||||
root.greeterAutoLoginSyncSuccessToast("");
|
||||
} else {
|
||||
let details = (root.greeterAutoLoginSyncTerminalFallbackStderr || "").trim();
|
||||
ToastService.showError(I18n.tr("Couldn't open a terminal for the auto-login update.") + " (exit " + exitCode + ")", details, "dms greeter sync --autologin-only", "greeter-autologin-sync");
|
||||
ToastService.showError(I18n.tr("Couldn't open a terminal for the auto-login update.") + " (exit " + exitCode + ")", details, "dms greeter sync --autologin", "greeter-autologin-sync");
|
||||
}
|
||||
root.finishGreeterAutoLoginSync();
|
||||
}
|
||||
|
||||
+18
-2
@@ -328,6 +328,16 @@ Item {
|
||||
}
|
||||
|
||||
property bool hadRealScreen: true
|
||||
property var previousRealScreenNames: []
|
||||
|
||||
function _getRealScreenNames() {
|
||||
const names = [];
|
||||
for (let i = 0; i < Quickshell.screens.length; i++) {
|
||||
if (Quickshell.screens[i].name.length > 0)
|
||||
names.push(Quickshell.screens[i].name);
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
function _hasRealScreen() {
|
||||
for (let i = 0; i < Quickshell.screens.length; i++) {
|
||||
@@ -353,14 +363,20 @@ Item {
|
||||
target: Quickshell
|
||||
function onScreensChanged() {
|
||||
const hasReal = root._hasRealScreen();
|
||||
const currentNames = root._getRealScreenNames();
|
||||
log.info("Screens changed:", Quickshell.screens.length,
|
||||
Quickshell.screens.map(s => "'" + s.name + "'").join(","),
|
||||
"hasReal:", hasReal, "hadReal:", root.hadRealScreen);
|
||||
if (!root.hadRealScreen && hasReal) {
|
||||
log.info("Real screen reappeared after placeholder state, triggering surface recovery");
|
||||
const fullReconnect = !root.hadRealScreen && hasReal;
|
||||
const partialReconnect = root.previousRealScreenNames.length > 0
|
||||
&& currentNames.some(name => !root.previousRealScreenNames.includes(name));
|
||||
if (fullReconnect || partialReconnect) {
|
||||
log.info("Screen reconnect detected, triggering surface recovery",
|
||||
"full:", fullReconnect, "partial:", partialReconnect);
|
||||
root.triggerSurfaceRecovery("screen-reconnect");
|
||||
}
|
||||
root.hadRealScreen = hasReal;
|
||||
root.previousRealScreenNames = currentNames;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ DankModal {
|
||||
|
||||
shouldBeVisible: false
|
||||
allowStacking: true
|
||||
useOverlayLayer: true
|
||||
modalWidth: 420
|
||||
modalHeight: contentLoader.item ? contentLoader.item.implicitHeight + Theme.spacingM * 2 : 200
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ DankModal {
|
||||
closeOnEscapeKey: true
|
||||
closeOnBackgroundClick: true
|
||||
allowStacking: true
|
||||
useOverlayLayer: true
|
||||
keepPopoutsOpen: true
|
||||
|
||||
onBackgroundClicked: close()
|
||||
|
||||
@@ -14,8 +14,8 @@ DankModal {
|
||||
useOverlayLayer: true
|
||||
property real scrollStep: 60
|
||||
property var activeFlickable: null
|
||||
property real _maxW: Math.min(Screen.width * 0.92, 1200)
|
||||
property real _maxH: Math.min(Screen.height * 0.92, 900)
|
||||
property real _maxW: Math.min(root.screenWidth * 0.92, 1200)
|
||||
property real _maxH: Math.min(root.screenHeight * 0.92, 900)
|
||||
modalWidth: _maxW
|
||||
modalHeight: _maxH
|
||||
onBackgroundClicked: close()
|
||||
|
||||
@@ -12,7 +12,7 @@ PluginComponent {
|
||||
service: CupsService
|
||||
}
|
||||
|
||||
ccWidgetIcon: CupsService.cupsAvailable && CupsService.getPrintersNum() > 0 ? "print" : "print_disabled"
|
||||
ccWidgetIcon: "print"
|
||||
ccWidgetPrimaryText: I18n.tr("Printers")
|
||||
ccWidgetSecondaryText: {
|
||||
if (CupsService.cupsAvailable && CupsService.getPrintersNum() > 0) {
|
||||
|
||||
@@ -11,7 +11,7 @@ PluginComponent {
|
||||
service: DMSNetworkService
|
||||
}
|
||||
|
||||
ccWidgetIcon: DMSNetworkService.isBusy ? "sync" : (DMSNetworkService.connected ? "vpn_lock" : "vpn_key_off")
|
||||
ccWidgetIcon: "vpn_key"
|
||||
ccWidgetPrimaryText: I18n.tr("VPN")
|
||||
ccWidgetSecondaryText: {
|
||||
if (!DMSNetworkService.connected)
|
||||
|
||||
@@ -102,6 +102,120 @@ Column {
|
||||
item.z = 1000;
|
||||
}
|
||||
|
||||
function getCompoundPillIconBlinking(id) {
|
||||
if (id === "wifi") return NetworkService.isWifiConnecting;
|
||||
if (id === "bluetooth") return BluetoothService.connecting;
|
||||
return false;
|
||||
}
|
||||
|
||||
function getCompoundPillIconName(id, widgetDef) {
|
||||
switch (id) {
|
||||
case "wifi": {
|
||||
if (NetworkService.wifiToggling) return "sync";
|
||||
if (NetworkService.isConnecting && !NetworkService.ethernetConnected) return NetworkService.wifiSignalIcon;
|
||||
const status = NetworkService.networkStatus;
|
||||
if (status === "ethernet") return "settings_ethernet";
|
||||
if (status === "vpn") return NetworkService.ethernetConnected ? "settings_ethernet" : NetworkService.wifiSignalIcon;
|
||||
if (status === "wifi") return NetworkService.wifiSignalIcon;
|
||||
return "wifi";
|
||||
}
|
||||
case "bluetooth": {
|
||||
return "bluetooth";
|
||||
}
|
||||
case "audioOutput": {
|
||||
if (!AudioService.sink?.audio) return "volume_off";
|
||||
let volume = AudioService.sink.audio.volume;
|
||||
let muted = AudioService.sink.audio.muted;
|
||||
if (muted) return "volume_off";
|
||||
if (volume === 0.0) return "volume_mute";
|
||||
if (volume <= 0.33) return "volume_down";
|
||||
if (volume <= 0.66) return "volume_up";
|
||||
return "volume_up";
|
||||
}
|
||||
case "audioInput": {
|
||||
if (!AudioService.source?.audio) return "mic_off";
|
||||
return AudioService.source.audio.muted ? "mic_off" : "mic";
|
||||
}
|
||||
default:
|
||||
return widgetDef?.icon || "help";
|
||||
}
|
||||
}
|
||||
|
||||
function getCompoundPillIsActive(id) {
|
||||
switch (id) {
|
||||
case "wifi": {
|
||||
if (NetworkService.wifiToggling) return false;
|
||||
const status = NetworkService.networkStatus;
|
||||
if (status === "ethernet") return true;
|
||||
if (status === "vpn") return NetworkService.ethernetConnected || NetworkService.wifiConnected;
|
||||
if (status === "wifi") return true;
|
||||
return NetworkService.wifiEnabled;
|
||||
}
|
||||
case "bluetooth":
|
||||
return !!(BluetoothService.available && BluetoothService.adapter && BluetoothService.adapter.enabled);
|
||||
case "audioOutput":
|
||||
return !!(AudioService.sink?.audio && !AudioService.sink.audio.muted);
|
||||
case "audioInput":
|
||||
return !!(AudioService.source?.audio && !AudioService.source.audio.muted);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
function handleCompoundPillToggled(id) {
|
||||
switch (id) {
|
||||
case "wifi": {
|
||||
if (NetworkService.networkStatus !== "ethernet" && !NetworkService.wifiToggling) {
|
||||
NetworkService.toggleWifiRadio();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "bluetooth": {
|
||||
if (BluetoothService.available && BluetoothService.adapter) {
|
||||
BluetoothService.adapter.enabled = !BluetoothService.adapter.enabled;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "audioOutput": {
|
||||
if (AudioService.sink && AudioService.sink.audio) {
|
||||
AudioService.sink.audio.muted = !AudioService.sink.audio.muted;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "audioInput": {
|
||||
if (AudioService.source && AudioService.source.audio) {
|
||||
AudioService.source.audio.muted = !AudioService.source.audio.muted;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function handleCompoundPillWheelEvent(id, wheelEvent) {
|
||||
if (id === "audioOutput") {
|
||||
if (!AudioService.sink || !AudioService.sink.audio) return;
|
||||
let delta = wheelEvent.angleDelta.y;
|
||||
let maxVol = AudioService.sinkMaxVolume;
|
||||
let currentVolume = AudioService.sink.audio.volume * 100;
|
||||
let newVolume;
|
||||
if (delta > 0) newVolume = Math.min(maxVol, currentVolume + 5);
|
||||
else newVolume = Math.max(0, currentVolume - 5);
|
||||
AudioService.sink.audio.muted = false;
|
||||
AudioService.sink.audio.volume = newVolume / 100;
|
||||
wheelEvent.accepted = true;
|
||||
} else if (id === "audioInput") {
|
||||
if (!AudioService.source || !AudioService.source.audio) return;
|
||||
let delta = wheelEvent.angleDelta.y;
|
||||
let currentVolume = AudioService.source.audio.volume * 100;
|
||||
let newVolume;
|
||||
if (delta > 0) newVolume = Math.min(100, currentVolume + 5);
|
||||
else newVolume = Math.max(0, currentVolume - 5);
|
||||
AudioService.source.audio.muted = false;
|
||||
AudioService.source.audio.volume = newVolume / 100;
|
||||
wheelEvent.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
function componentForWidget(widgetData) {
|
||||
const id = widgetData.id || "";
|
||||
const widgetWidth = widgetData.width || 50;
|
||||
@@ -114,7 +228,7 @@ Column {
|
||||
case "bluetooth":
|
||||
case "audioOutput":
|
||||
case "audioInput":
|
||||
return compoundPillComponent;
|
||||
return widgetWidth <= 25 ? smallCompoundComponent : compoundPillComponent;
|
||||
case "volumeSlider":
|
||||
return audioSliderComponent;
|
||||
case "brightnessSlider":
|
||||
@@ -126,7 +240,7 @@ Column {
|
||||
case "diskUsage":
|
||||
return widgetWidth <= 25 ? smallDiskUsageComponent : diskUsagePillComponent;
|
||||
case "colorPicker":
|
||||
return colorPickerPillComponent;
|
||||
return widgetWidth <= 25 ? smallColorPickerComponent : colorPickerPillComponent;
|
||||
case "doNotDisturb":
|
||||
return widgetWidth <= 25 ? smallToggleComponent : dndPillComponent;
|
||||
default:
|
||||
@@ -329,69 +443,8 @@ Column {
|
||||
property var widgetDef: root.model?.getWidgetForId(widgetData.id || "")
|
||||
width: parent.width
|
||||
height: 60
|
||||
iconBlinking: {
|
||||
const id = widgetData.id || "";
|
||||
if (id === "wifi")
|
||||
return NetworkService.isWifiConnecting;
|
||||
if (id === "bluetooth")
|
||||
return BluetoothService.connecting;
|
||||
return false;
|
||||
}
|
||||
iconName: {
|
||||
switch (widgetData.id || "") {
|
||||
case "wifi":
|
||||
{
|
||||
if (NetworkService.wifiToggling)
|
||||
return "sync";
|
||||
if (NetworkService.isConnecting && !NetworkService.ethernetConnected)
|
||||
return NetworkService.wifiSignalIcon;
|
||||
|
||||
const status = NetworkService.networkStatus;
|
||||
if (status === "ethernet")
|
||||
return "settings_ethernet";
|
||||
if (status === "vpn")
|
||||
return NetworkService.ethernetConnected ? "settings_ethernet" : NetworkService.wifiSignalIcon;
|
||||
if (status === "wifi")
|
||||
return NetworkService.wifiSignalIcon;
|
||||
if (NetworkService.wifiEnabled)
|
||||
return "wifi_off";
|
||||
return "wifi_off";
|
||||
}
|
||||
case "bluetooth":
|
||||
{
|
||||
if (!BluetoothService.available)
|
||||
return "bluetooth_disabled";
|
||||
if (!BluetoothService.adapter || !BluetoothService.adapter.enabled)
|
||||
return "bluetooth_disabled";
|
||||
return "bluetooth";
|
||||
}
|
||||
case "audioOutput":
|
||||
{
|
||||
if (!AudioService.sink?.audio)
|
||||
return "volume_off";
|
||||
let volume = AudioService.sink.audio.volume;
|
||||
let muted = AudioService.sink.audio.muted;
|
||||
if (muted)
|
||||
return "volume_off";
|
||||
if (volume === 0.0)
|
||||
return "volume_mute";
|
||||
if (volume <= 0.33)
|
||||
return "volume_down";
|
||||
if (volume <= 0.66)
|
||||
return "volume_up";
|
||||
return "volume_up";
|
||||
}
|
||||
case "audioInput":
|
||||
{
|
||||
if (!AudioService.source?.audio)
|
||||
return "mic_off";
|
||||
let muted = AudioService.source.audio.muted;
|
||||
return muted ? "mic_off" : "mic";
|
||||
}
|
||||
default:
|
||||
return widgetDef?.icon || "help";
|
||||
}
|
||||
}
|
||||
iconBlinking: root.getCompoundPillIconBlinking(widgetData.id || "")
|
||||
iconName: root.getCompoundPillIconName(widgetData.id || "", widgetDef)
|
||||
primaryText: {
|
||||
switch (widgetData.id || "") {
|
||||
case "wifi":
|
||||
@@ -506,66 +559,12 @@ Column {
|
||||
return widgetDef?.description || "";
|
||||
}
|
||||
}
|
||||
isActive: {
|
||||
switch (widgetData.id || "") {
|
||||
case "wifi":
|
||||
{
|
||||
if (NetworkService.wifiToggling)
|
||||
return false;
|
||||
|
||||
const status = NetworkService.networkStatus;
|
||||
if (status === "ethernet")
|
||||
return true;
|
||||
if (status === "vpn")
|
||||
return NetworkService.ethernetConnected || NetworkService.wifiConnected;
|
||||
if (status === "wifi")
|
||||
return true;
|
||||
return NetworkService.wifiEnabled;
|
||||
}
|
||||
case "bluetooth":
|
||||
return !!(BluetoothService.available && BluetoothService.adapter && BluetoothService.adapter.enabled);
|
||||
case "audioOutput":
|
||||
return !!(AudioService.sink?.audio && !AudioService.sink.audio.muted);
|
||||
case "audioInput":
|
||||
return !!(AudioService.source?.audio && !AudioService.source.audio.muted);
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
isActive: root.getCompoundPillIsActive(widgetData.id || "")
|
||||
enabled: widgetDef?.enabled ?? true
|
||||
onToggled: {
|
||||
if (root.editMode)
|
||||
return;
|
||||
switch (widgetData.id || "") {
|
||||
case "wifi":
|
||||
{
|
||||
if (NetworkService.networkStatus !== "ethernet" && !NetworkService.wifiToggling) {
|
||||
NetworkService.toggleWifiRadio();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "bluetooth":
|
||||
{
|
||||
if (BluetoothService.available && BluetoothService.adapter) {
|
||||
BluetoothService.adapter.enabled = !BluetoothService.adapter.enabled;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "audioOutput":
|
||||
{
|
||||
if (AudioService.sink && AudioService.sink.audio) {
|
||||
AudioService.sink.audio.muted = !AudioService.sink.audio.muted;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "audioInput":
|
||||
{
|
||||
if (AudioService.source && AudioService.source.audio) {
|
||||
AudioService.source.audio.muted = !AudioService.source.audio.muted;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
root.handleCompoundPillToggled(widgetData.id || "");
|
||||
}
|
||||
onExpandClicked: {
|
||||
if (root.editMode)
|
||||
@@ -575,35 +574,7 @@ Column {
|
||||
onWheelEvent: function (wheelEvent) {
|
||||
if (root.editMode)
|
||||
return;
|
||||
const id = widgetData.id || "";
|
||||
if (id === "audioOutput") {
|
||||
if (!AudioService.sink || !AudioService.sink.audio)
|
||||
return;
|
||||
let delta = wheelEvent.angleDelta.y;
|
||||
let maxVol = AudioService.sinkMaxVolume;
|
||||
let currentVolume = AudioService.sink.audio.volume * 100;
|
||||
let newVolume;
|
||||
if (delta > 0)
|
||||
newVolume = Math.min(maxVol, currentVolume + 5);
|
||||
else
|
||||
newVolume = Math.max(0, currentVolume - 5);
|
||||
AudioService.sink.audio.muted = false;
|
||||
AudioService.sink.audio.volume = newVolume / 100;
|
||||
wheelEvent.accepted = true;
|
||||
} else if (id === "audioInput") {
|
||||
if (!AudioService.source || !AudioService.source.audio)
|
||||
return;
|
||||
let delta = wheelEvent.angleDelta.y;
|
||||
let currentVolume = AudioService.source.audio.volume * 100;
|
||||
let newVolume;
|
||||
if (delta > 0)
|
||||
newVolume = Math.min(100, currentVolume + 5);
|
||||
else
|
||||
newVolume = Math.max(0, currentVolume - 5);
|
||||
AudioService.source.audio.muted = false;
|
||||
AudioService.source.audio.volume = newVolume / 100;
|
||||
wheelEvent.accepted = true;
|
||||
}
|
||||
root.handleCompoundPillWheelEvent(widgetData.id || "", wheelEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -736,7 +707,7 @@ Column {
|
||||
case "darkMode":
|
||||
return "contrast";
|
||||
case "idleInhibitor":
|
||||
return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle";
|
||||
return "motion_sensor_active";
|
||||
default:
|
||||
return "help";
|
||||
}
|
||||
@@ -821,9 +792,9 @@ Column {
|
||||
case "darkMode":
|
||||
return "contrast";
|
||||
case "doNotDisturb":
|
||||
return SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off";
|
||||
return "do_not_disturb_on";
|
||||
case "idleInhibitor":
|
||||
return SessionService.idleInhibited ? "motion_sensor_active" : "motion_sensor_idle";
|
||||
return "motion_sensor_active";
|
||||
default:
|
||||
return "help";
|
||||
}
|
||||
@@ -1223,4 +1194,47 @@ Column {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: smallCompoundComponent
|
||||
SmallCompoundButton {
|
||||
property var widgetData: parent.widgetData || {}
|
||||
property int widgetIndex: parent.widgetIndex || 0
|
||||
property var widgetDef: root.model?.getWidgetForId(widgetData.id || "")
|
||||
width: parent.width
|
||||
height: 48
|
||||
iconBlinking: root.getCompoundPillIconBlinking(widgetData.id || "")
|
||||
iconName: root.getCompoundPillIconName(widgetData.id || "", widgetDef)
|
||||
isActive: root.getCompoundPillIsActive(widgetData.id || "")
|
||||
enabled: (widgetDef?.enabled ?? true) && !root.editMode
|
||||
onToggled: {
|
||||
if (root.editMode) return;
|
||||
root.handleCompoundPillToggled(widgetData.id || "");
|
||||
}
|
||||
onExpandClicked: {
|
||||
if (root.editMode) return;
|
||||
root.expandClicked(widgetData, widgetIndex);
|
||||
}
|
||||
onWheelEvent: function(wheelEvent) {
|
||||
if (root.editMode) return;
|
||||
root.handleCompoundPillWheelEvent(widgetData.id || "", wheelEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Component {
|
||||
id: smallColorPickerComponent
|
||||
SmallColorPickerButton {
|
||||
property var widgetData: parent.widgetData || {}
|
||||
property int widgetIndex: parent.widgetIndex || 0
|
||||
width: parent.width
|
||||
height: 48
|
||||
colorPickerModal: root.colorPickerModal
|
||||
onClicked: {
|
||||
if (root.editMode) return;
|
||||
if (root.colorPickerModal)
|
||||
root.colorPickerModal.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@ import qs.Modules.ControlCenter.Widgets
|
||||
CompoundPill {
|
||||
id: root
|
||||
|
||||
iconName: SessionData.doNotDisturb ? "do_not_disturb_on" : "do_not_disturb_off"
|
||||
iconName: "do_not_disturb_on"
|
||||
iconColor: SessionData.doNotDisturb ? Theme.primary : Theme.surfaceText
|
||||
primaryText: I18n.tr("Do Not Disturb")
|
||||
isActive: SessionData.doNotDisturb
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
LayoutMirroring.enabled: I18n.isRtl
|
||||
LayoutMirroring.childrenInherit: true
|
||||
|
||||
property var colorPickerModal: null
|
||||
|
||||
signal clicked
|
||||
|
||||
width: parent ? ((parent.width - parent.spacing * 3) / 4) : 48
|
||||
height: 48
|
||||
radius: Theme.cornerRadius === 0 ? 0 : Theme.cornerRadius
|
||||
|
||||
function hoverTint(base) {
|
||||
const factor = 1.2;
|
||||
return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor);
|
||||
}
|
||||
|
||||
color: Theme.primary
|
||||
border.color: Theme.ccTileRing
|
||||
border.width: 1
|
||||
antialiasing: true
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: parent.radius
|
||||
color: hoverTint(root.color)
|
||||
opacity: mouseArea.pressed ? 0.3 : (mouseArea.containsMouse ? 0.2 : 0.0)
|
||||
visible: opacity > 0
|
||||
antialiasing: true
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
anchors.centerIn: parent
|
||||
name: "palette"
|
||||
size: Theme.iconSize
|
||||
color: Theme.primaryText
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: ripple
|
||||
cornerRadius: root.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
enabled: root.enabled
|
||||
onPressed: mouse => ripple.trigger(mouse.x, mouse.y)
|
||||
onClicked: root.clicked()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
import QtQuick
|
||||
import qs.Common
|
||||
import qs.Widgets
|
||||
|
||||
Rectangle {
|
||||
id: root
|
||||
|
||||
LayoutMirroring.enabled: I18n.isRtl
|
||||
LayoutMirroring.childrenInherit: true
|
||||
|
||||
property string iconName: ""
|
||||
property bool isActive: false
|
||||
property bool iconBlinking: false
|
||||
|
||||
// Left click expands the widget (primary detail action), right click toggles on/off.
|
||||
signal toggled
|
||||
signal expandClicked
|
||||
signal wheelEvent(var wheelEvent)
|
||||
|
||||
width: parent ? ((parent.width - parent.spacing * 3) / 4) : 48
|
||||
height: 48
|
||||
radius: {
|
||||
if (Theme.cornerRadius === 0)
|
||||
return 0;
|
||||
return isActive ? Theme.cornerRadius : Theme.cornerRadius + 4;
|
||||
}
|
||||
|
||||
function hoverTint(base) {
|
||||
const factor = 1.2;
|
||||
return Theme.isLightMode ? Qt.darker(base, factor) : Qt.lighter(base, factor);
|
||||
}
|
||||
|
||||
readonly property color _tileBgActive: Theme.ccTileActiveBg
|
||||
readonly property color _tileBgInactive: Theme.ccPillInactiveBg
|
||||
readonly property color _tileRingActive: Theme.ccTileRing
|
||||
readonly property color _tileIconActive: Theme.ccTileActiveText
|
||||
readonly property color _tileIconInactive: Theme.ccTileInactiveIcon
|
||||
|
||||
color: {
|
||||
if (isActive)
|
||||
return _tileBgActive;
|
||||
const baseColor = mouseArea.containsMouse ? Theme.ccPillInactiveHoverBg : _tileBgInactive;
|
||||
return baseColor;
|
||||
}
|
||||
border.color: isActive ? _tileRingActive : Theme.outlineMedium
|
||||
border.width: isActive ? 1 : Theme.layerOutlineWidth
|
||||
antialiasing: true
|
||||
opacity: enabled ? 1.0 : 0.6
|
||||
|
||||
Rectangle {
|
||||
anchors.fill: parent
|
||||
radius: parent.radius
|
||||
color: hoverTint(root.color)
|
||||
opacity: mouseArea.pressed ? 0.3 : (mouseArea.containsMouse ? 0.2 : 0.0)
|
||||
visible: opacity > 0
|
||||
antialiasing: true
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
id: tileIcon
|
||||
anchors.centerIn: parent
|
||||
name: iconName
|
||||
size: Theme.iconSize
|
||||
color: isActive ? _tileIconActive : _tileIconInactive
|
||||
|
||||
DankBlink {
|
||||
target: tileIcon
|
||||
running: root.iconBlinking
|
||||
}
|
||||
}
|
||||
|
||||
DankRipple {
|
||||
id: ripple
|
||||
cornerRadius: root.radius
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: mouseArea
|
||||
anchors.fill: parent
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||
enabled: root.enabled
|
||||
onPressed: mouse => ripple.trigger(mouse.x, mouse.y)
|
||||
onClicked: mouse => {
|
||||
if (mouse.button === Qt.RightButton)
|
||||
root.toggled();
|
||||
else
|
||||
root.expandClicked();
|
||||
}
|
||||
onWheel: function (ev) {
|
||||
root.wheelEvent(ev);
|
||||
}
|
||||
}
|
||||
|
||||
Behavior on radius {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ DankOSD {
|
||||
property string deviceName: ""
|
||||
property string deviceIcon: "speaker"
|
||||
|
||||
osdWidth: Math.min(Math.max(120, Theme.iconSize + textMetrics.width + Theme.spacingS * 4), Screen.width - Theme.spacingM * 2)
|
||||
osdWidth: Math.min(Math.max(120, Theme.iconSize + textMetrics.width + Theme.spacingS * 4), screenWidth - Theme.spacingM * 2)
|
||||
osdHeight: 40 + Theme.spacingS * 2
|
||||
autoHideInterval: 2500
|
||||
enableMouseInteraction: false
|
||||
|
||||
@@ -13,8 +13,8 @@ DankOSD {
|
||||
_displayBrightness = DisplayService.brightnessLevel;
|
||||
}
|
||||
|
||||
osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, Screen.width - Theme.spacingM * 2)
|
||||
osdHeight: useVertical ? Math.min(260, Screen.height - Theme.spacingM * 2) : (40 + Theme.spacingS * 2)
|
||||
osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, screenWidth - Theme.spacingM * 2)
|
||||
osdHeight: useVertical ? Math.min(260, screenHeight - Theme.spacingM * 2) : (40 + Theme.spacingS * 2)
|
||||
autoHideInterval: 3000
|
||||
enableMouseInteraction: true
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ DankOSD {
|
||||
readonly property bool useVertical: isVerticalLayout
|
||||
readonly property var player: MprisController.activePlayer
|
||||
|
||||
osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(280, Screen.width - Theme.spacingM * 2)
|
||||
osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(280, screenWidth - Theme.spacingM * 2)
|
||||
osdHeight: useVertical ? (Theme.iconSize * 2) : (40 + Theme.spacingS * 2)
|
||||
autoHideInterval: 3000
|
||||
enableMouseInteraction: true
|
||||
|
||||
@@ -30,8 +30,8 @@ DankOSD {
|
||||
onTriggered: _suppressNewPlayer = false
|
||||
}
|
||||
|
||||
osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, Screen.width - Theme.spacingM * 2)
|
||||
osdHeight: useVertical ? Math.min(260, Screen.height - Theme.spacingM * 2) : (40 + Theme.spacingS * 2)
|
||||
osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, screenWidth - Theme.spacingM * 2)
|
||||
osdHeight: useVertical ? Math.min(260, screenHeight - Theme.spacingM * 2) : (40 + Theme.spacingS * 2)
|
||||
autoHideInterval: 3000
|
||||
enableMouseInteraction: true
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ DankOSD {
|
||||
_displayVolume = Math.round(AudioService.source.audio.volume * 100);
|
||||
}
|
||||
|
||||
osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, Screen.width - Theme.spacingM * 2)
|
||||
osdHeight: useVertical ? Math.min(260, Screen.height - Theme.spacingM * 2) : (40 + Theme.spacingS * 2)
|
||||
osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, screenWidth - Theme.spacingM * 2)
|
||||
osdHeight: useVertical ? Math.min(260, screenHeight - Theme.spacingM * 2) : (40 + Theme.spacingS * 2)
|
||||
autoHideInterval: 3000
|
||||
enableMouseInteraction: true
|
||||
|
||||
|
||||
@@ -15,8 +15,8 @@ DankOSD {
|
||||
_displayVolume = Math.min(AudioService.sinkMaxVolume, Math.round(AudioService.sink.audio.volume * 100));
|
||||
}
|
||||
|
||||
osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, Screen.width - Theme.spacingM * 2)
|
||||
osdHeight: useVertical ? Math.min(260, Screen.height - Theme.spacingM * 2) : (40 + Theme.spacingS * 2)
|
||||
osdWidth: useVertical ? (40 + Theme.spacingS * 2) : Math.min(260, screenWidth - Theme.spacingM * 2)
|
||||
osdHeight: useVertical ? Math.min(260, screenHeight - Theme.spacingM * 2) : (40 + Theme.spacingS * 2)
|
||||
autoHideInterval: 3000
|
||||
enableMouseInteraction: true
|
||||
|
||||
|
||||
Reference in New Issue
Block a user