1
0
mirror of https://github.com/AvengeMedia/DankMaterialShell.git synced 2026-01-27 23:12:49 -05:00

clipboard: react to changes

This commit is contained in:
bbedward
2026-01-27 22:50:28 -05:00
parent d19e81ffac
commit eda59b348c
4 changed files with 111 additions and 17 deletions

View File

@@ -240,6 +240,7 @@ func runClipCopy(cmd *cobra.Command, args []string) {
if err := copyFileToClipboard(filePath); err != nil {
log.Fatalf("copy file: %v", err)
}
fmt.Printf("Downloaded and copied: %s\n", filePath)
return
}
@@ -872,24 +873,58 @@ func downloadToTempFile(rawURL string) (string, error) {
}
client := &http.Client{Timeout: 30 * time.Second}
resp, err := client.Get(rawURL)
if err != nil {
return "", fmt.Errorf("download: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("download failed: status %d", resp.StatusCode)
var data []byte
var contentType string
var lastErr error
for attempt := 0; attempt < 3; attempt++ {
if attempt > 0 {
time.Sleep(time.Duration(attempt) * 500 * time.Millisecond)
}
req, err := http.NewRequest("GET", rawURL, nil)
if err != nil {
lastErr = fmt.Errorf("create request: %w", err)
continue
}
req.Header.Set("User-Agent", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36")
req.Header.Set("Accept", "image/*,video/*,*/*")
resp, err := client.Do(req)
if err != nil {
lastErr = fmt.Errorf("download (attempt %d): %w", attempt+1, err)
continue
}
if resp.StatusCode != http.StatusOK {
resp.Body.Close()
lastErr = fmt.Errorf("download failed (attempt %d): status %d", attempt+1, resp.StatusCode)
continue
}
data, err = io.ReadAll(resp.Body)
resp.Body.Close()
if err != nil {
lastErr = fmt.Errorf("read response (attempt %d): %w", attempt+1, err)
continue
}
contentType = resp.Header.Get("Content-Type")
if idx := strings.Index(contentType, ";"); idx != -1 {
contentType = strings.TrimSpace(contentType[:idx])
}
lastErr = nil
break
}
data, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("read response: %w", err)
if lastErr != nil {
return "", lastErr
}
contentType := resp.Header.Get("Content-Type")
if idx := strings.Index(contentType, ";"); idx != -1 {
contentType = strings.TrimSpace(contentType[:idx])
if len(data) == 0 {
return "", fmt.Errorf("downloaded empty file")
}
if !strings.HasPrefix(contentType, "image/") && !strings.HasPrefix(contentType, "video/") {

View File

@@ -1543,16 +1543,56 @@ func (m *Manager) GetPinnedCount() int {
}
func (m *Manager) CopyFile(filePath string) error {
if _, err := os.Stat(filePath); err != nil {
fileInfo, err := os.Stat(filePath)
if err != nil {
return fmt.Errorf("file not found: %w", err)
}
cfg := m.getConfig()
if fileInfo.Size() > cfg.MaxEntrySize {
return fmt.Errorf("file too large: %d > %d", fileInfo.Size(), cfg.MaxEntrySize)
}
fileData, err := os.ReadFile(filePath)
if err != nil {
return fmt.Errorf("read file: %w", err)
}
exportedPath, err := m.ExportFileForFlatpak(filePath)
if err != nil {
exportedPath = filePath
}
fileURI := "file://" + exportedPath
if imgData, imgMime, ok := m.tryReadImageFromURI([]byte("file://" + filePath)); ok {
entry := Entry{
Data: imgData,
MimeType: imgMime,
Size: len(imgData),
Timestamp: time.Now(),
IsImage: true,
Preview: m.imagePreview(imgData, imgMime),
}
if err := m.storeEntry(entry); err != nil {
log.Errorf("Failed to store file entry: %v", err)
}
} else {
entry := Entry{
Data: fileData,
MimeType: "text/uri-list",
Size: len(fileData),
Timestamp: time.Now(),
IsImage: false,
Preview: fmt.Sprintf("[[ file %s ]]", filepath.Base(filePath)),
}
if err := m.storeEntry(entry); err != nil {
log.Errorf("Failed to store file entry: %v", err)
}
}
m.updateState()
m.notifySubscribers()
m.post(func() {
if m.dataControlMgr == nil || m.dataDevice == nil {
log.Error("Data control manager or device not initialized")

View File

@@ -284,6 +284,20 @@ DankModal {
modal: clipboardHistoryModal
}
Connections {
target: DMSService
function onClipboardStateUpdate(data) {
if (!clipboardHistoryModal.shouldBeVisible) {
return;
}
const newHistory = data.history || [];
internalEntries = newHistory;
pinnedEntries = newHistory.filter(e => e.pinned);
pinnedCount = pinnedEntries.length;
updateFilteredModel();
}
}
ConfirmModal {
id: clearConfirmDialog
confirmButtonText: I18n.tr("Clear All")

View File

@@ -60,12 +60,13 @@ Singleton {
signal openUrlRequested(string url)
signal appPickerRequested(var data)
signal screensaverStateUpdate(var data)
signal clipboardStateUpdate(var data)
property bool capsLockState: false
property bool screensaverInhibited: false
property var screensaverInhibitors: []
property var activeSubscriptions: ["network", "network.credentials", "loginctl", "freedesktop", "freedesktop.screensaver", "gamma", "theme.auto", "bluetooth", "bluetooth.pairing", "dwl", "brightness", "wlroutput", "evdev", "browser", "dbus"]
property var activeSubscriptions: ["network", "network.credentials", "loginctl", "freedesktop", "freedesktop.screensaver", "gamma", "theme.auto", "bluetooth", "bluetooth.pairing", "dwl", "brightness", "wlroutput", "evdev", "browser", "dbus", "clipboard"]
Component.onCompleted: {
if (socketPath && socketPath.length > 0) {
@@ -392,6 +393,8 @@ Singleton {
screensaverStateUpdate(data);
} else if (service === "dbus") {
dbusSignalReceived(data.subscriptionId || "", data);
} else if (service === "clipboard") {
clipboardStateUpdate(data);
}
}
@@ -726,7 +729,8 @@ Singleton {
if (!response.error && response.result?.subscriptionId) {
dbusSubscriptions[response.result.subscriptionId] = true;
}
if (callback) callback(response);
if (callback)
callback(response);
});
}
@@ -737,7 +741,8 @@ Singleton {
if (!response.error) {
delete dbusSubscriptions[subscriptionId];
}
if (callback) callback(response);
if (callback)
callback(response);
});
}