implement what's new

closes #669
pull/2575/head
Mikael Finstad 9 months ago
parent 25110621f0
commit 251106fbdf
No known key found for this signature in database
GPG Key ID: 25AB36E3E81CBC26

@ -97,6 +97,7 @@ const defaultKeyBindings: KeyBinding[] = [
const defaults: Config = { const defaults: Config = {
version: 1, version: 1,
lastAppVersion: app.getVersion(),
captureFormat: 'jpeg', captureFormat: 'jpeg',
customOutDir: undefined, customOutDir: undefined,
keyframeCut: true, keyframeCut: true,

@ -106,6 +106,7 @@ import ErrorDialog from './components/ErrorDialog';
import useErrorHandling from './hooks/useErrorHandling'; import useErrorHandling from './hooks/useErrorHandling';
import GenericDialog, { useDialog } from './components/GenericDialog'; import GenericDialog, { useDialog } from './components/GenericDialog';
import useHtml5ify from './hooks/useHtml5ify'; import useHtml5ify from './hooks/useHtml5ify';
import WhatsNew from './components/WhatsNew';
const electron = window.require('electron'); const electron = window.require('electron');
const { exists } = window.require('fs-extra'); const { exists } = window.require('fs-extra');
@ -2779,6 +2780,8 @@ function App() {
<GenericDialog dialog={genericDialog} onOpenChange={(open) => !open && closeGenericDialog()} /> <GenericDialog dialog={genericDialog} onOpenChange={(open) => !open && closeGenericDialog()} />
<WhatsNew />
<ErrorDialog error={genericError} onOpenChange={(open) => !open && setGenericError(undefined)} /> <ErrorDialog error={genericError} onOpenChange={(open) => !open && setGenericError(undefined)} />
</div> </div>

@ -0,0 +1,66 @@
import { useEffect, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import semver from 'semver';
import { FaCode, FaFile } from 'react-icons/fa';
import * as Dialog from './Dialog';
import useUserSettings from '../hooks/useUserSettings';
import { appVersion, isMasBuild } from '../util';
import versions from '../versions';
import Button from './Button';
const remote = window.require('@electron/remote');
const { shell } = remote;
export default function WhatsNew() {
const { t } = useTranslation();
const { lastAppVersion, setLastAppVersion } = useUserSettings();
const [initialLastAppVersion] = useState(lastAppVersion);
useEffect(() => {
//setLastAppVersion(appVersion);
}, [setLastAppVersion]);
const matchingVersions = useMemo(() => versions
.filter(({ version }) => semver.gt(version, initialLastAppVersion) && semver.lte(version, appVersion))
.sort(({ version: a }, { version: b }) => semver.compare(b, a)), [initialLastAppVersion]);
if (initialLastAppVersion === appVersion) return null;
return (
<Dialog.Root defaultOpen>
<Dialog.Portal>
<Dialog.Overlay />
<Dialog.Content style={{ width: '60em' }} aria-describedby={undefined}>
<Dialog.Title>
{t('What\'s new in LosslessCut?')}
</Dialog.Title>
<div>
{matchingVersions.map(({ version, highlights }, i) => {
// +1 because reverse order
const prevVersion = matchingVersions[i + 1]?.version ?? initialLastAppVersion;
return (
<div key={version}>
{!(isMasBuild && matchingVersions.length === 1) && <h2>v{version}</h2>}
<ul>
{highlights?.map((h) => (
<li key={h}>{h}</li>
))}
</ul>
<Button style={{ padding: '.5em 1em' }} onClick={() => shell.openExternal(`https://github.com/mifi/lossless-cut/releases/tag/v${version}`)}><FaFile style={{ verticalAlign: 'middle' }} /> {t('All release notes')}</Button>
<Button style={{ padding: '.5em 1em' }} onClick={() => shell.openExternal(`https://github.com/mifi/lossless-cut/compare/v${prevVersion}...v${version}`)}><FaCode style={{ verticalAlign: 'middle' }} /> {t('All code changes')}</Button>
</div>
);
})}
</div>
<Dialog.CloseButton />
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
);
}

@ -49,6 +49,8 @@ export default function useUserSettingsRoot() {
// Without this there was a huge performance issue https://github.com/mifi/lossless-cut/issues/1097 // Without this there was a huge performance issue https://github.com/mifi/lossless-cut/issues/1097
const safeGetConfigInitial = <T extends keyof Config>(key: T) => () => safeGetConfig(key); const safeGetConfigInitial = <T extends keyof Config>(key: T) => () => safeGetConfig(key);
const [lastAppVersion, setLastAppVersion] = useState(safeGetConfigInitial('lastAppVersion'));
useEffect(() => safeSetConfig({ lastAppVersion }), [lastAppVersion]);
const [captureFormat, setCaptureFormat] = useState(safeGetConfigInitial('captureFormat')); const [captureFormat, setCaptureFormat] = useState(safeGetConfigInitial('captureFormat'));
useEffect(() => safeSetConfig({ captureFormat }), [captureFormat]); useEffect(() => safeSetConfig({ captureFormat }), [captureFormat]);
const [customOutDir, setCustomOutDir] = useState(safeGetConfigInitial('customOutDir')); const [customOutDir, setCustomOutDir] = useState(safeGetConfigInitial('customOutDir'));
@ -222,6 +224,7 @@ export default function useUserSettingsRoot() {
const springAnimation = useMemo<Transition>(() => (prefersReducedMotion ? { duration: 0 } : mySpring), [prefersReducedMotion]); const springAnimation = useMemo<Transition>(() => (prefersReducedMotion ? { duration: 0 } : mySpring), [prefersReducedMotion]);
const settings = { const settings = {
lastAppVersion,
captureFormat, captureFormat,
customOutDir, customOutDir,
keyframeCut, keyframeCut,
@ -297,6 +300,7 @@ export default function useUserSettingsRoot() {
return { return {
settings, settings,
setLastAppVersion,
setCaptureFormat, setCaptureFormat,
setCustomOutDir, setCustomOutDir,
setKeyframeCut, setKeyframeCut,

@ -0,0 +1,18 @@
const versions: { version: string, highlights?: string[] }[] = [
{
version: '3.66.1',
highlights: [
'‼️ Upgraded Electron to 38 - They dropped support for macOS 11',
'🆕 Markers: Segments that don\'t have any end time are now considered "markers". They are rendered differently, and are excluded from exports. Markers can be useful for bookmarking locations on the timeline and all markers can be batch exported as screenshots.',
'🔈 Play multiple audio tracks simultaneously (with FFmpeg-assisted playback)',
'✅ Remember segment selected/deselected state inside .llc file',
'💿 Split timeline by byte size',
'Upgraded FFmpeg to 8.0',
],
},
{
version: '3.64.0',
},
];
export default versions;

@ -54,6 +54,7 @@ export type FixCodecTagOption = 'always' | 'never' | 'auto';
export interface Config { export interface Config {
version: number, version: number,
lastAppVersion: string,
captureFormat: CaptureFormat, captureFormat: CaptureFormat,
customOutDir: string | undefined, customOutDir: string | undefined,
keyframeCut: boolean, keyframeCut: boolean,

Loading…
Cancel
Save