Add native titlebar & fix app restart for AppImages

This commit is contained in:
Gelaechter 2023-05-24 17:35:04 +02:00 committed by Jeff
parent d055ae89e0
commit a878875f83
12 changed files with 82 additions and 23 deletions

View file

@ -183,8 +183,12 @@ const createWindow = async () => {
await installExtensions(); await installExtensions();
} }
const nativeFrame = store.get('window_window_bar_style') === 'linux';
store.set('window_has_frame', nativeFrame);
mainWindow = new BrowserWindow({ mainWindow = new BrowserWindow({
frame: false, autoHideMenuBar: nativeFrame,
frame: nativeFrame,
height: 900, height: 900,
icon: getAssetPath('icon.png'), icon: getAssetPath('icon.png'),
minHeight: 600, minHeight: 600,
@ -229,8 +233,18 @@ const createWindow = async () => {
}); });
ipcMain.on('app-restart', () => { ipcMain.on('app-restart', () => {
// Fix for .AppImage
if (process.env.APPIMAGE) {
app.exit();
app.relaunch({
args: process.argv.slice(1).concat(['--appimage-extract-and-run']),
execPath: process.env.APPIMAGE,
});
app.exit(0);
} else {
app.relaunch(); app.relaunch();
app.exit(0); app.exit(0);
}
}); });
ipcMain.on('global-media-keys-enable', () => { ipcMain.on('global-media-keys-enable', () => {

View file

@ -34,12 +34,16 @@ const StyledNativeScrollArea = styled.div<{ scrollBarOffset?: string; windowBarS
&::-webkit-scrollbar-track { &::-webkit-scrollbar-track {
margin-top: ${(props) => margin-top: ${(props) =>
props.windowBarStyle !== Platform.WEB ? '0px' : props.scrollBarOffset || '65px'}; props.windowBarStyle === Platform.WINDOWS || props.windowBarStyle === Platform.MACOS
? '0px'
: props.scrollBarOffset || '65px'};
} }
&::-webkit-scrollbar-thumb { &::-webkit-scrollbar-thumb {
margin-top: ${(props) => margin-top: ${(props) =>
props.windowBarStyle !== Platform.WEB ? '0px' : props.scrollBarOffset || '65px'}; props.windowBarStyle === Platform.WINDOWS || props.windowBarStyle === Platform.MACOS
? '0px'
: props.scrollBarOffset || '65px'};
} }
`; `;

View file

@ -9,7 +9,10 @@ export const useFixedTableHeader = () => {
const { windowBarStyle } = useWindowSettings(); const { windowBarStyle } = useWindowSettings();
const isNotPastTableIntersection = useInView(intersectRef, { const isNotPastTableIntersection = useInView(intersectRef, {
margin: windowBarStyle === Platform.WEB ? '-68px 0px 0px 0px' : '-98px 0px 0px 0px', margin:
windowBarStyle === Platform.WEB || windowBarStyle === Platform.LINUX
? '-68px 0px 0px 0px'
: '-98px 0px 0px 0px',
}); });
const tableInView = useInView(tableContainerRef, { const tableInView = useInView(tableContainerRef, {
@ -21,13 +24,13 @@ export const useFixedTableHeader = () => {
const root = document.querySelector('main .ag-root'); const root = document.querySelector('main .ag-root');
if (isNotPastTableIntersection || !tableInView) { if (isNotPastTableIntersection || !tableInView) {
if (windowBarStyle !== Platform.WEB) { if (windowBarStyle === Platform.WINDOWS || windowBarStyle === Platform.MACOS) {
header?.classList.remove('window-frame'); header?.classList.remove('window-frame');
} }
header?.classList.remove('ag-header-fixed'); header?.classList.remove('ag-header-fixed');
root?.classList.remove('ag-header-fixed-margin'); root?.classList.remove('ag-header-fixed-margin');
} else { } else {
if (windowBarStyle !== Platform.WEB) { if (windowBarStyle === Platform.WINDOWS || windowBarStyle === Platform.MACOS) {
header?.classList.add('window-frame'); header?.classList.add('window-frame');
} }
header?.classList.add('ag-header-fixed'); header?.classList.add('ag-header-fixed');

View file

@ -138,7 +138,9 @@ const HomeRoute = () => {
<Box <Box
ref={cq.ref} ref={cq.ref}
mb="5rem" mb="5rem"
pt={windowBarStyle === Platform.WEB ? '5rem' : '3rem'} pt={
windowBarStyle === Platform.WEB || windowBarStyle === Platform.LINUX ? '5rem' : '3rem'
}
px="2rem" px="2rem"
> >
<Stack spacing="lg"> <Stack spacing="lg">

View file

@ -13,16 +13,17 @@ export const SidebarPlayQueue = () => {
const queueRef = useRef<{ grid: AgGridReactType<Song> } | null>(null); const queueRef = useRef<{ grid: AgGridReactType<Song> } | null>(null);
const { windowBarStyle } = useWindowSettings(); const { windowBarStyle } = useWindowSettings();
const webOrNative = windowBarStyle === Platform.WEB || windowBarStyle === Platform.LINUX;
return ( return (
<VirtualGridContainer> <VirtualGridContainer>
{windowBarStyle === Platform.WEB && ( {webOrNative && (
<Stack mr={windowBarStyle === Platform.WEB ? '130px' : undefined}> <Stack mr={webOrNative ? '130px' : undefined}>
<PageHeader backgroundColor="var(--titlebar-bg)" /> <PageHeader backgroundColor="var(--titlebar-bg)" />
</Stack> </Stack>
)} )}
<Paper <Paper
display={windowBarStyle !== Platform.WEB ? 'flex' : undefined} display={!webOrNative ? 'flex' : undefined}
h={windowBarStyle !== Platform.WEB ? '65px' : undefined} h={!webOrNative ? '65px' : undefined}
> >
<PlayQueueListControls <PlayQueueListControls
tableRef={queueRef} tableRef={queueRef}

View file

@ -129,7 +129,10 @@ const containerVariants: Variants = {
closed: (custom) => { closed: (custom) => {
const { windowBarStyle } = custom; const { windowBarStyle } = custom;
return { return {
height: windowBarStyle !== Platform.WEB ? 'calc(100vh - 120px)' : 'calc(100vh - 90px)', height:
windowBarStyle === Platform.WINDOWS || windowBarStyle === Platform.MACOS
? 'calc(100vh - 120px)'
: 'calc(100vh - 90px)',
position: 'absolute', position: 'absolute',
top: '100vh', top: '100vh',
transition: { transition: {
@ -144,7 +147,10 @@ const containerVariants: Variants = {
const { dynamicBackground, background, windowBarStyle } = custom; const { dynamicBackground, background, windowBarStyle } = custom;
return { return {
background: dynamicBackground ? background : 'var(--main-bg)', background: dynamicBackground ? background : 'var(--main-bg)',
height: windowBarStyle !== Platform.WEB ? 'calc(100vh - 120px)' : 'calc(100vh - 90px)', height:
windowBarStyle === Platform.WINDOWS || windowBarStyle === Platform.MACOS
? 'calc(100vh - 120px)'
: 'calc(100vh - 90px)',
left: 0, left: 0,
position: 'absolute', position: 'absolute',
top: 0, top: 0,

View file

@ -5,12 +5,13 @@ import {
SettingsSection, SettingsSection,
SettingOption, SettingOption,
} from '/@/renderer/features/settings/components/settings-section'; } from '/@/renderer/features/settings/components/settings-section';
import { Select, Switch } from '/@/renderer/components'; import { Select, Switch, toast } from '/@/renderer/components';
const WINDOW_BAR_OPTIONS = [ const WINDOW_BAR_OPTIONS = [
{ label: 'Web (hidden)', value: Platform.WEB }, { label: 'Web (hidden)', value: Platform.WEB },
{ label: 'Windows', value: Platform.WINDOWS }, { label: 'Windows', value: Platform.WINDOWS },
{ label: 'macOS', value: Platform.MACOS }, { label: 'macOS', value: Platform.MACOS },
{ label: 'Native', value: Platform.LINUX },
]; ];
const localSettings = isElectron() ? window.electron.localSettings : null; const localSettings = isElectron() ? window.electron.localSettings : null;
@ -28,6 +29,26 @@ export const WindowSettings = () => {
value={settings.windowBarStyle} value={settings.windowBarStyle}
onChange={(e) => { onChange={(e) => {
if (!e) return; if (!e) return;
// warn that a restart is required
if (
(localSettings?.get('window_has_frame') && e !== Platform.LINUX) ||
(!localSettings?.get('window_has_frame') && e === Platform.LINUX)
) {
toast.info({
autoClose: false,
id: 'restart-toast',
message: 'Restart to apply changes... close the notification to restart Feishin',
onClose: () => {
window.electron.ipc.send('app-restart');
},
title: 'Restart required',
});
} else {
toast.update({ autoClose: 0, id: 'restart-toast', message: '', onClose: () => {} }); // clean old toasts
}
localSettings?.set('window_window_bar_style', e as Platform);
setSettings({ setSettings({
window: { window: {
...settings, ...settings,

View file

@ -34,7 +34,7 @@ const SidebarContainer = styled(motion.div)<{ windowBarStyle: Platform }>`
flex-direction: column; flex-direction: column;
height: 100%; height: 100%;
max-height: ${(props) => max-height: ${(props) =>
props.windowBarStyle === Platform.WEB props.windowBarStyle === Platform.WEB || props.windowBarStyle === Platform.LINUX
? 'calc(100vh - 149px)' ? 'calc(100vh - 149px)'
: 'calc(100vh - 119px)'}; // Playerbar (90px), titlebar (65px), windowbar (30px) : 'calc(100vh - 119px)'}; // Playerbar (90px), titlebar (65px), windowbar (30px)
user-select: none; user-select: none;

View file

@ -45,7 +45,7 @@ import { useWindowSettings } from '../../../store/settings.store';
const SidebarContainer = styled.div<{ windowBarStyle: Platform }>` const SidebarContainer = styled.div<{ windowBarStyle: Platform }>`
height: 100%; height: 100%;
max-height: ${(props) => max-height: ${(props) =>
props.windowBarStyle === Platform.WEB props.windowBarStyle === Platform.WEB || props.windowBarStyle === Platform.LINUX
? 'calc(100vh - 149px)' ? 'calc(100vh - 149px)'
: 'calc(100vh - 179px)'}; // Playerbar (90px), titlebar (65px), windowbar (30px) : 'calc(100vh - 179px)'}; // Playerbar (90px), titlebar (65px), windowbar (30px)
user-select: none; user-select: none;

View file

@ -29,7 +29,7 @@ const Layout = styled.div<{ windowBarStyle: Platform }>`
'main-content' 'main-content'
'player'; 'player';
grid-template-rows: ${(props) => grid-template-rows: ${(props) =>
props.windowBarStyle !== Platform.WEB props.windowBarStyle === Platform.WINDOWS || props.windowBarStyle === Platform.MACOS
? '30px calc(100vh - 120px) 90px' ? '30px calc(100vh - 120px) 90px'
: '0px calc(100vh - 90px) 90px'}; : '0px calc(100vh - 90px) 90px'};
grid-template-columns: 1fr; grid-template-columns: 1fr;

View file

@ -104,7 +104,10 @@ const QueueDrawerArea = styled(motion.div)`
const queueDrawerVariants: Variants = { const queueDrawerVariants: Variants = {
closed: (windowBarStyle) => ({ closed: (windowBarStyle) => ({
height: windowBarStyle !== Platform.WEB ? 'calc(100vh - 205px)' : 'calc(100vh - 175px)', height:
windowBarStyle === Platform.WINDOWS || Platform.MACOS
? 'calc(100vh - 205px)'
: 'calc(100vh - 175px)',
position: 'absolute', position: 'absolute',
right: 0, right: 0,
top: '75px', top: '75px',
@ -117,7 +120,10 @@ const queueDrawerVariants: Variants = {
}), }),
open: (windowBarStyle) => ({ open: (windowBarStyle) => ({
boxShadow: '0px 0px 10px 0px rgba(0, 0, 0, 0.8)', boxShadow: '0px 0px 10px 0px rgba(0, 0, 0, 0.8)',
height: windowBarStyle !== Platform.WEB ? 'calc(100vh - 205px)' : 'calc(100vh - 175px)', height:
windowBarStyle === Platform.WINDOWS || Platform.MACOS
? 'calc(100vh - 205px)'
: 'calc(100vh - 175px)',
position: 'absolute', position: 'absolute',
right: '20px', right: '20px',
top: '75px', top: '75px',

View file

@ -219,6 +219,7 @@ export const WindowBar = () => {
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 ? `${statusString}${queueString}${currentSong?.name}` : 'Feishin'; const title = length ? `${statusString}${queueString}${currentSong?.name}` : 'Feishin';
document.title = title;
const [max, setMax] = useState(false); const [max, setMax] = useState(false);
@ -237,12 +238,13 @@ export const WindowBar = () => {
return ( return (
<> <>
{windowBarStyle === Platform.WINDOWS ? ( {windowBarStyle === Platform.WINDOWS && (
<WindowsControls <WindowsControls
controls={{ handleClose, handleMaximize, handleMinimize }} controls={{ handleClose, handleMaximize, handleMinimize }}
title={title} title={title}
/> />
) : ( )}
{windowBarStyle === Platform.MACOS && (
<MacOsControls <MacOsControls
controls={{ handleClose, handleMaximize, handleMinimize }} controls={{ handleClose, handleMaximize, handleMinimize }}
title={title} title={title}