mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-15 15:54:00 -04:00
278 lines
7.9 KiB
QML
278 lines
7.9 KiB
QML
import QtQuick
|
|
import qs.Common
|
|
import qs.Modals.Common
|
|
import qs.DCommon.Widgets
|
|
import qs.Widgets
|
|
import qs.Modules.Settings.Widgets
|
|
|
|
DFloatingWindow {
|
|
id: root
|
|
|
|
property var parentModal: null
|
|
parentWindow: parentModal
|
|
property string searchQuery: ""
|
|
property int selectedIndex: -1
|
|
property bool keyboardNavigationActive: false
|
|
property bool isLoading: false
|
|
property bool pendingInstallHandled: false
|
|
property string headerTitle: title
|
|
property string searchPlaceholder: ""
|
|
property alias aboveSearch: aboveSearchSlot.data
|
|
property alias belowSearch: belowSearchSlot.data
|
|
property alias listContent: listSlot.data
|
|
property alias overlay: overlaySlot.data
|
|
property bool overlayActive: false
|
|
readonly property alias installConfirm: urlInstallConfirm
|
|
readonly property alias listArea: listSlot
|
|
|
|
function refresh() {
|
|
}
|
|
|
|
function resetContent() {
|
|
}
|
|
|
|
function applySearch() {
|
|
}
|
|
|
|
function selectNext() {
|
|
}
|
|
|
|
function selectPrevious() {
|
|
}
|
|
|
|
function selectStep(delta) {
|
|
}
|
|
|
|
function activateSelected() {
|
|
return false;
|
|
}
|
|
|
|
function handleEscape() {
|
|
hide();
|
|
}
|
|
|
|
function pendingInstallId() {
|
|
return "";
|
|
}
|
|
|
|
function checkPendingInstall() {
|
|
}
|
|
|
|
function focusSearch() {
|
|
Qt.callLater(() => browserSearchField.forceActiveFocus());
|
|
}
|
|
|
|
function restoreParentFocus() {
|
|
if (!parentModal)
|
|
return;
|
|
parentModal.shouldHaveFocus = Qt.binding(() => parentModal.shouldBeVisible);
|
|
Qt.callLater(() => {
|
|
if (parentModal.modalFocusScope)
|
|
parentModal.modalFocusScope.forceActiveFocus();
|
|
});
|
|
}
|
|
|
|
function show() {
|
|
if (parentModal)
|
|
parentModal.shouldHaveFocus = false;
|
|
const wasVisible = visible;
|
|
visible = true;
|
|
if (wasVisible && pendingInstallId() !== "") {
|
|
pendingInstallHandled = false;
|
|
checkPendingInstall();
|
|
}
|
|
focusSearch();
|
|
}
|
|
|
|
function hide() {
|
|
visible = false;
|
|
restoreParentFocus();
|
|
}
|
|
|
|
minimumSize: Qt.size(SettingsMetrics.windowMinWidth, SettingsMetrics.windowMinHeight)
|
|
implicitWidth: SettingsMetrics.windowWidth
|
|
implicitHeight: SettingsMetrics.windowHeight
|
|
visible: false
|
|
|
|
onClosed: hide()
|
|
|
|
onVisibleChanged: {
|
|
if (visible) {
|
|
pendingInstallHandled = false;
|
|
refresh();
|
|
Qt.callLater(() => {
|
|
browserSearchField.forceActiveFocus();
|
|
checkPendingInstall();
|
|
});
|
|
return;
|
|
}
|
|
searchQuery = "";
|
|
selectedIndex = -1;
|
|
keyboardNavigationActive = false;
|
|
isLoading = false;
|
|
resetContent();
|
|
}
|
|
|
|
ConfirmDialogOverlay {
|
|
id: urlInstallConfirm
|
|
|
|
onDialogClosed: root.focusSearch()
|
|
}
|
|
|
|
FocusScope {
|
|
id: browserKeyHandler
|
|
|
|
anchors.fill: parent
|
|
focus: true
|
|
|
|
Keys.onPressed: event => {
|
|
switch (event.key) {
|
|
case Qt.Key_Escape:
|
|
root.handleEscape();
|
|
event.accepted = true;
|
|
return;
|
|
case Qt.Key_Down:
|
|
root.selectNext();
|
|
event.accepted = true;
|
|
return;
|
|
case Qt.Key_Up:
|
|
root.selectPrevious();
|
|
event.accepted = true;
|
|
return;
|
|
case Qt.Key_Left:
|
|
if (!root.keyboardNavigationActive)
|
|
return;
|
|
root.selectStep(I18n.isRtl ? 1 : -1);
|
|
event.accepted = true;
|
|
return;
|
|
case Qt.Key_Right:
|
|
if (!root.keyboardNavigationActive)
|
|
return;
|
|
root.selectStep(I18n.isRtl ? -1 : 1);
|
|
event.accepted = true;
|
|
return;
|
|
case Qt.Key_Return:
|
|
case Qt.Key_Enter:
|
|
if (!root.activateSelected())
|
|
return;
|
|
event.accepted = true;
|
|
return;
|
|
}
|
|
}
|
|
|
|
DWindowHeader {
|
|
id: headerArea
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: parent.top
|
|
controls: windowControls
|
|
title: root.headerTitle
|
|
onCloseRequested: root.hide()
|
|
|
|
DRefreshButton {
|
|
buttonSize: Theme.buttonHeightXXS
|
|
iconSize: Theme.iconSizeSmall
|
|
iconColor: Theme.surfaceText
|
|
busy: root.isLoading
|
|
onClicked: root.refresh()
|
|
}
|
|
}
|
|
|
|
Item {
|
|
id: browserContent
|
|
LayoutMirroring.enabled: I18n.isRtl
|
|
LayoutMirroring.childrenInherit: true
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: headerArea.bottom
|
|
anchors.bottom: parent.bottom
|
|
anchors.leftMargin: Theme.windowInset
|
|
anchors.rightMargin: Theme.windowInset
|
|
anchors.bottomMargin: Theme.windowInset
|
|
|
|
Item {
|
|
id: browserBody
|
|
anchors.fill: parent
|
|
opacity: 1 - overlaySlot.opacity
|
|
visible: opacity > 0
|
|
|
|
Column {
|
|
id: aboveSearchSlot
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: parent.top
|
|
spacing: Theme.spacingS
|
|
}
|
|
|
|
DSearchField {
|
|
id: browserSearchField
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: aboveSearchSlot.bottom
|
|
anchors.topMargin: aboveSearchSlot.height > 0 ? Theme.spacingM : 0
|
|
height: Theme.fieldHeightLarge
|
|
textColor: Theme.surfaceText
|
|
font.pixelSize: Theme.fontSizeMedium
|
|
placeholderText: root.searchPlaceholder
|
|
text: root.searchQuery
|
|
focus: true
|
|
ignoreLeftRightKeys: true
|
|
keyForwardTargets: [browserKeyHandler]
|
|
onTextEdited: {
|
|
root.searchQuery = text;
|
|
root.applySearch();
|
|
}
|
|
}
|
|
|
|
Column {
|
|
id: belowSearchSlot
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: browserSearchField.bottom
|
|
anchors.topMargin: height > 0 ? Theme.spacingM : 0
|
|
spacing: Theme.spacingS
|
|
}
|
|
|
|
Item {
|
|
id: listSlot
|
|
anchors.left: parent.left
|
|
anchors.right: parent.right
|
|
anchors.top: belowSearchSlot.bottom
|
|
anchors.topMargin: Theme.spacingM
|
|
anchors.bottom: parent.bottom
|
|
|
|
Item {
|
|
anchors.fill: parent
|
|
visible: root.isLoading
|
|
|
|
DSpinner {
|
|
anchors.centerIn: parent
|
|
running: root.isLoading
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Item {
|
|
id: overlaySlot
|
|
anchors.fill: parent
|
|
opacity: root.overlayActive ? 1 : 0
|
|
visible: opacity > 0
|
|
|
|
Behavior on opacity {
|
|
NumberAnimation {
|
|
duration: Theme.expressiveDurations.expressiveEffects
|
|
easing.type: Easing.BezierSpline
|
|
easing.bezierCurve: Theme.expressiveCurves.expressiveEffects
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
FloatingWindowControls {
|
|
id: windowControls
|
|
targetWindow: root
|
|
}
|
|
}
|