mirror of
https://github.com/neosubhamoy/neodlp.git
synced 2026-03-22 10:15:50 +05:30
refactor: disabled uncompatible settings with flatpak and added healthcheck alert
This commit is contained in:
26
src/App.tsx
26
src/App.tsx
@@ -4,7 +4,7 @@ import { AppContext } from "@/providers/appContextProvider";
|
|||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { arch, exeExtension } from "@tauri-apps/plugin-os";
|
import { arch, exeExtension } from "@tauri-apps/plugin-os";
|
||||||
import { downloadDir, join, resourceDir, tempDir } from "@tauri-apps/api/path";
|
import { downloadDir, join, resourceDir, tempDir } from "@tauri-apps/api/path";
|
||||||
import { useBasePathsStore, useCurrentVideoMetadataStore, useDownloaderPageStatesStore, useDownloadStatesStore, useKvPairsStatesStore, useSettingsPageStatesStore } from "@/services/store";
|
import { useBasePathsStore, useCurrentVideoMetadataStore, useDownloaderPageStatesStore, useDownloadStatesStore, useEnvironmentStore, useKvPairsStatesStore, useSettingsPageStatesStore } from "@/services/store";
|
||||||
import { isObjEmpty} from "@/utils";
|
import { isObjEmpty} from "@/utils";
|
||||||
import { Command } from "@tauri-apps/plugin-shell";
|
import { Command } from "@tauri-apps/plugin-shell";
|
||||||
import { useUpdateDownloadStatus } from "@/services/mutations";
|
import { useUpdateDownloadStatus } from "@/services/mutations";
|
||||||
@@ -40,6 +40,10 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
const setDownloadStates = useDownloadStatesStore((state) => state.setDownloadStates);
|
const setDownloadStates = useDownloadStatesStore((state) => state.setDownloadStates);
|
||||||
const setPath = useBasePathsStore((state) => state.setPath);
|
const setPath = useBasePathsStore((state) => state.setPath);
|
||||||
|
|
||||||
|
const setIsFlatpak = useEnvironmentStore((state) => state.setIsFlatpak);
|
||||||
|
const setIsAppimage = useEnvironmentStore((state) => state.setIsAppimage);
|
||||||
|
const setAppDirPath = useEnvironmentStore((state) => state.setAppDirPath);
|
||||||
|
|
||||||
const setIsUsingDefaultSettings = useSettingsPageStatesStore((state) => state.setIsUsingDefaultSettings);
|
const setIsUsingDefaultSettings = useSettingsPageStatesStore((state) => state.setIsUsingDefaultSettings);
|
||||||
const setSettingsKey = useSettingsPageStatesStore((state) => state.setSettingsKey);
|
const setSettingsKey = useSettingsPageStatesStore((state) => state.setSettingsKey);
|
||||||
const appVersion = useSettingsPageStatesStore(state => state.appVersion);
|
const appVersion = useSettingsPageStatesStore(state => state.appVersion);
|
||||||
@@ -122,6 +126,26 @@ export default function App({ children }: { children: React.ReactNode }) {
|
|||||||
};
|
};
|
||||||
}, [stopPotServer]);
|
}, [stopPotServer]);
|
||||||
|
|
||||||
|
// Detect sandbox environments
|
||||||
|
useEffect(() => {
|
||||||
|
const detectEnvironment = async () => {
|
||||||
|
try {
|
||||||
|
const isFlatpak = await invoke<boolean>('is_flatpak');
|
||||||
|
const appimagePath = await invoke<string | null>('get_appimage_path');
|
||||||
|
console.log('Environment detection results:', { isFlatpak, appimagePath });
|
||||||
|
|
||||||
|
if (isFlatpak) setIsFlatpak(true);
|
||||||
|
if (appimagePath) {
|
||||||
|
setIsAppimage(true);
|
||||||
|
setAppDirPath(appimagePath);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to detect environment:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
detectEnvironment();
|
||||||
|
}, [setIsFlatpak, setIsAppimage, setAppDirPath]);
|
||||||
|
|
||||||
// Listen for websocket messages
|
// Listen for websocket messages
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const unlisten = listen<WebSocketMessage>('websocket-message', (event) => {
|
const unlisten = listen<WebSocketMessage>('websocket-message', (event) => {
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { AspectRatio } from "@/components/ui/aspect-ratio";
|
|||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { Separator } from "@/components/ui/separator";
|
import { Separator } from "@/components/ui/separator";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { useCurrentVideoMetadataStore, useDownloadActionStatesStore, useLibraryPageStatesStore } from "@/services/store";
|
import { useCurrentVideoMetadataStore, useDownloadActionStatesStore, useEnvironmentStore, useLibraryPageStatesStore } from "@/services/store";
|
||||||
import { formatBitrate, formatCodec, formatDurationString, formatFileSize, paginate } from "@/utils";
|
import { formatBitrate, formatCodec, formatDurationString, formatFileSize, paginate } from "@/utils";
|
||||||
import { ArrowUpRightIcon, AudioLines, CircleArrowDown, Clock, File, FileAudio2, FileQuestion, FileVideo2, FolderInput, ListVideo, Music, Play, Search, Trash2, Video } from "lucide-react";
|
import { ArrowUpRightIcon, AudioLines, CircleArrowDown, Clock, File, FileAudio2, FileQuestion, FileVideo2, FolderInput, ListVideo, Music, Play, Search, Trash2, Video } from "lucide-react";
|
||||||
import { invoke } from "@tauri-apps/api/core";
|
import { invoke } from "@tauri-apps/api/core";
|
||||||
@@ -33,6 +33,8 @@ export function CompletedDownload({ state }: CompletedDownloadProps) {
|
|||||||
const downloadActions = useDownloadActionStatesStore(state => state.downloadActions);
|
const downloadActions = useDownloadActionStatesStore(state => state.downloadActions);
|
||||||
const setIsDeleteFileChecked = useDownloadActionStatesStore(state => state.setIsDeleteFileChecked);
|
const setIsDeleteFileChecked = useDownloadActionStatesStore(state => state.setIsDeleteFileChecked);
|
||||||
|
|
||||||
|
const isFlatpak = useEnvironmentStore(state => state.isFlatpak);
|
||||||
|
|
||||||
const queryClient = useQueryClient();
|
const queryClient = useQueryClient();
|
||||||
const downloadStateDeleter = useDeleteDownloadState();
|
const downloadStateDeleter = useDeleteDownloadState();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
@@ -276,10 +278,12 @@ export function CompletedDownload({ state }: CompletedDownloadProps) {
|
|||||||
<Play className="w-4 h-4" />
|
<Play className="w-4 h-4" />
|
||||||
Open
|
Open
|
||||||
</Button>
|
</Button>
|
||||||
<Button size="sm" variant="outline" onClick={() => openFile(state.filepath, 'explorer')}>
|
{!isFlatpak && (
|
||||||
<FolderInput className="w-4 h-4" />
|
<Button size="sm" variant="outline" onClick={() => openFile(state.filepath, 'explorer')}>
|
||||||
Reveal
|
<FolderInput className="w-4 h-4" />
|
||||||
</Button>
|
Reveal
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
<Button size="sm" variant="outline" onClick={() => handleSearch(state.url, state.playlist_id ? true : false)}>
|
<Button size="sm" variant="outline" onClick={() => handleSearch(state.url, state.playlist_id ? true : false)}>
|
||||||
<Search className="w-4 h-4" />
|
<Search className="w-4 h-4" />
|
||||||
Search
|
Search
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { Card } from "@/components/ui/card";
|
import { Card } from "@/components/ui/card";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import { useBasePathsStore, useDownloaderPageStatesStore, useDownloadStatesStore, useSettingsPageStatesStore } from "@/services/store";
|
import { useBasePathsStore, useDownloaderPageStatesStore, useDownloadStatesStore, useEnvironmentStore, useSettingsPageStatesStore } from "@/services/store";
|
||||||
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select";
|
import { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectTrigger, SelectValue } from "@/components/ui/select";
|
||||||
import { Switch } from "@/components/ui/switch";
|
import { Switch } from "@/components/ui/switch";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
import { BadgeCheck, BellRing, BrushCleaning, Bug, Cookie, ExternalLink, FilePen, FileVideo, Folder, FolderOpen, Github, Globe, Heart, Info, KeyRound, Loader2, LucideIcon, Mail, Monitor, Moon, Package, Scale, ShieldMinus, SquareTerminal, Sun, Terminal, Timer, Trash, TriangleAlert, WandSparkles, Wifi, Wrench } from "lucide-react";
|
import { BadgeCheck, BellRing, BrushCleaning, Bug, CircleCheck, Cookie, ExternalLink, FilePen, FileVideo, Folder, FolderOpen, Github, Globe, Heart, Info, KeyRound, Loader2, LucideIcon, Mail, Monitor, Moon, Package, Scale, ShieldMinus, SquareTerminal, Sun, Terminal, Timer, Trash, TriangleAlert, WandSparkles, Wifi, Wrench } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { Slider } from "@/components/ui/slider";
|
import { Slider } from "@/components/ui/slider";
|
||||||
import { Input } from "@/components/ui/input";
|
import { Input } from "@/components/ui/input";
|
||||||
@@ -285,6 +285,8 @@ function AppAppearanceSettings() {
|
|||||||
function AppFolderSettings() {
|
function AppFolderSettings() {
|
||||||
const { saveSettingsKey } = useSettings();
|
const { saveSettingsKey } = useSettings();
|
||||||
|
|
||||||
|
const isFlatpak = useEnvironmentStore(state => state.isFlatpak);
|
||||||
|
|
||||||
const formResetTrigger = useSettingsPageStatesStore(state => state.formResetTrigger);
|
const formResetTrigger = useSettingsPageStatesStore(state => state.formResetTrigger);
|
||||||
const acknowledgeFormReset = useSettingsPageStatesStore(state => state.acknowledgeFormReset);
|
const acknowledgeFormReset = useSettingsPageStatesStore(state => state.acknowledgeFormReset);
|
||||||
|
|
||||||
@@ -364,6 +366,7 @@ function AppFolderSettings() {
|
|||||||
<Input className="focus-visible:ring-0" type="text" placeholder="Select download directory" value={downloadDirPath ?? 'Unknown'} readOnly/>
|
<Input className="focus-visible:ring-0" type="text" placeholder="Select download directory" value={downloadDirPath ?? 'Unknown'} readOnly/>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
|
disabled={isFlatpak}
|
||||||
onClick={async () => {
|
onClick={async () => {
|
||||||
try {
|
try {
|
||||||
const folder = await open({
|
const folder = await open({
|
||||||
@@ -1686,6 +1689,9 @@ function AppDebugSettings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function AppInfoSettings() {
|
function AppInfoSettings() {
|
||||||
|
const isFlatpak = useEnvironmentStore(state => state.isFlatpak);
|
||||||
|
const isAppimage = useEnvironmentStore(state => state.isAppimage);
|
||||||
|
|
||||||
const appVersion = useSettingsPageStatesStore(state => state.appVersion);
|
const appVersion = useSettingsPageStatesStore(state => state.appVersion);
|
||||||
|
|
||||||
const binDepsList = [
|
const binDepsList = [
|
||||||
@@ -1799,6 +1805,35 @@ function AppInfoSettings() {
|
|||||||
</Button>
|
</Button>
|
||||||
</Card>
|
</Card>
|
||||||
</div>
|
</div>
|
||||||
|
<div className="healthcheck">
|
||||||
|
<h3 className="font-semibold">Health Check</h3>
|
||||||
|
<p className="text-xs text-muted-foreground mb-3">Ensure everything is working fine</p>
|
||||||
|
{isFlatpak ? (
|
||||||
|
<Alert className="">
|
||||||
|
<TriangleAlert className="size-4 stroke-primary" />
|
||||||
|
<AlertTitle className="text-sm">Flatpak Sandbox Detected!</AlertTitle>
|
||||||
|
<AlertDescription className="text-xs">
|
||||||
|
It looks like you are running NeoDLP in a Flatpak sandbox. Some features like changing download folder, revealing completed downloads in explorer and automatic yt-dlp updates are not available in Flatpak due to sandbox restrictions. To use these features, please install the native build (DEB, RPM or AUR) of NeoDLP.
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
) : isAppimage ? (
|
||||||
|
<Alert className="">
|
||||||
|
<TriangleAlert className="size-4 stroke-primary" />
|
||||||
|
<AlertTitle className="text-sm">Appimage Environment Detected!</AlertTitle>
|
||||||
|
<AlertDescription className="text-xs">
|
||||||
|
Looks like you are using NeoDLP Appimage. NeoDLP's browser integration features are not available on Appimage environment due to it's limitations. To use NeoDLP's browser integration features please install the native build (DEB, RPM or AUR) of NeoDLP.
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
) : (
|
||||||
|
<Alert className="">
|
||||||
|
<CircleCheck className="size-4 stroke-primary" />
|
||||||
|
<AlertTitle className="text-sm">All Set! Cheers :)</AlertTitle>
|
||||||
|
<AlertDescription className="text-xs">
|
||||||
|
NeoDLP is running as normal without any limitations! You should be able to use all the features of NeoDLP without any issues. If you face any problem, feel free to report it to us.
|
||||||
|
</AlertDescription>
|
||||||
|
</Alert>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
<div className="bug-report">
|
<div className="bug-report">
|
||||||
<h3 className="font-semibold">Bug Report</h3>
|
<h3 className="font-semibold">Bug Report</h3>
|
||||||
<p className="text-xs text-muted-foreground mb-3">Noticed any bug or inconsistencies? Report it to help us improve</p>
|
<p className="text-xs text-muted-foreground mb-3">Noticed any bug or inconsistencies? Report it to help us improve</p>
|
||||||
@@ -1869,6 +1904,8 @@ function AppInfoSettings() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function ApplicationSettings() {
|
export function ApplicationSettings() {
|
||||||
|
const isFlatpak = useEnvironmentStore(state => state.isFlatpak);
|
||||||
|
|
||||||
const activeSubAppTab = useSettingsPageStatesStore(state => state.activeSubAppTab);
|
const activeSubAppTab = useSettingsPageStatesStore(state => state.activeSubAppTab);
|
||||||
const setActiveSubAppTab = useSettingsPageStatesStore(state => state.setActiveSubAppTab);
|
const setActiveSubAppTab = useSettingsPageStatesStore(state => state.setActiveSubAppTab);
|
||||||
|
|
||||||
@@ -1926,12 +1963,14 @@ export function ApplicationSettings() {
|
|||||||
<Switch
|
<Switch
|
||||||
id="ytdlp-auto-update"
|
id="ytdlp-auto-update"
|
||||||
checked={ytDlpAutoUpdate}
|
checked={ytDlpAutoUpdate}
|
||||||
|
disabled={isFlatpak}
|
||||||
onCheckedChange={(checked) => saveSettingsKey('ytdlp_auto_update', checked)}
|
onCheckedChange={(checked) => saveSettingsKey('ytdlp_auto_update', checked)}
|
||||||
/>
|
/>
|
||||||
<Label htmlFor="ytdlp-auto-update">Auto Update</Label>
|
<Label htmlFor="ytdlp-auto-update">Auto Update</Label>
|
||||||
</div>
|
</div>
|
||||||
<Select
|
<Select
|
||||||
value={ytDlpUpdateChannel}
|
value={ytDlpUpdateChannel}
|
||||||
|
disabled={isFlatpak}
|
||||||
onValueChange={(value) => saveSettingsKey('ytdlp_update_channel', value)}
|
onValueChange={(value) => saveSettingsKey('ytdlp_update_channel', value)}
|
||||||
>
|
>
|
||||||
<SelectTrigger className="w-37.5 ring-0 focus:ring-0">
|
<SelectTrigger className="w-37.5 ring-0 focus:ring-0">
|
||||||
@@ -1946,7 +1985,7 @@ export function ApplicationSettings() {
|
|||||||
</SelectContent>
|
</SelectContent>
|
||||||
</Select>
|
</Select>
|
||||||
<Button
|
<Button
|
||||||
disabled={ytDlpAutoUpdate || isUpdatingYtDlp || ongoingDownloads.length > 0}
|
disabled={ytDlpAutoUpdate || isUpdatingYtDlp || ongoingDownloads.length > 0 || isFlatpak}
|
||||||
onClick={async () => await updateYtDlp()}
|
onClick={async () => await updateYtDlp()}
|
||||||
>
|
>
|
||||||
{isUpdatingYtDlp ? (
|
{isUpdatingYtDlp ? (
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import { useEffect } from "react";
|
import { useEffect } from "react";
|
||||||
import { Card } from "@/components/ui/card";
|
import { Card } from "@/components/ui/card";
|
||||||
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
|
||||||
import { useSettingsPageStatesStore } from "@/services/store";
|
import { useEnvironmentStore, useSettingsPageStatesStore } from "@/services/store";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
@@ -32,6 +32,9 @@ const websocketPortSchema = z.object({
|
|||||||
});
|
});
|
||||||
|
|
||||||
function ExtInstallSettings() {
|
function ExtInstallSettings() {
|
||||||
|
const currentPlatform = platform();
|
||||||
|
const isFlatpak = useEnvironmentStore(state => state.isFlatpak);
|
||||||
|
|
||||||
const openLink = async (url: string, app: string | null) => {
|
const openLink = async (url: string, app: string | null) => {
|
||||||
try {
|
try {
|
||||||
await invoke('open_link_with_app', { url: url, appName: app }).then(() => {
|
await invoke('open_link_with_app', { url: url, appName: app }).then(() => {
|
||||||
@@ -59,11 +62,7 @@ function ExtInstallSettings() {
|
|||||||
<span>Get Now</span>
|
<span>Get Now</span>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
onClick={async() => {
|
onClick={() => openLink('https://chromewebstore.google.com/detail/neo-downloader-plus/mehopeailfjmiloiiohgicphlcgpompf', isFlatpak ? null : currentPlatform === "linux" ? 'google-chrome' : 'chrome')}
|
||||||
const isFlatpak = await invoke<boolean>('is_flatpak');
|
|
||||||
const currentPlatform = platform();
|
|
||||||
openLink('https://chromewebstore.google.com/detail/neo-downloader-plus/mehopeailfjmiloiiohgicphlcgpompf', isFlatpak ? null : currentPlatform === "linux" ? 'google-chrome' : 'chrome');
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<span className="font-semibold flex items-center gap-2">
|
<span className="font-semibold flex items-center gap-2">
|
||||||
<svg className="size-4 fill-primary-foreground" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
<svg className="size-4 fill-primary-foreground" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||||
@@ -80,10 +79,7 @@ function ExtInstallSettings() {
|
|||||||
<span>Get Now</span>
|
<span>Get Now</span>
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
onClick={async() => {
|
onClick={() => openLink('https://addons.mozilla.org/en-US/firefox/addon/neo-downloader-plus', isFlatpak ? null : 'firefox')}
|
||||||
const isFlatpak = await invoke<boolean>('is_flatpak');
|
|
||||||
openLink('https://addons.mozilla.org/en-US/firefox/addon/neo-downloader-plus', isFlatpak ? null : 'firefox');
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<span className="font-semibold flex items-center gap-2">
|
<span className="font-semibold flex items-center gap-2">
|
||||||
<svg className="size-4 fill-primary-foreground" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
<svg className="size-4 fill-primary-foreground" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512">
|
||||||
@@ -95,38 +91,13 @@ function ExtInstallSettings() {
|
|||||||
</SlidingButton>
|
</SlidingButton>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex gap-2 mb-4">
|
<div className="flex gap-2 mb-4">
|
||||||
<Button variant="outline" onClick={async() => {
|
<Button variant="outline" onClick={() => openLink('https://chromewebstore.google.com/detail/neo-downloader-plus/mehopeailfjmiloiiohgicphlcgpompf', isFlatpak ? null : 'msedge')}>Edge</Button>
|
||||||
const isFlatpak = await invoke<boolean>('is_flatpak');
|
<Button variant="outline" onClick={() => openLink('https://chromewebstore.google.com/detail/neo-downloader-plus/mehopeailfjmiloiiohgicphlcgpompf', isFlatpak ? null : 'opera')}>Opera</Button>
|
||||||
openLink('https://chromewebstore.google.com/detail/neo-downloader-plus/mehopeailfjmiloiiohgicphlcgpompf', isFlatpak ? null : 'msedge');
|
<Button variant="outline" onClick={() => openLink('https://chromewebstore.google.com/detail/neo-downloader-plus/mehopeailfjmiloiiohgicphlcgpompf', isFlatpak ? null : 'brave')}>Brave</Button>
|
||||||
}}>
|
<Button variant="outline" onClick={() => openLink('https://chromewebstore.google.com/detail/neo-downloader-plus/mehopeailfjmiloiiohgicphlcgpompf', isFlatpak ? null : 'vivaldi')}>Vivaldi</Button>
|
||||||
Edge
|
<Button variant="outline" onClick={() => openLink('https://addons.mozilla.org/en-US/firefox/addon/neo-downloader-plus', isFlatpak ? null : 'zen')}>Zen</Button>
|
||||||
</Button>
|
|
||||||
<Button variant="outline" onClick={async() => {
|
|
||||||
const isFlatpak = await invoke<boolean>('is_flatpak');
|
|
||||||
openLink('https://chromewebstore.google.com/detail/neo-downloader-plus/mehopeailfjmiloiiohgicphlcgpompf', isFlatpak ? null : 'opera');
|
|
||||||
}}>
|
|
||||||
Opera
|
|
||||||
</Button>
|
|
||||||
<Button variant="outline" onClick={async() => {
|
|
||||||
const isFlatpak = await invoke<boolean>('is_flatpak');
|
|
||||||
openLink('https://chromewebstore.google.com/detail/neo-downloader-plus/mehopeailfjmiloiiohgicphlcgpompf', isFlatpak ? null : 'brave');
|
|
||||||
}}>
|
|
||||||
Brave
|
|
||||||
</Button>
|
|
||||||
<Button variant="outline" onClick={async() => {
|
|
||||||
const isFlatpak = await invoke<boolean>('is_flatpak');
|
|
||||||
openLink('https://chromewebstore.google.com/detail/neo-downloader-plus/mehopeailfjmiloiiohgicphlcgpompf', isFlatpak ? null : 'vivaldi');
|
|
||||||
}}>
|
|
||||||
Vivaldi
|
|
||||||
</Button>
|
|
||||||
<Button variant="outline" onClick={async() => {
|
|
||||||
const isFlatpak = await invoke<boolean>('is_flatpak');
|
|
||||||
openLink('https://addons.mozilla.org/en-US/firefox/addon/neo-downloader-plus', isFlatpak ? null : 'zen');
|
|
||||||
}}>
|
|
||||||
Zen
|
|
||||||
</Button>
|
|
||||||
</div>
|
</div>
|
||||||
<p className="text-xs text-muted-foreground mb-2">* These links opens with coresponding browsers only (except on flatpak). Make sure the browser is installed before clicking the link</p>
|
<p className="text-xs text-muted-foreground mb-2">* These links opens with coresponding browsers only. Make sure the browser is installed before clicking the link</p>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export function AppSidebar() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let timeout: NodeJS.Timeout;
|
let timeout: ReturnType<typeof setTimeout>;
|
||||||
if (open) {
|
if (open) {
|
||||||
timeout = setTimeout(() => {
|
timeout = setTimeout(() => {
|
||||||
setShowBadge(true);
|
setShowBadge(true);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { BasePathsStore, CurrentVideoMetadataStore, DownloadActionStatesStore, DownloaderPageStatesStore, DownloadStatesStore, KvPairsStatesStore, LibraryPageStatesStore, LogsStore, SettingsPageStatesStore } from '@/types/store';
|
import { BasePathsStore, CurrentVideoMetadataStore, DownloadActionStatesStore, DownloaderPageStatesStore, DownloadStatesStore, EnvironmentStore, KvPairsStatesStore, LibraryPageStatesStore, LogsStore, SettingsPageStatesStore } from '@/types/store';
|
||||||
import { create } from 'zustand';
|
import { create } from 'zustand';
|
||||||
|
|
||||||
export const useBasePathsStore = create<BasePathsStore>((set) => ({
|
export const useBasePathsStore = create<BasePathsStore>((set) => ({
|
||||||
@@ -352,3 +352,12 @@ export const useLogsStore = create<LogsStore>((set) => ({
|
|||||||
addLog: (log) => set((state) => ({ logs: [...state.logs, log] })),
|
addLog: (log) => set((state) => ({ logs: [...state.logs, log] })),
|
||||||
clearLogs: () => set(() => ({ logs: [] }))
|
clearLogs: () => set(() => ({ logs: [] }))
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
export const useEnvironmentStore = create<EnvironmentStore>((set) => ({
|
||||||
|
isFlatpak: false,
|
||||||
|
isAppimage: false,
|
||||||
|
appDirPath: null,
|
||||||
|
setIsFlatpak: (isFlatpak) => set(() => ({ isFlatpak })),
|
||||||
|
setIsAppimage: (isAppimage) => set(() => ({ isAppimage })),
|
||||||
|
setAppDirPath: (path) => set(() => ({ appDirPath: path }))
|
||||||
|
}));
|
||||||
|
|||||||
@@ -152,3 +152,12 @@ export interface LogsStore {
|
|||||||
addLog: (log: Log) => void;
|
addLog: (log: Log) => void;
|
||||||
clearLogs: () => void;
|
clearLogs: () => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface EnvironmentStore {
|
||||||
|
isFlatpak: boolean;
|
||||||
|
isAppimage: boolean;
|
||||||
|
appDirPath: string | null;
|
||||||
|
setIsFlatpak: (isFlatpak: boolean) => void;
|
||||||
|
setIsAppimage: (isAppimage: boolean) => void;
|
||||||
|
setAppDirPath: (path: string) => void;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user