mirror of
https://github.com/antebudimir/feishin.git
synced 2025-12-31 18:13:31 +00:00
Merge pull request #1034 from Lyall-A/private-mode
add private mode toggle to app menu
This commit is contained in:
commit
59065d24bc
7 changed files with 81 additions and 20 deletions
|
|
@ -288,6 +288,11 @@
|
||||||
"updateServer": {
|
"updateServer": {
|
||||||
"success": "server updated successfully",
|
"success": "server updated successfully",
|
||||||
"title": "update server"
|
"title": "update server"
|
||||||
|
},
|
||||||
|
"privateMode": {
|
||||||
|
"enabled": "private mode enabled, playback status is now hidden from external integrations",
|
||||||
|
"disabled": "private mode disabled, playback status is now visible to enabled external integrations",
|
||||||
|
"title": "private mode"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"page": {
|
"page": {
|
||||||
|
|
@ -321,6 +326,8 @@
|
||||||
"goBack": "go back",
|
"goBack": "go back",
|
||||||
"goForward": "go forward",
|
"goForward": "go forward",
|
||||||
"manageServers": "manage servers",
|
"manageServers": "manage servers",
|
||||||
|
"privateModeOff": "turn off private mode",
|
||||||
|
"privateModeOn": "turn on private mode",
|
||||||
"openBrowserDevtools": "open browser devtools",
|
"openBrowserDevtools": "open browser devtools",
|
||||||
"quit": "$t(common.quit)",
|
"quit": "$t(common.quit)",
|
||||||
"selectServer": "select server",
|
"selectServer": "select server",
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@ import { controller } from '/@/renderer/api/controller';
|
||||||
import {
|
import {
|
||||||
DiscordDisplayType,
|
DiscordDisplayType,
|
||||||
getServerById,
|
getServerById,
|
||||||
|
useAppStore,
|
||||||
useDiscordSetttings,
|
useDiscordSetttings,
|
||||||
useGeneralSettings,
|
useGeneralSettings,
|
||||||
usePlayerStore,
|
usePlayerStore,
|
||||||
|
|
@ -18,6 +19,7 @@ const discordRpc = isElectron() ? window.api.discordRpc : null;
|
||||||
export const useDiscordRpc = () => {
|
export const useDiscordRpc = () => {
|
||||||
const discordSettings = useDiscordSetttings();
|
const discordSettings = useDiscordSetttings();
|
||||||
const generalSettings = useGeneralSettings();
|
const generalSettings = useGeneralSettings();
|
||||||
|
const { privateMode } = useAppStore();
|
||||||
const [lastUniqueId, setlastUniqueId] = useState('');
|
const [lastUniqueId, setlastUniqueId] = useState('');
|
||||||
|
|
||||||
const setActivity = useCallback(
|
const setActivity = useCallback(
|
||||||
|
|
@ -148,15 +150,15 @@ export const useDiscordRpc = () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!discordSettings.enabled) return discordRpc?.quit();
|
if (!discordSettings.enabled || privateMode) return discordRpc?.quit();
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
discordRpc?.quit();
|
discordRpc?.quit();
|
||||||
};
|
};
|
||||||
}, [discordSettings.clientId, discordSettings.enabled]);
|
}, [discordSettings.clientId, privateMode, discordSettings.enabled]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!discordSettings.enabled) return;
|
if (!discordSettings.enabled || privateMode) return;
|
||||||
const unsubSongChange = usePlayerStore.subscribe(
|
const unsubSongChange = usePlayerStore.subscribe(
|
||||||
(state) => [state.current.song, state.current.time, state.current.status],
|
(state) => [state.current.song, state.current.time, state.current.status],
|
||||||
setActivity,
|
setActivity,
|
||||||
|
|
@ -164,5 +166,5 @@ export const useDiscordRpc = () => {
|
||||||
return () => {
|
return () => {
|
||||||
unsubSongChange();
|
unsubSongChange();
|
||||||
};
|
};
|
||||||
}, [discordSettings.enabled, setActivity]);
|
}, [discordSettings.enabled, privateMode, setActivity]);
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,7 @@
|
||||||
import { useCallback, useEffect, useRef, useState } from 'react';
|
import { useCallback, useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { useSendScrobble } from '/@/renderer/features/player/mutations/scrobble-mutation';
|
import { useSendScrobble } from '/@/renderer/features/player/mutations/scrobble-mutation';
|
||||||
import { usePlayerStore } from '/@/renderer/store';
|
import { useAppStore, usePlaybackSettings, usePlayerStore } from '/@/renderer/store';
|
||||||
import { usePlaybackSettings } from '/@/renderer/store/settings.store';
|
|
||||||
import { QueueSong, ServerType } from '/@/shared/types/domain-types';
|
import { QueueSong, ServerType } from '/@/shared/types/domain-types';
|
||||||
import { PlayerStatus } from '/@/shared/types/types';
|
import { PlayerStatus } from '/@/shared/types/types';
|
||||||
|
|
||||||
|
|
@ -59,13 +58,14 @@ const checkScrobbleConditions = (args: {
|
||||||
export const useScrobble = () => {
|
export const useScrobble = () => {
|
||||||
const scrobbleSettings = usePlaybackSettings().scrobble;
|
const scrobbleSettings = usePlaybackSettings().scrobble;
|
||||||
const isScrobbleEnabled = scrobbleSettings?.enabled;
|
const isScrobbleEnabled = scrobbleSettings?.enabled;
|
||||||
|
const isPrivateModeEnabled = useAppStore().privateMode;
|
||||||
const sendScrobble = useSendScrobble();
|
const sendScrobble = useSendScrobble();
|
||||||
|
|
||||||
const [isCurrentSongScrobbled, setIsCurrentSongScrobbled] = useState(false);
|
const [isCurrentSongScrobbled, setIsCurrentSongScrobbled] = useState(false);
|
||||||
|
|
||||||
const handleScrobbleFromSeek = useCallback(
|
const handleScrobbleFromSeek = useCallback(
|
||||||
(currentTime: number) => {
|
(currentTime: number) => {
|
||||||
if (!isScrobbleEnabled) return;
|
if (!isScrobbleEnabled || isPrivateModeEnabled) return;
|
||||||
|
|
||||||
const currentSong = usePlayerStore.getState().current.song;
|
const currentSong = usePlayerStore.getState().current.song;
|
||||||
|
|
||||||
|
|
@ -84,7 +84,7 @@ export const useScrobble = () => {
|
||||||
serverId: currentSong?.serverId,
|
serverId: currentSong?.serverId,
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
[isScrobbleEnabled, sendScrobble],
|
[isScrobbleEnabled, isPrivateModeEnabled, sendScrobble],
|
||||||
);
|
);
|
||||||
|
|
||||||
const progressIntervalId = useRef<null | ReturnType<typeof setInterval>>(null);
|
const progressIntervalId = useRef<null | ReturnType<typeof setInterval>>(null);
|
||||||
|
|
@ -119,7 +119,7 @@ export const useScrobble = () => {
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!isScrobbleEnabled) return;
|
if (!isScrobbleEnabled || isPrivateModeEnabled) return;
|
||||||
|
|
||||||
if (progressIntervalId.current) {
|
if (progressIntervalId.current) {
|
||||||
clearInterval(progressIntervalId.current);
|
clearInterval(progressIntervalId.current);
|
||||||
|
|
@ -201,6 +201,7 @@ export const useScrobble = () => {
|
||||||
scrobbleSettings?.scrobbleAtDuration,
|
scrobbleSettings?.scrobbleAtDuration,
|
||||||
scrobbleSettings?.scrobbleAtPercentage,
|
scrobbleSettings?.scrobbleAtPercentage,
|
||||||
isScrobbleEnabled,
|
isScrobbleEnabled,
|
||||||
|
isPrivateModeEnabled,
|
||||||
isCurrentSongScrobbled,
|
isCurrentSongScrobbled,
|
||||||
sendScrobble,
|
sendScrobble,
|
||||||
handleScrobbleFromSeek,
|
handleScrobbleFromSeek,
|
||||||
|
|
@ -209,7 +210,7 @@ export const useScrobble = () => {
|
||||||
|
|
||||||
const handleScrobbleFromStatusChange = useCallback(
|
const handleScrobbleFromStatusChange = useCallback(
|
||||||
(current: PlayerEvent, previous: PlayerEvent) => {
|
(current: PlayerEvent, previous: PlayerEvent) => {
|
||||||
if (!isScrobbleEnabled) return;
|
if (!isScrobbleEnabled || isPrivateModeEnabled) return;
|
||||||
|
|
||||||
const currentSong = usePlayerStore.getState().current.song;
|
const currentSong = usePlayerStore.getState().current.song;
|
||||||
|
|
||||||
|
|
@ -293,6 +294,7 @@ export const useScrobble = () => {
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
isScrobbleEnabled,
|
isScrobbleEnabled,
|
||||||
|
isPrivateModeEnabled,
|
||||||
sendScrobble,
|
sendScrobble,
|
||||||
handleScrobbleFromSeek,
|
handleScrobbleFromSeek,
|
||||||
scrobbleSettings?.scrobbleAtDuration,
|
scrobbleSettings?.scrobbleAtDuration,
|
||||||
|
|
@ -306,7 +308,7 @@ export const useScrobble = () => {
|
||||||
// need to perform another check to see if the scrobble conditions are met
|
// need to perform another check to see if the scrobble conditions are met
|
||||||
const handleScrobbleFromSongRestart = useCallback(
|
const handleScrobbleFromSongRestart = useCallback(
|
||||||
(currentTime: number) => {
|
(currentTime: number) => {
|
||||||
if (!isScrobbleEnabled) return;
|
if (!isScrobbleEnabled || isPrivateModeEnabled) return;
|
||||||
|
|
||||||
const currentSong = usePlayerStore.getState().current.song;
|
const currentSong = usePlayerStore.getState().current.song;
|
||||||
|
|
||||||
|
|
@ -349,6 +351,7 @@ export const useScrobble = () => {
|
||||||
},
|
},
|
||||||
[
|
[
|
||||||
isScrobbleEnabled,
|
isScrobbleEnabled,
|
||||||
|
isPrivateModeEnabled,
|
||||||
scrobbleSettings?.scrobbleAtDuration,
|
scrobbleSettings?.scrobbleAtDuration,
|
||||||
scrobbleSettings?.scrobbleAtPercentage,
|
scrobbleSettings?.scrobbleAtPercentage,
|
||||||
isCurrentSongScrobbled,
|
isCurrentSongScrobbled,
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ import { ServerList } from '/@/renderer/features/servers';
|
||||||
import { EditServerForm } from '/@/renderer/features/servers/components/edit-server-form';
|
import { EditServerForm } from '/@/renderer/features/servers/components/edit-server-form';
|
||||||
import { AppRoute } from '/@/renderer/router/routes';
|
import { AppRoute } from '/@/renderer/router/routes';
|
||||||
import {
|
import {
|
||||||
|
useAppStore,
|
||||||
useAppStoreActions,
|
useAppStoreActions,
|
||||||
useAuthStoreActions,
|
useAuthStoreActions,
|
||||||
useCurrentServer,
|
useCurrentServer,
|
||||||
|
|
@ -18,6 +19,7 @@ import {
|
||||||
} from '/@/renderer/store';
|
} from '/@/renderer/store';
|
||||||
import { DropdownMenu } from '/@/shared/components/dropdown-menu/dropdown-menu';
|
import { DropdownMenu } from '/@/shared/components/dropdown-menu/dropdown-menu';
|
||||||
import { Icon } from '/@/shared/components/icon/icon';
|
import { Icon } from '/@/shared/components/icon/icon';
|
||||||
|
import { toast } from '/@/shared/components/toast/toast';
|
||||||
import { ServerListItem, ServerType } from '/@/shared/types/domain-types';
|
import { ServerListItem, ServerType } from '/@/shared/types/domain-types';
|
||||||
|
|
||||||
const browser = isElectron() ? window.api.browser : null;
|
const browser = isElectron() ? window.api.browser : null;
|
||||||
|
|
@ -30,7 +32,8 @@ export const AppMenu = () => {
|
||||||
const serverList = useServerList();
|
const serverList = useServerList();
|
||||||
const { setCurrentServer } = useAuthStoreActions();
|
const { setCurrentServer } = useAuthStoreActions();
|
||||||
const { collapsed } = useSidebarStore();
|
const { collapsed } = useSidebarStore();
|
||||||
const { setSideBar } = useAppStoreActions();
|
const { privateMode } = useAppStore();
|
||||||
|
const { setPrivateMode, setSideBar } = useAppStoreActions();
|
||||||
|
|
||||||
const handleSetCurrentServer = (server: ServerListItem) => {
|
const handleSetCurrentServer = (server: ServerListItem) => {
|
||||||
navigate(AppRoute.HOME);
|
navigate(AppRoute.HOME);
|
||||||
|
|
@ -80,6 +83,22 @@ export const AppMenu = () => {
|
||||||
setSideBar({ collapsed: false });
|
setSideBar({ collapsed: false });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handlePrivateModeOff = () => {
|
||||||
|
setPrivateMode(false);
|
||||||
|
toast.info({
|
||||||
|
message: t('form.privateMode.disabled', { postProcess: 'sentenceCase' }),
|
||||||
|
title: t('form.privateMode.title', { postProcess: 'sentenceCase' }),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const handlePrivateModeOn = () => {
|
||||||
|
setPrivateMode(true);
|
||||||
|
toast.info({
|
||||||
|
message: t('form.privateMode.enabled', { postProcess: 'sentenceCase' }),
|
||||||
|
title: t('form.privateMode.title', { postProcess: 'sentenceCase' }),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const handleQuit = () => {
|
const handleQuit = () => {
|
||||||
browser?.quit();
|
browser?.quit();
|
||||||
};
|
};
|
||||||
|
|
@ -127,7 +146,21 @@ export const AppMenu = () => {
|
||||||
>
|
>
|
||||||
{t('page.appMenu.manageServers', { postProcess: 'sentenceCase' })}
|
{t('page.appMenu.manageServers', { postProcess: 'sentenceCase' })}
|
||||||
</DropdownMenu.Item>
|
</DropdownMenu.Item>
|
||||||
|
{privateMode ? (
|
||||||
|
<DropdownMenu.Item
|
||||||
|
leftSection={<Icon color="error" icon="lock" />}
|
||||||
|
onClick={handlePrivateModeOff}
|
||||||
|
>
|
||||||
|
{t('page.appMenu.privateModeOff', { postProcess: 'sentenceCase' })}
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
) : (
|
||||||
|
<DropdownMenu.Item
|
||||||
|
leftSection={<Icon icon="lockOpen" />}
|
||||||
|
onClick={handlePrivateModeOn}
|
||||||
|
>
|
||||||
|
{t('page.appMenu.privateModeOn', { postProcess: 'sentenceCase' })}
|
||||||
|
</DropdownMenu.Item>
|
||||||
|
)}
|
||||||
<DropdownMenu.Divider />
|
<DropdownMenu.Divider />
|
||||||
<DropdownMenu.Label>
|
<DropdownMenu.Label>
|
||||||
{t('page.appMenu.selectServer', { postProcess: 'sentenceCase' })}
|
{t('page.appMenu.selectServer', { postProcess: 'sentenceCase' })}
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,12 @@ import macMinHover from './assets/min-mac-hover.png';
|
||||||
import macMin from './assets/min-mac.png';
|
import macMin from './assets/min-mac.png';
|
||||||
import styles from './window-bar.module.css';
|
import styles from './window-bar.module.css';
|
||||||
|
|
||||||
import { useCurrentStatus, useQueueStatus } from '/@/renderer/store';
|
import {
|
||||||
import { useWindowSettings } from '/@/renderer/store/settings.store';
|
useAppStore,
|
||||||
|
useCurrentStatus,
|
||||||
|
useQueueStatus,
|
||||||
|
useWindowSettings,
|
||||||
|
} from '/@/renderer/store';
|
||||||
import { Text } from '/@/shared/components/text/text';
|
import { Text } from '/@/shared/components/text/text';
|
||||||
import { Platform, PlayerStatus } from '/@/shared/types/types';
|
import { Platform, PlayerStatus } from '/@/shared/types/types';
|
||||||
|
|
||||||
|
|
@ -126,14 +130,16 @@ export const WindowBar = () => {
|
||||||
const playerStatus = useCurrentStatus();
|
const playerStatus = useCurrentStatus();
|
||||||
const { currentSong, index, length } = useQueueStatus();
|
const { currentSong, index, length } = useQueueStatus();
|
||||||
const { windowBarStyle } = useWindowSettings();
|
const { windowBarStyle } = useWindowSettings();
|
||||||
|
const { privateMode } = useAppStore();
|
||||||
|
|
||||||
const statusString = playerStatus === PlayerStatus.PAUSED ? '(Paused) ' : '';
|
const statusString = playerStatus === PlayerStatus.PAUSED ? '(Paused) ' : '';
|
||||||
const queueString = length ? `(${index + 1} / ${length}) ` : '';
|
const queueString = length ? `(${index + 1} / ${length}) ` : '';
|
||||||
const title = length
|
const privateModeString = privateMode ? '(Private mode)' : '';
|
||||||
? currentSong?.artistName
|
const title = `${
|
||||||
? `${statusString}${queueString}${currentSong?.name} — ${currentSong?.artistName}`
|
length
|
||||||
: `${statusString}${queueString}${currentSong?.name}`
|
? `${statusString}${queueString}${currentSong?.name}${currentSong?.artistName ? ` — ${currentSong?.artistName}` : ''}`
|
||||||
: 'Feishin';
|
: 'Feishin'
|
||||||
|
}${privateMode ? ` ${privateModeString}` : ''}`;
|
||||||
document.title = title;
|
document.title = title;
|
||||||
|
|
||||||
const [max, setMax] = useState(localSettings?.env.START_MAXIMIZED || false);
|
const [max, setMax] = useState(localSettings?.env.START_MAXIMIZED || false);
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ import { Platform } from '/@/shared/types/types';
|
||||||
export interface AppSlice extends AppState {
|
export interface AppSlice extends AppState {
|
||||||
actions: {
|
actions: {
|
||||||
setAppStore: (data: Partial<AppSlice>) => void;
|
setAppStore: (data: Partial<AppSlice>) => void;
|
||||||
|
setPrivateMode: (enabled: boolean) => void;
|
||||||
setSideBar: (options: Partial<SidebarProps>) => void;
|
setSideBar: (options: Partial<SidebarProps>) => void;
|
||||||
setTitleBar: (options: Partial<TitlebarProps>) => void;
|
setTitleBar: (options: Partial<TitlebarProps>) => void;
|
||||||
};
|
};
|
||||||
|
|
@ -17,6 +18,7 @@ export interface AppState {
|
||||||
commandPalette: CommandPaletteProps;
|
commandPalette: CommandPaletteProps;
|
||||||
isReorderingQueue: boolean;
|
isReorderingQueue: boolean;
|
||||||
platform: Platform;
|
platform: Platform;
|
||||||
|
privateMode: boolean;
|
||||||
sidebar: SidebarProps;
|
sidebar: SidebarProps;
|
||||||
titlebar: TitlebarProps;
|
titlebar: TitlebarProps;
|
||||||
}
|
}
|
||||||
|
|
@ -50,6 +52,11 @@ export const useAppStore = createWithEqualityFn<AppSlice>()(
|
||||||
setAppStore: (data) => {
|
setAppStore: (data) => {
|
||||||
set({ ...get(), ...data });
|
set({ ...get(), ...data });
|
||||||
},
|
},
|
||||||
|
setPrivateMode: (privateMode) => {
|
||||||
|
set((state) => {
|
||||||
|
state.privateMode = privateMode;
|
||||||
|
});
|
||||||
|
},
|
||||||
setSideBar: (options) => {
|
setSideBar: (options) => {
|
||||||
set((state) => {
|
set((state) => {
|
||||||
state.sidebar = { ...state.sidebar, ...options };
|
state.sidebar = { ...state.sidebar, ...options };
|
||||||
|
|
@ -81,6 +88,7 @@ export const useAppStore = createWithEqualityFn<AppSlice>()(
|
||||||
},
|
},
|
||||||
isReorderingQueue: false,
|
isReorderingQueue: false,
|
||||||
platform: Platform.WINDOWS,
|
platform: Platform.WINDOWS,
|
||||||
|
privateMode: false,
|
||||||
sidebar: {
|
sidebar: {
|
||||||
collapsed: false,
|
collapsed: false,
|
||||||
expanded: [],
|
expanded: [],
|
||||||
|
|
|
||||||
|
|
@ -59,6 +59,7 @@ import {
|
||||||
LuListPlus,
|
LuListPlus,
|
||||||
LuLoader,
|
LuLoader,
|
||||||
LuLock,
|
LuLock,
|
||||||
|
LuLockOpen,
|
||||||
LuLogIn,
|
LuLogIn,
|
||||||
LuLogOut,
|
LuLogOut,
|
||||||
LuMenu,
|
LuMenu,
|
||||||
|
|
@ -163,6 +164,7 @@ export const AppIcon = {
|
||||||
listInfinite: LuInfinity,
|
listInfinite: LuInfinity,
|
||||||
listPaginated: LuArrowRightToLine,
|
listPaginated: LuArrowRightToLine,
|
||||||
lock: LuLock,
|
lock: LuLock,
|
||||||
|
lockOpen: LuLockOpen,
|
||||||
mediaNext: LuSkipForward,
|
mediaNext: LuSkipForward,
|
||||||
mediaPause: LuPause,
|
mediaPause: LuPause,
|
||||||
mediaPlay: LuPlay,
|
mediaPlay: LuPlay,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue