another cleanup pass
This commit is contained in:
parent
898b495f52
commit
ad568b5c9f
8 changed files with 125 additions and 124 deletions
|
|
@ -22,7 +22,7 @@ export class MediaDbAdvancedSearchModal extends Modal {
|
|||
super(plugin.app);
|
||||
|
||||
this.plugin = plugin;
|
||||
this.selectedApis = [];
|
||||
this.selectedApis = [...(advancedSearchModalOptions.preselectedAPIs ?? [])];
|
||||
this.title = advancedSearchModalOptions.modalTitle ?? '';
|
||||
this.query = advancedSearchModalOptions.prefilledSearchString ?? '';
|
||||
this.isBusy = false;
|
||||
|
|
@ -101,7 +101,9 @@ export class MediaDbAdvancedSearchModal extends Modal {
|
|||
apiToggleComponent.setValue(this.selectedApis.some(x => x === api.apiName));
|
||||
apiToggleComponent.onChange(value => {
|
||||
if (value) {
|
||||
this.selectedApis.push(api.apiName);
|
||||
if (!this.selectedApis.includes(api.apiName)) {
|
||||
this.selectedApis.push(api.apiName);
|
||||
}
|
||||
} else {
|
||||
this.selectedApis = this.selectedApis.filter(x => x !== api.apiName);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,8 +23,8 @@ export class MediaDbIdSearchModal extends Modal {
|
|||
|
||||
this.plugin = plugin;
|
||||
this.title = idSearchModalOptions.modalTitle ?? '';
|
||||
this.selectedApi = idSearchModalOptions.preselectedAPI ?? plugin.apiManager.apis[0].apiName;
|
||||
this.query = '';
|
||||
this.selectedApi = idSearchModalOptions.preselectedAPI ?? plugin.apiManager.apis[0]?.apiName ?? '';
|
||||
this.query = idSearchModalOptions.prefilledSearchString ?? '';
|
||||
this.isBusy = false;
|
||||
}
|
||||
|
||||
|
|
@ -74,6 +74,7 @@ export class MediaDbIdSearchModal extends Modal {
|
|||
const searchComponent = new TextComponent(contentEl);
|
||||
searchComponent.inputEl.addClass('media-db-plugin-search-input');
|
||||
searchComponent.setPlaceholder(placeholder);
|
||||
searchComponent.setValue(this.query);
|
||||
searchComponent.onChange(value => (this.query = value));
|
||||
searchComponent.inputEl.addEventListener('keydown', this.keyPressCallback.bind(this));
|
||||
|
||||
|
|
@ -93,6 +94,7 @@ export class MediaDbIdSearchModal extends Modal {
|
|||
for (const api of this.plugin.apiManager.apis) {
|
||||
apiSelectorComponent.addOption(api.apiName, api.apiName);
|
||||
}
|
||||
apiSelectorComponent.setValue(this.selectedApi);
|
||||
apiSelectorWrapper.appendChild(apiSelectorComponent.selectEl);
|
||||
|
||||
contentEl.createDiv({ cls: 'media-db-plugin-spacer' });
|
||||
|
|
|
|||
|
|
@ -109,12 +109,13 @@ export class MediaDbSearchModal extends Modal {
|
|||
if (value) {
|
||||
if (currentToggle && currentToggle !== apiToggleComponent) {
|
||||
currentToggle.setValue(false);
|
||||
this.selectedTypes = this.selectedTypes.filter(x => x !== mediaType);
|
||||
}
|
||||
currentToggle = apiToggleComponent;
|
||||
this.selectedTypes.push(mediaType);
|
||||
this.selectedTypes = [mediaType];
|
||||
} else {
|
||||
currentToggle = undefined;
|
||||
if (currentToggle === apiToggleComponent) {
|
||||
currentToggle = undefined;
|
||||
}
|
||||
this.selectedTypes = this.selectedTypes.filter(x => x !== mediaType);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -62,5 +62,6 @@ export class MediaDbSearchResultModal extends SelectModal<MediaTypeModel> {
|
|||
|
||||
onClose(): void {
|
||||
this.closeCallback?.();
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@ import { SelectModal } from 'packages/obsidian/src/modals/SelectModal';
|
|||
export interface SeasonSelectModalElement {
|
||||
season_number: number;
|
||||
name: string;
|
||||
episode_count?: number;
|
||||
air_date?: string;
|
||||
poster_path?: string;
|
||||
}
|
||||
|
|
@ -33,7 +34,6 @@ export class MediaDbSeasonSelectModal extends SelectModal<SeasonSelectModalEleme
|
|||
submit(): void {
|
||||
const selected = this.selectModalElements.filter(x => x.isActive()).map(x => x.value);
|
||||
this.submitCallback?.(selected);
|
||||
this.close();
|
||||
}
|
||||
|
||||
skip(): void {
|
||||
|
|
@ -47,4 +47,9 @@ export class MediaDbSeasonSelectModal extends SelectModal<SeasonSelectModalEleme
|
|||
setCloseCb(cb: (err?: Error) => void): void {
|
||||
this.closeCallback = cb;
|
||||
}
|
||||
|
||||
onClose(): void {
|
||||
this.closeCallback?.();
|
||||
super.onClose();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -81,6 +81,7 @@ export abstract class SelectModal<T> extends Modal {
|
|||
onOpen(): void {
|
||||
const { contentEl, titleEl } = this;
|
||||
|
||||
this.selectModalElements = [];
|
||||
titleEl.createEl('h2', { text: this.title });
|
||||
contentEl.addClass('media-db-plugin-select-modal');
|
||||
contentEl.createEl('p', { text: this.description });
|
||||
|
|
@ -125,6 +126,11 @@ export abstract class SelectModal<T> extends Modal {
|
|||
});
|
||||
}
|
||||
|
||||
onClose(): void {
|
||||
this.selectModalElements = [];
|
||||
this.contentEl.empty();
|
||||
}
|
||||
|
||||
activateHighlighted(): void {
|
||||
for (const selectModalElement of this.selectModalElements) {
|
||||
if (selectModalElement.isHighlighted()) {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@ import { MarkdownView, Notice } from 'obsidian';
|
|||
import type { TMDBSeasonAPI } from 'packages/obsidian/src/api/apis/TMDBSeasonAPI';
|
||||
import type MediaDbPlugin from 'packages/obsidian/src/main';
|
||||
import type { SeasonSelectModalElement } from 'packages/obsidian/src/modals/MediaDbSeasonSelectModal';
|
||||
import { MediaDbSeasonSelectModal } from 'packages/obsidian/src/modals/MediaDbSeasonSelectModal';
|
||||
import type { MediaTypeModel } from 'packages/obsidian/src/models/MediaTypeModel';
|
||||
import type { SeasonModel } from 'packages/obsidian/src/models/SeasonModel';
|
||||
import type { MDBError } from 'packages/obsidian/src/utils/MDBError';
|
||||
|
|
@ -288,22 +287,16 @@ export class MediaDbEntryHelper {
|
|||
}
|
||||
|
||||
private async showSeasonSelectModal(allSeasons: SeasonModel[], seriesTitle: string): Promise<SeasonSelectModalElement[] | undefined> {
|
||||
const modal = new MediaDbSeasonSelectModal(
|
||||
this.plugin,
|
||||
allSeasons.map(season => ({
|
||||
return await this.plugin.modalHelper.promptSeasonSelectModal({
|
||||
seasons: allSeasons.map(season => ({
|
||||
season_number: season.seasonNumber,
|
||||
name: season.seasonTitle || season.title,
|
||||
episode_count: season.episodes || 0,
|
||||
air_date: season.year,
|
||||
poster_path: season.image,
|
||||
})),
|
||||
true,
|
||||
seriesTitle,
|
||||
);
|
||||
|
||||
return await new Promise(resolve => {
|
||||
modal.setSubmitCb(resolve);
|
||||
modal.open();
|
||||
multiSelect: true,
|
||||
seriesName: seriesTitle,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -4,6 +4,8 @@ import { MediaDbIdSearchModal } from 'packages/obsidian/src/modals/MediaDbIdSear
|
|||
import { MediaDbPreviewModal } from 'packages/obsidian/src/modals/MediaDbPreviewModal';
|
||||
import { MediaDbSearchModal } from 'packages/obsidian/src/modals/MediaDbSearchModal';
|
||||
import { MediaDbSearchResultModal } from 'packages/obsidian/src/modals/MediaDbSearchResultModal';
|
||||
import type { SeasonSelectModalElement } from 'packages/obsidian/src/modals/MediaDbSeasonSelectModal';
|
||||
import { MediaDbSeasonSelectModal } from 'packages/obsidian/src/modals/MediaDbSeasonSelectModal';
|
||||
import type { MediaTypeModel } from 'packages/obsidian/src/models/MediaTypeModel';
|
||||
import type { MDBError } from 'packages/obsidian/src/utils/MDBError';
|
||||
import { MDBErrorKind, toMdbError } from 'packages/obsidian/src/utils/MDBError';
|
||||
|
|
@ -66,6 +68,12 @@ export interface PreviewModalOptions {
|
|||
elements?: MediaTypeModel[];
|
||||
}
|
||||
|
||||
export interface SeasonSelectModalOptions {
|
||||
seasons?: SeasonSelectModalElement[];
|
||||
multiSelect?: boolean;
|
||||
seriesName?: string;
|
||||
}
|
||||
|
||||
export const SEARCH_MODAL_DEFAULT_OPTIONS: SearchModalOptions = {
|
||||
modalTitle: 'Media DB Search',
|
||||
preselectedTypes: [],
|
||||
|
|
@ -110,6 +118,14 @@ export interface ModalLifecycle {
|
|||
close(): void;
|
||||
}
|
||||
|
||||
interface CloseAwareModal extends ModalLifecycle {
|
||||
setCloseCb(closeCallback: (err?: Error) => void): void;
|
||||
}
|
||||
|
||||
interface SubmitModal<TData> extends CloseAwareModal {
|
||||
setSubmitCb(submitCallback: (res: TData) => void): void;
|
||||
}
|
||||
|
||||
export interface ModalSession<T, TModal extends ModalLifecycle> {
|
||||
modalResult: Outcome<T, MDBError>;
|
||||
modal: TModal;
|
||||
|
|
@ -134,11 +150,11 @@ export class ModalHelper {
|
|||
let resolved = false;
|
||||
const modalResult = await new Promise<Outcome<TData, MDBError>>(resolve => {
|
||||
const resolveSession = (result: Outcome<TData, MDBError>): void => {
|
||||
if (result.status === OutcomeStatus.Cancelled && !closeRequested) {
|
||||
cancelledByUser = true;
|
||||
}
|
||||
|
||||
if (!resolved) {
|
||||
if (result.status === OutcomeStatus.Cancelled && !closeRequested) {
|
||||
cancelledByUser = true;
|
||||
}
|
||||
|
||||
resolved = true;
|
||||
resolve(result);
|
||||
}
|
||||
|
|
@ -159,6 +175,40 @@ export class ModalHelper {
|
|||
};
|
||||
}
|
||||
|
||||
private createCloseOutcome(err: Error | undefined, message: string): Outcome<never, MDBError> {
|
||||
if (err) {
|
||||
return failure(toMdbError(err, { kind: MDBErrorKind.Modal, message }));
|
||||
}
|
||||
|
||||
return cancelled();
|
||||
}
|
||||
|
||||
private async openSubmitModalSession<TData, TModal extends SubmitModal<TData>>(
|
||||
createModal: () => TModal,
|
||||
closeErrorMessage: string,
|
||||
wireExtraHandlers?: (modal: TModal, resolve: (result: Outcome<TData, MDBError>) => void) => void,
|
||||
): Promise<ModalSession<TData, TModal>> {
|
||||
return await this.openModalCore<TData, TModal>(createModal, (modal, resolve) => {
|
||||
modal.setSubmitCb(res => resolve(success(res)));
|
||||
modal.setCloseCb(err => resolve(this.createCloseOutcome(err, closeErrorMessage)));
|
||||
wireExtraHandlers?.(modal, resolve);
|
||||
});
|
||||
}
|
||||
|
||||
private async resolveModalSessionOutcome<TData, TModal extends ModalLifecycle>(
|
||||
sessionPromise: Promise<ModalSession<TData, TModal>>,
|
||||
closeOn: readonly OutcomeStatus[] = [OutcomeStatus.Ok],
|
||||
): Promise<Outcome<TData, MDBError>> {
|
||||
const session = await sessionPromise;
|
||||
const { modalResult } = session;
|
||||
|
||||
if (closeOn.includes(modalResult.status)) {
|
||||
session.close();
|
||||
}
|
||||
|
||||
return modalResult;
|
||||
}
|
||||
|
||||
private async resolveOutcome<T>(outcomePromise: Promise<Outcome<T, MDBError>>): Promise<T | undefined> {
|
||||
const outcome = await outcomePromise;
|
||||
|
||||
|
|
@ -200,30 +250,13 @@ export class ModalHelper {
|
|||
}
|
||||
|
||||
async createSearchModalOutcome(searchModalOptions: SearchModalOptions): Promise<Outcome<SearchModalData, MDBError>> {
|
||||
const session = await this.createSearchModalSession(searchModalOptions);
|
||||
const { modalResult } = session;
|
||||
|
||||
if (modalResult.status === OutcomeStatus.Ok) {
|
||||
session.close();
|
||||
}
|
||||
|
||||
return modalResult;
|
||||
return await this.resolveModalSessionOutcome(this.createSearchModalSession(searchModalOptions));
|
||||
}
|
||||
|
||||
async createSearchModalSession(searchModalOptions: SearchModalOptions): Promise<ModalSession<SearchModalData, MediaDbSearchModal>> {
|
||||
return await this.openModalCore<SearchModalData, MediaDbSearchModal>(
|
||||
return await this.openSubmitModalSession<SearchModalData, MediaDbSearchModal>(
|
||||
() => new MediaDbSearchModal(this.plugin, searchModalOptions),
|
||||
(modal, resolve) => {
|
||||
modal.setSubmitCb(res => resolve(success(res)));
|
||||
modal.setCloseCb(err => {
|
||||
if (err) {
|
||||
resolve(failure(toMdbError(err, { kind: MDBErrorKind.Modal, message: 'Search modal closed with an error' })));
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(cancelled());
|
||||
});
|
||||
},
|
||||
'Search modal closed with an error',
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -232,30 +265,13 @@ export class ModalHelper {
|
|||
}
|
||||
|
||||
async createAdvancedSearchModalOutcome(advancedSearchModalOptions: AdvancedSearchModalOptions): Promise<Outcome<AdvancedSearchModalData, MDBError>> {
|
||||
const session = await this.createAdvancedSearchModalSession(advancedSearchModalOptions);
|
||||
const { modalResult } = session;
|
||||
|
||||
if (modalResult.status === OutcomeStatus.Ok) {
|
||||
session.close();
|
||||
}
|
||||
|
||||
return modalResult;
|
||||
return await this.resolveModalSessionOutcome(this.createAdvancedSearchModalSession(advancedSearchModalOptions));
|
||||
}
|
||||
|
||||
async createAdvancedSearchModalSession(advancedSearchModalOptions: AdvancedSearchModalOptions): Promise<ModalSession<AdvancedSearchModalData, MediaDbAdvancedSearchModal>> {
|
||||
return await this.openModalCore<AdvancedSearchModalData, MediaDbAdvancedSearchModal>(
|
||||
return await this.openSubmitModalSession<AdvancedSearchModalData, MediaDbAdvancedSearchModal>(
|
||||
() => new MediaDbAdvancedSearchModal(this.plugin, advancedSearchModalOptions),
|
||||
(modal, resolve) => {
|
||||
modal.setSubmitCb(res => resolve(success(res)));
|
||||
modal.setCloseCb(err => {
|
||||
if (err) {
|
||||
resolve(failure(toMdbError(err, { kind: MDBErrorKind.Modal, message: 'Advanced search modal closed with an error' })));
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(cancelled());
|
||||
});
|
||||
},
|
||||
'Advanced search modal closed with an error',
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -264,30 +280,13 @@ export class ModalHelper {
|
|||
}
|
||||
|
||||
async createIdSearchModalOutcome(idSearchModalOptions: IdSearchModalOptions): Promise<Outcome<IdSearchModalData, MDBError>> {
|
||||
const session = await this.createIdSearchModalSession(idSearchModalOptions);
|
||||
const { modalResult } = session;
|
||||
|
||||
if (modalResult.status === OutcomeStatus.Ok) {
|
||||
session.close();
|
||||
}
|
||||
|
||||
return modalResult;
|
||||
return await this.resolveModalSessionOutcome(this.createIdSearchModalSession(idSearchModalOptions));
|
||||
}
|
||||
|
||||
async createIdSearchModalSession(idSearchModalOptions: IdSearchModalOptions): Promise<ModalSession<IdSearchModalData, MediaDbIdSearchModal>> {
|
||||
return await this.openModalCore<IdSearchModalData, MediaDbIdSearchModal>(
|
||||
return await this.openSubmitModalSession<IdSearchModalData, MediaDbIdSearchModal>(
|
||||
() => new MediaDbIdSearchModal(this.plugin, idSearchModalOptions),
|
||||
(modal, resolve) => {
|
||||
modal.setSubmitCb(res => resolve(success(res)));
|
||||
modal.setCloseCb(err => {
|
||||
if (err) {
|
||||
resolve(failure(toMdbError(err, { kind: MDBErrorKind.Modal, message: 'Id search modal closed with an error' })));
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(cancelled());
|
||||
});
|
||||
},
|
||||
'Id search modal closed with an error',
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -296,28 +295,16 @@ export class ModalHelper {
|
|||
}
|
||||
|
||||
async createSelectModalOutcome(selectModalOptions: SelectModalOptions): Promise<Outcome<SelectModalData, MDBError>> {
|
||||
const session = await this.openModalCore<SelectModalData, MediaDbSearchResultModal>(
|
||||
() => new MediaDbSearchResultModal(this.plugin, selectModalOptions),
|
||||
(modal, resolve) => {
|
||||
modal.setSubmitCb(res => resolve(success(res)));
|
||||
modal.setSkipCallback(() => resolve(skipped()));
|
||||
modal.setCloseCb(err => {
|
||||
if (err) {
|
||||
resolve(failure(toMdbError(err, { kind: MDBErrorKind.Modal, message: 'Select modal closed with an error' })));
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(cancelled());
|
||||
});
|
||||
},
|
||||
return await this.resolveModalSessionOutcome(
|
||||
this.openSubmitModalSession<SelectModalData, MediaDbSearchResultModal>(
|
||||
() => new MediaDbSearchResultModal(this.plugin, selectModalOptions),
|
||||
'Select modal closed with an error',
|
||||
(modal, resolve) => {
|
||||
modal.setSkipCallback(() => resolve(skipped()));
|
||||
},
|
||||
),
|
||||
[OutcomeStatus.Ok, OutcomeStatus.Skipped],
|
||||
);
|
||||
const { modalResult } = session;
|
||||
|
||||
if (modalResult.status === OutcomeStatus.Ok || modalResult.status === OutcomeStatus.Skipped) {
|
||||
session.close();
|
||||
}
|
||||
|
||||
return modalResult;
|
||||
}
|
||||
|
||||
async promptSelectModal(selectModalOptions: SelectModalOptions): Promise<SelectModalData | undefined> {
|
||||
|
|
@ -325,30 +312,34 @@ export class ModalHelper {
|
|||
}
|
||||
|
||||
async createPreviewModalOutcome(previewModalOptions: PreviewModalOptions): Promise<Outcome<PreviewModalData, MDBError>> {
|
||||
const session = await this.openModalCore<PreviewModalData, MediaDbPreviewModal>(
|
||||
() => new MediaDbPreviewModal(this.plugin, previewModalOptions),
|
||||
(modal, resolve) => {
|
||||
modal.setSubmitCb(res => resolve(success(res)));
|
||||
modal.setCloseCb(err => {
|
||||
if (err) {
|
||||
resolve(failure(toMdbError(err, { kind: MDBErrorKind.Modal, message: 'Preview modal closed with an error' })));
|
||||
return;
|
||||
}
|
||||
|
||||
resolve(cancelled());
|
||||
});
|
||||
},
|
||||
return await this.resolveModalSessionOutcome(
|
||||
this.openSubmitModalSession<PreviewModalData, MediaDbPreviewModal>(
|
||||
() => new MediaDbPreviewModal(this.plugin, previewModalOptions),
|
||||
'Preview modal closed with an error',
|
||||
),
|
||||
);
|
||||
const { modalResult } = session;
|
||||
|
||||
if (modalResult.status === OutcomeStatus.Ok) {
|
||||
session.close();
|
||||
}
|
||||
|
||||
return modalResult;
|
||||
}
|
||||
|
||||
async promptPreviewModal(previewModalOptions: PreviewModalOptions): Promise<PreviewModalData | undefined> {
|
||||
return await this.resolveOutcome(this.createPreviewModalOutcome(previewModalOptions));
|
||||
}
|
||||
|
||||
async createSeasonSelectModalOutcome(seasonSelectModalOptions: SeasonSelectModalOptions): Promise<Outcome<SeasonSelectModalElement[], MDBError>> {
|
||||
return await this.resolveModalSessionOutcome(
|
||||
this.openSubmitModalSession<SeasonSelectModalElement[], MediaDbSeasonSelectModal>(
|
||||
() =>
|
||||
new MediaDbSeasonSelectModal(
|
||||
this.plugin,
|
||||
seasonSelectModalOptions.seasons ?? [],
|
||||
seasonSelectModalOptions.multiSelect ?? true,
|
||||
seasonSelectModalOptions.seriesName,
|
||||
),
|
||||
'Season select modal closed with an error',
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
async promptSeasonSelectModal(seasonSelectModalOptions: SeasonSelectModalOptions): Promise<SeasonSelectModalElement[] | undefined> {
|
||||
return await this.resolveOutcome(this.createSeasonSelectModalOutcome(seasonSelectModalOptions));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue