1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-28 07:22:50 -05:00

refactor: common DankTextField widget

This commit is contained in:
bbedward
2025-07-21 22:10:46 -04:00
parent 303dc70c28
commit 9730e4edae
7 changed files with 352 additions and 351 deletions

View File

@@ -18,10 +18,12 @@ PanelWindow {
// App management // App management
property var categories: AppSearchService.getAllCategories() property var categories: AppSearchService.getAllCategories()
property string selectedCategory: "All" property string selectedCategory: "All"
property var recentApps: Prefs.recentlyUsedApps.map(recentApp => { property var recentApps: Prefs.recentlyUsedApps.map((recentApp) => {
var app = AppSearchService.getAppByExec(recentApp.exec); var app = AppSearchService.getAppByExec(recentApp.exec);
return app && !app.noDisplay ? app : null; return app && !app.noDisplay ? app : null;
}).filter(app => app !== null) }).filter((app) => {
return app !== null;
})
property var pinnedApps: ["firefox", "code", "terminal", "file-manager"] property var pinnedApps: ["firefox", "code", "terminal", "file-manager"]
property bool showCategories: false property bool showCategories: false
property string viewMode: Prefs.appLauncherViewMode // "list" or "grid" property string viewMode: Prefs.appLauncherViewMode // "list" or "grid"
@@ -140,6 +142,7 @@ PanelWindow {
function show() { function show() {
launcher.isVisible = true; launcher.isVisible = true;
searchField.enabled = true;
searchDebounceTimer.stop(); // Stop any pending search searchDebounceTimer.stop(); // Stop any pending search
updateFilteredModel(); updateFilteredModel();
Qt.callLater(function() { Qt.callLater(function() {
@@ -148,6 +151,7 @@ PanelWindow {
} }
function hide() { function hide() {
searchField.enabled = false; // Disable before hiding to prevent Wayland warnings
launcher.isVisible = false; launcher.isVisible = false;
searchDebounceTimer.stop(); // Stop any pending search searchDebounceTimer.stop(); // Stop any pending search
searchField.text = ""; searchField.text = "";
@@ -221,8 +225,6 @@ PanelWindow {
} }
Component { Component {
id: iconComponent id: iconComponent
@@ -424,117 +426,43 @@ PanelWindow {
} }
// Enhanced search field // Enhanced search field
Rectangle { DankTextField {
id: searchContainer id: searchField
width: parent.width width: parent.width
height: 52 height: 52
radius: Theme.cornerRadiusLarge cornerRadius: Theme.cornerRadiusLarge
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, Theme.getContentBackgroundAlpha() * 0.7) backgroundColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, Theme.getContentBackgroundAlpha() * 0.7)
border.width: searchField.activeFocus ? 2 : 1 normalBorderColor: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
border.color: searchField.activeFocus ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) focusedBorderColor: Theme.primary
leftIconName: "search"
Row { leftIconSize: Theme.iconSize
anchors.fill: parent leftIconColor: Theme.surfaceVariantText
anchors.leftMargin: Theme.spacingL leftIconFocusedColor: Theme.primary
anchors.rightMargin: Theme.spacingL showClearButton: true
spacing: Theme.spacingM font.pixelSize: Theme.fontSizeLarge
focus: launcher.isVisible
DankIcon { enabled: launcher.isVisible
anchors.verticalCenter: parent.verticalCenter placeholderText: "Search applications..."
name: "search" onTextEdited: {
size: Theme.iconSize searchDebounceTimer.restart();
color: searchField.activeFocus ? Theme.primary : Theme.surfaceVariantText
}
TextInput {
id: searchField
anchors.verticalCenter: parent.verticalCenter
width: parent.width - parent.spacing - Theme.iconSize - 32
height: parent.height - Theme.spacingS
color: Theme.surfaceText
font.pixelSize: Theme.fontSizeLarge
verticalAlignment: TextInput.AlignVCenter
focus: launcher.isVisible
selectByMouse: true
activeFocusOnTab: true
onTextChanged: {
searchDebounceTimer.restart();
}
Keys.onPressed: function(event) {
if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && filteredModel.count) {
var firstApp = filteredModel.get(0);
if (firstApp.desktopEntry) {
Prefs.addRecentApp(firstApp.desktopEntry);
firstApp.desktopEntry.execute();
} else {
launcher.launchApp(firstApp.exec);
}
launcher.hide();
event.accepted = true;
} else if (event.key === Qt.Key_Escape) {
launcher.hide();
event.accepted = true;
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.IBeamCursor
acceptedButtons: Qt.NoButton
}
// Placeholder text
Text {
anchors.verticalCenter: parent.verticalCenter
text: "Search applications..."
color: Theme.surfaceVariantText
font.pixelSize: Theme.fontSizeLarge
visible: searchField.text.length === 0 && !searchField.activeFocus
}
// Clear button
Rectangle {
width: 24
height: 24
radius: 12
color: clearSearchArea.containsMouse ? Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) : "transparent"
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
visible: searchField.text.length > 0
DankIcon {
anchors.centerIn: parent
name: "close"
size: 16
color: clearSearchArea.containsMouse ? Theme.outline : Theme.surfaceVariantText
}
MouseArea {
id: clearSearchArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: searchField.text = ""
}
}
}
} }
Keys.onPressed: function(event) {
Behavior on border.color { if ((event.key === Qt.Key_Return || event.key === Qt.Key_Enter) && filteredModel.count) {
ColorAnimation { var firstApp = filteredModel.get(0);
duration: Theme.shortDuration if (firstApp.desktopEntry) {
easing.type: Theme.standardEasing Prefs.addRecentApp(firstApp.desktopEntry);
firstApp.desktopEntry.execute();
} else {
launcher.launchApp(firstApp.exec);
}
launcher.hide();
event.accepted = true;
} else if (event.key === Qt.Key_Escape) {
launcher.hide();
event.accepted = true;
} }
} }
} }
// Category filter and view mode controls // Category filter and view mode controls
@@ -656,6 +584,7 @@ PanelWindow {
// List view // List view
DankListView { DankListView {
id: appList id: appList
anchors.fill: parent anchors.fill: parent
visible: viewMode === "list" visible: viewMode === "list"
model: filteredModel model: filteredModel
@@ -680,6 +609,7 @@ PanelWindow {
// Grid view // Grid view
DankGridView { DankGridView {
id: appGrid id: appGrid
anchors.fill: parent anchors.fill: parent
visible: viewMode === "grid" visible: viewMode === "grid"
model: filteredModel model: filteredModel
@@ -821,6 +751,4 @@ PanelWindow {
} }
} }

View File

@@ -49,14 +49,17 @@ PanelWindow {
function show() { function show() {
clipboardHistory.isVisible = true; clipboardHistory.isVisible = true;
searchField.focus = true; searchField.enabled = true;
refreshClipboard(); refreshClipboard();
Qt.callLater(function() {
searchField.forceActiveFocus();
});
console.log("ClipboardHistory: Opening and refreshing"); console.log("ClipboardHistory: Opening and refreshing");
} }
function hide() { function hide() {
searchField.enabled = false; // Disable before hiding to prevent Wayland warnings
clipboardHistory.isVisible = false; clipboardHistory.isVisible = false;
searchField.focus = false;
searchField.text = ""; searchField.text = "";
// Clean up temporary image files // Clean up temporary image files
cleanupTempFiles(); cleanupTempFiles();
@@ -244,71 +247,30 @@ PanelWindow {
} }
// Search field // Search field
Rectangle { DankTextField {
id: searchField
width: parent.width width: parent.width
height: 48 height: 48
radius: activeTheme.cornerRadiusLarge cornerRadius: activeTheme.cornerRadiusLarge
color: Qt.rgba(activeTheme.surfaceVariant.r, activeTheme.surfaceVariant.g, activeTheme.surfaceVariant.b, activeTheme.getContentBackgroundAlpha() * 0.4) backgroundColor: Qt.rgba(activeTheme.surfaceVariant.r, activeTheme.surfaceVariant.g, activeTheme.surfaceVariant.b, activeTheme.getContentBackgroundAlpha() * 0.4)
border.color: searchField.focus ? activeTheme.primary : Qt.rgba(activeTheme.outline.r, activeTheme.outline.g, activeTheme.outline.b, 0.08) normalBorderColor: Qt.rgba(activeTheme.outline.r, activeTheme.outline.g, activeTheme.outline.b, 0.08)
border.width: searchField.focus ? 2 : 1 focusedBorderColor: activeTheme.primary
leftIconName: "search"
Row { leftIconSize: activeTheme.iconSize
anchors.left: parent.left leftIconColor: Qt.rgba(activeTheme.surfaceText.r, activeTheme.surfaceText.g, activeTheme.surfaceText.b, 0.6)
anchors.leftMargin: activeTheme.spacingL leftIconFocusedColor: activeTheme.primary
anchors.verticalCenter: parent.verticalCenter showClearButton: true
spacing: activeTheme.spacingM font.pixelSize: activeTheme.fontSizeLarge
textColor: activeTheme.surfaceText
DankIcon { placeholderText: "Search clipboard entries..."
name: "search" enabled: clipboardHistory.isVisible
size: activeTheme.iconSize onTextEdited: updateFilteredModel()
color: searchField.focus ? activeTheme.primary : Qt.rgba(activeTheme.surfaceText.r, activeTheme.surfaceText.g, activeTheme.surfaceText.b, 0.6) Keys.onPressed: (event) => {
anchors.verticalCenter: parent.verticalCenter if (event.key === Qt.Key_Escape)
} clipboardHistory.hide();
TextInput {
id: searchField
width: parent.parent.width - 80
height: parent.parent.height
font.pixelSize: activeTheme.fontSizeLarge
color: activeTheme.surfaceText
verticalAlignment: TextInput.AlignVCenter
selectByMouse: true
enabled: clipboardHistory.isVisible
onTextChanged: updateFilteredModel()
Keys.onPressed: (event) => {
if (event.key === Qt.Key_Escape)
clipboardHistory.hide();
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.IBeamCursor
acceptedButtons: Qt.NoButton
}
// Placeholder text
Text {
text: "Search clipboard entries..."
font: searchField.font
color: Qt.rgba(activeTheme.surfaceText.r, activeTheme.surfaceText.g, activeTheme.surfaceText.b, 0.6)
anchors.verticalCenter: parent.verticalCenter
visible: searchField.text.length === 0 && !searchField.focus
}
}
} }
Behavior on border.color {
ColorAnimation {
duration: activeTheme.shortDuration
}
}
} }
} }

View File

@@ -33,6 +33,7 @@ PanelWindow {
} }
function hideDialog() { function hideDialog() {
textInput.enabled = false; // Disable before hiding to prevent Wayland warnings
dialogVisible = false; dialogVisible = false;
inputValue = ""; inputValue = "";
} }
@@ -44,8 +45,13 @@ PanelWindow {
color: "transparent" color: "transparent"
onVisibleChanged: { onVisibleChanged: {
if (visible) { if (visible) {
textInput.forceActiveFocus(); textInput.enabled = true;
textInput.text = inputValue; Qt.callLater(function() {
textInput.forceActiveFocus();
textInput.text = inputValue;
});
} else {
textInput.enabled = false;
} }
} }
@@ -64,6 +70,7 @@ PanelWindow {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
textInput.enabled = false; // Disable before hiding to prevent Wayland warnings
inputDialog.cancelled(); inputDialog.cancelled();
hideDialog(); hideDialog();
} }
@@ -144,18 +151,19 @@ PanelWindow {
border.color: textInput.activeFocus ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) border.color: textInput.activeFocus ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
border.width: textInput.activeFocus ? 2 : 1 border.width: textInput.activeFocus ? 2 : 1
TextInput { DankTextField {
id: textInput id: textInput
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.spacingM
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText textColor: Theme.surfaceText
echoMode: isPassword && !showPasswordCheckbox.checked ? TextInput.Password : TextInput.Normal echoMode: isPassword && !showPasswordCheckbox.checked ? TextInput.Password : TextInput.Normal
verticalAlignment: TextInput.AlignVCenter enabled: dialogVisible
cursorVisible: activeFocus placeholderText: inputPlaceholder
selectByMouse: true backgroundColor: "transparent"
onTextChanged: { normalBorderColor: "transparent"
focusedBorderColor: "transparent"
onTextEdited: {
inputValue = text; inputValue = text;
} }
onAccepted: { onAccepted: {
@@ -168,23 +176,6 @@ PanelWindow {
} }
Text {
anchors.fill: parent
text: inputPlaceholder
font: parent.font
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
verticalAlignment: Text.AlignVCenter
visible: parent.text.length === 0
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.IBeamCursor
onClicked: {
textInput.forceActiveFocus();
}
} }
} }
@@ -269,6 +260,7 @@ PanelWindow {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
textInput.enabled = false; // Disable before hiding to prevent Wayland warnings
inputDialog.cancelled(); inputDialog.cancelled();
hideDialog(); hideDialog();
} }

View File

@@ -385,36 +385,21 @@ PanelWindow {
border.color: profileImageInput.activeFocus ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) border.color: profileImageInput.activeFocus ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
border.width: profileImageInput.activeFocus ? 2 : 1 border.width: profileImageInput.activeFocus ? 2 : 1
TextInput { DankTextField {
id: profileImageInput id: profileImageInput
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.spacingM textColor: Theme.surfaceText
verticalAlignment: TextInput.AlignVCenter
color: Theme.surfaceText
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
text: Prefs.profileImage text: Prefs.profileImage
selectByMouse: true placeholderText: "Enter image path or URL..."
backgroundColor: "transparent"
normalBorderColor: "transparent"
focusedBorderColor: "transparent"
onEditingFinished: { onEditingFinished: {
Prefs.setProfileImage(text); Prefs.setProfileImage(text);
} }
// Placeholder text
Text {
anchors.verticalCenter: parent.verticalCenter
text: "Enter image path or URL..."
color: Qt.rgba(Theme.surfaceVariantText.r, Theme.surfaceVariantText.g, Theme.surfaceVariantText.b, 0.6)
font.pixelSize: Theme.fontSizeMedium
visible: profileImageInput.text.length === 0 && !profileImageInput.activeFocus
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.IBeamCursor
acceptedButtons: Qt.NoButton
}
} }
} }
@@ -498,36 +483,21 @@ PanelWindow {
border.color: weatherLocationInput.activeFocus ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3) border.color: weatherLocationInput.activeFocus ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.3)
border.width: weatherLocationInput.activeFocus ? 2 : 1 border.width: weatherLocationInput.activeFocus ? 2 : 1
TextInput { DankTextField {
id: weatherLocationInput id: weatherLocationInput
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.spacingM textColor: Theme.surfaceText
verticalAlignment: TextInput.AlignVCenter
color: Theme.surfaceText
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
text: Prefs.weatherLocationOverride text: Prefs.weatherLocationOverride
selectByMouse: true placeholderText: "Enter location..."
backgroundColor: "transparent"
normalBorderColor: "transparent"
focusedBorderColor: "transparent"
onEditingFinished: { onEditingFinished: {
Prefs.setWeatherLocationOverride(text); Prefs.setWeatherLocationOverride(text);
} }
// Placeholder text
Text {
anchors.verticalCenter: parent.verticalCenter
text: "Enter location..."
color: Qt.rgba(Theme.surfaceVariantText.r, Theme.surfaceVariantText.g, Theme.surfaceVariantText.b, 0.6)
font.pixelSize: Theme.fontSizeMedium
visible: weatherLocationInput.text.length === 0 && !weatherLocationInput.activeFocus
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.IBeamCursor
acceptedButtons: Qt.NoButton
}
} }
} }

View File

@@ -33,6 +33,7 @@ PanelWindow {
function show() { function show() {
console.log("SpotlightLauncher: show() called"); console.log("SpotlightLauncher: show() called");
spotlightOpen = true; spotlightOpen = true;
searchField.enabled = true;
console.log("SpotlightLauncher: spotlightOpen set to", spotlightOpen); console.log("SpotlightLauncher: spotlightOpen set to", spotlightOpen);
searchDebounceTimer.stop(); // Stop any pending search searchDebounceTimer.stop(); // Stop any pending search
updateFilteredApps(); // Immediate update when showing updateFilteredApps(); // Immediate update when showing
@@ -43,6 +44,7 @@ PanelWindow {
} }
function hide() { function hide() {
searchField.enabled = false; // Disable before hiding to prevent Wayland warnings
spotlightOpen = false; spotlightOpen = false;
searchDebounceTimer.stop(); // Stop any pending search searchDebounceTimer.stop(); // Stop any pending search
searchField.text = ""; searchField.text = "";
@@ -239,7 +241,6 @@ PanelWindow {
} }
Connections { Connections {
target: AppSearchService
function onReadyChanged() { function onReadyChanged() {
if (AppSearchService.ready) { if (AppSearchService.ready) {
var allCategories = AppSearchService.getAllCategories().filter((cat) => { var allCategories = AppSearchService.getAllCategories().filter((cat) => {
@@ -255,8 +256,9 @@ PanelWindow {
} }
} }
}
target: AppSearchService
}
// Dimmed overlay background // Dimmed overlay background
Rectangle { Rectangle {
@@ -426,92 +428,49 @@ PanelWindow {
width: parent.width width: parent.width
spacing: Theme.spacingM spacing: Theme.spacingM
Rectangle { DankTextField {
id: searchContainer id: searchField
width: parent.width - 80 - Theme.spacingM // Leave space for view toggle buttons width: parent.width - 80 - Theme.spacingM // Leave space for view toggle buttons
height: 56 height: 56
radius: Theme.cornerRadiusLarge cornerRadius: Theme.cornerRadiusLarge
color: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, Theme.getContentBackgroundAlpha() * 0.7) backgroundColor: Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, Theme.getContentBackgroundAlpha() * 0.7)
border.width: searchField.activeFocus ? 2 : 1 normalBorderColor: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08)
border.color: searchField.activeFocus ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.08) focusedBorderColor: Theme.primary
leftIconName: "search"
Row { leftIconSize: Theme.iconSize
anchors.fill: parent leftIconColor: Theme.surfaceVariantText
anchors.leftMargin: Theme.spacingL leftIconFocusedColor: Theme.primary
anchors.rightMargin: Theme.spacingL showClearButton: true
spacing: Theme.spacingM textColor: Theme.surfaceText
font.pixelSize: Theme.fontSizeLarge
DankIcon { focus: spotlightOpen
anchors.verticalCenter: parent.verticalCenter enabled: spotlightOpen
name: "search" placeholderText: "Search applications..."
size: Theme.iconSize onTextEdited: {
color: searchField.activeFocus ? Theme.primary : Theme.surfaceVariantText searchDebounceTimer.restart();
}
TextInput {
id: searchField
anchors.verticalCenter: parent.verticalCenter
width: parent.width - parent.spacing - Theme.iconSize - 32
height: parent.height - Theme.spacingS
color: Theme.surfaceText
font.pixelSize: Theme.fontSizeLarge
verticalAlignment: Text.AlignVCenter
focus: spotlightOpen
selectByMouse: true
onTextChanged: {
searchDebounceTimer.restart();
}
Keys.onPressed: (event) => {
if (event.key === Qt.Key_Escape) {
hide();
event.accepted = true;
} else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
launchSelected();
event.accepted = true;
} else if (event.key === Qt.Key_Down) {
selectNext();
event.accepted = true;
} else if (event.key === Qt.Key_Up) {
selectPrevious();
event.accepted = true;
} else if (event.key === Qt.Key_Right && viewMode === "grid") {
selectNextInRow();
event.accepted = true;
} else if (event.key === Qt.Key_Left && viewMode === "grid") {
selectPreviousInRow();
event.accepted = true;
}
}
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.IBeamCursor
acceptedButtons: Qt.NoButton
}
Text {
anchors.verticalCenter: parent.verticalCenter
text: "Search applications..."
color: Theme.surfaceVariantText
font.pixelSize: Theme.fontSizeLarge
visible: searchField.text.length === 0 && !searchField.activeFocus
}
}
} }
Keys.onPressed: (event) => {
Behavior on border.color { if (event.key === Qt.Key_Escape) {
ColorAnimation { hide();
duration: Theme.shortDuration event.accepted = true;
easing.type: Theme.standardEasing } else if (event.key === Qt.Key_Return || event.key === Qt.Key_Enter) {
launchSelected();
event.accepted = true;
} else if (event.key === Qt.Key_Down) {
selectNext();
event.accepted = true;
} else if (event.key === Qt.Key_Up) {
selectPrevious();
event.accepted = true;
} else if (event.key === Qt.Key_Right && viewMode === "grid") {
selectNextInRow();
event.accepted = true;
} else if (event.key === Qt.Key_Left && viewMode === "grid") {
selectPreviousInRow();
event.accepted = true;
} }
} }
} }
// View mode toggle buttons next to search bar // View mode toggle buttons next to search bar
@@ -595,6 +554,7 @@ PanelWindow {
// List view // List view
DankListView { DankListView {
id: resultsList id: resultsList
anchors.fill: parent anchors.fill: parent
visible: viewMode === "list" visible: viewMode === "list"
model: filteredModel model: filteredModel
@@ -613,6 +573,7 @@ PanelWindow {
// Grid view // Grid view
DankGridView { DankGridView {
id: resultsGrid id: resultsGrid
anchors.fill: parent anchors.fill: parent
visible: viewMode === "grid" visible: viewMode === "grid"
model: filteredModel model: filteredModel

View File

@@ -20,9 +20,14 @@ PanelWindow {
WlrLayershell.keyboardFocus: wifiPasswordDialogVisible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None WlrLayershell.keyboardFocus: wifiPasswordDialogVisible ? WlrKeyboardFocus.Exclusive : WlrKeyboardFocus.None
color: "transparent" color: "transparent"
onVisibleChanged: { onVisibleChanged: {
if (visible) if (visible) {
passwordInput.forceActiveFocus(); passwordInput.enabled = true;
Qt.callLater(function() {
passwordInput.forceActiveFocus();
});
} else {
passwordInput.enabled = false;
}
} }
anchors { anchors {
@@ -40,6 +45,7 @@ PanelWindow {
MouseArea { MouseArea {
anchors.fill: parent anchors.fill: parent
onClicked: { onClicked: {
passwordInput.enabled = false; // Disable before hiding to prevent Wayland warnings
wifiPasswordDialogVisible = false; wifiPasswordDialogVisible = false;
wifiPasswordInput = ""; wifiPasswordInput = "";
} }
@@ -102,6 +108,7 @@ PanelWindow {
iconColor: Theme.surfaceText iconColor: Theme.surfaceText
hoverColor: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12) hoverColor: Qt.rgba(Theme.error.r, Theme.error.g, Theme.error.b, 0.12)
onClicked: { onClicked: {
passwordInput.enabled = false; // Disable before hiding to prevent Wayland warnings
wifiPasswordDialogVisible = false; wifiPasswordDialogVisible = false;
wifiPasswordInput = ""; wifiPasswordInput = "";
} }
@@ -118,18 +125,19 @@ PanelWindow {
border.color: passwordInput.activeFocus ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) border.color: passwordInput.activeFocus ? Theme.primary : Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
border.width: passwordInput.activeFocus ? 2 : 1 border.width: passwordInput.activeFocus ? 2 : 1
TextInput { DankTextField {
id: passwordInput id: passwordInput
anchors.fill: parent anchors.fill: parent
anchors.margins: Theme.spacingM
font.pixelSize: Theme.fontSizeMedium font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText textColor: Theme.surfaceText
echoMode: showPasswordCheckbox.checked ? TextInput.Normal : TextInput.Password echoMode: showPasswordCheckbox.checked ? TextInput.Normal : TextInput.Password
verticalAlignment: TextInput.AlignVCenter enabled: wifiPasswordDialogVisible
cursorVisible: activeFocus placeholderText: "Enter password"
selectByMouse: true backgroundColor: "transparent"
onTextChanged: { normalBorderColor: "transparent"
focusedBorderColor: "transparent"
onTextEdited: {
wifiPasswordInput = text; wifiPasswordInput = text;
} }
onAccepted: { onAccepted: {
@@ -141,23 +149,6 @@ PanelWindow {
} }
Text {
anchors.fill: parent
text: "Enter password"
font: parent.font
color: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
verticalAlignment: Text.AlignVCenter
visible: parent.text.length === 0
}
}
MouseArea {
anchors.fill: parent
cursorShape: Qt.IBeamCursor
onClicked: {
passwordInput.forceActiveFocus();
}
} }
} }
@@ -241,6 +232,7 @@ PanelWindow {
hoverEnabled: true hoverEnabled: true
cursorShape: Qt.PointingHandCursor cursorShape: Qt.PointingHandCursor
onClicked: { onClicked: {
passwordInput.enabled = false; // Disable before hiding to prevent Wayland warnings
wifiPasswordDialogVisible = false; wifiPasswordDialogVisible = false;
wifiPasswordInput = ""; wifiPasswordInput = "";
} }

196
Widgets/DankTextField.qml Normal file
View File

@@ -0,0 +1,196 @@
import QtQuick
import QtQuick.Controls
import qs.Common
import qs.Widgets
Rectangle {
id: root
property alias text: textInput.text
property string placeholderText: ""
property alias font: textInput.font
property alias textColor: textInput.color
property alias selectByMouse: textInput.selectByMouse
property alias enabled: textInput.enabled
property alias echoMode: textInput.echoMode
property alias verticalAlignment: textInput.verticalAlignment
property alias cursorVisible: textInput.cursorVisible
property alias readOnly: textInput.readOnly
property alias validator: textInput.validator
property alias inputMethodHints: textInput.inputMethodHints
property alias maximumLength: textInput.maximumLength
// Icon properties
property string leftIconName: ""
property int leftIconSize: Theme.iconSize
property color leftIconColor: Theme.surfaceVariantText
property color leftIconFocusedColor: Theme.primary
property bool showClearButton: false
// Custom properties
property color backgroundColor: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.9)
property color focusedBorderColor: Theme.primary
property color normalBorderColor: Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12)
property color placeholderColor: Qt.rgba(Theme.surfaceText.r, Theme.surfaceText.g, Theme.surfaceText.b, 0.5)
property int borderWidth: 1
property int focusedBorderWidth: 2
property real cornerRadius: Theme.cornerRadius
// Internal padding calculations
readonly property real leftPadding: Theme.spacingM + (leftIconName ? leftIconSize + Theme.spacingM : 0)
readonly property real rightPadding: Theme.spacingM + (showClearButton && text.length > 0 ? 24 + Theme.spacingM : 0)
property real topPadding: Theme.spacingM
property real bottomPadding: Theme.spacingM
// Signals
signal textEdited()
signal editingFinished()
signal accepted()
signal focusChanged(bool hasFocus)
// Access to inner TextInput properties via functions
function getActiveFocus() {
return textInput.activeFocus;
}
function getFocus() {
return textInput.focus;
}
function setFocus(value) {
textInput.focus = value;
}
// Functions
function forceActiveFocus() {
textInput.forceActiveFocus();
}
function selectAll() {
textInput.selectAll();
}
function clear() {
textInput.clear();
}
function paste() {
textInput.paste();
}
function copy() {
textInput.copy();
}
function cut() {
textInput.cut();
}
// Default styling
width: 200
height: 48
radius: cornerRadius
color: backgroundColor
border.color: textInput.activeFocus ? focusedBorderColor : normalBorderColor
border.width: textInput.activeFocus ? focusedBorderWidth : borderWidth
// Left icon
DankIcon {
id: leftIcon
anchors.left: parent.left
anchors.leftMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
name: leftIconName
size: leftIconSize
color: textInput.activeFocus ? leftIconFocusedColor : leftIconColor
visible: leftIconName !== ""
}
TextInput {
id: textInput
anchors.fill: parent
anchors.leftMargin: root.leftPadding
anchors.rightMargin: root.rightPadding
anchors.topMargin: root.topPadding
anchors.bottomMargin: root.bottomPadding
font.pixelSize: Theme.fontSizeMedium
color: Theme.surfaceText
verticalAlignment: TextInput.AlignVCenter
selectByMouse: true
clip: true
onTextChanged: root.textEdited()
onEditingFinished: root.editingFinished()
onAccepted: root.accepted()
onActiveFocusChanged: root.focusChanged(activeFocus)
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.IBeamCursor
acceptedButtons: Qt.NoButton
}
}
// Clear button
Rectangle {
id: clearButton
width: 24
height: 24
radius: 12
color: clearArea.containsMouse ? Qt.rgba(Theme.outline.r, Theme.outline.g, Theme.outline.b, 0.12) : "transparent"
anchors.right: parent.right
anchors.rightMargin: Theme.spacingM
anchors.verticalCenter: parent.verticalCenter
visible: showClearButton && text.length > 0
DankIcon {
anchors.centerIn: parent
name: "close"
size: 16
color: clearArea.containsMouse ? Theme.outline : Theme.surfaceVariantText
}
MouseArea {
id: clearArea
anchors.fill: parent
hoverEnabled: true
cursorShape: Qt.PointingHandCursor
onClicked: {
textInput.text = "";
textInput.forceActiveFocus();
}
}
}
Text {
id: placeholderLabel
anchors.fill: textInput
text: root.placeholderText
font: textInput.font
color: placeholderColor
verticalAlignment: textInput.verticalAlignment
visible: textInput.text.length === 0 && !textInput.activeFocus
elide: Text.ElideRight
}
Behavior on border.color {
ColorAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
Behavior on border.width {
NumberAnimation {
duration: Theme.shortDuration
easing.type: Theme.standardEasing
}
}
}