Skip to content

Commit

Permalink
Merge pull request #647 from tuanchauict/change-project-management-di…
Browse files Browse the repository at this point in the history
…alog

Correct the initial project id and update title after rename
  • Loading branch information
tuanchauict authored Feb 3, 2025
2 parents 158c471 + 6646efe commit 232a119
Show file tree
Hide file tree
Showing 16 changed files with 97 additions and 96 deletions.
19 changes: 7 additions & 12 deletions monosketch-svelte/src/app/app-context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ export class AppContext {

actionManager = new ActionManager(this.appLifecycleOwner);

browserManager = new BrowserManager((projectId: string) => {
this.actionManager.setOneTimeAction(OneTimeAction.ProjectAction.SwitchProject(projectId));
});

workspaceDao: WorkspaceDao = WorkspaceDao.instance;

// Workspace must be set before MainStateManager is initiated.
Expand All @@ -42,6 +46,7 @@ export class AppContext {
);

this.mainStateManager?.onStart(this.appLifecycleOwner);
this.browserManager.startObserveStateChange(this.shapeManager.rootIdFlow, this.appLifecycleOwner,);
};

setWorkspace(workspace: Workspace) {
Expand All @@ -68,27 +73,17 @@ export class AppContext {
}
this.actionManager.installDebugCommand();

const selectedShapeManager = new SelectedShapeManager();

const browserManager = new BrowserManager((projectId: string) => {
this.actionManager.setOneTimeAction(OneTimeAction.ProjectAction.SwitchProject(projectId));
});
browserManager.startObserveStateChange(
this.shapeManager.rootIdFlow,
this.appLifecycleOwner,
WorkspaceDao.instance);

this.mainStateManager = new MainStateManager(
this.monoBoard,
this.shapeManager,
selectedShapeManager,
new SelectedShapeManager(),
new MonoBitmapManager(),
this.workspace,
this.workspaceDao,
this.actionManager,
new ShapeClipboardManager(),
this.appUiStateManager,
browserManager.rootIdFromUrl,
this.browserManager.rootIdFromUrl,
);
// TODO: Replicate from MonoSketchApplication
}
Expand Down
5 changes: 3 additions & 2 deletions monosketch-svelte/src/lib/mono/shape/shape-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ export class ShapeManager {
private rootInner: Group = RootGroup(null);
private allShapeMap: Map<string | null, AbstractShape> = new Map([[this.rootInner.id, this.rootInner]]);

private rootIdMutableFlow: Flow<string> = new Flow(this.rootInner.id);
// The initial rootInner is a default root, means the app is not ready.
// The rootId should be undefined until `replaceRoot` is called.
private rootIdMutableFlow: Flow<string> = new Flow();
public readonly rootIdFlow: Flow<string> = this.rootIdMutableFlow.immutable();

public shapeConnectorInner: ShapeConnector = new ShapeConnector();
Expand All @@ -38,7 +40,6 @@ export class ShapeManager {
public readonly versionFlow: Flow<number> = this.versionMutableFlow.immutable();

constructor() {
this.replaceRoot(this.rootInner, this.shapeConnectorInner);
}

get root(): Group {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export class StateHistoryManager {
}

/**
* Restores and starts observing the state change of the object with [rootId].
* Restores of the object with [rootId].
* If [rootId] is empty, the last opened object is used. In case of there is no objects in the
* database, a new ID is generated with [UUID.generate].
*
Expand All @@ -39,7 +39,6 @@ export class StateHistoryManager {
*/
restoreState(rootId: string) {
const objectDao = this.getObjectDaoById(rootId);

this.restoreShapes(objectDao);
this.workspace.setDrawingOffset(objectDao.offset);
}
Expand Down
2 changes: 1 addition & 1 deletion monosketch-svelte/src/lib/mono/store-manager/consts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const StoreKeys = {
FONT_SIZE: 'font-size',

WORKSPACE: 'workspace',
LAST_OPEN: 'last-open',
LAST_OPEN: 'last-open', // deprecated

OBJECT_NAME: 'name',
OBJECT_CONTENT: 'content',
Expand Down
26 changes: 13 additions & 13 deletions monosketch-svelte/src/lib/mono/store-manager/dao/workspace-dao.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { StorageDocument } from "$mono/store-manager";
import { StorageDocument, StoreKeys } from "$mono/store-manager";
import { WorkspaceObjectDao } from "$mono/store-manager/dao/workspace-object-dao";

/**
Expand All @@ -13,16 +13,22 @@ export class WorkspaceDao {
private constructor(workspaceDocument: StorageDocument) {
this.workspaceDocument = workspaceDocument;
this.objectDaos = new Map<string, WorkspaceObjectDao>();

workspaceDocument.setObserver(StoreKeys.LAST_OPEN, {
onChange: (key, oldValue, newValue) => {
console.log(`Last opened object changed: ${oldValue} -> ${newValue}`);
},
});
}

// Accessor property for lastOpenedObjectId
get lastOpenedObjectId(): string | null {
return this.workspaceDocument.get(WorkspaceDao.LAST_OPEN);
return this.workspaceDocument.get(StoreKeys.LAST_OPEN);
}

set lastOpenedObjectId(value: string | null) {
if (value !== null) {
this.workspaceDocument.set(WorkspaceDao.LAST_OPEN, value);
this.workspaceDocument.set(StoreKeys.LAST_OPEN, value);
}
}

Expand All @@ -46,24 +52,18 @@ export class WorkspaceDao {
// Gets list of all objects in the storage, ordered by last opened time desc.
getObjects(): WorkspaceObjectDao[] {
return Array.from(this.workspaceDocument.getKeys(key =>
key.startsWith(WorkspaceDao.WORKSPACE + WorkspaceDao.PATH_SEPARATOR) &&
key.endsWith(WorkspaceDao.PATH_SEPARATOR + WorkspaceDao.OBJECT_CONTENT)
key.startsWith(StoreKeys.WORKSPACE + StoreKeys.PATH_SEPARATOR) &&
key.endsWith(StoreKeys.PATH_SEPARATOR + StoreKeys.OBJECT_CONTENT),
))
.map(key => this.getObject(key.split(WorkspaceDao.PATH_SEPARATOR)[1]))
.map(key => this.getObject(key.split(StoreKeys.PATH_SEPARATOR)[1]))
.sort((a, b) => b.lastOpened - a.lastOpened); // Assuming lastOpened is a numeric timestamp
}

// Singleton instance accessor
static get instance(): WorkspaceDao {
if (!WorkspaceDao._instance) {
WorkspaceDao._instance = new WorkspaceDao(StorageDocument.get(WorkspaceDao.WORKSPACE));
WorkspaceDao._instance = new WorkspaceDao(StorageDocument.get(StoreKeys.WORKSPACE));
}
return WorkspaceDao._instance;
}

// Constants
private static readonly LAST_OPEN = "lastOpen";
private static readonly WORKSPACE = "workspace";
private static readonly PATH_SEPARATOR = "/";
private static readonly OBJECT_CONTENT = "objectContent";
}
13 changes: 5 additions & 8 deletions monosketch-svelte/src/lib/mono/window/browser-manager.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { Flow, LifecycleOwner } from "$libs/flow";
import type { WorkspaceDao } from "$mono/store-manager/dao/workspace-dao";

/**
* A class for managing the states related to the browser such as the title, address bar, etc.
Expand Down Expand Up @@ -37,14 +36,7 @@ export class BrowserManager {
startObserveStateChange(
workingProjectIdFlow: Flow<string>,
lifecycleOwner: LifecycleOwner,
workspaceDao: WorkspaceDao,
): void {
// Observe changes to the project ID and update the document title
workingProjectIdFlow.observe(lifecycleOwner, projectId => {
const project = workspaceDao.getObject(projectId);
document.title = `${project.name} - MonoSketch`;
});

// Observe distinct changes to the project ID and update the URL
workingProjectIdFlow.distinctUntilChanged().observe(lifecycleOwner, projectId => {
if (projectId === this.rootIdFromUrl || this.willChangedByUrlPopStateEvent) {
Expand All @@ -58,6 +50,11 @@ export class BrowserManager {
});
}

updateAppTitle(projectName: string) {
// Update the document title with the current project name
document.title = `${projectName} - MonoSketch`;
}

// Static property for the URL parameter key
private static URL_PARAM_ID: string = 'id';

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script lang="ts">
import type { ProjectAction } from '../model';
import type { ProjectAction } from '$ui/nav/project/model';
import TooltipTarget from '../../tooltip/TooltipTarget.svelte';
import { TooltipDirection } from '../../tooltip/model';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import ProjectActionView from './ProjectActionView.svelte';
import { ProjectAction } from '../model';
import { ProjectAction } from '$ui/nav/project/model';
import OpenInNewTab from './icons/OpenInNewTab.svelte';
import Remove from './icons/Remove.svelte';
import RemoveConfirmation from './icons/RemoveConfirmation.svelte';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<script lang="ts">
import ProjectRow from './ProjectRow.svelte';
import { ProjectAction, type ProjectItem } from '../model';
import { ProjectAction, type ProjectItem } from '$ui/nav/project/model';
import { getContext, onDestroy, onMount } from 'svelte';
import { LifecycleOwner } from '$libs/flow';
import { BrowserManager } from "$mono/window/browser-manager";
Expand All @@ -18,12 +18,14 @@ let deletingId: string = '';
onMount(() => {
const lifecycleOwner = LifecycleOwner.start();
// Manually update the project list to ensure the list is up-to-date when the modal is opened
projectDataViewModel.updateProjectList();
projectDataViewModel.projectFlow.observe(lifecycleOwner, (list) => {
projectList = list;
});
projectDataViewModel.openingProjectIdFlow.observe(lifecycleOwner, (id) => {
openingId = id;
projectDataViewModel.openingProjectFlow.observe(lifecycleOwner, (project) => {
openingId = project.id;
});
projectDataViewModel.deletingProjectIdFlow.observe(lifecycleOwner, (id) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
import MenuItem from '../common/MenuItem.svelte';
import ProjectActions from './ProjectActions.svelte';
import ProjectIcon from './ProjectIcon.svelte';
import { ProjectAction, type ProjectItem } from '../model';
import { ProjectAction, type ProjectItem } from '$ui/nav/project/model';
export let project: ProjectItem;
export let opening: boolean;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import { onMount } from 'svelte';
export let name: string;
export let onDone: () => void;
let textInput: HTMLInputElement;
Expand All @@ -10,10 +11,22 @@ onMount(() => {
textInput.focus();
}, 10);
});
function onKeydown(event: KeyboardEvent) {
if (event.key === 'Enter') {
// Prevent the default behavior of the Enter key to avoid submitting the form
event.preventDefault();
onDone();
} else if (event.key === 'Escape') {
name = '';
onDone();
event.preventDefault();
}
}
</script>

<div>
<input type="text" bind:value="{name}" bind:this="{textInput}" />
<input type="text" bind:value="{name}" bind:this="{textInput}" on:keydown="{onKeydown}"/>
</div>

<style lang="scss">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,5 +33,5 @@ onMount(() => {
</script>

<NoBackgroundModal onDismiss="{onDone}" {left} {top} width="{180}">
<ProjectNameTextField bind:name />
<ProjectNameTextField bind:name {onDone}/>
</NoBackgroundModal>
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,12 @@
import ProjectManagerButton from "$ui/nav/project/ProjectManagerButton.svelte";
import ToolbarContainer from "$ui/nav/common/ToolbarContainer.svelte";
import { ProjectDataViewModel } from "$ui/nav/project/project-data-viewmodel";
import { setContext } from "svelte";
import { getContext, setContext } from "svelte";
import { PROJECT_CONTEXT } from "$ui/nav/project/constants";
import { sampleProjectItems } from "$ui/modal/recent-project/model";
import { APP_CONTEXT } from "$mono/common/constant";
const projectDataViewModel = new ProjectDataViewModel();
const projectDataViewModel = new ProjectDataViewModel(getContext(APP_CONTEXT));
setContext(PROJECT_CONTEXT, projectDataViewModel);
projectDataViewModel.setProjectList(sampleProjectItems);
</script>

<ToolbarContainer>
Expand Down
27 changes: 6 additions & 21 deletions monosketch-svelte/src/lib/ui/nav/project/WorkingProject.svelte
Original file line number Diff line number Diff line change
@@ -1,41 +1,26 @@
<script lang="ts">
import WorkingProjectView from './WorkingProjectView.svelte';
import { Flow, LifecycleOwner } from '$libs/flow';
import { LifecycleOwner } from '$libs/flow';
import { getContext, onMount } from 'svelte';
import type { ProjectDataViewModel } from "$ui/nav/project/project-data-viewmodel";
import { PROJECT_CONTEXT } from "$ui/nav/project/constants";
import { APP_CONTEXT } from "$mono/common/constant";
import { AppContext } from "$app/app-context";
const appContext = getContext<AppContext>(APP_CONTEXT);
const projectDataViewModel = getContext<ProjectDataViewModel>(PROJECT_CONTEXT);
let projectId = '';
let projectName = '';
// TODO: the current flow of showing the working project info and renaming project is not intuitive. Fix it!
const openingProjectFlow = Flow.combine2(
projectDataViewModel.openingProjectIdFlow,
projectDataViewModel.renamingProjectIdFlow,
(id) => projectDataViewModel.getProject(id),
);
const renamingProjectFlow = projectDataViewModel.renamingProjectIdFlow.map((id) => {
const project = projectDataViewModel.getProject(id);
return project ? project : null;
});
onMount(() => {
const lifecycleOwner = LifecycleOwner.start();
openingProjectFlow.observe(lifecycleOwner, (project) => {
projectDataViewModel.openingProjectFlow.observe(lifecycleOwner, (project) => {
// TODO: make the flow mapping ignore undefined value as return type.
projectId = project!.id;
projectName = project!.name;
});
renamingProjectFlow.observe(lifecycleOwner, (project) => {
if (!project) {
return;
}
projectDataViewModel.setRenamingProject(project.id);
appContext.browserManager.updateAppTitle(projectName);
});
return () => {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
/*
* Copyright (c) 2025, tuanchauict
*/

export enum ProjectAction {
Open,
OpenInNewTab,
Expand All @@ -10,8 +14,3 @@ export interface ProjectItem {
id: string;
name: string;
}

export const sampleProjectItems: ProjectItem[] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10].map((i) => ({
id: `id:${i}`,
name: `File ${i}`,
}));
Loading

0 comments on commit 232a119

Please sign in to comment.