mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-04-15 18:22:08 -04:00
keyboard navigation on clipboard history
This commit is contained in:
@@ -8,7 +8,6 @@ import qs.Services
|
||||
import qs.Widgets
|
||||
|
||||
DankModal {
|
||||
|
||||
id: clipboardHistoryModal
|
||||
|
||||
property int totalCount: 0
|
||||
@@ -16,122 +15,110 @@ DankModal {
|
||||
property bool showClearConfirmation: false
|
||||
property var clipboardEntries: []
|
||||
property string searchText: ""
|
||||
property int selectedIndex: 0
|
||||
property bool keyboardNavigationActive: false
|
||||
property bool showKeyboardHints: false
|
||||
property Component clipboardContent
|
||||
|
||||
function updateFilteredModel() {
|
||||
filteredClipboardModel.clear()
|
||||
filteredClipboardModel.clear();
|
||||
for (var i = 0; i < clipboardModel.count; i++) {
|
||||
const entry = clipboardModel.get(i).entry
|
||||
const entry = clipboardModel.get(i).entry;
|
||||
if (searchText.trim().length === 0) {
|
||||
filteredClipboardModel.append({
|
||||
"entry": entry
|
||||
})
|
||||
});
|
||||
} else {
|
||||
const content = getEntryPreview(entry).toLowerCase()
|
||||
const content = getEntryPreview(entry).toLowerCase();
|
||||
if (content.includes(searchText.toLowerCase()))
|
||||
filteredClipboardModel.append({
|
||||
"entry": entry
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
clipboardHistoryModal.totalCount = filteredClipboardModel.count
|
||||
clipboardHistoryModal.totalCount = filteredClipboardModel.count;
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
if (visible)
|
||||
hide()
|
||||
hide();
|
||||
else
|
||||
show()
|
||||
show();
|
||||
}
|
||||
|
||||
function show() {
|
||||
clipboardHistoryModal.visible = true
|
||||
initializeThumbnailSystem()
|
||||
refreshClipboard()
|
||||
|
||||
Qt.callLater(function() {
|
||||
if (contentLoader.item) {
|
||||
const content = contentLoader.item
|
||||
if (content.children && content.children.length > 1) {
|
||||
const searchField = content.children[1]
|
||||
if (searchField && searchField.forceActiveFocus) {
|
||||
searchField.text = ""
|
||||
searchField.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
clipboardHistoryModal.visible = true;
|
||||
initializeThumbnailSystem();
|
||||
refreshClipboard();
|
||||
keyboardController.reset();
|
||||
}
|
||||
|
||||
function hide() {
|
||||
clipboardHistoryModal.visible = false
|
||||
clipboardHistoryModal.searchText = ""
|
||||
cleanupTempFiles()
|
||||
clipboardHistoryModal.visible = false;
|
||||
clipboardHistoryModal.searchText = "";
|
||||
keyboardController.reset();
|
||||
cleanupTempFiles();
|
||||
}
|
||||
|
||||
function initializeThumbnailSystem() {// No initialization needed - using direct image display
|
||||
function initializeThumbnailSystem() {
|
||||
}
|
||||
|
||||
function cleanupTempFiles() {
|
||||
Quickshell.execDetached(["sh", "-c", "rm -f /tmp/clipboard_*.png"])
|
||||
Quickshell.execDetached(["sh", "-c", "rm -f /tmp/clipboard_*.png"]);
|
||||
}
|
||||
|
||||
function generateThumbnails() {// No thumbnail generation needed - using direct image display
|
||||
function generateThumbnails() {
|
||||
}
|
||||
|
||||
function refreshClipboard() {
|
||||
clipboardProcess.running = true
|
||||
clipboardProcess.running = true;
|
||||
}
|
||||
|
||||
function copyEntry(entry) {
|
||||
const entryId = entry.split('\t')[0]
|
||||
Quickshell.execDetached(
|
||||
["sh", "-c", `cliphist decode ${entryId} | wl-copy`])
|
||||
|
||||
ToastService.showInfo("Copied to clipboard")
|
||||
clipboardHistoryModal.hide()
|
||||
const entryId = entry.split('\t')[0];
|
||||
Quickshell.execDetached(["sh", "-c", `cliphist decode ${entryId} | wl-copy`]);
|
||||
ToastService.showInfo("Copied to clipboard");
|
||||
clipboardHistoryModal.hide();
|
||||
}
|
||||
|
||||
function deleteEntry(entry) {
|
||||
|
||||
deleteProcess.command = ["sh", "-c", `echo '${entry.replace(
|
||||
/'/g, "'\\''")}' | cliphist delete`]
|
||||
deleteProcess.running = true
|
||||
/'/g, "'\\''")}' | cliphist delete`];
|
||||
deleteProcess.running = true;
|
||||
}
|
||||
|
||||
function clearAll() {
|
||||
clearProcess.running = true
|
||||
clearProcess.running = true;
|
||||
}
|
||||
|
||||
function getEntryPreview(entry) {
|
||||
let content = entry.replace(/^\s*\d+\s+/, "")
|
||||
if (content.includes("image/") || content.includes("binary data")
|
||||
|| /\.(png|jpg|jpeg|gif|bmp|webp)/i.test(content)) {
|
||||
const dimensionMatch = content.match(/(\d+)x(\d+)/)
|
||||
let content = entry.replace(/^\s*\d+\s+/, "");
|
||||
if (content.includes("image/") || content.includes("binary data") || /\.(png|jpg|jpeg|gif|bmp|webp)/i.test(content)) {
|
||||
const dimensionMatch = content.match(/(\d+)x(\d+)/);
|
||||
if (dimensionMatch)
|
||||
return `Image ${dimensionMatch[1]}×${dimensionMatch[2]}`
|
||||
return `Image ${dimensionMatch[1]}×${dimensionMatch[2]}`;
|
||||
|
||||
const typeMatch = content.match(/\b(png|jpg|jpeg|gif|bmp|webp)\b/i)
|
||||
const typeMatch = content.match(/\b(png|jpg|jpeg|gif|bmp|webp)\b/i);
|
||||
if (typeMatch)
|
||||
return `Image (${typeMatch[1].toUpperCase()})`
|
||||
return `Image (${typeMatch[1].toUpperCase()})`;
|
||||
|
||||
return "Image"
|
||||
return "Image";
|
||||
}
|
||||
if (content.length > 100)
|
||||
return content.substring(0, 100) + "..."
|
||||
return content.substring(0, 100) + "...";
|
||||
|
||||
return content
|
||||
return content;
|
||||
}
|
||||
|
||||
function getEntryType(entry) {
|
||||
if (entry.includes("image/") || entry.includes("binary data")
|
||||
|| /\.(png|jpg|jpeg|gif|bmp|webp)/i.test(entry)
|
||||
|| /\b(png|jpg|jpeg|gif|bmp|webp)\b/i.test(entry))
|
||||
return "image"
|
||||
if (entry.includes("image/") || entry.includes("binary data") || /\.(png|jpg|jpeg|gif|bmp|webp)/i.test(entry) || /\b(png|jpg|jpeg|gif|bmp|webp)\b/i.test(entry))
|
||||
return "image";
|
||||
|
||||
if (entry.length > 200)
|
||||
return "long_text"
|
||||
return "long_text";
|
||||
|
||||
return "text"
|
||||
return "text";
|
||||
}
|
||||
|
||||
visible: false
|
||||
@@ -144,7 +131,125 @@ DankModal {
|
||||
borderWidth: 1
|
||||
enableShadow: true
|
||||
onBackgroundClicked: {
|
||||
hide()
|
||||
hide();
|
||||
}
|
||||
modalFocusScope.Keys.onPressed: function(event) {
|
||||
keyboardController.handleKey(event);
|
||||
}
|
||||
content: clipboardContent
|
||||
|
||||
QtObject {
|
||||
id: keyboardController
|
||||
|
||||
function reset() {
|
||||
selectedIndex = 0;
|
||||
keyboardNavigationActive = false;
|
||||
showKeyboardHints = false;
|
||||
if (typeof clipboardListView !== 'undefined' && clipboardListView)
|
||||
clipboardListView.keyboardActive = false;
|
||||
|
||||
}
|
||||
|
||||
function selectNext() {
|
||||
if (filteredClipboardModel.count === 0)
|
||||
return ;
|
||||
|
||||
keyboardNavigationActive = true;
|
||||
selectedIndex = Math.min(selectedIndex + 1, filteredClipboardModel.count - 1);
|
||||
}
|
||||
|
||||
function selectPrevious() {
|
||||
if (filteredClipboardModel.count === 0)
|
||||
return ;
|
||||
|
||||
keyboardNavigationActive = true;
|
||||
selectedIndex = Math.max(selectedIndex - 1, 0);
|
||||
}
|
||||
|
||||
function copySelected() {
|
||||
if (filteredClipboardModel.count === 0 || selectedIndex < 0 || selectedIndex >= filteredClipboardModel.count)
|
||||
return ;
|
||||
|
||||
var selectedEntry = filteredClipboardModel.get(selectedIndex).entry;
|
||||
copyEntry(selectedEntry);
|
||||
}
|
||||
|
||||
function deleteSelected() {
|
||||
if (filteredClipboardModel.count === 0 || selectedIndex < 0 || selectedIndex >= filteredClipboardModel.count)
|
||||
return ;
|
||||
|
||||
var selectedEntry = filteredClipboardModel.get(selectedIndex).entry;
|
||||
deleteEntry(selectedEntry);
|
||||
if (selectedIndex >= filteredClipboardModel.count && filteredClipboardModel.count > 0)
|
||||
selectedIndex = filteredClipboardModel.count - 1;
|
||||
|
||||
}
|
||||
|
||||
function ensureVisible() {
|
||||
}
|
||||
|
||||
function handleKey(event) {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
if (keyboardNavigationActive) {
|
||||
keyboardNavigationActive = false;
|
||||
if (typeof clipboardListView !== 'undefined' && clipboardListView)
|
||||
clipboardListView.keyboardActive = false;
|
||||
|
||||
event.accepted = true;
|
||||
} else {
|
||||
hide();
|
||||
event.accepted = true;
|
||||
}
|
||||
} else if (event.key === Qt.Key_Down) {
|
||||
if (!keyboardNavigationActive) {
|
||||
keyboardNavigationActive = true;
|
||||
selectedIndex = 0;
|
||||
if (typeof clipboardListView !== 'undefined' && clipboardListView)
|
||||
clipboardListView.keyboardActive = true;
|
||||
|
||||
event.accepted = true;
|
||||
} else {
|
||||
selectNext();
|
||||
event.accepted = true;
|
||||
}
|
||||
} else if (event.key === Qt.Key_Up) {
|
||||
if (!keyboardNavigationActive) {
|
||||
keyboardNavigationActive = true;
|
||||
selectedIndex = 0;
|
||||
if (typeof clipboardListView !== 'undefined' && clipboardListView)
|
||||
clipboardListView.keyboardActive = true;
|
||||
|
||||
event.accepted = true;
|
||||
} else if (selectedIndex === 0) {
|
||||
keyboardNavigationActive = false;
|
||||
if (typeof clipboardListView !== 'undefined' && clipboardListView)
|
||||
clipboardListView.keyboardActive = false;
|
||||
|
||||
event.accepted = true;
|
||||
} else {
|
||||
selectPrevious();
|
||||
event.accepted = true;
|
||||
}
|
||||
} else if (keyboardNavigationActive) {
|
||||
if (event.key === Qt.Key_C && (event.modifiers & Qt.ControlModifier)) {
|
||||
copySelected();
|
||||
event.accepted = true;
|
||||
} else if (event.key === Qt.Key_Delete) {
|
||||
if (event.modifiers & Qt.ShiftModifier) {
|
||||
showClearConfirmation = true;
|
||||
event.accepted = true;
|
||||
} else {
|
||||
deleteSelected();
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (event.key === Qt.Key_F10) {
|
||||
showKeyboardHints = !showKeyboardHints;
|
||||
event.accepted = true;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DankModal {
|
||||
@@ -155,7 +260,7 @@ DankModal {
|
||||
height: 150
|
||||
keyboardFocus: "ondemand"
|
||||
onBackgroundClicked: {
|
||||
showClearConfirmation = false
|
||||
showClearConfirmation = false;
|
||||
}
|
||||
|
||||
content: Component {
|
||||
@@ -211,6 +316,7 @@ DankModal {
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: showClearConfirmation = false
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
@@ -234,16 +340,22 @@ DankModal {
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: {
|
||||
clearAll()
|
||||
showClearConfirmation = false
|
||||
hide()
|
||||
clearAll();
|
||||
showClearConfirmation = false;
|
||||
hide();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ListModel {
|
||||
@@ -262,28 +374,30 @@ DankModal {
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
clipboardModel.clear()
|
||||
const lines = text.trim().split('\n')
|
||||
clipboardModel.clear();
|
||||
const lines = text.trim().split('\n');
|
||||
for (const line of lines) {
|
||||
if (line.trim().length > 0)
|
||||
clipboardModel.append({
|
||||
"entry": line
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
updateFilteredModel()
|
||||
updateFilteredModel();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Process {
|
||||
id: deleteProcess
|
||||
|
||||
running: false
|
||||
onExited: exitCode => {
|
||||
onExited: (exitCode) => {
|
||||
if (exitCode === 0)
|
||||
refreshClipboard()
|
||||
refreshClipboard();
|
||||
else
|
||||
console.warn("Failed to delete clipboard entry")
|
||||
console.warn("Failed to delete clipboard entry");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -292,51 +406,44 @@ DankModal {
|
||||
|
||||
command: ["cliphist", "wipe"]
|
||||
running: false
|
||||
onExited: exitCode => {
|
||||
onExited: (exitCode) => {
|
||||
if (exitCode === 0) {
|
||||
clipboardModel.clear()
|
||||
filteredClipboardModel.clear()
|
||||
totalCount = 0
|
||||
clipboardModel.clear();
|
||||
filteredClipboardModel.clear();
|
||||
totalCount = 0;
|
||||
} else {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
IpcHandler {
|
||||
function open() {
|
||||
|
||||
clipboardHistoryModal.show()
|
||||
return "CLIPBOARD_OPEN_SUCCESS"
|
||||
clipboardHistoryModal.show();
|
||||
return "CLIPBOARD_OPEN_SUCCESS";
|
||||
}
|
||||
|
||||
function close() {
|
||||
|
||||
clipboardHistoryModal.hide()
|
||||
return "CLIPBOARD_CLOSE_SUCCESS"
|
||||
clipboardHistoryModal.hide();
|
||||
return "CLIPBOARD_CLOSE_SUCCESS";
|
||||
}
|
||||
|
||||
function toggle() {
|
||||
|
||||
clipboardHistoryModal.toggle()
|
||||
return "CLIPBOARD_TOGGLE_SUCCESS"
|
||||
clipboardHistoryModal.toggle();
|
||||
return "CLIPBOARD_TOGGLE_SUCCESS";
|
||||
}
|
||||
|
||||
target: "clipboard"
|
||||
}
|
||||
|
||||
property Component clipboardContent: Component {
|
||||
clipboardContent: Component {
|
||||
Item {
|
||||
anchors.fill: parent
|
||||
|
||||
Column {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingL
|
||||
spacing: Theme.spacingL
|
||||
focus: true
|
||||
Keys.onPressed: function (event) {
|
||||
if (event.key === Qt.Key_Escape) {
|
||||
hide()
|
||||
event.accepted = true
|
||||
}
|
||||
}
|
||||
focus: false
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
@@ -361,6 +468,7 @@ DankModal {
|
||||
font.weight: Font.Medium
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Row {
|
||||
@@ -368,13 +476,23 @@ DankModal {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: Theme.spacingS
|
||||
|
||||
DankActionButton {
|
||||
iconName: "help"
|
||||
iconSize: Theme.iconSize - 4
|
||||
iconColor: showKeyboardHints ? Theme.primary : Theme.surfaceText
|
||||
hoverColor: Theme.primaryHover
|
||||
onClicked: {
|
||||
showKeyboardHints = !showKeyboardHints;
|
||||
}
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
iconName: "delete_sweep"
|
||||
iconSize: Theme.iconSize
|
||||
iconColor: Theme.error
|
||||
hoverColor: Theme.errorHover
|
||||
onClicked: {
|
||||
showClearConfirmation = true
|
||||
showClearConfirmation = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -385,7 +503,9 @@ DankModal {
|
||||
hoverColor: Theme.errorHover
|
||||
onClicked: hide()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DankTextField {
|
||||
@@ -395,9 +515,21 @@ DankModal {
|
||||
placeholderText: "Search clipboard history..."
|
||||
leftIconName: "search"
|
||||
showClearButton: true
|
||||
focus: true
|
||||
ignoreLeftRightKeys: true
|
||||
keyForwardTargets: [modalFocusScope]
|
||||
onTextChanged: {
|
||||
clipboardHistoryModal.searchText = text
|
||||
updateFilteredModel()
|
||||
clipboardHistoryModal.searchText = text;
|
||||
updateFilteredModel();
|
||||
}
|
||||
Keys.onEscapePressed: function(event) {
|
||||
clipboardHistoryModal.hide();
|
||||
event.accepted = true;
|
||||
}
|
||||
Component.onCompleted: {
|
||||
Qt.callLater(function() {
|
||||
forceActiveFocus();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,17 +549,17 @@ DankModal {
|
||||
anchors.margins: Theme.spacingS
|
||||
clip: true
|
||||
model: filteredClipboardModel
|
||||
currentIndex: selectedIndex
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
// Qt 6.9+ scrolling: flickDeceleration/maximumFlickVelocity only affect touch now
|
||||
interactive: true
|
||||
flickDeceleration: 1500 // Touch only in Qt 6.9+ // Lower = more momentum, longer scrolling
|
||||
maximumFlickVelocity: 2000 // Touch only in Qt 6.9+ // Higher = faster maximum scroll speed
|
||||
flickDeceleration: 1500
|
||||
maximumFlickVelocity: 2000
|
||||
boundsBehavior: Flickable.DragAndOvershootBounds
|
||||
boundsMovement: Flickable.FollowBoundsBehavior
|
||||
pressDelay: 0
|
||||
flickableDirection: Flickable.VerticalFlick
|
||||
|
||||
|
||||
StyledText {
|
||||
text: "No clipboard entries found"
|
||||
anchors.centerIn: parent
|
||||
@@ -452,17 +584,26 @@ DankModal {
|
||||
property alias thumbnailImageSource: thumbnailImageSource
|
||||
|
||||
width: clipboardListView.width
|
||||
height: Math.max(entryType === "image" ? 72 : 60,
|
||||
contentText.contentHeight + Theme.spacingL)
|
||||
height: Math.max(entryType === "image" ? 72 : 60, contentText.contentHeight + Theme.spacingL)
|
||||
radius: Theme.cornerRadius
|
||||
color: mouseArea.containsMouse ? Theme.primaryHover : Theme.primaryBackground
|
||||
border.color: Theme.outlineStrong
|
||||
border.width: 1
|
||||
color: {
|
||||
if (keyboardNavigationActive && index === selectedIndex)
|
||||
return Qt.rgba(Theme.surfaceVariant.r, Theme.surfaceVariant.g, Theme.surfaceVariant.b, 0.2);
|
||||
|
||||
return mouseArea.containsMouse ? Theme.primaryHover : Theme.primaryBackground;
|
||||
}
|
||||
border.color: {
|
||||
if (keyboardNavigationActive && index === selectedIndex)
|
||||
return Qt.rgba(Theme.primary.r, Theme.primary.g, Theme.primary.b, 0.5);
|
||||
|
||||
return Theme.outlineStrong;
|
||||
}
|
||||
border.width: keyboardNavigationActive && index === selectedIndex ? 1.5 : 1
|
||||
|
||||
Row {
|
||||
anchors.fill: parent
|
||||
anchors.margins: Theme.spacingM
|
||||
anchors.rightMargin: Theme.spacingS // Reduced right margin
|
||||
anchors.rightMargin: Theme.spacingS
|
||||
spacing: Theme.spacingL
|
||||
|
||||
Rectangle {
|
||||
@@ -479,11 +620,12 @@ DankModal {
|
||||
font.weight: Font.Bold
|
||||
color: Theme.primary
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: parent.width - 68 // Account for index (24) + spacing (16) + delete button (32) - small margin
|
||||
width: parent.width - 68
|
||||
spacing: Theme.spacingM
|
||||
|
||||
Item {
|
||||
@@ -493,18 +635,20 @@ DankModal {
|
||||
|
||||
CachingImage {
|
||||
id: thumbnailImageSource
|
||||
anchors.fill: parent
|
||||
|
||||
property string entryId: model.entry.split('\t')[0]
|
||||
source: entryType === "image"
|
||||
&& imageLoader.imageData ? `data:image/png;base64,${imageLoader.imageData}` : ""
|
||||
|
||||
anchors.fill: parent
|
||||
source: entryType === "image" && imageLoader.imageData ? `data:image/png;base64,${imageLoader.imageData}` : ""
|
||||
fillMode: Image.PreserveAspectCrop
|
||||
smooth: true
|
||||
cache: true
|
||||
visible: false // Hide the original image
|
||||
visible: false
|
||||
asynchronous: true
|
||||
|
||||
Process {
|
||||
id: imageLoader
|
||||
|
||||
property string imageData: ""
|
||||
|
||||
command: ["sh", "-c", `cliphist decode ${thumbnailImageSource.entryId} | base64 -w 0`]
|
||||
@@ -512,10 +656,12 @@ DankModal {
|
||||
|
||||
stdout: StdioCollector {
|
||||
onStreamFinished: {
|
||||
imageLoader.imageData = text.trim()
|
||||
imageLoader.imageData = text.trim();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
MultiEffect {
|
||||
@@ -524,8 +670,7 @@ DankModal {
|
||||
source: thumbnailImageSource
|
||||
maskEnabled: true
|
||||
maskSource: clipboardCircularMask
|
||||
visible: entryType === "image"
|
||||
&& thumbnailImageSource.status === Image.Ready
|
||||
visible: entryType === "image" && thumbnailImageSource.status === Image.Ready
|
||||
maskThresholdMin: 0.5
|
||||
maskSpreadAtMin: 1
|
||||
}
|
||||
@@ -545,41 +690,41 @@ DankModal {
|
||||
color: "black"
|
||||
antialiasing: true
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DankIcon {
|
||||
visible: !(entryType === "image"
|
||||
&& thumbnailImageSource.status === Image.Ready)
|
||||
visible: !(entryType === "image" && thumbnailImageSource.status === Image.Ready)
|
||||
name: {
|
||||
if (entryType === "image")
|
||||
return "image"
|
||||
return "image";
|
||||
|
||||
if (entryType === "long_text")
|
||||
return "subject"
|
||||
return "subject";
|
||||
|
||||
return "content_copy"
|
||||
return "content_copy";
|
||||
}
|
||||
size: Theme.iconSize
|
||||
color: Theme.primary
|
||||
anchors.centerIn: parent
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: parent.width - (entryType === "image" ? 48 : Theme.iconSize)
|
||||
- Theme.spacingM
|
||||
width: parent.width - (entryType === "image" ? 48 : Theme.iconSize) - Theme.spacingM
|
||||
spacing: Theme.spacingXS
|
||||
|
||||
StyledText {
|
||||
text: {
|
||||
switch (entryType) {
|
||||
case "image":
|
||||
return "Image • " + entryPreview
|
||||
return "Image • " + entryPreview;
|
||||
case "long_text":
|
||||
return "Long Text"
|
||||
return "Long Text";
|
||||
default:
|
||||
return "Text"
|
||||
return "Text";
|
||||
}
|
||||
}
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
@@ -600,8 +745,11 @@ DankModal {
|
||||
maximumLineCount: entryType === "long_text" ? 3 : 1
|
||||
elide: Text.ElideRight
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
DankActionButton {
|
||||
@@ -613,8 +761,7 @@ DankModal {
|
||||
iconColor: Theme.error
|
||||
hoverColor: Theme.errorHover
|
||||
onClicked: {
|
||||
|
||||
deleteEntry(model.entry)
|
||||
deleteEntry(model.entry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -622,22 +769,79 @@ DankModal {
|
||||
id: mouseArea
|
||||
|
||||
anchors.fill: parent
|
||||
anchors.rightMargin: 40 // Enough space to avoid delete button (32 + 8 margin)
|
||||
anchors.rightMargin: 40
|
||||
hoverEnabled: true
|
||||
cursorShape: Qt.PointingHandCursor
|
||||
onClicked: copyEntry(model.entry)
|
||||
}
|
||||
|
||||
Behavior on color {
|
||||
ColorAnimation {
|
||||
duration: Theme.shortDuration
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
content: clipboardContent
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Item {
|
||||
width: parent.width
|
||||
height: showKeyboardHints ? 80 + Theme.spacingL : 0
|
||||
|
||||
Behavior on height {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.right: parent.right
|
||||
anchors.margins: Theme.spacingL
|
||||
height: 80
|
||||
radius: Theme.cornerRadius
|
||||
color: Qt.rgba(Theme.surfaceContainer.r, Theme.surfaceContainer.g, Theme.surfaceContainer.b, 0.95)
|
||||
border.color: Theme.primary
|
||||
border.width: 2
|
||||
opacity: showKeyboardHints ? 1 : 0
|
||||
z: 100
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: 2
|
||||
|
||||
StyledText {
|
||||
text: "↑/↓: Navigate • Ctrl+C: Copy • Del: Delete • F10: Help"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Shift+Del: Clear All • Esc: Close"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -478,7 +478,7 @@ QtObject {
|
||||
}
|
||||
}
|
||||
|
||||
if (event.key === Qt.Key_Question || event.key === Qt.Key_H) {
|
||||
if (event.key === Qt.Key_F10) {
|
||||
showKeyboardHints = !showKeyboardHints
|
||||
event.accepted = true
|
||||
}
|
||||
|
||||
@@ -15,13 +15,6 @@ Rectangle {
|
||||
opacity: showHints ? 1 : 0
|
||||
z: 100
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.centerIn: parent
|
||||
spacing: 2
|
||||
@@ -34,10 +27,20 @@ Rectangle {
|
||||
}
|
||||
|
||||
StyledText {
|
||||
text: "Del: Clear • Shift+Del: Clear All • 1-9: Actions • ?: Help • Esc: Close"
|
||||
text: "Del: Clear • Shift+Del: Clear All • 1-9: Actions • F10: Help • Esc: Close"
|
||||
font.pixelSize: Theme.fontSizeSmall
|
||||
color: Theme.surfaceText
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Behavior on opacity {
|
||||
NumberAnimation {
|
||||
duration: Theme.shortDuration
|
||||
easing.type: Theme.standardEasing
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user