1// Copyright (C) 2024 The Android Open Source Project 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15import { 16 AddNoteArgs, 17 AddSpanNoteArgs, 18 Note, 19 NoteManager, 20 SpanNote, 21} from '../public/note'; 22import {randomColor} from '../components/colorizer'; 23 24export class NoteManagerImpl implements NoteManager { 25 private _lastNodeId = 0; 26 private _notes = new Map<string, Note | SpanNote>(); 27 28 // This function is wired up to clear the SelectionManager state if the 29 // current selection is a note. 30 // TODO(primiano): figure out some better (de-)coupling here. 31 // We cannot pass SelectionManager in our constructor because doing so would 32 // create a cyclic ctor dependency (SelectionManager requires NoteManager in 33 // its ctor). There is a 2way logical dependency between NoteManager and 34 // SelectionManager: 35 // 1. SM needs NM to handle SM.findTimeRangeOfSelection(), for [M]ark. 36 // 2. NM needs SM to tell it that a note has been delete and should be 37 // deselected if it was currently selected. 38 onNoteDeleted?: (nodeId: string) => void; 39 40 get notes(): ReadonlyMap<string, Note | SpanNote> { 41 return this._notes; 42 } 43 44 getNote(id: string): Note | SpanNote | undefined { 45 return this._notes.get(id); 46 } 47 48 addNote(args: AddNoteArgs): string { 49 const id = args.id ?? `note_${++this._lastNodeId}`; 50 this._notes.set(id, { 51 ...args, 52 noteType: 'DEFAULT', 53 id, 54 color: args.color ?? randomColor(), 55 text: args.text ?? '', 56 }); 57 return id; 58 } 59 60 addSpanNote(args: AddSpanNoteArgs): string { 61 const id = args.id ?? `note_${++this._lastNodeId}`; 62 this._notes.set(id, { 63 ...args, 64 noteType: 'SPAN', 65 id, 66 color: args.color ?? randomColor(), 67 text: args.text ?? '', 68 }); 69 return id; 70 } 71 72 changeNote(id: string, args: {color?: string; text?: string}) { 73 const note = this._notes.get(id); 74 if (note === undefined) return; 75 76 this._notes.set(id, { 77 ...note, 78 color: args.color ?? note.color, 79 text: args.text ?? note.text, 80 }); 81 } 82 83 removeNote(id: string) { 84 this._notes.delete(id); 85 this.onNoteDeleted?.(id); 86 } 87} 88