mirror of
https://github.com/zhom/donutbrowser.git
synced 2026-04-23 04:16:29 +02:00
refactor: move useBrowserState to its own file
This commit is contained in:
@@ -45,7 +45,7 @@ import {
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { useBrowserState } from "@/hooks/use-browser-support";
|
||||
import { useBrowserState } from "@/hooks/use-browser-state";
|
||||
import { useTableSorting } from "@/hooks/use-table-sorting";
|
||||
import {
|
||||
getBrowserDisplayName,
|
||||
|
||||
@@ -27,7 +27,7 @@ import {
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from "@/components/ui/tooltip";
|
||||
import { useBrowserState } from "@/hooks/use-browser-support";
|
||||
import { useBrowserState } from "@/hooks/use-browser-state";
|
||||
import { getBrowserDisplayName, getBrowserIcon } from "@/lib/browser-utils";
|
||||
import type { BrowserProfile, StoredProxy } from "@/types";
|
||||
|
||||
|
||||
@@ -0,0 +1,224 @@
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { getBrowserDisplayName } from "@/lib/browser-utils";
|
||||
import type { BrowserProfile } from "@/types";
|
||||
|
||||
/**
|
||||
* Hook for managing browser state and enforcing single-instance rules for Tor and Mullvad browsers
|
||||
*/
|
||||
export function useBrowserState(
|
||||
profiles: BrowserProfile[],
|
||||
runningProfiles: Set<string>,
|
||||
isUpdating?: (browser: string) => boolean,
|
||||
) {
|
||||
const [isClient, setIsClient] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsClient(true);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Check if a browser type allows only one instance to run at a time
|
||||
*/
|
||||
const isSingleInstanceBrowser = useCallback(
|
||||
(browserType: string): boolean => {
|
||||
return browserType === "tor-browser" || browserType === "mullvad-browser";
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
/**
|
||||
* Check if any instance of a specific browser type is currently running
|
||||
*/
|
||||
const isAnyInstanceRunning = useCallback(
|
||||
(browserType: string): boolean => {
|
||||
if (!isClient) return false;
|
||||
return profiles.some(
|
||||
(p) => p.browser === browserType && runningProfiles.has(p.name),
|
||||
);
|
||||
},
|
||||
[profiles, runningProfiles, isClient],
|
||||
);
|
||||
|
||||
/**
|
||||
* Check if a profile can be launched (not disabled by single-instance rules)
|
||||
*/
|
||||
const canLaunchProfile = useCallback(
|
||||
(profile: BrowserProfile): boolean => {
|
||||
if (!isClient) return false;
|
||||
|
||||
const isRunning = runningProfiles.has(profile.name);
|
||||
const isBrowserUpdating = isUpdating?.(profile.browser) ?? false;
|
||||
|
||||
// If the profile is already running, it can always be stopped
|
||||
if (isRunning) return true;
|
||||
|
||||
// If THIS specific browser is updating or downloading, block this profile
|
||||
if (isBrowserUpdating) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// For single-instance browsers, check if any instance is running
|
||||
if (isSingleInstanceBrowser(profile.browser)) {
|
||||
return !isAnyInstanceRunning(profile.browser);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
[
|
||||
runningProfiles,
|
||||
isClient,
|
||||
isUpdating,
|
||||
isSingleInstanceBrowser,
|
||||
isAnyInstanceRunning,
|
||||
],
|
||||
);
|
||||
|
||||
/**
|
||||
* Check if a profile can be used for opening links
|
||||
* This is more restrictive than canLaunchProfile as it considers running state
|
||||
*/
|
||||
const canUseProfileForLinks = useCallback(
|
||||
(profile: BrowserProfile): boolean => {
|
||||
if (!isClient) return false;
|
||||
|
||||
const isRunning = runningProfiles.has(profile.name);
|
||||
const isBrowserUpdating = isUpdating?.(profile.browser) ?? false;
|
||||
|
||||
// If this specific browser is updating or downloading, block it
|
||||
if (isBrowserUpdating) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// For single-instance browsers (Tor and Mullvad)
|
||||
if (isSingleInstanceBrowser(profile.browser)) {
|
||||
const runningInstancesOfType = profiles.filter(
|
||||
(p) => p.browser === profile.browser && runningProfiles.has(p.name),
|
||||
);
|
||||
|
||||
// If no instances are running, any profile of this type can be used
|
||||
if (runningInstancesOfType.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If instances are running, only the running ones can be used
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
// For other browsers, any profile can be used
|
||||
return true;
|
||||
},
|
||||
[profiles, runningProfiles, isClient, isSingleInstanceBrowser, isUpdating],
|
||||
);
|
||||
|
||||
/**
|
||||
* Check if a profile can be selected for actions (delete, move group, etc.)
|
||||
*/
|
||||
const canSelectProfile = useCallback(
|
||||
(profile: BrowserProfile): boolean => {
|
||||
if (!isClient) return false;
|
||||
|
||||
const isBrowserUpdating = isUpdating?.(profile.browser) ?? false;
|
||||
|
||||
// If this specific browser is updating or downloading, block selection
|
||||
if (isBrowserUpdating) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
[isClient, isUpdating],
|
||||
);
|
||||
|
||||
/**
|
||||
* Get tooltip content for a profile's launch button
|
||||
*/
|
||||
const getLaunchTooltipContent = useCallback(
|
||||
(profile: BrowserProfile): string => {
|
||||
if (!isClient) return "Loading...";
|
||||
|
||||
const isRunning = runningProfiles.has(profile.name);
|
||||
const isBrowserUpdating = isUpdating?.(profile.browser) ?? false;
|
||||
|
||||
if (isRunning) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (isBrowserUpdating) {
|
||||
return `${getBrowserDisplayName(profile.browser)} is being updated. Please wait for the update to complete.`;
|
||||
}
|
||||
|
||||
if (
|
||||
isSingleInstanceBrowser(profile.browser) &&
|
||||
!canLaunchProfile(profile)
|
||||
) {
|
||||
const browserDisplayName =
|
||||
profile.browser === "tor-browser" ? "TOR" : "Mullvad";
|
||||
return `Only one ${browserDisplayName} browser instance can run at a time. Stop the running ${browserDisplayName} browser first.`;
|
||||
}
|
||||
|
||||
return "";
|
||||
},
|
||||
[
|
||||
runningProfiles,
|
||||
isClient,
|
||||
isUpdating,
|
||||
isSingleInstanceBrowser,
|
||||
canLaunchProfile,
|
||||
],
|
||||
);
|
||||
|
||||
/**
|
||||
* Get tooltip content for profile selection (for opening links)
|
||||
*/
|
||||
const getProfileTooltipContent = useCallback(
|
||||
(profile: BrowserProfile): string | null => {
|
||||
if (!isClient) return null;
|
||||
|
||||
const canUseForLinks = canUseProfileForLinks(profile);
|
||||
|
||||
if (canUseForLinks) return null;
|
||||
|
||||
const isBrowserUpdating = isUpdating?.(profile.browser) ?? false;
|
||||
|
||||
if (isBrowserUpdating) {
|
||||
return `${getBrowserDisplayName(profile.browser)} is being updated. Please wait for the update to complete.`;
|
||||
}
|
||||
|
||||
if (isSingleInstanceBrowser(profile.browser)) {
|
||||
const browserDisplayName =
|
||||
profile.browser === "tor-browser" ? "TOR" : "Mullvad";
|
||||
const runningInstancesOfType = profiles.filter(
|
||||
(p) => p.browser === profile.browser && runningProfiles.has(p.name),
|
||||
);
|
||||
|
||||
if (runningInstancesOfType.length > 0) {
|
||||
const runningProfileNames = runningInstancesOfType
|
||||
.map((p) => p.name)
|
||||
.join(", ");
|
||||
return `${browserDisplayName} browser is already running (${runningProfileNames}). Only one instance can run at a time.`;
|
||||
}
|
||||
}
|
||||
|
||||
return "This profile cannot be used for opening links right now.";
|
||||
},
|
||||
[
|
||||
profiles,
|
||||
runningProfiles,
|
||||
isClient,
|
||||
canUseProfileForLinks,
|
||||
isSingleInstanceBrowser,
|
||||
isUpdating,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
isClient,
|
||||
isSingleInstanceBrowser,
|
||||
isAnyInstanceRunning,
|
||||
canLaunchProfile,
|
||||
canUseProfileForLinks,
|
||||
canSelectProfile,
|
||||
getLaunchTooltipContent,
|
||||
getProfileTooltipContent,
|
||||
};
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { useCallback, useEffect, useState } from "react";
|
||||
import { getBrowserDisplayName } from "@/lib/browser-utils";
|
||||
import type { BrowserProfile } from "@/types";
|
||||
import { useEffect, useState } from "react";
|
||||
|
||||
export function useBrowserSupport() {
|
||||
const [supportedBrowsers, setSupportedBrowsers] = useState<string[]>([]);
|
||||
@@ -53,224 +51,3 @@ export function useBrowserSupport() {
|
||||
checkBrowserSupport,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Hook for managing browser state and enforcing single-instance rules for Tor and Mullvad browsers
|
||||
*/
|
||||
export function useBrowserState(
|
||||
profiles: BrowserProfile[],
|
||||
runningProfiles: Set<string>,
|
||||
isUpdating?: (browser: string) => boolean,
|
||||
) {
|
||||
const [isClient, setIsClient] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
setIsClient(true);
|
||||
}, []);
|
||||
|
||||
/**
|
||||
* Check if a browser type allows only one instance to run at a time
|
||||
*/
|
||||
const isSingleInstanceBrowser = useCallback(
|
||||
(browserType: string): boolean => {
|
||||
return browserType === "tor-browser" || browserType === "mullvad-browser";
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
/**
|
||||
* Check if any instance of a specific browser type is currently running
|
||||
*/
|
||||
const isAnyInstanceRunning = useCallback(
|
||||
(browserType: string): boolean => {
|
||||
if (!isClient) return false;
|
||||
return profiles.some(
|
||||
(p) => p.browser === browserType && runningProfiles.has(p.name),
|
||||
);
|
||||
},
|
||||
[profiles, runningProfiles, isClient],
|
||||
);
|
||||
|
||||
/**
|
||||
* Check if a profile can be launched (not disabled by single-instance rules)
|
||||
*/
|
||||
const canLaunchProfile = useCallback(
|
||||
(profile: BrowserProfile): boolean => {
|
||||
if (!isClient) return false;
|
||||
|
||||
const isRunning = runningProfiles.has(profile.name);
|
||||
const isBrowserUpdating = isUpdating?.(profile.browser) ?? false;
|
||||
|
||||
// If the profile is already running, it can always be stopped
|
||||
if (isRunning) return true;
|
||||
|
||||
// If THIS specific browser is updating or downloading, block this profile
|
||||
if (isBrowserUpdating) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// For single-instance browsers, check if any instance is running
|
||||
if (isSingleInstanceBrowser(profile.browser)) {
|
||||
return !isAnyInstanceRunning(profile.browser);
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
[
|
||||
runningProfiles,
|
||||
isClient,
|
||||
isUpdating,
|
||||
isSingleInstanceBrowser,
|
||||
isAnyInstanceRunning,
|
||||
],
|
||||
);
|
||||
|
||||
/**
|
||||
* Check if a profile can be used for opening links
|
||||
* This is more restrictive than canLaunchProfile as it considers running state
|
||||
*/
|
||||
const canUseProfileForLinks = useCallback(
|
||||
(profile: BrowserProfile): boolean => {
|
||||
if (!isClient) return false;
|
||||
|
||||
const isRunning = runningProfiles.has(profile.name);
|
||||
const isBrowserUpdating = isUpdating?.(profile.browser) ?? false;
|
||||
|
||||
// If this specific browser is updating or downloading, block it
|
||||
if (isBrowserUpdating) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// For single-instance browsers (Tor and Mullvad)
|
||||
if (isSingleInstanceBrowser(profile.browser)) {
|
||||
const runningInstancesOfType = profiles.filter(
|
||||
(p) => p.browser === profile.browser && runningProfiles.has(p.name),
|
||||
);
|
||||
|
||||
// If no instances are running, any profile of this type can be used
|
||||
if (runningInstancesOfType.length === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If instances are running, only the running ones can be used
|
||||
return isRunning;
|
||||
}
|
||||
|
||||
// For other browsers, any profile can be used
|
||||
return true;
|
||||
},
|
||||
[profiles, runningProfiles, isClient, isSingleInstanceBrowser, isUpdating],
|
||||
);
|
||||
|
||||
/**
|
||||
* Check if a profile can be selected for actions (delete, move group, etc.)
|
||||
*/
|
||||
const canSelectProfile = useCallback(
|
||||
(profile: BrowserProfile): boolean => {
|
||||
if (!isClient) return false;
|
||||
|
||||
const isBrowserUpdating = isUpdating?.(profile.browser) ?? false;
|
||||
|
||||
// If this specific browser is updating or downloading, block selection
|
||||
if (isBrowserUpdating) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
},
|
||||
[isClient, isUpdating],
|
||||
);
|
||||
|
||||
/**
|
||||
* Get tooltip content for a profile's launch button
|
||||
*/
|
||||
const getLaunchTooltipContent = useCallback(
|
||||
(profile: BrowserProfile): string => {
|
||||
if (!isClient) return "Loading...";
|
||||
|
||||
const isRunning = runningProfiles.has(profile.name);
|
||||
const isBrowserUpdating = isUpdating?.(profile.browser) ?? false;
|
||||
|
||||
if (isRunning) {
|
||||
return "";
|
||||
}
|
||||
|
||||
if (isBrowserUpdating) {
|
||||
return `${getBrowserDisplayName(profile.browser)} is being updated. Please wait for the update to complete.`;
|
||||
}
|
||||
|
||||
if (
|
||||
isSingleInstanceBrowser(profile.browser) &&
|
||||
!canLaunchProfile(profile)
|
||||
) {
|
||||
const browserDisplayName =
|
||||
profile.browser === "tor-browser" ? "TOR" : "Mullvad";
|
||||
return `Only one ${browserDisplayName} browser instance can run at a time. Stop the running ${browserDisplayName} browser first.`;
|
||||
}
|
||||
|
||||
return "";
|
||||
},
|
||||
[
|
||||
runningProfiles,
|
||||
isClient,
|
||||
isUpdating,
|
||||
isSingleInstanceBrowser,
|
||||
canLaunchProfile,
|
||||
],
|
||||
);
|
||||
|
||||
/**
|
||||
* Get tooltip content for profile selection (for opening links)
|
||||
*/
|
||||
const getProfileTooltipContent = useCallback(
|
||||
(profile: BrowserProfile): string | null => {
|
||||
if (!isClient) return null;
|
||||
|
||||
const canUseForLinks = canUseProfileForLinks(profile);
|
||||
|
||||
if (canUseForLinks) return null;
|
||||
|
||||
const isBrowserUpdating = isUpdating?.(profile.browser) ?? false;
|
||||
|
||||
if (isBrowserUpdating) {
|
||||
return `${getBrowserDisplayName(profile.browser)} is being updated. Please wait for the update to complete.`;
|
||||
}
|
||||
|
||||
if (isSingleInstanceBrowser(profile.browser)) {
|
||||
const browserDisplayName =
|
||||
profile.browser === "tor-browser" ? "TOR" : "Mullvad";
|
||||
const runningInstancesOfType = profiles.filter(
|
||||
(p) => p.browser === profile.browser && runningProfiles.has(p.name),
|
||||
);
|
||||
|
||||
if (runningInstancesOfType.length > 0) {
|
||||
const runningProfileNames = runningInstancesOfType
|
||||
.map((p) => p.name)
|
||||
.join(", ");
|
||||
return `${browserDisplayName} browser is already running (${runningProfileNames}). Only one instance can run at a time.`;
|
||||
}
|
||||
}
|
||||
|
||||
return "This profile cannot be used for opening links right now.";
|
||||
},
|
||||
[
|
||||
profiles,
|
||||
runningProfiles,
|
||||
isClient,
|
||||
canUseProfileForLinks,
|
||||
isSingleInstanceBrowser,
|
||||
isUpdating,
|
||||
],
|
||||
);
|
||||
|
||||
return {
|
||||
isClient,
|
||||
isSingleInstanceBrowser,
|
||||
isAnyInstanceRunning,
|
||||
canLaunchProfile,
|
||||
canUseProfileForLinks,
|
||||
canSelectProfile,
|
||||
getLaunchTooltipContent,
|
||||
getProfileTooltipContent,
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user