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:
@@ -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/") {
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user