diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index c2a5f32..5c2e980 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -8,7 +8,7 @@ }, "package": { "productName": "Quran Caption", - "version": "1.9.0" + "version": "2.1.0" }, "tauri": { "allowlist": { diff --git a/src/lib/components/subtitles/VersePicker.svelte b/src/lib/components/subtitles/VersePicker.svelte index ffe399d..8a28414 100644 --- a/src/lib/components/subtitles/VersePicker.svelte +++ b/src/lib/components/subtitles/VersePicker.svelte @@ -26,8 +26,10 @@ if (element.isLastWordInVerse) { // Go to next verse - verseNumber += 1; - verseNumberInInput += 1; + if (verseNumberInInput < $Mushaf.surahs[surahNumber - 1].verses.length) { + verseNumber += 1; + verseNumberInInput += 1; + } } break; } diff --git a/src/lib/ext/GlobalVariables.ts b/src/lib/ext/GlobalVariables.ts index 0269aa0..a7e5512 100644 --- a/src/lib/ext/GlobalVariables.ts +++ b/src/lib/ext/GlobalVariables.ts @@ -1,4 +1,4 @@ -export const SOFTWARE_VERSION = 'v1.9'; +export const SOFTWARE_VERSION = 'v2.1'; export const GITHUB_API_URL = 'https://api.github.com/repos/zonetecde/QuranCaption-2/releases/latest'; export const GITHUB_REPO_LINK = 'https://github.com/zonetecde/QuranCaption-2'; diff --git a/src/lib/ext/VersionFix.ts b/src/lib/ext/VersionFix.ts new file mode 100644 index 0000000..38fc94e --- /dev/null +++ b/src/lib/ext/VersionFix.ts @@ -0,0 +1,35 @@ +import type { ProjectDesc } from '$lib/models/Project'; + +/** + * From v2.0.0 to v2.1.0, the project system was changed. + */ +export function newProjectSystemMigration() { + const projects: any[] = JSON.parse(localStorage.getItem('projects') || '[]'); + if (projects.length > 0) { + if (projects[0].timeline !== undefined) { + // backup and download the old projects + const data = JSON.stringify(projects, null, 2); + const blob = new Blob([data], { type: 'application/json' }); + const url = URL.createObjectURL(blob); + const a = document.createElement('a'); + a.href = url; + a.download = 'BACKUP FILE IN CASE EVERYTHING BROKE.qcb'; + a.click(); + + // Make each project occupy one different localstorage item + let projectsDesc: ProjectDesc[] = []; + for (let i = 0; i < projects.length; i++) { + const element = projects[i]; + + localStorage.setItem(element.id, JSON.stringify(element)); + projectsDesc.push({ + name: element.name, + updatedAt: element.updatedAt, + id: element.id + }); + } + + localStorage.setItem('projects', JSON.stringify(projectsDesc)); + } + } +} diff --git a/src/lib/models/Project.ts b/src/lib/models/Project.ts index 2af6851..f2e34dc 100644 --- a/src/lib/models/Project.ts +++ b/src/lib/models/Project.ts @@ -4,6 +4,12 @@ import type Timeline from './Timeline'; import Id from '../ext/Id'; import { cursorPosition, zoom } from '../stores/TimelineStore'; +export interface ProjectDesc { + id: string; + name: string; + updatedAt: Date; +} + /** * Represents a project. */ diff --git a/src/lib/stores/ProjectStore.ts b/src/lib/stores/ProjectStore.ts index 5c5ed2a..c131512 100644 --- a/src/lib/stores/ProjectStore.ts +++ b/src/lib/stores/ProjectStore.ts @@ -2,6 +2,7 @@ import type Project from '$lib/models/Project'; import { get, writable, type Writable } from 'svelte/store'; import { cursorPosition, scrollPosition, zoom } from './TimelineStore'; import Id from '$lib/ext/Id'; +import type { ProjectDesc } from '$lib/models/Project'; export const currentProject: Writable = writable(); @@ -107,23 +108,21 @@ export function createBlankProject(name: string): Project { * @param id - The ID of the project to delete. * @returns An array of user projects. */ -export function delProject(id: string): Project[] { - const projects = getUserProjects(); - const index = projects.findIndex((p) => p.id === id); +export function delProject(id: string): ProjectDesc[] { + localStorage.removeItem(id); - if (index !== -1) { - projects.splice(index, 1); - localStorage.setItem('projects', JSON.stringify(projects)); - } + let userProjects = getUserProjects(); + userProjects = userProjects.filter((x) => x.id !== id); + localStorage.setItem('projects', JSON.stringify(userProjects)); - return projects; + return userProjects; } /** * Retrieves the user's projects from local storage. * @returns An array of user projects. */ -export function getUserProjects(): Project[] { +export function getUserProjects(): ProjectDesc[] { return JSON.parse(localStorage.getItem('projects') || '[]'); } @@ -133,33 +132,45 @@ export function getUserProjects(): Project[] { * @returns The project with the specified ID, or undefined if not found. */ export function getProjectById(id: string): Project | undefined { - return getUserProjects().find((p) => p.id === id); + const projJson = localStorage.getItem(id); + if (projJson) return JSON.parse(projJson); + else return createBlankProject('undefined project'); } /** * Updates the user's projects in local storage. * @param project - The project to update. */ -export function updateUsersProjects(project: Project): void { - if (project === undefined) return; // No project is open +export function updateUsersProjects(project: Project): ProjectDesc[] { + const projects: ProjectDesc[] = getUserProjects(); + + if (project === undefined) return projects; // No project is open project.projectSettings.zoom = get(zoom); project.projectSettings.cursorPosition = get(cursorPosition); project.projectSettings.scrollLeft = get(scrollPosition); - const projects = getUserProjects(); - const index = projects.findIndex((p) => p.id === project.id); if (index === -1) { if (projects.find((p) => p.name === project.name)) { project.name = project.name + ' - New'; } - projects.push(project); + projects.push({ + id: project.id, + name: project.name, + updatedAt: project.updatedAt + }); } else { - projects[index] = project; + projects[index] = { + id: project.id, + name: project.name, + updatedAt: project.updatedAt + }; } - //localStorage.removeItem('projects'); + localStorage.setItem(project.id, JSON.stringify(project)); localStorage.setItem('projects', JSON.stringify(projects)); + + return projects; } diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index b1c6f1a..b51a3e7 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -6,6 +6,7 @@ createBlankProject, currentProject, delProject, + getProjectById, getUserProjects, updateUsersProjects } from '$lib/stores/ProjectStore'; @@ -24,16 +25,20 @@ import { invoke } from '@tauri-apps/api/tauri'; import { open } from '@tauri-apps/api/dialog'; import { addAssets } from '$lib/models/Asset'; + import type { ProjectDesc } from '$lib/models/Project'; + import { newProjectSystemMigration } from '$lib/ext/VersionFix'; let createProjectVisibility = false; let projectName = 'New Project'; - let userProjects: Project[] = []; + let userProjectsDesc: ProjectDesc[] = []; let searchText = ''; onMount(async () => { - userProjects = getUserProjects(); + newProjectSystemMigration(); + + userProjectsDesc = getUserProjects(); // Check if a new version is available const response = await fetch(GITHUB_API_URL); @@ -69,21 +74,21 @@ updateUsersProjects(project); // Save the project to the local storage - openProject(project); // Open the project + openProject(project.id); // Open the project } /** * Open a project */ - function openProject(project: Project) { - window.location.href = `/editor?${project.id}`; // Redirect to the editor page + function openProject(projectId: string) { + window.location.href = `/editor?${projectId}`; // Redirect to the editor page } /** * Handle delete project */ function handleDelProject(id: string) { - userProjects = delProject(id); + userProjectsDesc = delProject(id); } /** @@ -97,9 +102,9 @@ project.id = Id.generate(); // Generate a new id for the project - updateUsersProjects(project); // Save the project to the local storage + userProjectsDesc = updateUsersProjects(project); // Save the project to the local storage - openProject(project); // Open the project + openProject(project.id); // Open the project } } @@ -107,6 +112,14 @@ * Handle backup all projects button clicked */ function handleBackupAllProjectsButtonClicked() { + let userProjects: Project[] = []; + + for (let i = 0; i < userProjectsDesc.length; i++) { + const element = userProjectsDesc[i]; + + userProjects.push(JSON.parse(localStorage.getItem(element.id)!)); + } + const data = JSON.stringify(userProjects, null, 2); const blob = new Blob([data], { type: 'application/json' }); @@ -130,16 +143,17 @@ projects.forEach((project: Project) => { // if project id already exists, replace it if the updatedAt is more recent - const existingProject = userProjects.find((p) => p.id === project.id); + const existingProject = userProjectsDesc.find((p) => p.id === project.id); if (existingProject && new Date(existingProject.updatedAt) > new Date(project.updatedAt)) { - userProjects = userProjects.map((p) => (p.id === project.id ? project : p)); - } else { + userProjectsDesc = userProjectsDesc.map((p) => (p.id === project.id ? project : p)); + updateUsersProjects(project); + } else if (!existingProject) { // Project does not exist, add it updateUsersProjects(project); } }); - userProjects = getUserProjects(); + userProjectsDesc = getUserProjects(); } } @@ -149,7 +163,7 @@

Quran Caption

-

Project{userProjects.length > 1 ? 's' : ''} :

+

Project{userProjectsDesc.length > 1 ? 's' : ''} :

= 4 ? 'justify-evenly h-80' : '')} + (userProjectsDesc.length >= 4 ? 'justify-evenly h-80' : '')} > - {#each userProjects.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()) as project} + {#each userProjectsDesc.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime()) as project} {#if searchText === '' || project.name.toLowerCase().includes(searchText.toLowerCase())}
- @@ -200,8 +214,14 @@ // window text prompt const newName = prompt('Enter the new name of the project', project.name); if (newName) { - project.name = newName; - updateUsersProjects(project); + userProjectsDesc = userProjectsDesc.map((x) => + x.id === project.id ? { ...x, name: newName } : x + ); + let _project = getProjectById(project.id); + // @ts-ignore + _project.name = newName; + // @ts-ignores + updateUsersProjects(_project); } }} >