import * as Mobx from 'mobx' ; import * as Types from '@meetalva/types' ; import * as uuid from 'uuid' ; import * as M from '@meetalva/message' ; import { Message } from '@meetalva/message' ; export interface AlvaAppInit { id ? : string ; activeView : Types . AlvaView ; hasFocusedInput : boolean ; hostType : Types . HostType ; panes : Set < Types . AppPane > ; paneSizes : Types . PaneSize [ ] ; searchTerm : string ; state : Types . AppState ; } export class AlvaApp < M extends Message > { public static Defaults : AlvaAppInit = { activeView : Types . AlvaView . SplashScreen , hasFocusedInput : false , hostType : Types . HostType . Electron , panes : new Set ( [ Types . AppPane . PagesPane , Types . AppPane . ElementsPane , Types . AppPane . PropertiesPane ] ) , paneSizes : [ ] , searchTerm : '' , state : Types . AppState . Starting } ; public readonly model = Types . ModelName . AlvaApp ; private id : string ; @ Mobx . observable private hostType : Types . HostType ; @ Mobx . observable private activeView : Types . AlvaView = Types . AlvaView . SplashScreen ; @ Mobx . observable private projectViewMode : Types . ProjectViewMode = Types . ProjectViewMode . Design ; @ Mobx . observable private paneSelectOpen : boolean = false ; @ Mobx . observable private searchTerm : string = '' ; @ Mobx . observable private state : Types . AppState = Types . AppState . Starting ; @ Mobx . observable private panes : Set < Types . AppPane > = new Set ( [ Types . AppPane . PagesPane , Types . AppPane . ElementsPane , Types . AppPane . PropertiesPane ] ) ; @ Mobx . observable private paneSizes : Map < Types . AppPane , Types . PaneSize > = new Map ( ) ; @ Mobx . observable private hasFocusedInput : boolean = false ; @ Mobx . observable private udpate : Types . UpdateInfo | undefined ; private sender : Types . Sender < M > ; public constructor ( init , ctx ) { this . id = init . id || uuid . v4 ( ) ; this . activeView = init . activeView ; this . panes = init . panes ; this . searchTerm = init . searchTerm ; this . state = init . state ; this . hasFocusedInput = init . hasFocusedInput ; this . hostType = init . hostType ; this . sender = ctx . sender ; init . paneSizes . forEach ( paneSize => this . setPaneSize ( paneSize ) ) ; } public static from ( serialized , ctx ) { return new AlvaApp ( { id : serialized . id , activeView : deserializeView ( serialized . activeView ) , hasFocusedInput : serialized . hasFocusedInput , hostType : serialized . hostType as Types . HostType , panes : new Set ( serialized . panes . map ( deserializePane ) ) , paneSizes : serialized . paneSizes . map ( p => ( { width : p . width , height : p . height , pane : deserializePane ( p . pane ) } ) ) , searchTerm : serialized . searchTerm , state : deserializeState ( serialized . state ) } , ctx ) ; } public static fromSender ( sender ) { return new AlvaApp ( AlvaApp . Defaults , { sender } ) ; } public hasFileAccess ( ) { return [ Types . HostType . Electron ] . includes ( this . hostType ) ; } public getActiveView ( ) { return this . activeView ; } public isActiveView ( candidateView ) { return this . activeView === candidateView ; } public getHasFocusedInput ( ) { return this . hasFocusedInput ; } public getHostType ( ) { return this . hostType ; } public isHostType ( candidateType ) { return this . hostType === candidateType ; } public getId ( ) { return this . id ; } public getPanes ( ) { return this . panes ; } public getPaneSelectOpen ( ) { return this . paneSelectOpen ; } public getPaneSize ( pane ) { return this . paneSizes . get ( pane ) ; } public getSearchTerm ( ) { return this . searchTerm ; } public getState ( ) { return this . state ; } public getProjectViewMode ( ) { return this . projectViewMode ; } public isVisible ( pane ) { return this . panes . has ( pane ) ; } @ Mobx . action public setActiveView ( view ) { this . activeView = view ; } @ Mobx . action public setProjectViewMode ( mode ) { this . projectViewMode = mode ; } @ Mobx . action public setHasFocusedInput ( hasFocusedInput ) { this . hasFocusedInput = hasFocusedInput ; } @ Mobx . action public setHostType ( hostType ) { this . hostType = hostType ; } @ Mobx . action public setPaneSelectOpen ( paneSelectOpen ) { this . paneSelectOpen = paneSelectOpen ; } @ Mobx . action public setPaneSize ( size ) { this . paneSizes . set ( size . pane , size ) ; } @ Mobx . action public setPane ( pane , visible ) { if ( visible ) { this . panes . add ( pane ) ; } else { this . panes . delete ( pane . toString ( ) as Types . AppPane ) ; } this . panes = new Set ( this . panes . values ( ) ) ; } @ Mobx . action public setPanes ( panes ) { this . panes = new Set ( panes ) ; } @ Mobx . action public setSearchTerm ( term ) { this . searchTerm = term ; } @ Mobx . action public setState ( state ) { this . state = state ; } @ Mobx . action public setUpdate ( update ) { this . udpate = update ; } public getUpdate ( ) { return this . udpate ; } public setSender ( sender ) { this . sender = sender ; } public toJSON ( ) { return { id : this . id , model : this . model , activeView : serializeView ( this . activeView ) , hasFocusedInput : this . hasFocusedInput , hostType : this . hostType , panes : [ ... this . panes . values ( ) ] . map ( serializePane ) , paneSizes : [ ... this . paneSizes . values ( ) ] . map ( paneSize => ( { width : paneSize . width , height : paneSize . height , pane : serializePane ( paneSize . pane ) } ) ) , searchTerm : this . searchTerm , state : serializeState ( this . state ) } ; } @ Mobx . action public update ( b ) { this . activeView = b . activeView ; this . panes = b . panes ; this . paneSizes = b . paneSizes ; this . searchTerm = b . searchTerm ; this . state = b . state ; } public send < T extends M > ( message ) { if ( ! this . sender ) { return ; } message . appId = this . id ; this . sender . send ( message ) ; } public match < T extends M . Message > ( t , h ) { this . sender . match ( t , m => { if ( m . appId !== this . id ) { return ; } h ( m as any ) ; } ) ; } public async transaction < T extends M , V extends M > ( message , { type } ) { message . appId = this . id ; return this . sender . transaction ( message , { type } ) ; } } function deserializePane ( state ) { switch ( state ) { case 'pages-pane' : return Types . AppPane . PagesPane ; case 'patterns-pane' : return Types . AppPane . PatternsPane ; case 'elements-pane' : return Types . AppPane . ElementsPane ; case 'properties-pane' : return Types . AppPane . PropertiesPane ; case 'development-pane' : return Types . AppPane . DevelopmentPane ; } throw new Error ( `Unknown app pane: ${ state }` ) ; } function deserializeState ( state ) { switch ( state ) { case 'starting' : return Types . AppState . Starting ; case 'started' : return Types . AppState . Started ; } throw new Error ( `Unknown app state: ${ state }` ) ; } function deserializeView ( state ) { switch ( state ) { case 'SplashScreen' : return Types . AlvaView . SplashScreen ; case 'PageDetail' : return Types . AlvaView . PageDetail ; } throw new Error ( `Unknown app state: ${ state }` ) ; } function serializePane ( pane ) { switch ( pane ) { case Types . AppPane . PagesPane : return 'pages-pane' ; case Types . AppPane . PatternsPane : return 'patterns-pane' ; case Types . AppPane . ElementsPane : return 'elements-pane' ; case Types . AppPane . PropertiesPane : return 'properties-pane' ; case Types . AppPane . DevelopmentPane : return 'development-pane' ; } throw new Error ( `Unknown app pane: ${ pane }` ) ; } function serializeState ( state ) { switch ( state ) { case Types . AppState . Starting : return 'starting' ; case Types . AppState . Started : return 'started' ; } throw new Error ( `Unknown app state: ${ state }` ) ; } function serializeView ( view ) { switch ( view ) { case Types . AlvaView . SplashScreen : return 'SplashScreen' ; case Types . AlvaView . PageDetail : return 'PageDetail' ; } throw new Error ( `Unknown app state: ${ view }` ) ; }