Revert to version 5d79b82
This commit is contained in:
parent
5e2bccdca0
commit
07dccfbc37
@ -392,7 +392,18 @@ const resolveDurationWithFallback = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
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);
|
const blobUrl = URL.createObjectURL(response.data);
|
||||||
try {
|
try {
|
||||||
const blobDuration = await readMediaDuration(blobUrl, mediaType);
|
const blobDuration = await readMediaDuration(blobUrl, mediaType);
|
||||||
@ -538,7 +549,6 @@ const createDefaultElement = (
|
|||||||
navType: getNavigationButtonKind(type),
|
navType: getNavigationButtonKind(type),
|
||||||
iconUrl: '',
|
iconUrl: '',
|
||||||
transitionReverseMode: 'auto_reverse',
|
transitionReverseMode: 'auto_reverse',
|
||||||
transitionDurationSec: 0.7,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -739,6 +749,7 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
useState<EditorMenuItem>('none');
|
useState<EditorMenuItem>('none');
|
||||||
const [transitionPreview, setTransitionPreview] =
|
const [transitionPreview, setTransitionPreview] =
|
||||||
useState<TransitionPreviewState | null>(null);
|
useState<TransitionPreviewState | null>(null);
|
||||||
|
const [pendingNavigationPageId, setPendingNavigationPageId] = useState('');
|
||||||
|
|
||||||
const [isLoading, setIsLoading] = useState(true);
|
const [isLoading, setIsLoading] = useState(true);
|
||||||
const [isSaving, setIsSaving] = useState(false);
|
const [isSaving, setIsSaving] = useState(false);
|
||||||
@ -748,7 +759,6 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
const [newTransitionVideoUrl, setNewTransitionVideoUrl] = useState('');
|
const [newTransitionVideoUrl, setNewTransitionVideoUrl] = useState('');
|
||||||
const [newTransitionSupportsReverse, setNewTransitionSupportsReverse] =
|
const [newTransitionSupportsReverse, setNewTransitionSupportsReverse] =
|
||||||
useState(true);
|
useState(true);
|
||||||
const [newTransitionDurationSec, setNewTransitionDurationSec] = useState(0.7);
|
|
||||||
const [errorMessage, setErrorMessage] = useState('');
|
const [errorMessage, setErrorMessage] = useState('');
|
||||||
const [successMessage, setSuccessMessage] = useState('');
|
const [successMessage, setSuccessMessage] = useState('');
|
||||||
const [resolvedDurationBySource, setResolvedDurationBySource] = 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;
|
return targets;
|
||||||
}, [backgroundAudioUrl, backgroundVideoUrl, selectedElement]);
|
}, [
|
||||||
|
backgroundAudioUrl,
|
||||||
|
backgroundVideoUrl,
|
||||||
|
elements,
|
||||||
|
newTransitionVideoUrl,
|
||||||
|
selectedElement,
|
||||||
|
]);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
let isCancelled = false;
|
let isCancelled = false;
|
||||||
@ -1050,6 +1080,19 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
getKnownDurationForSource(selectedElement.mediaUrl || ''),
|
getKnownDurationForSource(selectedElement.mediaUrl || ''),
|
||||||
);
|
);
|
||||||
}, [getKnownDurationForSource, selectedElement]);
|
}, [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(() => {
|
useEffect(() => {
|
||||||
if (newTransitionVideoUrl) return;
|
if (newTransitionVideoUrl) return;
|
||||||
@ -1057,6 +1100,32 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
setNewTransitionVideoUrl(transitionVideoAssetOptions[0].value);
|
setNewTransitionVideoUrl(transitionVideoAssetOptions[0].value);
|
||||||
}, [newTransitionVideoUrl, transitionVideoAssetOptions]);
|
}, [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 () => {
|
const loadData = useCallback(async () => {
|
||||||
if (!projectId || !router.isReady || !isAuthReady) return;
|
if (!projectId || !router.isReady || !isAuthReady) return;
|
||||||
|
|
||||||
@ -1643,7 +1712,13 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
const sanitizedName =
|
const sanitizedName =
|
||||||
String(newTransitionName || '').trim() ||
|
String(newTransitionName || '').trim() ||
|
||||||
`Transition ${Date.now().toString().slice(-4)}`;
|
`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 {
|
try {
|
||||||
setIsCreatingTransition(true);
|
setIsCreatingTransition(true);
|
||||||
@ -1659,10 +1734,7 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
video_url: sanitizedVideoUrl,
|
video_url: sanitizedVideoUrl,
|
||||||
audio_url: '',
|
audio_url: '',
|
||||||
supports_reverse: Boolean(newTransitionSupportsReverse),
|
supports_reverse: Boolean(newTransitionSupportsReverse),
|
||||||
duration_sec:
|
duration_sec: resolvedDurationSec,
|
||||||
Number.isFinite(parsedDuration) && parsedDuration > 0
|
|
||||||
? parsedDuration
|
|
||||||
: 0.7,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
await axios.post('/transitions', { data: payload });
|
await axios.post('/transitions', { data: payload });
|
||||||
@ -1680,7 +1752,7 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
activePage?.environment,
|
activePage?.environment,
|
||||||
newTransitionDurationSec,
|
getKnownDurationForSource,
|
||||||
newTransitionName,
|
newTransitionName,
|
||||||
newTransitionSupportsReverse,
|
newTransitionSupportsReverse,
|
||||||
newTransitionVideoUrl,
|
newTransitionVideoUrl,
|
||||||
@ -1924,6 +1996,44 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
element.navType === 'back' || element.type === 'navigation_prev'
|
element.navType === 'back' || element.type === 'navigation_prev'
|
||||||
? 'back'
|
? 'back'
|
||||||
: 'forward';
|
: '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);
|
openTransitionPreviewForElement(element, direction);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
@ -2266,6 +2376,16 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
const finishPreview = () => {
|
const finishPreview = () => {
|
||||||
cleanupReverseFrame();
|
cleanupReverseFrame();
|
||||||
setTransitionPreview(null);
|
setTransitionPreview(null);
|
||||||
|
setPendingNavigationPageId((pendingPageId) => {
|
||||||
|
const nextPageId = String(pendingPageId || '').trim();
|
||||||
|
if (nextPageId) {
|
||||||
|
setActivePageId(nextPageId);
|
||||||
|
setSelectedElementId('');
|
||||||
|
setSelectedMenuItem('none');
|
||||||
|
setErrorMessage('');
|
||||||
|
}
|
||||||
|
return '';
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const configuredDurationMs =
|
const configuredDurationMs =
|
||||||
@ -2700,6 +2820,10 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</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'>
|
<label className='flex items-center gap-2 text-[11px] text-gray-700'>
|
||||||
<input
|
<input
|
||||||
type='checkbox'
|
type='checkbox'
|
||||||
@ -2710,18 +2834,6 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
/>
|
/>
|
||||||
Supports reverse playback
|
Supports reverse playback
|
||||||
</label>
|
</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
|
<button
|
||||||
type='button'
|
type='button'
|
||||||
className='menu-action-btn'
|
className='menu-action-btn'
|
||||||
@ -2888,6 +3000,9 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
<p className='mt-1 text-[11px] text-gray-500'>
|
||||||
|
{selectedMediaDurationNote}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<label className='mb-1 block text-[11px] font-semibold text-gray-600'>
|
<label className='mb-1 block text-[11px] font-semibold text-gray-600'>
|
||||||
@ -2919,11 +3034,15 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
<select
|
<select
|
||||||
className='w-full rounded border border-gray-300 px-2 py-1 text-xs'
|
className='w-full rounded border border-gray-300 px-2 py-1 text-xs'
|
||||||
value={selectedElement.transitionVideoUrl || ''}
|
value={selectedElement.transitionVideoUrl || ''}
|
||||||
onChange={(event) =>
|
onChange={(event) => {
|
||||||
|
const nextVideoUrl = event.target.value;
|
||||||
|
const resolvedDuration =
|
||||||
|
getKnownDurationForSource(nextVideoUrl);
|
||||||
updateSelectedElement({
|
updateSelectedElement({
|
||||||
transitionVideoUrl: event.target.value,
|
transitionVideoUrl: nextVideoUrl,
|
||||||
})
|
transitionDurationSec: resolvedDuration || undefined,
|
||||||
}
|
});
|
||||||
|
}}
|
||||||
>
|
>
|
||||||
<option value=''>Not selected</option>
|
<option value=''>Not selected</option>
|
||||||
{addFallbackAssetOption(
|
{addFallbackAssetOption(
|
||||||
@ -2937,7 +3056,7 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
<p className='mt-1 text-[11px] text-gray-500'>
|
<p className='mt-1 text-[11px] text-gray-500'>
|
||||||
{selectedMediaDurationNote}
|
{selectedTransitionDurationNote}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
@ -2995,25 +3114,10 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<div>
|
<p className='text-[11px] text-gray-500'>
|
||||||
<label className='mb-1 block text-[11px] font-semibold text-gray-600'>
|
Transition duration is set automatically from the selected
|
||||||
Transition duration (sec)
|
video. {selectedTransitionDurationNote}
|
||||||
</label>
|
</p>
|
||||||
<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>
|
|
||||||
<div className='flex gap-2 pt-1'>
|
<div className='flex gap-2 pt-1'>
|
||||||
<BaseButton
|
<BaseButton
|
||||||
small
|
small
|
||||||
@ -3584,7 +3688,19 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
<button
|
<button
|
||||||
type='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'
|
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
|
Close
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user