mirror of
https://github.com/OpenCut-app/OpenCut.git
synced 2026-07-13 21:52:53 +02:00
fix rendering issue from v1 to current
This commit is contained in:
@@ -862,7 +862,7 @@ function ProjectsSkeleton() {
|
|||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="xs:grid-cols-2 grid grid-cols-1 gap-6 sm:grid-cols-3 lg:grid-cols-4">
|
<div className="px-4 xs:grid-cols-2 grid grid-cols-1 gap-6 sm:grid-cols-3 lg:grid-cols-4">
|
||||||
{skeletonIds.map((skeletonId) => (
|
{skeletonIds.map((skeletonId) => (
|
||||||
<Card
|
<Card
|
||||||
key={skeletonId}
|
key={skeletonId}
|
||||||
|
|||||||
@@ -29,10 +29,9 @@ export function buildScene(params: BuildSceneParams) {
|
|||||||
(track) => !("hidden" in track && track.hidden),
|
(track) => !("hidden" in track && track.hidden),
|
||||||
);
|
);
|
||||||
|
|
||||||
const mainTrack = visibleTracks.find((track) => isMainTrack(track)) ?? null;
|
|
||||||
const orderedTracksTopToBottom = [
|
const orderedTracksTopToBottom = [
|
||||||
...visibleTracks.filter((track) => !isMainTrack(track)),
|
...visibleTracks.filter((track) => !isMainTrack(track)),
|
||||||
...(mainTrack ? [mainTrack] : []),
|
...visibleTracks.filter((track) => isMainTrack(track)),
|
||||||
];
|
];
|
||||||
|
|
||||||
const orderedTracksBottomToTop = orderedTracksTopToBottom.slice().reverse();
|
const orderedTracksBottomToTop = orderedTracksTopToBottom.slice().reverse();
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ export interface MigrationProgress {
|
|||||||
|
|
||||||
let hasCleanedUpMetaDb = false;
|
let hasCleanedUpMetaDb = false;
|
||||||
|
|
||||||
|
const MIN_MIGRATION_DISPLAY_MS = 1000;
|
||||||
|
|
||||||
export async function runStorageMigrations({
|
export async function runStorageMigrations({
|
||||||
migrations,
|
migrations,
|
||||||
onProgress,
|
onProgress,
|
||||||
@@ -45,6 +47,7 @@ export async function runStorageMigrations({
|
|||||||
|
|
||||||
const orderedMigrations = [...migrations].sort((a, b) => a.from - b.from);
|
const orderedMigrations = [...migrations].sort((a, b) => a.from - b.from);
|
||||||
let migratedCount = 0;
|
let migratedCount = 0;
|
||||||
|
let migrationStartTime: number | null = null;
|
||||||
|
|
||||||
for (const project of projects) {
|
for (const project of projects) {
|
||||||
if (typeof project !== "object" || project === null) {
|
if (typeof project !== "object" || project === null) {
|
||||||
@@ -59,6 +62,11 @@ export async function runStorageMigrations({
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Track when we first showed the migration dialog
|
||||||
|
if (migrationStartTime === null) {
|
||||||
|
migrationStartTime = Date.now();
|
||||||
|
}
|
||||||
|
|
||||||
const projectName = getProjectName({ project: projectRecord });
|
const projectName = getProjectName({ project: projectRecord });
|
||||||
onProgress?.({
|
onProgress?.({
|
||||||
isMigrating: true,
|
isMigrating: true,
|
||||||
@@ -90,6 +98,16 @@ export async function runStorageMigrations({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Ensure dialog is visible for minimum time so users can see it
|
||||||
|
if (migrationStartTime !== null) {
|
||||||
|
const elapsed = Date.now() - migrationStartTime;
|
||||||
|
if (elapsed < MIN_MIGRATION_DISPLAY_MS) {
|
||||||
|
await new Promise((resolve) =>
|
||||||
|
setTimeout(resolve, MIN_MIGRATION_DISPLAY_MS - elapsed),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
onProgress?.({
|
onProgress?.({
|
||||||
isMigrating: false,
|
isMigrating: false,
|
||||||
fromVersion: null,
|
fromVersion: null,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ interface LegacyMediaElement {
|
|||||||
type: "media";
|
type: "media";
|
||||||
mediaId: string;
|
mediaId: string;
|
||||||
muted?: boolean;
|
muted?: boolean;
|
||||||
[id: string]: unknown;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LegacyTextElement {
|
interface LegacyTextElement {
|
||||||
@@ -35,19 +35,19 @@ interface LegacyTextElement {
|
|||||||
y: number;
|
y: number;
|
||||||
rotation: number;
|
rotation: number;
|
||||||
opacity: number;
|
opacity: number;
|
||||||
[id: string]: unknown;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LegacyAudioElement {
|
interface LegacyAudioElement {
|
||||||
type: "audio";
|
type: "audio";
|
||||||
mediaId: string;
|
mediaId: string;
|
||||||
[id: string]: unknown;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface LegacyMediaTrack {
|
interface LegacyMediaTrack {
|
||||||
type: "media";
|
type: "media";
|
||||||
elements: unknown[];
|
elements: unknown[];
|
||||||
[id: string]: unknown;
|
[key: string]: unknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface TransformV1ToV2Options {
|
export interface TransformV1ToV2Options {
|
||||||
@@ -265,35 +265,38 @@ async function transformTracks({
|
|||||||
}
|
}
|
||||||
|
|
||||||
let isFirstVideoTrackFound = false;
|
let isFirstVideoTrackFound = false;
|
||||||
|
const transformedTracks: (TimelineTrack | null)[] = [];
|
||||||
|
|
||||||
const transformedTracks = await Promise.all(
|
for (const track of tracks) {
|
||||||
tracks.map(async (track) => {
|
if (!isRecord(track)) {
|
||||||
if (!isRecord(track)) {
|
transformedTracks.push(null);
|
||||||
return null;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const trackType = track.type;
|
const trackType = track.type;
|
||||||
if (trackType === "media") {
|
if (trackType === "media") {
|
||||||
const videoTrack = await transformMediaTrack({
|
const videoTrack = await transformMediaTrack({
|
||||||
track: track as LegacyMediaTrack,
|
track: track as LegacyMediaTrack,
|
||||||
loadMediaAsset,
|
loadMediaAsset,
|
||||||
isMain: !isFirstVideoTrackFound,
|
isMain: !isFirstVideoTrackFound,
|
||||||
});
|
});
|
||||||
isFirstVideoTrackFound = true;
|
isFirstVideoTrackFound = true;
|
||||||
return videoTrack;
|
transformedTracks.push(videoTrack);
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (trackType === "text") {
|
if (trackType === "text") {
|
||||||
return transformTextTrack({ track });
|
transformedTracks.push(transformTextTrack({ track }));
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (trackType === "audio") {
|
if (trackType === "audio") {
|
||||||
return transformAudioTrack({ track });
|
transformedTracks.push(transformAudioTrack({ track }));
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
transformedTracks.push(null);
|
||||||
}),
|
}
|
||||||
);
|
|
||||||
|
|
||||||
return transformedTracks.filter(
|
return transformedTracks.filter(
|
||||||
(track): track is TimelineTrack => track !== null,
|
(track): track is TimelineTrack => track !== null,
|
||||||
|
|||||||
@@ -33,8 +33,7 @@ export class V1toV2Migration extends StorageMigration {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!result.skipped) {
|
if (!result.skipped) {
|
||||||
// cleanup legacy timeline DBs after successful transformation
|
void cleanupLegacyTimelineDBs({
|
||||||
await cleanupLegacyTimelineDBs({
|
|
||||||
projectId,
|
projectId,
|
||||||
project: result.project,
|
project: result.project,
|
||||||
});
|
});
|
||||||
@@ -60,13 +59,13 @@ function createMediaAssetLoader({
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function cleanupLegacyTimelineDBs({
|
function cleanupLegacyTimelineDBs({
|
||||||
projectId,
|
projectId,
|
||||||
project,
|
project,
|
||||||
}: {
|
}: {
|
||||||
projectId: string;
|
projectId: string;
|
||||||
project: ProjectRecord;
|
project: ProjectRecord;
|
||||||
}): Promise<void> {
|
}): void {
|
||||||
const scenes = project.scenes;
|
const scenes = project.scenes;
|
||||||
if (!Array.isArray(scenes)) {
|
if (!Array.isArray(scenes)) {
|
||||||
return;
|
return;
|
||||||
@@ -89,11 +88,12 @@ async function cleanupLegacyTimelineDBs({
|
|||||||
const projectDbName = `video-editor-timelines-${projectId}`;
|
const projectDbName = `video-editor-timelines-${projectId}`;
|
||||||
dbNamesToDelete.push(projectDbName);
|
dbNamesToDelete.push(projectDbName);
|
||||||
|
|
||||||
for (const dbName of dbNamesToDelete) {
|
// Fire-and-forget: delete in parallel, don't block migration
|
||||||
try {
|
void Promise.all(
|
||||||
await deleteDatabase({ dbName });
|
dbNamesToDelete.map((dbName) =>
|
||||||
} catch {
|
deleteDatabase({ dbName }).catch(() => {
|
||||||
// ignore errors, DB might not exist or already deleted
|
// ignore errors, DB might not exist or already deleted
|
||||||
}
|
}),
|
||||||
}
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user