Merge branch 'develop' into feature/remove-batch-manager

This commit is contained in:
Antonella Sgarlatta
2021-06-08 18:59:39 -03:00
committed by GitHub
24 changed files with 1026 additions and 371 deletions

View File

@@ -16,6 +16,7 @@ import { Bridge } from '@/services/bridge';
import { storage, StorageKey } from '@/services/localStorage';
import { AccountMenuState } from './account_menu_state';
import { ActionsMenuState } from './actions_menu_state';
import { NoteTagsState } from './note_tags_state';
import { NoAccountWarningState } from './no_account_warning_state';
import { SyncState } from './sync_state';
import { SearchOptionsState } from './search_options_state';
@@ -63,6 +64,7 @@ export class AppState {
readonly accountMenu = new AccountMenuState();
readonly actionsMenu = new ActionsMenuState();
readonly noAccountWarning: NoAccountWarningState;
readonly noteTags: NoteTagsState;
readonly sync = new SyncState();
readonly searchOptions: SearchOptionsState;
readonly notes: NotesState;
@@ -82,12 +84,18 @@ export class AppState {
this.$rootScope = $rootScope;
this.application = application;
this.notes = new NotesState(
this.application,
application,
this,
async () => {
await this.notifyEvent(AppStateEvent.ActiveEditorChanged);
},
this.appEventObserverRemovers,
);
this.noteTags = new NoteTagsState(
application,
this,
this.appEventObserverRemovers
);
this.tags = new TagsState(
application,
this.appEventObserverRemovers,

View File

@@ -0,0 +1,208 @@
import { SNNote, ContentType, SNTag, UuidString } from '@standardnotes/snjs';
import { action, computed, makeObservable, observable } from 'mobx';
import { WebApplication } from '../application';
import { AppState } from './app_state';
export class NoteTagsState {
autocompleteInputFocused = false;
autocompleteSearchQuery = '';
autocompleteTagHintFocused = false;
autocompleteTagResults: SNTag[] = [];
focusedTagResultUuid: UuidString | undefined = undefined;
focusedTagUuid: UuidString | undefined = undefined;
tags: SNTag[] = [];
tagsContainerMaxWidth: number | 'auto' = 0;
constructor(
private application: WebApplication,
private appState: AppState,
appEventListeners: (() => void)[]
) {
makeObservable(this, {
autocompleteInputFocused: observable,
autocompleteSearchQuery: observable,
autocompleteTagHintFocused: observable,
autocompleteTagResults: observable,
focusedTagUuid: observable,
focusedTagResultUuid: observable,
tags: observable,
tagsContainerMaxWidth: observable,
autocompleteTagHintVisible: computed,
clearAutocompleteSearch: action,
focusNextTag: action,
focusPreviousTag: action,
setAutocompleteInputFocused: action,
setAutocompleteSearchQuery: action,
setAutocompleteTagHintFocused: action,
setAutocompleteTagResults: action,
setFocusedTagResultUuid: action,
setFocusedTagUuid: action,
setTags: action,
setTagsContainerMaxWidth: action,
reloadTags: action,
});
appEventListeners.push(
application.streamItems(ContentType.Tag, () => {
this.reloadTags();
})
);
}
get activeNote(): SNNote | undefined {
return this.appState.notes.activeEditor?.note;
}
get autocompleteTagHintVisible(): boolean {
return (
this.autocompleteSearchQuery !== '' &&
!this.autocompleteTagResults.some(
(tagResult) => tagResult.title === this.autocompleteSearchQuery
)
);
}
setAutocompleteInputFocused(focused: boolean): void {
this.autocompleteInputFocused = focused;
}
setAutocompleteSearchQuery(query: string): void {
this.autocompleteSearchQuery = query;
}
setAutocompleteTagHintFocused(focused: boolean): void {
this.autocompleteTagHintFocused = focused;
}
setAutocompleteTagResults(results: SNTag[]): void {
this.autocompleteTagResults = results;
}
setFocusedTagUuid(tagUuid: UuidString | undefined): void {
this.focusedTagUuid = tagUuid;
}
setFocusedTagResultUuid(tagUuid: UuidString | undefined): void {
this.focusedTagResultUuid = tagUuid;
}
setTags(tags: SNTag[]): void {
this.tags = tags;
}
setTagsContainerMaxWidth(width: number): void {
this.tagsContainerMaxWidth = width;
}
clearAutocompleteSearch(): void {
this.setAutocompleteSearchQuery('');
this.searchActiveNoteAutocompleteTags();
}
async createAndAddNewTag(): Promise<void> {
const newTag = await this.application.findOrCreateTag(
this.autocompleteSearchQuery
);
await this.addTagToActiveNote(newTag);
this.clearAutocompleteSearch();
}
focusNextTag(tag: SNTag): void {
const nextTagIndex = this.getTagIndex(tag, this.tags) + 1;
if (nextTagIndex > -1 && this.tags.length > nextTagIndex) {
const nextTag = this.tags[nextTagIndex];
this.setFocusedTagUuid(nextTag.uuid);
}
}
focusNextTagResult(tagResult: SNTag): void {
const nextTagResultIndex =
this.getTagIndex(tagResult, this.autocompleteTagResults) + 1;
if (
nextTagResultIndex > -1 &&
this.autocompleteTagResults.length > nextTagResultIndex
) {
const nextTagResult = this.autocompleteTagResults[nextTagResultIndex];
this.setFocusedTagResultUuid(nextTagResult.uuid);
}
}
focusPreviousTag(tag: SNTag): void {
const previousTagIndex = this.getTagIndex(tag, this.tags) - 1;
if (previousTagIndex > -1 && this.tags.length > previousTagIndex) {
const previousTag = this.tags[previousTagIndex];
this.setFocusedTagUuid(previousTag.uuid);
}
}
focusPreviousTagResult(tagResult: SNTag): void {
const previousTagResultIndex =
this.getTagIndex(tagResult, this.autocompleteTagResults) - 1;
if (
previousTagResultIndex > -1 &&
this.autocompleteTagResults.length > previousTagResultIndex
) {
const previousTagResult =
this.autocompleteTagResults[previousTagResultIndex];
this.setFocusedTagResultUuid(previousTagResult.uuid);
}
}
searchActiveNoteAutocompleteTags(): void {
const newResults = this.application.searchTags(
this.autocompleteSearchQuery,
this.activeNote
);
this.setAutocompleteTagResults(newResults);
}
getTagIndex(tag: SNTag, tagsArr: SNTag[]): number {
return tagsArr.findIndex((t) => t.uuid === tag.uuid);
}
reloadTags(): void {
const { activeNote } = this;
if (activeNote) {
const tags = this.application.getSortedTagsForNote(activeNote);
this.setTags(tags);
}
}
reloadTagsContainerMaxWidth(): void {
const EDITOR_ELEMENT_ID = 'editor-column';
const editorWidth = document.getElementById(EDITOR_ELEMENT_ID)?.clientWidth;
if (editorWidth) {
this.setTagsContainerMaxWidth(editorWidth);
}
}
async addTagToActiveNote(tag: SNTag): Promise<void> {
const { activeNote } = this;
if (activeNote) {
const parentChainTags = this.application.getTagParentChain(tag);
const tagsToAdd = [...parentChainTags, tag];
await Promise.all(
tagsToAdd.map(async (tag) => {
await this.application.changeItem(tag.uuid, (mutator) => {
mutator.addItemAsRelationship(activeNote);
});
})
);
this.application.sync();
this.reloadTags();
}
}
async removeTagFromActiveNote(tag: SNTag): Promise<void> {
const { activeNote } = this;
if (activeNote) {
await this.application.changeItem(tag.uuid, (mutator) => {
mutator.removeItemAsRelationship(activeNote);
});
this.application.sync();
this.reloadTags();
}
}
}

View File

@@ -18,6 +18,7 @@ import {
} from 'mobx';
import { WebApplication } from '../application';
import { Editor } from '../editor';
import { AppState } from './app_state';
export class NotesState {
lastSelectedNote: SNNote | undefined;
@@ -32,6 +33,7 @@ export class NotesState {
constructor(
private application: WebApplication,
private appState: AppState,
private onActiveEditorChanged: () => Promise<void>,
appEventListeners: (() => void)[]
) {
@@ -168,6 +170,8 @@ export class NotesState {
} else {
this.activeEditor.setNote(note);
}
this.appState.noteTags.reloadTags();
await this.onActiveEditorChanged();
if (note.waitingForKey) {
@@ -326,11 +330,17 @@ export class NotesState {
async addTagToSelectedNotes(tag: SNTag): Promise<void> {
const selectedNotes = Object.values(this.selectedNotes);
await this.application.changeItem(tag.uuid, (mutator) => {
for (const note of selectedNotes) {
mutator.addItemAsRelationship(note);
}
});
const parentChainTags = this.application.getTagParentChain(tag);
const tagsToAdd = [...parentChainTags, tag];
await Promise.all(
tagsToAdd.map(async (tag) => {
await this.application.changeItem(tag.uuid, (mutator) => {
for (const note of selectedNotes) {
mutator.addItemAsRelationship(note);
}
});
})
);
this.application.sync();
}
@@ -342,13 +352,13 @@ export class NotesState {
}
});
this.application.sync();
}
isTagInSelectedNotes(tag: SNTag): boolean {
const selectedNotes = Object.values(this.selectedNotes);
return selectedNotes.every((note) =>
this.application
.getAppState()
this.appState
.getNoteTags(note)
.find((noteTag) => noteTag.uuid === tag.uuid)
);