PresenterBase.ts 3.84 KB
import { View, Subview, OnSubviewCreated } from "./ViewBase";
import { CompositeDisposable } from "simba-eventkit";

let presenterViewFactory: (<P, V extends View, PR extends Presenter<P, V>>(presenterCls: { new(): PR, uuid: string }) => Promise<V>) & { preloadView: (presenterCls: { new(): Presenter, uuid: string }) => Promise<void> };

export function setPresenterViewFactory(factory: typeof presenterViewFactory) {
    presenterViewFactory = factory;
}

let subpresenterFactory: (subview: Subview) => Subpresenter;

export function setSubpresenterwFactory(factory: (subview: Subview) => Subpresenter) {
    subpresenterFactory = factory;
}

let currentCreatingPresenter: Presenter<any, any> | undefined;
export async function createPresenter<P, V extends View, PR extends Presenter<P, V>>(presenterCls: { new(): PR, uuid: string }): Promise<PR> {
    await presenterViewFactory.preloadView(presenterCls as any);
    if (currentCreatingPresenter) {
        console.warn("create presenter simultaneously will cause sub presenters error!");
    }
    let presenter = currentCreatingPresenter = new presenterCls;
    let view = await presenterViewFactory<P, V, PR>(presenterCls);
    presenter.attachView(view);
    currentCreatingPresenter = undefined;
    return presenter;
}

OnSubviewCreated.on((subview) => {
    if (!currentCreatingPresenter) {
        return;
    }
    let presenter = subpresenterFactory(subview);
    presenter.owner = currentCreatingPresenter;
    (currentCreatingPresenter as any)._subpresenters.push(presenter);
});

export type PresenterParamType<T> = T extends Presenter<infer U, any> ? U : any;

class PresenterBase {
    protected _disposable: CompositeDisposable;

    onShow() {

    }

    onHide() {

    }
}

export class Subpresenter<V extends Subview = Subview, Owner extends Presenter<any, any> = Presenter<any, any>> extends PresenterBase {
    owner: Owner;
    _view: Subview;

    get view() { return this._view as V; }

    attachView(view: V) {
        this._view = view;
    }

    onOpen() {
        this._disposable = new CompositeDisposable;
        this._disposable.add(this._view.onShow.on(() => this.onShow()));
        this._disposable.add(this._view.onHide.on(() => this.onHide()));
    }

    onClose() {
        this._disposable.dispose();
    }

    onOwnerShow() {

    }

    onOwnerHide() {

    }

    onOwnerEnterForeground() {

    }

    onOwnerEnterBackground() {

    }
}

export class Presenter<P = undefined, V extends View = View> extends PresenterBase {
    protected _view: V;
    protected _isInBackground = false;
    protected _subpresenters: Subpresenter[] = [];

    get view() { return this._view as V; }

    open = (parent: View, props: P) => {
        this._view.open(parent);
        this.onOpen(props);
    }

    attachView(view: V) {
        this._view = view;
    }

    onOpen(props: P) {
        this._disposable = new CompositeDisposable;
        this._disposable.add(this._view.onClose.on(() => this.onClose()));
        this._disposable.add(this._view.onShow.on(() => this.onShow()));
        this._disposable.add(this._view.onHide.on(() => this.onHide()));
        this._subpresenters.forEach((p) => {
            p.onOpen();
        });
    }

    onClose() {
        this._disposable.dispose();
        this._subpresenters.forEach((p) => {
            p.onClose();
        });
    }

    onShow() {
        this._subpresenters.forEach((p) => {
            p.onOwnerShow();
        });
    }

    onHide() {
        this._subpresenters.forEach((p) => {
            p.onOwnerHide();
        });
    }

    onEnterForeground() {
        this._isInBackground = false;
        this._subpresenters.forEach((p) => {
            p.onOwnerEnterForeground();
        });
    }

    onEnterBackground() {
        this._isInBackground = true;
        this._subpresenters.forEach((p) => {
            p.onOwnerEnterBackground();
        });
    }
}