mirror of
https://github.com/AvengeMedia/DankMaterialShell.git
synced 2026-10-18 09:14:01 -04:00
default apps: add mime-type options for file browser
This commit is contained in:
@@ -302,6 +302,22 @@ func AppsForMime(mimeType string) []string {
|
||||
return out
|
||||
}
|
||||
|
||||
// HandlersForMime lists launchable handler entries for a mime type,
|
||||
// excluding Terminal=true and NoDisplay=true desktop entries so pickers
|
||||
// only offer graphical applications.
|
||||
func HandlersForMime(mimeType string) []*Entry {
|
||||
ids := AppsForMime(mimeType)
|
||||
out := make([]*Entry, 0, len(ids))
|
||||
for _, id := range ids {
|
||||
entry := EntryByID(id)
|
||||
if entry == nil || entry.Hidden || entry.NoDisplay || entry.Terminal {
|
||||
continue
|
||||
}
|
||||
out = append(out, entry)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
func QueryDefaults(mimeTypes []string) map[string]string {
|
||||
out := make(map[string]string, len(mimeTypes))
|
||||
for _, m := range mimeTypes {
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"fmt"
|
||||
"maps"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"slices"
|
||||
@@ -81,7 +82,10 @@ func readAssociations(path string) (*MimeAssociations, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return associationsFromData(data), nil
|
||||
}
|
||||
|
||||
func associationsFromData(data []byte) *MimeAssociations {
|
||||
groups := parseGroups(data)
|
||||
assoc := newAssociations()
|
||||
|
||||
@@ -106,7 +110,7 @@ func readAssociations(path string) (*MimeAssociations, error) {
|
||||
}
|
||||
}
|
||||
|
||||
return assoc, nil
|
||||
return assoc
|
||||
}
|
||||
|
||||
func mergedAssociations() *MimeAssociations {
|
||||
@@ -144,40 +148,22 @@ func writeUserMimeapps(update func(*MimeAssociations)) error {
|
||||
|
||||
path := mimeappsWritePath()
|
||||
|
||||
assoc, err := readAssociations(path)
|
||||
if err != nil {
|
||||
if !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
assoc = newAssociations()
|
||||
original, err := os.ReadFile(path)
|
||||
if err != nil && !os.IsNotExist(err) {
|
||||
return err
|
||||
}
|
||||
|
||||
assoc := associationsFromData(original)
|
||||
update(assoc)
|
||||
|
||||
var buf bytes.Buffer
|
||||
w := bufio.NewWriter(&buf)
|
||||
|
||||
var writeErr error
|
||||
writeSection := func(name string, entries map[string]string) {
|
||||
fmt.Fprintf(w, "[%s]\n", name)
|
||||
keys := make([]string, 0, len(entries))
|
||||
for k := range entries {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
for _, k := range keys {
|
||||
v := entries[k]
|
||||
if !isSafeIniField(k) || !isSafeIniField(v) {
|
||||
if writeErr == nil {
|
||||
writeErr = fmt.Errorf("invalid mimeapps.list field %q=%q", k, v)
|
||||
}
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(w, "%s=%s\n", k, v)
|
||||
}
|
||||
fmt.Fprintln(w)
|
||||
rendered, err := renderMimeapps(original, assoc)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return atomicWriteFile(path, rendered)
|
||||
}
|
||||
|
||||
func managedGroups(assoc *MimeAssociations) (map[string]map[string]string, error) {
|
||||
flatten := func(m map[string][]string) map[string]string {
|
||||
out := make(map[string]string, len(m))
|
||||
for k, list := range m {
|
||||
@@ -186,22 +172,172 @@ func writeUserMimeapps(update func(*MimeAssociations)) error {
|
||||
return out
|
||||
}
|
||||
|
||||
writeSection(groupDefaults, assoc.Defaults)
|
||||
writeSection(groupAdded, flatten(assoc.Added))
|
||||
writeSection(groupRemoved, flatten(assoc.Removed))
|
||||
groups := map[string]map[string]string{
|
||||
groupDefaults: maps.Clone(assoc.Defaults),
|
||||
groupAdded: flatten(assoc.Added),
|
||||
groupRemoved: flatten(assoc.Removed),
|
||||
}
|
||||
for name, entries := range groups {
|
||||
for k, v := range entries {
|
||||
if isSafeIniField(k) && isSafeIniField(v) {
|
||||
continue
|
||||
}
|
||||
return nil, fmt.Errorf("invalid mimeapps.list field in [%s]: %q=%q", name, k, v)
|
||||
}
|
||||
}
|
||||
return groups, nil
|
||||
}
|
||||
|
||||
if writeErr != nil {
|
||||
return writeErr
|
||||
// renderMimeapps rewrites only the three association groups defined by the
|
||||
// mime-apps spec (https://specifications.freedesktop.org/mime-apps-spec/),
|
||||
// keeping comments, blank lines, and unrelated groups verbatim.
|
||||
func renderMimeapps(original []byte, assoc *MimeAssociations) ([]byte, error) {
|
||||
managed, err := managedGroups(assoc)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if err := w.Flush(); err != nil {
|
||||
written := map[string]map[string]bool{
|
||||
groupDefaults: {},
|
||||
groupAdded: {},
|
||||
groupRemoved: {},
|
||||
}
|
||||
|
||||
var out []string
|
||||
|
||||
flushMissing := func(group string) {
|
||||
entries, ok := managed[group]
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
keys := make([]string, 0, len(entries))
|
||||
for k := range entries {
|
||||
if !written[group][k] {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
}
|
||||
if len(keys) == 0 {
|
||||
return
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
insertAt := len(out)
|
||||
for insertAt > 0 && strings.TrimSpace(out[insertAt-1]) == "" {
|
||||
insertAt--
|
||||
}
|
||||
lines := make([]string, 0, len(keys))
|
||||
for _, k := range keys {
|
||||
written[group][k] = true
|
||||
lines = append(lines, k+"="+entries[k])
|
||||
}
|
||||
tail := append([]string(nil), out[insertAt:]...)
|
||||
out = append(out[:insertAt], append(lines, tail...)...)
|
||||
}
|
||||
|
||||
current := ""
|
||||
scanner := bufio.NewScanner(bytes.NewReader(original))
|
||||
scanner.Buffer(make([]byte, 64*1024), 1024*1024)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
trimmed := strings.TrimSpace(line)
|
||||
|
||||
if strings.HasPrefix(trimmed, "[") && strings.HasSuffix(trimmed, "]") {
|
||||
flushMissing(current)
|
||||
current = trimmed[1 : len(trimmed)-1]
|
||||
out = append(out, line)
|
||||
continue
|
||||
}
|
||||
|
||||
entries, isManaged := managed[current]
|
||||
if !isManaged {
|
||||
out = append(out, line)
|
||||
continue
|
||||
}
|
||||
|
||||
if trimmed == "" || strings.HasPrefix(trimmed, "#") {
|
||||
out = append(out, line)
|
||||
continue
|
||||
}
|
||||
|
||||
eq := strings.IndexByte(trimmed, '=')
|
||||
if eq <= 0 {
|
||||
out = append(out, line)
|
||||
continue
|
||||
}
|
||||
|
||||
key := strings.TrimSpace(trimmed[:eq])
|
||||
val, keep := entries[key]
|
||||
if !keep || written[current][key] {
|
||||
continue
|
||||
}
|
||||
written[current][key] = true
|
||||
out = append(out, key+"="+val)
|
||||
}
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
flushMissing(current)
|
||||
|
||||
for _, group := range []string{groupDefaults, groupAdded, groupRemoved} {
|
||||
entries := managed[group]
|
||||
pending := make([]string, 0, len(entries))
|
||||
for k := range entries {
|
||||
if !written[group][k] {
|
||||
pending = append(pending, k)
|
||||
}
|
||||
}
|
||||
if len(pending) == 0 {
|
||||
continue
|
||||
}
|
||||
sort.Strings(pending)
|
||||
|
||||
if len(out) > 0 && strings.TrimSpace(out[len(out)-1]) != "" {
|
||||
out = append(out, "")
|
||||
}
|
||||
out = append(out, "["+group+"]")
|
||||
for _, k := range pending {
|
||||
written[group][k] = true
|
||||
out = append(out, k+"="+entries[k])
|
||||
}
|
||||
}
|
||||
|
||||
if len(out) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
return []byte(strings.Join(out, "\n") + "\n"), nil
|
||||
}
|
||||
|
||||
func atomicWriteFile(path string, data []byte) error {
|
||||
dir := filepath.Dir(path)
|
||||
if err := os.MkdirAll(dir, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(path), 0o755); err != nil {
|
||||
tmp, err := os.CreateTemp(dir, ".mimeapps-*.tmp")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return os.WriteFile(path, buf.Bytes(), 0o644)
|
||||
tmpPath := tmp.Name()
|
||||
|
||||
if _, err := tmp.Write(data); err != nil {
|
||||
tmp.Close()
|
||||
os.Remove(tmpPath)
|
||||
return err
|
||||
}
|
||||
if err := tmp.Chmod(0o644); err != nil {
|
||||
tmp.Close()
|
||||
os.Remove(tmpPath)
|
||||
return err
|
||||
}
|
||||
if err := tmp.Close(); err != nil {
|
||||
os.Remove(tmpPath)
|
||||
return err
|
||||
}
|
||||
if err := os.Rename(tmpPath, path); err != nil {
|
||||
os.Remove(tmpPath)
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func setDefaultAssociation(mimeType, desktopID string) error {
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
package desktop
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestSetDefaultsPreservesUnrelatedContent(t *testing.T) {
|
||||
configHome, _ := setupFakeXDG(t)
|
||||
path := filepath.Join(configHome, "mimeapps.list")
|
||||
writeFile(t, path, `# managed by hand
|
||||
[Default Applications]
|
||||
text/html=firefox.desktop
|
||||
# pinned image viewer
|
||||
image/png=eog.desktop
|
||||
|
||||
[Added Associations]
|
||||
text/html=firefox.desktop;
|
||||
|
||||
[Custom Section]
|
||||
foo=bar
|
||||
`)
|
||||
|
||||
if err := SetDefaults([]string{"inode/directory", "x-scheme-handler/sftp"}, "org.kde.dolphin.desktop"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := string(data)
|
||||
|
||||
preserved := []string{
|
||||
"# managed by hand",
|
||||
"# pinned image viewer",
|
||||
"text/html=firefox.desktop",
|
||||
"image/png=eog.desktop",
|
||||
"[Custom Section]",
|
||||
"foo=bar",
|
||||
}
|
||||
for _, want := range preserved {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Errorf("rewrite lost %q:\n%s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
written := []string{
|
||||
"inode/directory=org.kde.dolphin.desktop",
|
||||
"x-scheme-handler/sftp=org.kde.dolphin.desktop",
|
||||
}
|
||||
for _, want := range written {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Errorf("rewrite missing %q:\n%s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
if got := GetDefault("inode/directory"); got != "org.kde.dolphin.desktop" {
|
||||
t.Errorf("GetDefault(inode/directory) = %q", got)
|
||||
}
|
||||
if got := GetDefault("x-scheme-handler/sftp"); got != "org.kde.dolphin.desktop" {
|
||||
t.Errorf("GetDefault(x-scheme-handler/sftp) = %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetDefaultReplacesKeyInPlace(t *testing.T) {
|
||||
configHome, _ := setupFakeXDG(t)
|
||||
path := filepath.Join(configHome, "mimeapps.list")
|
||||
writeFile(t, path, `[Default Applications]
|
||||
inode/directory=foot.desktop
|
||||
text/html=firefox.desktop
|
||||
`)
|
||||
|
||||
if err := SetDefault("inode/directory", "org.gnome.Nautilus.desktop"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := string(data)
|
||||
|
||||
if n := strings.Count(got, "inode/directory=org.gnome.Nautilus.desktop\n"); n != 1 {
|
||||
t.Errorf("expected exactly one replaced default line, got %d:\n%s", n, got)
|
||||
}
|
||||
if strings.Contains(got, "foot.desktop") {
|
||||
t.Errorf("old default still present:\n%s", got)
|
||||
}
|
||||
if !strings.Contains(got, "text/html=firefox.desktop") {
|
||||
t.Errorf("unrelated default lost:\n%s", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetDefaultsCreatesFileWhenAbsent(t *testing.T) {
|
||||
configHome, _ := setupFakeXDG(t)
|
||||
path := filepath.Join(configHome, "mimeapps.list")
|
||||
|
||||
if err := SetDefaults([]string{"inode/directory", "x-scheme-handler/sftp"}, "org.kde.dolphin"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := string(data)
|
||||
|
||||
expected := []string{
|
||||
"[Default Applications]",
|
||||
"inode/directory=org.kde.dolphin.desktop",
|
||||
"x-scheme-handler/sftp=org.kde.dolphin.desktop",
|
||||
"[Added Associations]",
|
||||
}
|
||||
for _, want := range expected {
|
||||
if !strings.Contains(got, want) {
|
||||
t.Errorf("new file missing %q:\n%s", want, got)
|
||||
}
|
||||
}
|
||||
|
||||
entries, err := os.ReadDir(configHome)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, e := range entries {
|
||||
if strings.HasSuffix(e.Name(), ".tmp") {
|
||||
t.Errorf("leftover temp file %q", e.Name())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSetDefaultClearsRemovedAssociation(t *testing.T) {
|
||||
configHome, _ := setupFakeXDG(t)
|
||||
path := filepath.Join(configHome, "mimeapps.list")
|
||||
writeFile(t, path, `[Removed Associations]
|
||||
inode/directory=org.kde.dolphin.desktop;other.desktop;
|
||||
`)
|
||||
|
||||
if err := SetDefault("inode/directory", "org.kde.dolphin.desktop"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
data, err := os.ReadFile(path)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
got := string(data)
|
||||
|
||||
if !strings.Contains(got, "inode/directory=other.desktop;") {
|
||||
t.Errorf("unrelated removed entry lost:\n%s", got)
|
||||
}
|
||||
if strings.Contains(got, "org.kde.dolphin.desktop;other.desktop") {
|
||||
t.Errorf("chosen app still in removed list:\n%s", got)
|
||||
}
|
||||
if got := GetDefault("inode/directory"); got != "org.kde.dolphin.desktop" {
|
||||
t.Errorf("GetDefault = %q", got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestHandlersForMimeExcludesTerminalAndNoDisplay(t *testing.T) {
|
||||
_, dataHome := setupFakeXDG(t)
|
||||
apps := filepath.Join(dataHome, "applications")
|
||||
writeFile(t, filepath.Join(apps, "org.kde.dolphin.desktop"), `[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Dolphin
|
||||
Icon=system-file-manager
|
||||
MimeType=inode/directory;
|
||||
`)
|
||||
writeFile(t, filepath.Join(apps, "ghost-term.desktop"), `[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Ghost Terminal
|
||||
Terminal=true
|
||||
MimeType=inode/directory;
|
||||
`)
|
||||
writeFile(t, filepath.Join(apps, "hidden-fm.desktop"), `[Desktop Entry]
|
||||
Type=Application
|
||||
Name=Hidden FM
|
||||
NoDisplay=true
|
||||
MimeType=inode/directory;
|
||||
`)
|
||||
writeFile(t, filepath.Join(apps, "mimeinfo.cache"), `[MIME Cache]
|
||||
inode/directory=ghost-term.desktop;org.kde.dolphin.desktop;hidden-fm.desktop;stale.desktop;
|
||||
`)
|
||||
|
||||
handlers := HandlersForMime("inode/directory")
|
||||
byID := make(map[string]*Entry, len(handlers))
|
||||
for _, h := range handlers {
|
||||
byID[h.ID] = h
|
||||
}
|
||||
|
||||
dolphin := byID["org.kde.dolphin.desktop"]
|
||||
if dolphin == nil {
|
||||
t.Fatal("org.kde.dolphin.desktop missing from handlers")
|
||||
}
|
||||
if dolphin.Name != "Dolphin" {
|
||||
t.Errorf("Name = %q", dolphin.Name)
|
||||
}
|
||||
if dolphin.Icon != "system-file-manager" {
|
||||
t.Errorf("Icon = %q", dolphin.Icon)
|
||||
}
|
||||
|
||||
excluded := []string{"ghost-term.desktop", "hidden-fm.desktop", "stale.desktop"}
|
||||
for _, id := range excluded {
|
||||
if byID[id] != nil {
|
||||
t.Errorf("%s should be excluded from handlers", id)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,6 +18,17 @@ type appsResult struct {
|
||||
DesktopIDs []string `json:"desktopIds"`
|
||||
}
|
||||
|
||||
type handlerApp struct {
|
||||
ID string `json:"id"`
|
||||
Name string `json:"name"`
|
||||
Icon string `json:"icon,omitempty"`
|
||||
}
|
||||
|
||||
type handlersResult struct {
|
||||
MimeType string `json:"mimeType"`
|
||||
Apps []handlerApp `json:"apps"`
|
||||
}
|
||||
|
||||
type queryResult struct {
|
||||
Defaults map[string]string `json:"defaults"`
|
||||
}
|
||||
@@ -32,6 +43,8 @@ func HandleRequest(conn *models.Conn, req models.Request) {
|
||||
handleSetDefaults(conn, req)
|
||||
case "mime.appsForMime":
|
||||
handleAppsForMime(conn, req)
|
||||
case "mime.handlersForMime":
|
||||
handleHandlersForMime(conn, req)
|
||||
case "mime.queryDefaults":
|
||||
handleQueryDefaults(conn, req)
|
||||
case "mime.invalidate":
|
||||
@@ -106,6 +119,27 @@ func handleAppsForMime(conn *models.Conn, req models.Request) {
|
||||
})
|
||||
}
|
||||
|
||||
func handleHandlersForMime(conn *models.Conn, req models.Request) {
|
||||
mimeType, err := mimeParam(req.Params, "mimeType")
|
||||
if err != nil {
|
||||
models.RespondError(conn, req.ID, err.Error())
|
||||
return
|
||||
}
|
||||
entries := desktop.HandlersForMime(mimeType)
|
||||
apps := make([]handlerApp, 0, len(entries))
|
||||
for _, entry := range entries {
|
||||
apps = append(apps, handlerApp{
|
||||
ID: entry.ID,
|
||||
Name: entry.Name,
|
||||
Icon: entry.Icon,
|
||||
})
|
||||
}
|
||||
models.Respond(conn, req.ID, handlersResult{
|
||||
MimeType: mimeType,
|
||||
Apps: apps,
|
||||
})
|
||||
}
|
||||
|
||||
func handleQueryDefaults(conn *models.Conn, req models.Request) {
|
||||
mimeTypes, err := mimeListParam(req, "mimeTypes")
|
||||
if err != nil {
|
||||
|
||||
@@ -42,7 +42,7 @@ Item {
|
||||
// the rest are for setting the default app.
|
||||
readonly property var mimeMapping: ({
|
||||
[root.appCategory.WebBrowser]: ["x-scheme-handler/https", "x-scheme-handler/http", "text/html", "application/xhtml+xml"],
|
||||
[root.appCategory.FileManager]: ["inode/directory", "x-scheme-handler/file"],
|
||||
[root.appCategory.FileManager]: ["inode/directory", "x-scheme-handler/file", "x-scheme-handler/sftp"],
|
||||
[root.appCategory.TextEditor]: ["text/plain", "text/markdown", "application/x-zerosize", "text/x-c++src", "text/x-csrc", "text/x-python", "text/x-shellscript", "application/json"],
|
||||
[root.appCategory.ImageViewer]: ["image/png", "image/jpeg", "image/gif", "image/bmp", "image/webp", "image/avif", "image/svg+xml"],
|
||||
[root.appCategory.VideoPlayer]: ["video/mp4", "video/x-matroska", "video/webm", "video/avi", "video/mpeg", "video/quicktime", "video/x-msvideo"],
|
||||
@@ -131,6 +131,7 @@ Item {
|
||||
// you don't want Kate as your file manager just because it can open folders
|
||||
loadCategoryModel(root.appCategory.FileManager, "FileManager");
|
||||
DesktopService.getDefaultApp(mimeMapping[category][0], category.toString());
|
||||
DesktopService.getHandlersForMimeType(mimeMapping[category][0], category.toString());
|
||||
break;
|
||||
default:
|
||||
const mimeType = mimeMapping[category][0];
|
||||
@@ -216,6 +217,22 @@ Item {
|
||||
root.categoryModels = models;
|
||||
}
|
||||
|
||||
function onGetHandlersForMimeResult(mimeType, apps, callbackId) {
|
||||
const categoryIndex = parseInt(callbackId);
|
||||
let models = Object.assign({}, root.categoryModels);
|
||||
const existing = models[categoryIndex] || root.withDmsChooser([]);
|
||||
const known = new Set(existing.map(opt => opt.value));
|
||||
const extra = (apps || []).filter(app => app.id && !known.has(app.id)).map(app => ({
|
||||
text: app.name || root.getAppDisplayName(app.id),
|
||||
value: app.id
|
||||
}));
|
||||
if (extra.length === 0) {
|
||||
return;
|
||||
}
|
||||
models[categoryIndex] = existing.concat(extra);
|
||||
root.categoryModels = models;
|
||||
}
|
||||
|
||||
function onGetDefaultAppResult(mimeType, desktopFileId, callbackId) {
|
||||
if (!desktopFileId) {
|
||||
log.info("No default app found for MIME type:", mimeType);
|
||||
@@ -302,7 +319,7 @@ Item {
|
||||
|
||||
AppSelector {
|
||||
text: I18n.tr("File Manager", "File Manager")
|
||||
tags: ["file", "manager"]
|
||||
tags: ["file", "manager", "directory", "sftp"]
|
||||
category: root.appCategory.FileManager
|
||||
description: I18n.tr("Manages files and directories", "Manages files and directories")
|
||||
}
|
||||
|
||||
@@ -127,6 +127,7 @@ Singleton {
|
||||
|
||||
signal getDefaultAppResult(string mimeType, string desktopFileId, string callbackId)
|
||||
signal getAppsForMimeResult(string mimeType, var appIds, string callbackId)
|
||||
signal getHandlersForMimeResult(string mimeType, var apps, string callbackId)
|
||||
|
||||
function setDefaultApp(mimeType, desktopFileId, callbackId = "") {
|
||||
setDefaultAppForMimes([mimeType], desktopFileId, callbackId);
|
||||
@@ -162,6 +163,19 @@ Singleton {
|
||||
});
|
||||
}
|
||||
|
||||
function getHandlersForMimeType(mimeType, callbackId = "") {
|
||||
DMSService.sendRequest("mime.handlersForMime", {
|
||||
"mimeType": mimeType
|
||||
}, response => {
|
||||
if (response.error) {
|
||||
log.warn("DesktopService.getHandlersForMimeType failed:", response.error, "mime:", mimeType);
|
||||
return;
|
||||
}
|
||||
const result = response.result || {};
|
||||
root.getHandlersForMimeResult(mimeType, result.apps || [], callbackId);
|
||||
});
|
||||
}
|
||||
|
||||
function getAppsForMimeType(mimeType, callbackId = "") {
|
||||
DMSService.sendRequest("mime.appsForMime", {
|
||||
"mimeType": mimeType
|
||||
|
||||
Reference in New Issue
Block a user