Revert to version 5d79b82
This commit is contained in:
parent
5e2bccdca0
commit
07dccfbc37
@ -392,7 +392,18 @@ const resolveDurationWithFallback = async (
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await axios.get(playbackUrl, { responseType: 'blob' });
|
||||
const requestUrl =
|
||||
playbackUrl.startsWith('http://') || playbackUrl.startsWith('https://')
|
||||
? playbackUrl
|
||||
: playbackUrl.replace(/^\/api(?=\/)/, '');
|
||||
|
||||
const token =
|
||||
typeof window !== 'undefined' ? localStorage.getItem('token') || '' : '';
|
||||
const response = await axios.get(requestUrl, {
|
||||
responseType: 'blob',
|
||||
headers: token ? { Authorization: `Bearer ${token}` } : undefined,
|
||||
});
|
||||
|
||||
const blobUrl = URL.createObjectURL(response.data);
|
||||
try {
|
||||
const blobDuration = await readMediaDuration(blobUrl, mediaType);
|
||||
@ -538,7 +549,6 @@ const createDefaultElement = (
|
||||
navType: getNavigationButtonKind(type),
|
||||
iconUrl: '',
|
||||
transitionReverseMode: 'auto_reverse',
|
||||
transitionDurationSec: 0.7,
|
||||
};
|
||||
}
|
||||
|
||||
@ -739,6 +749,7 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
useState<EditorMenuItem>('none');
|
||||
const [transitionPreview, setTransitionPreview] =
|
||||
useState<TransitionPreviewState | null>(null);
|
||||
const [pendingNavigationPageId, setPendingNavigationPageId] = useState('');
|
||||
|
||||
const [isLoading, setIsLoading] = useState(true);
|
||||
const [isSaving, setIsSaving] = useState(false);
|
||||
@ -748,7 +759,6 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
const [newTransitionVideoUrl, setNewTransitionVideoUrl] = useState('');
|
||||
const [newTransitionSupportsReverse, setNewTransitionSupportsReverse] =
|
||||
useState(true);
|
||||
const [newTransitionDurationSec, setNewTransitionDurationSec] = useState(0.7);
|
||||
const [errorMessage, setErrorMessage] = useState('');
|
||||
const [successMessage, setSuccessMessage] = useState('');
|
||||
const [resolvedDurationBySource, setResolvedDurationBySource] = useState<
|
||||
@ -984,8 +994,28 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
});
|
||||
}
|
||||
|
||||
if (newTransitionVideoUrl) {
|
||||
targets.push({ source: newTransitionVideoUrl, mediaType: 'video' });
|
||||
}
|
||||
|
||||
elements.forEach((element) => {
|
||||
if (!isNavigationElementType(element.type)) return;
|
||||
if (element.transitionVideoUrl) {
|
||||
targets.push({ source: element.transitionVideoUrl, mediaType: 'video' });
|
||||
}
|
||||
if (element.reverseVideoUrl) {
|
||||
targets.push({ source: element.reverseVideoUrl, mediaType: 'video' });
|
||||
}
|
||||
});
|
||||
|
||||
return targets;
|
||||
}, [backgroundAudioUrl, backgroundVideoUrl, selectedElement]);
|
||||
}, [
|
||||
backgroundAudioUrl,
|
||||
backgroundVideoUrl,
|
||||
elements,
|
||||
newTransitionVideoUrl,
|
||||
selectedElement,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
let isCancelled = false;
|
||||
@ -1050,6 +1080,19 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
getKnownDurationForSource(selectedElement.mediaUrl || ''),
|
||||
);
|
||||
}, [getKnownDurationForSource, selectedElement]);
|
||||
const newTransitionDurationNote = useMemo(
|
||||
() => formatDurationNote(getKnownDurationForSource(newTransitionVideoUrl)),
|
||||
[getKnownDurationForSource, newTransitionVideoUrl],
|
||||
);
|
||||
const selectedTransitionDurationNote = useMemo(() => {
|
||||
if (!selectedElement || !isNavigationElementType(selectedElement.type)) {
|
||||
return 'Duration: unknown';
|
||||
}
|
||||
|
||||
return formatDurationNote(
|
||||
getKnownDurationForSource(selectedElement.transitionVideoUrl || ''),
|
||||
);
|
||||
}, [getKnownDurationForSource, selectedElement]);
|
||||
|
||||
useEffect(() => {
|
||||
if (newTransitionVideoUrl) return;
|
||||
@ -1057,6 +1100,32 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
setNewTransitionVideoUrl(transitionVideoAssetOptions[0].value);
|
||||
}, [newTransitionVideoUrl, transitionVideoAssetOptions]);
|
||||
|
||||
useEffect(() => {
|
||||
setElements((prev) => {
|
||||
let hasChanges = false;
|
||||
const next = prev.map((element) => {
|
||||
if (!isNavigationElementType(element.type)) return element;
|
||||
|
||||
const resolvedDuration = getKnownDurationForSource(
|
||||
element.transitionVideoUrl || '',
|
||||
);
|
||||
const nextDuration =
|
||||
Number.isFinite(resolvedDuration) && Number(resolvedDuration) > 0
|
||||
? Number(resolvedDuration)
|
||||
: undefined;
|
||||
if (element.transitionDurationSec === nextDuration) return element;
|
||||
|
||||
hasChanges = true;
|
||||
return {
|
||||
...element,
|
||||
transitionDurationSec: nextDuration,
|
||||
};
|
||||
});
|
||||
|
||||
return hasChanges ? next : prev;
|
||||
});
|
||||
}, [getKnownDurationForSource]);
|
||||
|
||||
const loadData = useCallback(async () => {
|
||||
if (!projectId || !router.isReady || !isAuthReady) return;
|
||||
|
||||
@ -1643,7 +1712,13 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
const sanitizedName =
|
||||
String(newTransitionName || '').trim() ||
|
||||
`Transition ${Date.now().toString().slice(-4)}`;
|
||||
const parsedDuration = Number(newTransitionDurationSec);
|
||||
const resolvedDurationSec = getKnownDurationForSource(sanitizedVideoUrl);
|
||||
if (!resolvedDurationSec) {
|
||||
setErrorMessage(
|
||||
'Could not resolve transition video duration yet. Please wait a moment and try again.',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
setIsCreatingTransition(true);
|
||||
@ -1659,10 +1734,7 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
video_url: sanitizedVideoUrl,
|
||||
audio_url: '',
|
||||
supports_reverse: Boolean(newTransitionSupportsReverse),
|
||||
duration_sec:
|
||||
Number.isFinite(parsedDuration) && parsedDuration > 0
|
||||
? parsedDuration
|
||||
: 0.7,
|
||||
duration_sec: resolvedDurationSec,
|
||||
};
|
||||
|
||||
await axios.post('/transitions', { data: payload });
|
||||
@ -1680,7 +1752,7 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
}
|
||||
}, [
|
||||
activePage?.environment,
|
||||
newTransitionDurationSec,
|
||||
getKnownDurationForSource,
|
||||
newTransitionName,
|
||||
newTransitionSupportsReverse,
|
||||
newTransitionVideoUrl,
|
||||
@ -1924,6 +1996,44 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
element.navType === 'back' || element.type === 'navigation_prev'
|
||||
? 'back'
|
||||
: 'forward';
|
||||
const configuredTargetId = String(element.targetPageId || '').trim();
|
||||
const fallbackTargetId = (() => {
|
||||
const currentPageIndex = pages.findIndex(
|
||||
(page) => page.id === activePageId,
|
||||
);
|
||||
if (currentPageIndex < 0) return '';
|
||||
|
||||
const nextPageIndex =
|
||||
direction === 'back' ? currentPageIndex - 1 : currentPageIndex + 1;
|
||||
const nextPage = pages[nextPageIndex];
|
||||
return nextPage ? String(nextPage.id || '').trim() : '';
|
||||
})();
|
||||
const targetPageId = configuredTargetId || fallbackTargetId;
|
||||
|
||||
if (!targetPageId) {
|
||||
setErrorMessage('No target page available for this navigation button.');
|
||||
return;
|
||||
}
|
||||
|
||||
const hasPlayableTransition =
|
||||
Boolean(element.transitionVideoUrl) &&
|
||||
!(
|
||||
direction === 'back' &&
|
||||
element.transitionReverseMode === 'separate_video' &&
|
||||
!element.reverseVideoUrl
|
||||
);
|
||||
|
||||
if (!hasPlayableTransition) {
|
||||
setPendingNavigationPageId('');
|
||||
setTransitionPreview(null);
|
||||
setActivePageId(targetPageId);
|
||||
setSelectedElementId('');
|
||||
setSelectedMenuItem('none');
|
||||
setErrorMessage('');
|
||||
return;
|
||||
}
|
||||
|
||||
setPendingNavigationPageId(targetPageId);
|
||||
openTransitionPreviewForElement(element, direction);
|
||||
}
|
||||
return;
|
||||
@ -2266,6 +2376,16 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
const finishPreview = () => {
|
||||
cleanupReverseFrame();
|
||||
setTransitionPreview(null);
|
||||
setPendingNavigationPageId((pendingPageId) => {
|
||||
const nextPageId = String(pendingPageId || '').trim();
|
||||
if (nextPageId) {
|
||||
setActivePageId(nextPageId);
|
||||
setSelectedElementId('');
|
||||
setSelectedMenuItem('none');
|
||||
setErrorMessage('');
|
||||
}
|
||||
return '';
|
||||
});
|
||||
};
|
||||
|
||||
const configuredDurationMs =
|
||||
@ -2700,6 +2820,10 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<p className='text-[11px] text-gray-500'>
|
||||
Transition duration is automatic from video metadata.{' '}
|
||||
{newTransitionDurationNote}
|
||||
</p>
|
||||
<label className='flex items-center gap-2 text-[11px] text-gray-700'>
|
||||
<input
|
||||
type='checkbox'
|
||||
@ -2710,18 +2834,6 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
/>
|
||||
Supports reverse playback
|
||||
</label>
|
||||
<input
|
||||
className='w-full rounded border border-gray-300 px-2 py-1 text-xs'
|
||||
type='number'
|
||||
min='0.2'
|
||||
step='0.1'
|
||||
value={newTransitionDurationSec}
|
||||
onChange={(event) =>
|
||||
setNewTransitionDurationSec(
|
||||
Number(event.target.value || 0.7),
|
||||
)
|
||||
}
|
||||
/>
|
||||
<button
|
||||
type='button'
|
||||
className='menu-action-btn'
|
||||
@ -2888,6 +3000,9 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
<p className='mt-1 text-[11px] text-gray-500'>
|
||||
{selectedMediaDurationNote}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
<label className='mb-1 block text-[11px] font-semibold text-gray-600'>
|
||||
@ -2919,11 +3034,15 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
<select
|
||||
className='w-full rounded border border-gray-300 px-2 py-1 text-xs'
|
||||
value={selectedElement.transitionVideoUrl || ''}
|
||||
onChange={(event) =>
|
||||
onChange={(event) => {
|
||||
const nextVideoUrl = event.target.value;
|
||||
const resolvedDuration =
|
||||
getKnownDurationForSource(nextVideoUrl);
|
||||
updateSelectedElement({
|
||||
transitionVideoUrl: event.target.value,
|
||||
})
|
||||
}
|
||||
transitionVideoUrl: nextVideoUrl,
|
||||
transitionDurationSec: resolvedDuration || undefined,
|
||||
});
|
||||
}}
|
||||
>
|
||||
<option value=''>Not selected</option>
|
||||
{addFallbackAssetOption(
|
||||
@ -2937,7 +3056,7 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
))}
|
||||
</select>
|
||||
<p className='mt-1 text-[11px] text-gray-500'>
|
||||
{selectedMediaDurationNote}
|
||||
{selectedTransitionDurationNote}
|
||||
</p>
|
||||
</div>
|
||||
<div>
|
||||
@ -2995,25 +3114,10 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
</select>
|
||||
</div>
|
||||
)}
|
||||
<div>
|
||||
<label className='mb-1 block text-[11px] font-semibold text-gray-600'>
|
||||
Transition duration (sec)
|
||||
</label>
|
||||
<input
|
||||
className='w-full rounded border border-gray-300 px-2 py-1 text-xs'
|
||||
type='number'
|
||||
min='0.2'
|
||||
step='0.1'
|
||||
value={selectedElement.transitionDurationSec ?? 0.7}
|
||||
onChange={(event) =>
|
||||
updateSelectedElement({
|
||||
transitionDurationSec: Number(
|
||||
event.target.value || 0.7,
|
||||
),
|
||||
})
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<p className='text-[11px] text-gray-500'>
|
||||
Transition duration is set automatically from the selected
|
||||
video. {selectedTransitionDurationNote}
|
||||
</p>
|
||||
<div className='flex gap-2 pt-1'>
|
||||
<BaseButton
|
||||
small
|
||||
@ -3584,7 +3688,19 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
||||
<button
|
||||
type='button'
|
||||
className='absolute top-4 right-4 rounded bg-white/20 px-3 py-1 text-xs text-white hover:bg-white/30'
|
||||
onClick={() => setTransitionPreview(null)}
|
||||
onClick={() => {
|
||||
setTransitionPreview(null);
|
||||
setPendingNavigationPageId((pendingPageId) => {
|
||||
const nextPageId = String(pendingPageId || '').trim();
|
||||
if (nextPageId) {
|
||||
setActivePageId(nextPageId);
|
||||
setSelectedElementId('');
|
||||
setSelectedMenuItem('none');
|
||||
setErrorMessage('');
|
||||
}
|
||||
return '';
|
||||
});
|
||||
}}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user