menu icons

Signed-off-by: FTCHD <144691102+FTCHD@users.noreply.github.com>
This commit is contained in:
FTCHD
2025-09-21 17:20:12 +02:00
parent ebb93c3d60
commit b3d905116c
59 changed files with 135 additions and 112 deletions
+134 -91
View File
@@ -1,6 +1,6 @@
import * as Sentry from '@sentry/browser'
import { Menu, MenuItem, PredefinedMenuItem, Submenu } from '@tauri-apps/api/menu'
import { sep } from '@tauri-apps/api/path'
import { resolveResource, sep } from '@tauri-apps/api/path'
import { getCurrentWindow } from '@tauri-apps/api/window'
import { ask, message, open } from '@tauri-apps/plugin-dialog'
import { exists, mkdir, remove } from '@tauri-apps/plugin-fs'
@@ -11,12 +11,14 @@ import notify from './notify'
import {
cleanupRemote,
deleteRemote,
getRemote,
listMounts,
listServes,
mountRemote,
stopServe,
unmountRemote,
} from './rclone/api'
import { compareVersions, getRcloneVersion } from './rclone/common'
import { dialogGetMountPlugin, needsMountPlugin } from './rclone/mount'
import { usePersistedStore, useStore } from './store'
import { showDefaultTray, showLoadingTray } from './tray'
@@ -33,15 +35,22 @@ async function parseRemotes(remotes: string[]) {
const currentServes = await listServes()
console.log('[parseRemotes] currentServes', currentServes)
const parsedRemotes: Record<string, (MenuItem | Submenu | PredefinedMenuItem)[]> = {}
const parsedRemotes: Record<
string,
{ icon: string; items: (MenuItem | Submenu | PredefinedMenuItem)[] }
> = {}
for (const remote of remotes) {
console.log('[parseRemotes] remote', remote)
const remoteConfig = persistedStoreState.remoteConfigList?.[remote]
if (remoteConfig?.disabledActions?.includes('tray')) {
continue
}
const remoteInfo = await getRemote(remote).catch(null)
console.log('[parseRemotes] remoteInfo', remoteInfo)
const submenuItems: (MenuItem | Submenu | PredefinedMenuItem)[] = []
if (!remoteConfig?.disabledActions?.includes('tray-mount')) {
@@ -206,37 +215,42 @@ async function parseRemotes(remotes: string[]) {
}
if (!remoteConfig?.disabledActions?.includes('tray-cleanup')) {
const cleanupMenuItem = await MenuItem.new({
id: `cleanup-${remote}`,
text: 'Cleanup',
action: async () => {
try {
const confirmed = await ask(`Start cleanup on ${remote}?`, {
title: `Cleaning up ${remote}`,
kind: 'warning',
okLabel: 'Start',
cancelLabel: 'Cancel',
})
if (
remoteInfo?.provider &&
['s3', 'b2', 'box', 'drive', 'onedrive'].includes(remoteInfo.provider)
) {
const cleanupMenuItem = await MenuItem.new({
id: `cleanup-${remote}`,
text: 'Cleanup',
action: async () => {
try {
const confirmed = await ask(`Start cleanup on ${remote}?`, {
title: `Cleaning up ${remote}`,
kind: 'warning',
okLabel: 'Start',
cancelLabel: 'Cancel',
})
if (!confirmed) {
return
if (!confirmed) {
return
}
await cleanupRemote(remote)
await message(`Cleanup started for ${remote}`, {
title: 'Cleanup Started',
okLabel: 'OK',
})
} catch (error) {
await message(`Failed to start cleanup job, ${error}`, {
title: 'Cleanup Error',
kind: 'error',
okLabel: 'OK',
})
}
await cleanupRemote(remote)
await message(`Cleanup started for ${remote}`, {
title: 'Cleanup Started',
okLabel: 'OK',
})
} catch (error) {
await message(`Failed to start cleanup job, ${error}`, {
title: 'Cleanup Error',
kind: 'error',
okLabel: 'OK',
})
}
},
})
submenuItems.push(cleanupMenuItem)
},
})
submenuItems.push(cleanupMenuItem)
}
}
if (!remoteConfig?.disabledActions?.includes('tray-remove')) {
@@ -358,7 +372,12 @@ async function parseRemotes(remotes: string[]) {
submenuItems.push(stopServeMenuItem)
}
parsedRemotes[remote] = submenuItems
parsedRemotes[remote] = {
icon: remoteInfo?.provider
? await resolveResource(`icons/small/providers/${remoteInfo.provider}.png`)
: await resolveResource(`icons/small/backends/${remoteInfo?.type}.png`),
items: submenuItems,
}
}
return parsedRemotes
@@ -383,13 +402,14 @@ export async function buildMenu() {
})
menuItems.push(noRemotesMenuItem)
} else if (remotes.length > 5) {
const items = await parseRemotes(remotes)
const parsedRemotes = await parseRemotes(remotes)
const submenuItems: (MenuItem | Submenu | PredefinedMenuItem)[] = []
for (const remote in items) {
for (const r in parsedRemotes) {
const sub = await Submenu.new({
items: items[remote],
text: remote,
items: parsedRemotes[r].items,
icon: parsedRemotes[r].icon,
text: r,
})
submenuItems.push(sub)
}
@@ -401,12 +421,13 @@ export async function buildMenu() {
menuItems.push(sub)
} else {
const items = await parseRemotes(remotes)
const parsedRemotes = await parseRemotes(remotes)
for (const remote in items) {
for (const r in parsedRemotes) {
const sub = await Submenu.new({
items: items[remote],
text: remote,
items: parsedRemotes[r].items,
icon: parsedRemotes[r].icon,
text: r,
})
menuItems.push(sub)
}
@@ -446,20 +467,6 @@ export async function buildMenu() {
menuItems.push(copyMenuItem)
}
if (!persistedStoreState.disabledActions?.includes('tray-move')) {
const moveMenuItem = await MenuItem.new({
id: 'move',
text: 'Move',
action: async () => {
await openWindow({
name: 'Move',
url: '/move',
})
},
})
menuItems.push(moveMenuItem)
}
if (!persistedStoreState.disabledActions?.includes('tray-sync')) {
const syncMenuItem = await MenuItem.new({
id: 'sync',
@@ -474,46 +481,82 @@ export async function buildMenu() {
menuItems.push(syncMenuItem)
}
if (!persistedStoreState.disabledActions?.includes('tray-serve')) {
const serveToMenuItem = await MenuItem.new({
id: 'serve',
text: 'Serve',
action: async () => {
await openWindow({
name: 'Serve',
url: '/serve',
})
},
})
menuItems.push(serveToMenuItem)
}
const allowsAdditional =
!persistedStoreState.disabledActions?.includes('tray-move') ||
!persistedStoreState.disabledActions?.includes('tray-serve') ||
!persistedStoreState.disabledActions?.includes('tray-purge') ||
!persistedStoreState.disabledActions?.includes('tray-delete')
if (!persistedStoreState.disabledActions?.includes('tray-purge')) {
const purgeMenuItem = await MenuItem.new({
id: 'purge',
text: 'Purge',
action: async () => {
await openWindow({
name: 'Purge',
url: '/purge',
})
},
})
menuItems.push(purgeMenuItem)
}
if (allowsAdditional) {
const commandsSubmenuItems: (MenuItem | Submenu | PredefinedMenuItem)[] = []
if (!persistedStoreState.disabledActions?.includes('tray-delete')) {
const deleteMenuItem = await MenuItem.new({
id: 'delete',
text: 'Delete',
action: async () => {
await openWindow({
name: 'Delete',
url: '/delete',
})
},
if (!persistedStoreState.disabledActions?.includes('tray-move')) {
const moveMenuItem = await MenuItem.new({
id: 'move',
text: 'Move',
action: async () => {
await openWindow({
name: 'Move',
url: '/move',
})
},
})
commandsSubmenuItems.push(moveMenuItem)
}
const rcloneVersion = await getRcloneVersion()
if (
rcloneVersion?.yours &&
compareVersions(rcloneVersion.yours, '1.70.0') === 1 &&
!persistedStoreState.disabledActions?.includes('tray-serve')
) {
const serveToMenuItem = await MenuItem.new({
id: 'serve',
text: 'Serve',
action: async () => {
await openWindow({
name: 'Serve',
url: '/serve',
})
},
})
commandsSubmenuItems.push(serveToMenuItem)
}
if (!persistedStoreState.disabledActions?.includes('tray-purge')) {
const purgeMenuItem = await MenuItem.new({
id: 'purge',
text: 'Purge',
action: async () => {
await openWindow({
name: 'Purge',
url: '/purge',
})
},
})
commandsSubmenuItems.push(purgeMenuItem)
}
if (!persistedStoreState.disabledActions?.includes('tray-delete')) {
const deleteMenuItem = await MenuItem.new({
id: 'delete',
text: 'Delete',
action: async () => {
await openWindow({
name: 'Delete',
url: '/delete',
})
},
})
commandsSubmenuItems.push(deleteMenuItem)
}
const commandsSubmenu = await Submenu.new({
items: commandsSubmenuItems,
text: 'Commands',
})
menuItems.push(deleteMenuItem)
menuItems.push(commandsSubmenu)
}
await PredefinedMenuItem.new({
Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 774 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 734 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 698 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 848 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 787 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 777 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 784 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 764 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 997 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

+1 -21
View File
@@ -44,27 +44,7 @@
"icons/icon.icns",
"icons/icon.ico"
],
"resources": [
"icons/favicon/icon.png",
"icons/favicon/frame_00_delay-0.1s.png",
"icons/favicon/frame_01_delay-0.1s.png",
"icons/favicon/frame_02_delay-0.1s.png",
"icons/favicon/frame_03_delay-0.1s.png",
"icons/favicon/frame_04_delay-0.1s.png",
"icons/favicon/frame_05_delay-0.1s.png",
"icons/favicon/frame_06_delay-0.1s.png",
"icons/favicon/frame_07_delay-0.1s.png",
"icons/favicon/frame_08_delay-0.1s.png",
"icons/favicon/frame_09_delay-0.1s.png",
"icons/favicon/frame_10_delay-0.1s.png",
"icons/favicon/frame_11_delay-0.1s.png",
"icons/favicon/frame_12_delay-0.1s.png",
"icons/favicon/frame_13_delay-0.1s.png",
"icons/favicon/frame_14_delay-0.1s.png",
"icons/favicon/frame_15_delay-0.1s.png",
"icons/favicon/frame_16_delay-0.1s.png",
"icons/favicon/frame_17_delay-0.1s.png"
],
"resources": ["icons/favicon/", "icons/small/"],
"shortDescription": "Cross-platform GUI for rclone & S3",
"longDescription": "Cross-platform GUI for rclone & S3",
"license": "Apache-2.0",