mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2025-12-05 21:15:38 -05:00
keybinds: always parse binds.kdl, show warning on position-conflicts
This commit is contained in:
@@ -18,6 +18,9 @@ Item {
|
||||
property int _lastDataVersion: -1
|
||||
property var _cachedCategories: []
|
||||
property var _filteredBinds: []
|
||||
property real _savedScrollY: 0
|
||||
property bool _preserveScroll: false
|
||||
property string _editingKey: ""
|
||||
|
||||
function _updateFiltered() {
|
||||
const allBinds = KeybindsService.getFlatBinds();
|
||||
@@ -87,6 +90,9 @@ Item {
|
||||
function saveNewBind(bindData) {
|
||||
KeybindsService.saveBind("", bindData);
|
||||
showingNewBind = false;
|
||||
selectedCategory = "";
|
||||
_editingKey = bindData.key;
|
||||
expandedKey = bindData.action;
|
||||
}
|
||||
|
||||
function scrollToTop() {
|
||||
@@ -102,9 +108,24 @@ Item {
|
||||
Connections {
|
||||
target: KeybindsService
|
||||
function onBindsLoaded() {
|
||||
const savedY = keybindsTab._savedScrollY;
|
||||
const wasPreserving = keybindsTab._preserveScroll;
|
||||
keybindsTab._lastDataVersion = KeybindsService._dataVersion;
|
||||
keybindsTab._updateCategories();
|
||||
keybindsTab._updateFiltered();
|
||||
keybindsTab._preserveScroll = false;
|
||||
if (wasPreserving)
|
||||
Qt.callLater(() => flickable.contentY = savedY);
|
||||
}
|
||||
function onBindSaved(key) {
|
||||
keybindsTab._savedScrollY = flickable.contentY;
|
||||
keybindsTab._preserveScroll = true;
|
||||
keybindsTab._editingKey = key;
|
||||
}
|
||||
function onBindRemoved(key) {
|
||||
keybindsTab._savedScrollY = flickable.contentY;
|
||||
keybindsTab._preserveScroll = true;
|
||||
keybindsTab._editingKey = "";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,14 +249,33 @@ Item {
|
||||
}
|
||||
|
||||
StyledRect {
|
||||
id: warningBox
|
||||
width: Math.min(650, parent.width - Theme.spacingL * 2)
|
||||
height: warningSection.implicitHeight + Theme.spacingL * 2
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.error, 0.15)
|
||||
border.color: Theme.withAlpha(Theme.error, 0.3)
|
||||
|
||||
readonly property var status: KeybindsService.dmsStatus
|
||||
readonly property bool showError: !status.included && status.exists
|
||||
readonly property bool showWarning: status.included && status.overriddenBy > 0
|
||||
readonly property bool showSetup: !status.exists
|
||||
|
||||
color: {
|
||||
if (showError || showSetup)
|
||||
return Theme.withAlpha(Theme.error, 0.15);
|
||||
if (showWarning)
|
||||
return Theme.withAlpha(Theme.warning ?? Theme.tertiary, 0.15);
|
||||
return "transparent";
|
||||
}
|
||||
border.color: {
|
||||
if (showError || showSetup)
|
||||
return Theme.withAlpha(Theme.error, 0.3);
|
||||
if (showWarning)
|
||||
return Theme.withAlpha(Theme.warning ?? Theme.tertiary, 0.3);
|
||||
return "transparent";
|
||||
}
|
||||
border.width: 1
|
||||
visible: !KeybindsService.dmsBindsIncluded && !KeybindsService.loading
|
||||
visible: (showError || showWarning || showSetup) && !KeybindsService.loading
|
||||
|
||||
Column {
|
||||
id: warningSection
|
||||
@@ -248,26 +288,44 @@ Item {
|
||||
spacing: Theme.spacingM
|
||||
|
||||
DankIcon {
|
||||
name: "warning"
|
||||
name: warningBox.showWarning ? "info" : "warning"
|
||||
size: Theme.iconSize
|
||||
color: Theme.error
|
||||
color: warningBox.showWarning ? (Theme.warning ?? Theme.tertiary) : Theme.error
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
Column {
|
||||
width: parent.width - Theme.iconSize - 100 - Theme.spacingM * 2
|
||||
width: parent.width - Theme.iconSize - (fixButton.visible ? fixButton.width + Theme.spacingM : 0) - Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Binds Include Missing")
|
||||
text: {
|
||||
if (warningBox.showSetup)
|
||||
return I18n.tr("First Time Setup");
|
||||
if (warningBox.showError)
|
||||
return I18n.tr("Binds Include Missing");
|
||||
if (warningBox.showWarning)
|
||||
return I18n.tr("Possible Override Conflicts");
|
||||
return "";
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeMedium
|
||||
font.weight: Font.Medium
|
||||
color: Theme.error
|
||||
color: warningBox.showWarning ? (Theme.warning ?? Theme.tertiary) : Theme.error
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("dms/binds.kdl is not included in config.kdl. Custom keybinds will not work until this is fixed.")
|
||||
text: {
|
||||
if (warningBox.showSetup)
|
||||
return I18n.tr("Click 'Setup' to create dms/binds.kdl and add include to config.kdl.");
|
||||
if (warningBox.showError)
|
||||
return I18n.tr("dms/binds.kdl exists but is not included in config.kdl. Custom keybinds will not work until this is fixed.");
|
||||
if (warningBox.showWarning) {
|
||||
const count = warningBox.status.overriddenBy;
|
||||
return I18n.tr("%1 DMS bind(s) may be overridden by config binds that come after the include.").arg(count);
|
||||
}
|
||||
return "";
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
wrapMode: Text.WordWrap
|
||||
@@ -280,12 +338,19 @@ Item {
|
||||
width: fixButtonText.implicitWidth + Theme.spacingL * 2
|
||||
height: 36
|
||||
radius: Theme.cornerRadius
|
||||
visible: warningBox.showError || warningBox.showSetup
|
||||
color: KeybindsService.fixing ? Theme.withAlpha(Theme.error, 0.6) : Theme.error
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
StyledText {
|
||||
id: fixButtonText
|
||||
text: KeybindsService.fixing ? I18n.tr("Fixing...") : I18n.tr("Fix Now")
|
||||
text: {
|
||||
if (KeybindsService.fixing)
|
||||
return I18n.tr("Fixing...");
|
||||
if (warningBox.showSetup)
|
||||
return I18n.tr("Setup");
|
||||
return I18n.tr("Fix Now");
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.surface
|
||||
@@ -532,6 +597,7 @@ Item {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
bindData: modelData
|
||||
isExpanded: keybindsTab.expandedKey === modelData.action
|
||||
restoreKey: isExpanded ? keybindsTab._editingKey : ""
|
||||
panelWindow: keybindsTab.parentModal
|
||||
onToggleExpand: keybindsTab.toggleExpanded(modelData.action)
|
||||
onSaveBind: (originalKey, newData) => {
|
||||
@@ -539,6 +605,7 @@ Item {
|
||||
keybindsTab.expandedKey = modelData.action;
|
||||
}
|
||||
onRemoveBind: key => KeybindsService.removeBind(key)
|
||||
onRestoreKeyConsumed: keybindsTab._editingKey = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,6 +28,17 @@ Singleton {
|
||||
property string lastError: ""
|
||||
property bool dmsBindsIncluded: true
|
||||
|
||||
property var dmsStatus: ({
|
||||
exists: true,
|
||||
included: true,
|
||||
includePosition: -1,
|
||||
totalIncludes: 0,
|
||||
bindsAfterDms: 0,
|
||||
effective: true,
|
||||
overriddenBy: 0,
|
||||
statusMessage: ""
|
||||
})
|
||||
|
||||
property var _rawData: null
|
||||
property var keybinds: ({})
|
||||
property var _allBinds: ({})
|
||||
@@ -60,6 +71,14 @@ Singleton {
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
target: NiriService
|
||||
enabled: CompositorService.isNiri
|
||||
function onConfigReloaded() {
|
||||
Qt.callLater(root.loadBinds, false);
|
||||
}
|
||||
}
|
||||
|
||||
Process {
|
||||
id: loadProcess
|
||||
running: false
|
||||
@@ -178,7 +197,7 @@ Singleton {
|
||||
}
|
||||
|
||||
function loadBinds(showLoading) {
|
||||
if (loading || !available)
|
||||
if (loadProcess.running || !available)
|
||||
return;
|
||||
const hasData = Object.keys(_allBinds).length > 0;
|
||||
loading = showLoading !== false && !hasData;
|
||||
@@ -188,8 +207,22 @@ Singleton {
|
||||
|
||||
function _processData() {
|
||||
keybinds = _rawData || {};
|
||||
if (currentProvider === "niri")
|
||||
if (currentProvider === "niri") {
|
||||
dmsBindsIncluded = _rawData?.dmsBindsIncluded ?? true;
|
||||
const status = _rawData?.dmsStatus;
|
||||
if (status) {
|
||||
dmsStatus = {
|
||||
exists: status.exists ?? true,
|
||||
included: status.included ?? true,
|
||||
includePosition: status.includePosition ?? -1,
|
||||
totalIncludes: status.totalIncludes ?? 0,
|
||||
bindsAfterDms: status.bindsAfterDms ?? 0,
|
||||
effective: status.effective ?? true,
|
||||
overriddenBy: status.overriddenBy ?? 0,
|
||||
statusMessage: status.statusMessage ?? ""
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (!_rawData?.binds) {
|
||||
_allBinds = {};
|
||||
@@ -239,12 +272,15 @@ Singleton {
|
||||
actionMap[action].keys.push(keyData);
|
||||
if (!actionMap[action].desc && bind.desc)
|
||||
actionMap[action].desc = bind.desc;
|
||||
if (!actionMap[action].conflict && bind.conflict)
|
||||
actionMap[action].conflict = bind.conflict;
|
||||
} else {
|
||||
const entry = {
|
||||
category: category,
|
||||
action: action,
|
||||
desc: bind.desc || "",
|
||||
keys: [keyData]
|
||||
keys: [keyData],
|
||||
conflict: bind.conflict || null
|
||||
};
|
||||
actionMap[action] = entry;
|
||||
grouped.push(entry);
|
||||
|
||||
@@ -39,6 +39,7 @@ Singleton {
|
||||
property string pendingScreenshotPath: ""
|
||||
|
||||
signal windowUrgentChanged
|
||||
signal configReloaded
|
||||
|
||||
function setWorkspaces(newMap) {
|
||||
root.workspaces = newMap;
|
||||
@@ -508,16 +509,19 @@ Singleton {
|
||||
function handleConfigLoaded(data) {
|
||||
if (data.failed) {
|
||||
validateProcess.running = true;
|
||||
} else {
|
||||
configValidationOutput = "";
|
||||
ToastService.dismissCategory("niri-config");
|
||||
fetchOutputs();
|
||||
if (hasInitialConnection && !suppressConfigToast && !suppressNextConfigToast && !matugenSuppression) {
|
||||
ToastService.showInfo("niri: config reloaded", "", "", "niri-config");
|
||||
} else if (suppressNextConfigToast) {
|
||||
suppressNextConfigToast = false;
|
||||
suppressResetTimer.stop();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
configValidationOutput = "";
|
||||
ToastService.dismissCategory("niri-config");
|
||||
fetchOutputs();
|
||||
configReloaded();
|
||||
|
||||
if (hasInitialConnection && !suppressConfigToast && !suppressNextConfigToast && !matugenSuppression) {
|
||||
ToastService.showInfo("niri: config reloaded", "", "", "niri-config");
|
||||
} else if (suppressNextConfigToast) {
|
||||
suppressNextConfigToast = false;
|
||||
suppressResetTimer.stop();
|
||||
}
|
||||
|
||||
if (!hasInitialConnection) {
|
||||
|
||||
@@ -17,6 +17,7 @@ Item {
|
||||
property var panelWindow: null
|
||||
property bool recording: false
|
||||
property bool isNew: false
|
||||
property string restoreKey: ""
|
||||
|
||||
property int editingKeyIndex: -1
|
||||
property string editKey: ""
|
||||
@@ -44,6 +45,8 @@ Item {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
readonly property var configConflict: bindData.conflict || null
|
||||
readonly property bool hasConfigConflict: configConflict !== null
|
||||
readonly property string _originalKey: editingKeyIndex >= 0 && editingKeyIndex < keys.length ? keys[editingKeyIndex].key : ""
|
||||
readonly property var _conflicts: editKey ? KeyUtils.getConflictingBinds(editKey, bindData.action, KeybindsService.getFlatBinds()) : []
|
||||
readonly property bool hasConflict: _conflicts.length > 0
|
||||
@@ -52,6 +55,7 @@ Item {
|
||||
signal saveBind(string originalKey, var newData)
|
||||
signal removeBind(string key)
|
||||
signal cancelEdit
|
||||
signal restoreKeyConsumed
|
||||
|
||||
implicitHeight: contentColumn.implicitHeight
|
||||
height: implicitHeight
|
||||
@@ -59,8 +63,37 @@ Item {
|
||||
Component.onDestruction: _destroyShortcutInhibitor()
|
||||
|
||||
onIsExpandedChanged: {
|
||||
if (isExpanded)
|
||||
if (!isExpanded)
|
||||
return;
|
||||
if (restoreKey) {
|
||||
restoreToKey(restoreKey);
|
||||
restoreKeyConsumed();
|
||||
} else {
|
||||
resetEdits();
|
||||
}
|
||||
}
|
||||
|
||||
onRestoreKeyChanged: {
|
||||
if (!isExpanded || !restoreKey)
|
||||
return;
|
||||
restoreToKey(restoreKey);
|
||||
restoreKeyConsumed();
|
||||
}
|
||||
|
||||
function restoreToKey(keyToFind) {
|
||||
for (let i = 0; i < keys.length; i++) {
|
||||
if (keys[i].key === keyToFind) {
|
||||
editingKeyIndex = i;
|
||||
editKey = keyToFind;
|
||||
editAction = bindData.action || "";
|
||||
editDesc = bindData.desc || "";
|
||||
hasChanges = false;
|
||||
_actionType = Actions.getActionType(editAction);
|
||||
useCustomCompositor = _actionType === "compositor" && !Actions.isKnownCompositorAction(editAction);
|
||||
return;
|
||||
}
|
||||
}
|
||||
resetEdits();
|
||||
}
|
||||
|
||||
onEditActionChanged: {
|
||||
@@ -276,7 +309,21 @@ Item {
|
||||
text: I18n.tr("Override")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.primary
|
||||
visible: root.hasOverride
|
||||
visible: root.hasOverride && !root.hasConfigConflict
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
name: "warning"
|
||||
size: 14
|
||||
color: Theme.warning ?? Theme.tertiary
|
||||
visible: root.hasConfigConflict
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Overridden by config")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.warning ?? Theme.tertiary
|
||||
visible: root.hasConfigConflict
|
||||
}
|
||||
|
||||
Item {
|
||||
@@ -334,6 +381,58 @@ Item {
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Rectangle {
|
||||
Layout.fillWidth: true
|
||||
Layout.preferredHeight: conflictColumn.implicitHeight + Theme.spacingM * 2
|
||||
radius: Theme.cornerRadius
|
||||
color: Theme.withAlpha(Theme.warning ?? Theme.tertiary, 0.15)
|
||||
border.color: Theme.withAlpha(Theme.warning ?? Theme.tertiary, 0.3)
|
||||
border.width: 1
|
||||
visible: root.hasConfigConflict
|
||||
|
||||
Column {
|
||||
id: conflictColumn
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
spacing: Theme.spacingS
|
||||
|
||||
RowLayout {
|
||||
width: parent.width
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankIcon {
|
||||
name: "warning"
|
||||
size: 16
|
||||
color: Theme.warning ?? Theme.tertiary
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("This bind is overridden by config.kdl")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
font.weight: Font.Medium
|
||||
color: Theme.warning ?? Theme.tertiary
|
||||
Layout.fillWidth: true
|
||||
}
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("Config action: %1").arg(root.configConflict?.action ?? "")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: I18n.tr("To use this DMS bind, remove or change the keybind in your config.kdl")
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceVariantText
|
||||
width: parent.width
|
||||
wrapMode: Text.WordWrap
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Reference in New Issue
Block a user