1.0.0-rc4 rc4

This commit is contained in:
2026-06-08 12:15:36 +02:00
parent 1502d4d9d0
commit 6d3c6fed0f
23 changed files with 968 additions and 667 deletions
+148 -43
View File
@@ -665,63 +665,146 @@ function isReadonlySetting(setting) {
}
}
function MakeMKVBetaKeyHint({ onApply, disabled = false }) {
function MakeMKVBetaKeyHint({ disabled = false, onNotify = null, onSettingApplied = null }) {
const [loading, setLoading] = useState(true);
const [checking, setChecking] = useState(false);
const [applying, setApplying] = useState(false);
const [betaKey, setBetaKey] = useState('');
const [validUntil, setValidUntil] = useState('');
const [fetchedAt, setFetchedAt] = useState('');
const [appliedKey, setAppliedKey] = useState('');
const [error, setError] = useState('');
const [warning, setWarning] = useState('');
useEffect(() => {
let active = true;
const loadCachedState = async () => {
setLoading(true);
setError('');
setWarning('');
setValidUntil('');
try {
const response = await api.getMakeMKVBetaKey();
setBetaKey(String(response?.betaKey || '').trim());
setValidUntil(String(response?.validUntil || '').trim());
setFetchedAt(String(response?.fetchedAt || '').trim());
setAppliedKey(String(response?.appliedKey || '').trim());
if (response?.stale) {
setWarning('Zwischengespeicherter Betakey ist veraltet. Bitte bei Bedarf neu prüfen.');
} else if (!response?.betaKey) {
setWarning('Noch kein geprüfter Betakey im Cache. Prüfung startet nur per Button.');
} else if (response?.appliedMatchesCache) {
setWarning('Geprüfter Betakey ist bereits übernommen.');
} else {
setWarning('');
}
} catch (loadError) {
setBetaKey('');
setValidUntil('');
setFetchedAt('');
setAppliedKey('');
setError(loadError?.message || 'Betakey konnte nicht geladen werden.');
} finally {
setLoading(false);
}
};
api.getMakeMKVBetaKey()
.then((response) => {
if (!active) {
return;
}
setBetaKey(String(response?.betaKey || '').trim());
setValidUntil(String(response?.validUntil || '').trim());
setWarning(String(response?.warning || '').trim());
})
.catch((loadError) => {
if (!active) {
return;
}
setBetaKey('');
setValidUntil('');
setError(loadError?.message || 'Betakey konnte nicht geladen werden.');
})
.finally(() => {
if (active) {
setLoading(false);
}
});
return () => {
active = false;
};
useEffect(() => {
void loadCachedState();
}, []);
const handleCheck = async () => {
setChecking(true);
setError('');
setWarning('');
try {
const response = await api.checkMakeMKVBetaKey();
const nextKey = String(response?.betaKey || '').trim();
setBetaKey(nextKey);
setValidUntil(String(response?.validUntil || '').trim());
setFetchedAt(String(response?.fetchedAt || '').trim());
setWarning('');
if (typeof onNotify === 'function') {
onNotify({
severity: 'success',
summary: 'MakeMKV Betakey',
detail: nextKey ? 'Betakey erfolgreich geprüft.' : 'Betakey-Prüfung abgeschlossen.'
});
}
} catch (checkError) {
setError(checkError?.message || 'Betakey konnte nicht geprüft werden.');
if (typeof onNotify === 'function') {
onNotify({
severity: 'error',
summary: 'MakeMKV Betakey',
detail: checkError?.message || 'Betakey konnte nicht geprüft werden.'
});
}
} finally {
setChecking(false);
}
};
const handleApply = async () => {
if (!betaKey) {
return;
}
setApplying(true);
setError('');
try {
const response = await api.applyMakeMKVBetaKey({ betaKey });
const nextAppliedKey = String(response?.betaKey || betaKey).trim();
setAppliedKey(nextAppliedKey);
setWarning('Geprüfter Betakey ist bereits übernommen.');
if (typeof onSettingApplied === 'function') {
onSettingApplied({
key: 'makemkv_registration_key',
value: nextAppliedKey
});
}
if (typeof onNotify === 'function') {
onNotify({
severity: 'success',
summary: 'MakeMKV Betakey',
detail: 'Betakey wurde übernommen und gespeichert.'
});
}
} catch (applyError) {
setError(applyError?.message || 'Betakey konnte nicht übernommen werden.');
if (typeof onNotify === 'function') {
onNotify({
severity: 'error',
summary: 'MakeMKV Betakey',
detail: applyError?.message || 'Betakey konnte nicht übernommen werden.'
});
}
} finally {
setApplying(false);
}
};
return (
<div className="makemkv-beta-key-box">
<div className="makemkv-beta-key-head">
<span className="makemkv-beta-key-title">Betakey</span>
<Button
type="button"
size="small"
text
label="übernehmen"
disabled={disabled || loading || !betaKey}
onClick={() => onApply?.(betaKey)}
/>
<div className="settings-inline-actions">
<Button
type="button"
size="small"
text
label="prüfen"
disabled={disabled || loading || checking || applying}
onClick={() => void handleCheck()}
/>
<Button
type="button"
size="small"
text
label="übernehmen"
disabled={disabled || loading || checking || applying || !betaKey || betaKey === appliedKey}
onClick={() => void handleApply()}
/>
</div>
</div>
{loading ? (
<small className="setting-description">Aktueller Betakey wird geladen</small>
<small className="setting-description">Zwischengespeicherter Betakey wird geladen</small>
) : null}
{!loading && error ? (
<small className="error-text">{error}</small>
@@ -729,6 +812,9 @@ function MakeMKVBetaKeyHint({ onApply, disabled = false }) {
{!loading && !error && warning ? (
<small className="setting-description">{warning}</small>
) : null}
{!loading && !error && fetchedAt ? (
<small className="setting-description">Zuletzt geprüft: {new Date(fetchedAt).toLocaleString('de-DE')}</small>
) : null}
{!loading && !error && validUntil ? (
<small className="setting-description">Gültig bis: {new Date(validUntil).toLocaleString('de-DE')}</small>
) : null}
@@ -786,7 +872,9 @@ function SettingField({
ownerDirty,
onChange,
variant = 'default',
disabled = false
disabled = false,
onNotify = null,
onSettingApplied = null
}) {
const ownerKey = ownerSetting?.key;
const pathHasValue = Boolean(String(value ?? '').trim());
@@ -905,7 +993,8 @@ function SettingField({
{normalizeSettingKey(setting?.key) === 'makemkv_registration_key' ? (
<MakeMKVBetaKeyHint
disabled={isDisabled}
onApply={(nextKey) => onChange?.(setting.key, nextKey)}
onNotify={onNotify}
onSettingApplied={onSettingApplied}
/>
) : null}
{error ? (
@@ -946,7 +1035,16 @@ function SettingField({
}
function PathCategoryTab({ settings, values, errors, dirtyKeys, onChange, effectivePaths }) {
function PathCategoryTab({
settings,
values,
errors,
dirtyKeys,
onChange,
effectivePaths,
onNotify,
onSettingApplied
}) {
const list = Array.isArray(settings) ? settings : [];
const settingsByKey = new Map(list.map((s) => [s.key, s]));
@@ -1153,6 +1251,8 @@ function PathCategoryTab({ settings, values, errors, dirtyKeys, onChange, effect
ownerError={ownerError}
ownerDirty={ownerDirty}
onChange={onChange}
onNotify={onNotify}
onSettingApplied={onSettingApplied}
/>
);
})}
@@ -1173,7 +1273,8 @@ export default function DynamicSettingsForm({
onChange,
effectivePaths,
activationBytes = [],
onNotify
onNotify,
onSettingApplied
}) {
const safeCategories = Array.isArray(categories) ? categories : [];
const expertModeEnabled = toBoolean(values?.[EXPERT_MODE_SETTING_KEY]);
@@ -1258,6 +1359,8 @@ export default function DynamicSettingsForm({
dirtyKeys={dirtyKeys}
onChange={onChange}
effectivePaths={effectivePaths}
onNotify={onNotify}
onSettingApplied={onSettingApplied}
/>
) : (() => {
const sections = buildSectionsForCategory(category?.category, category?.settings || []);
@@ -1339,6 +1442,8 @@ export default function DynamicSettingsForm({
onChange={onChangeFn}
variant={variant}
disabled={disabled}
onNotify={onNotify}
onSettingApplied={onSettingApplied}
/>
);
};