menu icons
Signed-off-by: FTCHD <144691102+FTCHD@users.noreply.github.com>
@@ -1,6 +1,6 @@
|
|||||||
import * as Sentry from '@sentry/browser'
|
import * as Sentry from '@sentry/browser'
|
||||||
import { Menu, MenuItem, PredefinedMenuItem, Submenu } from '@tauri-apps/api/menu'
|
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 { getCurrentWindow } from '@tauri-apps/api/window'
|
||||||
import { ask, message, open } from '@tauri-apps/plugin-dialog'
|
import { ask, message, open } from '@tauri-apps/plugin-dialog'
|
||||||
import { exists, mkdir, remove } from '@tauri-apps/plugin-fs'
|
import { exists, mkdir, remove } from '@tauri-apps/plugin-fs'
|
||||||
@@ -11,12 +11,14 @@ import notify from './notify'
|
|||||||
import {
|
import {
|
||||||
cleanupRemote,
|
cleanupRemote,
|
||||||
deleteRemote,
|
deleteRemote,
|
||||||
|
getRemote,
|
||||||
listMounts,
|
listMounts,
|
||||||
listServes,
|
listServes,
|
||||||
mountRemote,
|
mountRemote,
|
||||||
stopServe,
|
stopServe,
|
||||||
unmountRemote,
|
unmountRemote,
|
||||||
} from './rclone/api'
|
} from './rclone/api'
|
||||||
|
import { compareVersions, getRcloneVersion } from './rclone/common'
|
||||||
import { dialogGetMountPlugin, needsMountPlugin } from './rclone/mount'
|
import { dialogGetMountPlugin, needsMountPlugin } from './rclone/mount'
|
||||||
import { usePersistedStore, useStore } from './store'
|
import { usePersistedStore, useStore } from './store'
|
||||||
import { showDefaultTray, showLoadingTray } from './tray'
|
import { showDefaultTray, showLoadingTray } from './tray'
|
||||||
@@ -33,15 +35,22 @@ async function parseRemotes(remotes: string[]) {
|
|||||||
const currentServes = await listServes()
|
const currentServes = await listServes()
|
||||||
console.log('[parseRemotes] currentServes', currentServes)
|
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) {
|
for (const remote of remotes) {
|
||||||
console.log('[parseRemotes] remote', remote)
|
console.log('[parseRemotes] remote', remote)
|
||||||
|
|
||||||
const remoteConfig = persistedStoreState.remoteConfigList?.[remote]
|
const remoteConfig = persistedStoreState.remoteConfigList?.[remote]
|
||||||
if (remoteConfig?.disabledActions?.includes('tray')) {
|
if (remoteConfig?.disabledActions?.includes('tray')) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const remoteInfo = await getRemote(remote).catch(null)
|
||||||
|
console.log('[parseRemotes] remoteInfo', remoteInfo)
|
||||||
|
|
||||||
const submenuItems: (MenuItem | Submenu | PredefinedMenuItem)[] = []
|
const submenuItems: (MenuItem | Submenu | PredefinedMenuItem)[] = []
|
||||||
|
|
||||||
if (!remoteConfig?.disabledActions?.includes('tray-mount')) {
|
if (!remoteConfig?.disabledActions?.includes('tray-mount')) {
|
||||||
@@ -206,37 +215,42 @@ async function parseRemotes(remotes: string[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!remoteConfig?.disabledActions?.includes('tray-cleanup')) {
|
if (!remoteConfig?.disabledActions?.includes('tray-cleanup')) {
|
||||||
const cleanupMenuItem = await MenuItem.new({
|
if (
|
||||||
id: `cleanup-${remote}`,
|
remoteInfo?.provider &&
|
||||||
text: 'Cleanup',
|
['s3', 'b2', 'box', 'drive', 'onedrive'].includes(remoteInfo.provider)
|
||||||
action: async () => {
|
) {
|
||||||
try {
|
const cleanupMenuItem = await MenuItem.new({
|
||||||
const confirmed = await ask(`Start cleanup on ${remote}?`, {
|
id: `cleanup-${remote}`,
|
||||||
title: `Cleaning up ${remote}`,
|
text: 'Cleanup',
|
||||||
kind: 'warning',
|
action: async () => {
|
||||||
okLabel: 'Start',
|
try {
|
||||||
cancelLabel: 'Cancel',
|
const confirmed = await ask(`Start cleanup on ${remote}?`, {
|
||||||
})
|
title: `Cleaning up ${remote}`,
|
||||||
|
kind: 'warning',
|
||||||
|
okLabel: 'Start',
|
||||||
|
cancelLabel: 'Cancel',
|
||||||
|
})
|
||||||
|
|
||||||
if (!confirmed) {
|
if (!confirmed) {
|
||||||
return
|
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}`, {
|
submenuItems.push(cleanupMenuItem)
|
||||||
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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!remoteConfig?.disabledActions?.includes('tray-remove')) {
|
if (!remoteConfig?.disabledActions?.includes('tray-remove')) {
|
||||||
@@ -358,7 +372,12 @@ async function parseRemotes(remotes: string[]) {
|
|||||||
submenuItems.push(stopServeMenuItem)
|
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
|
return parsedRemotes
|
||||||
@@ -383,13 +402,14 @@ export async function buildMenu() {
|
|||||||
})
|
})
|
||||||
menuItems.push(noRemotesMenuItem)
|
menuItems.push(noRemotesMenuItem)
|
||||||
} else if (remotes.length > 5) {
|
} else if (remotes.length > 5) {
|
||||||
const items = await parseRemotes(remotes)
|
const parsedRemotes = await parseRemotes(remotes)
|
||||||
const submenuItems: (MenuItem | Submenu | PredefinedMenuItem)[] = []
|
const submenuItems: (MenuItem | Submenu | PredefinedMenuItem)[] = []
|
||||||
|
|
||||||
for (const remote in items) {
|
for (const r in parsedRemotes) {
|
||||||
const sub = await Submenu.new({
|
const sub = await Submenu.new({
|
||||||
items: items[remote],
|
items: parsedRemotes[r].items,
|
||||||
text: remote,
|
icon: parsedRemotes[r].icon,
|
||||||
|
text: r,
|
||||||
})
|
})
|
||||||
submenuItems.push(sub)
|
submenuItems.push(sub)
|
||||||
}
|
}
|
||||||
@@ -401,12 +421,13 @@ export async function buildMenu() {
|
|||||||
|
|
||||||
menuItems.push(sub)
|
menuItems.push(sub)
|
||||||
} else {
|
} 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({
|
const sub = await Submenu.new({
|
||||||
items: items[remote],
|
items: parsedRemotes[r].items,
|
||||||
text: remote,
|
icon: parsedRemotes[r].icon,
|
||||||
|
text: r,
|
||||||
})
|
})
|
||||||
menuItems.push(sub)
|
menuItems.push(sub)
|
||||||
}
|
}
|
||||||
@@ -446,20 +467,6 @@ export async function buildMenu() {
|
|||||||
menuItems.push(copyMenuItem)
|
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')) {
|
if (!persistedStoreState.disabledActions?.includes('tray-sync')) {
|
||||||
const syncMenuItem = await MenuItem.new({
|
const syncMenuItem = await MenuItem.new({
|
||||||
id: 'sync',
|
id: 'sync',
|
||||||
@@ -474,46 +481,82 @@ export async function buildMenu() {
|
|||||||
menuItems.push(syncMenuItem)
|
menuItems.push(syncMenuItem)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!persistedStoreState.disabledActions?.includes('tray-serve')) {
|
const allowsAdditional =
|
||||||
const serveToMenuItem = await MenuItem.new({
|
!persistedStoreState.disabledActions?.includes('tray-move') ||
|
||||||
id: 'serve',
|
!persistedStoreState.disabledActions?.includes('tray-serve') ||
|
||||||
text: 'Serve',
|
!persistedStoreState.disabledActions?.includes('tray-purge') ||
|
||||||
action: async () => {
|
!persistedStoreState.disabledActions?.includes('tray-delete')
|
||||||
await openWindow({
|
|
||||||
name: 'Serve',
|
|
||||||
url: '/serve',
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
menuItems.push(serveToMenuItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!persistedStoreState.disabledActions?.includes('tray-purge')) {
|
if (allowsAdditional) {
|
||||||
const purgeMenuItem = await MenuItem.new({
|
const commandsSubmenuItems: (MenuItem | Submenu | PredefinedMenuItem)[] = []
|
||||||
id: 'purge',
|
|
||||||
text: 'Purge',
|
|
||||||
action: async () => {
|
|
||||||
await openWindow({
|
|
||||||
name: 'Purge',
|
|
||||||
url: '/purge',
|
|
||||||
})
|
|
||||||
},
|
|
||||||
})
|
|
||||||
menuItems.push(purgeMenuItem)
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!persistedStoreState.disabledActions?.includes('tray-delete')) {
|
if (!persistedStoreState.disabledActions?.includes('tray-move')) {
|
||||||
const deleteMenuItem = await MenuItem.new({
|
const moveMenuItem = await MenuItem.new({
|
||||||
id: 'delete',
|
id: 'move',
|
||||||
text: 'Delete',
|
text: 'Move',
|
||||||
action: async () => {
|
action: async () => {
|
||||||
await openWindow({
|
await openWindow({
|
||||||
name: 'Delete',
|
name: 'Move',
|
||||||
url: '/delete',
|
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({
|
await PredefinedMenuItem.new({
|
||||||
|
|||||||
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 2.8 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 5.1 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 2.3 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 1.8 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 5.9 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 774 B |
|
After Width: | Height: | Size: 4.7 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 734 B |
|
After Width: | Height: | Size: 698 B |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 848 B |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 787 B |
|
After Width: | Height: | Size: 777 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 635 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 4.9 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 4.5 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 2.0 KiB |
|
After Width: | Height: | Size: 784 B |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 3.4 KiB |
|
After Width: | Height: | Size: 3.3 KiB |
|
After Width: | Height: | Size: 2.9 KiB |
|
After Width: | Height: | Size: 5.3 KiB |
|
After Width: | Height: | Size: 1.5 KiB |
|
After Width: | Height: | Size: 764 B |
|
After Width: | Height: | Size: 6.3 KiB |
|
After Width: | Height: | Size: 1.1 KiB |
|
After Width: | Height: | Size: 1.0 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 997 B |
|
After Width: | Height: | Size: 1.3 KiB |
|
After Width: | Height: | Size: 1.7 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
@@ -44,27 +44,7 @@
|
|||||||
"icons/icon.icns",
|
"icons/icon.icns",
|
||||||
"icons/icon.ico"
|
"icons/icon.ico"
|
||||||
],
|
],
|
||||||
"resources": [
|
"resources": ["icons/favicon/", "icons/small/"],
|
||||||
"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"
|
|
||||||
],
|
|
||||||
"shortDescription": "Cross-platform GUI for rclone & S3",
|
"shortDescription": "Cross-platform GUI for rclone & S3",
|
||||||
"longDescription": "Cross-platform GUI for rclone & S3",
|
"longDescription": "Cross-platform GUI for rclone & S3",
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
|
|||||||