diff --git a/Android/app/src/main/java/pub/doric/demo/MainActivity.java b/Android/app/src/main/java/pub/doric/demo/MainActivity.java index 791d7735..60d5c84c 100644 --- a/Android/app/src/main/java/pub/doric/demo/MainActivity.java +++ b/Android/app/src/main/java/pub/doric/demo/MainActivity.java @@ -25,9 +25,9 @@ import androidx.appcompat.app.AppCompatActivity; import java.io.IOException; +import pub.doric.dev.DevPanel; import pub.doric.DoricContext; import pub.doric.DoricDriver; -import pub.doric.dev.DevPanel; import pub.doric.dev.LocalServer; import pub.doric.dev.event.EnterDebugEvent; import pub.doric.dev.event.QuitDebugEvent; diff --git a/js-framework/index.ts b/js-framework/index.ts index 99f7d6a8..ed664e67 100644 --- a/js-framework/index.ts +++ b/js-framework/index.ts @@ -16,6 +16,7 @@ export * from "./src/ui/view" export * from "./src/ui/layout" export * from "./src/ui/listview" +export * from "./src/ui/widgets" export * from "./src/ui/panel" export * from "./src/ui/declarative" export * from "./src/util/color" diff --git a/js-framework/src/ui/declarative.ts b/js-framework/src/ui/declarative.ts index 7eecbf2c..bf5ddeda 100644 --- a/js-framework/src/ui/declarative.ts +++ b/js-framework/src/ui/declarative.ts @@ -13,8 +13,9 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -import { Text, Image, LayoutConfig, View, IText, IImage } from './view' +import { View, } from './view' import { Stack, HLayout, VLayout } from './layout' +import { IText, IImage, Text, Image } from './widgets' export function text(config: IText) { const ret = new Text diff --git a/js-framework/src/ui/listview.ts b/js-framework/src/ui/listview.ts index 78b9955e..cfc1f48a 100644 --- a/js-framework/src/ui/listview.ts +++ b/js-framework/src/ui/listview.ts @@ -14,7 +14,7 @@ * limitations under the License. */ -import { View, Property, SuperView, Group, LayoutSpec } from "./view"; +import { View, Property, LayoutSpec, Superview } from "./view"; import { Model } from "../util/types"; import { O_TRUNC } from "constants"; import { Stack } from "./layout"; @@ -35,12 +35,9 @@ export class ListItem extends Stack { @Property identifier?: string list!: List - onChildPropertyChanged(child: View) { - super.onChildPropertyChanged(child) - } } -export class List extends View implements SuperView { +export class List extends Superview { private cachedViews: Map = new Map subviewById(id: string): ListItem | undefined { diff --git a/js-framework/src/ui/view.ts b/js-framework/src/ui/view.ts index d199ae79..5be2291f 100644 --- a/js-framework/src/ui/view.ts +++ b/js-framework/src/ui/view.ts @@ -110,7 +110,7 @@ export abstract class View implements Modeling, IView { @Property onClick?: Function - parent?: Group + superview?: Superview callbacks: Map = new Map @@ -188,7 +188,11 @@ export abstract class View implements Modeling, IView { } /** Anchor end*/ - __dirty_props__: { [index: string]: Model | undefined } = {} + private __dirty_props__: { [index: string]: Model | undefined } = {} + + get dirtyProps() { + return this.__dirty_props__ + } nativeViewModel = { id: this.viewId, @@ -203,9 +207,6 @@ export abstract class View implements Modeling, IView { newV = obj2Model(newV) } this.__dirty_props__[propKey] = newV - if (this.parent instanceof Group) { - this.parent.onChildPropertyChanged(this) - } } clean() { @@ -236,48 +237,33 @@ export abstract class View implements Modeling, IView { toModel() { return this.nativeViewModel } + let(block: (it: this) => void) { block(this) } + also(block: (it: this) => void) { block(this) return this } + in(group: Group) { group.addChild(this) } } -export interface StackConfig extends LayoutConfig { - +export abstract class Superview extends View { + abstract subviewById(id: string): View | undefined } -export interface LinearConfig extends LayoutConfig { - weight?: number -} +export abstract class Group extends Superview { -export interface SuperView { - subviewById(id: string): View | undefined -} - -export abstract class Group extends View implements SuperView { - @Property readonly children: View[] = new Proxy([], { set: (target, index, value) => { - if (index === 'length') { - this.getDirtyChildrenModel().length = value as number - } else if (typeof index === 'string' - && parseInt(index) >= 0 - && value instanceof View) { - value.parent = this - const childrenModel = this.getDirtyChildrenModel() - childrenModel[parseInt(index)] = value.nativeViewModel - } - if (this.parent) { - this.parent.onChildPropertyChanged(this) - } - - return Reflect.set(target, index, value) + const ret = Reflect.set(target, index, value) + // Let getDirty return true + this.dirtyProps.children = [] + return ret } }) @@ -289,195 +275,21 @@ export abstract class Group extends View implements SuperView { } return undefined } + addChild(view: View) { this.children.push(view) } - clean() { - this.children.forEach(e => { e.clean() }) - super.clean() - } - - getDirtyChildrenModel(): Model[] { - if (this.__dirty_props__.children === undefined) { - this.__dirty_props__.children = [] - } - return this.__dirty_props__.children as Model[] - } - toModel() { - if (this.__dirty_props__.children != undefined) { - (this.__dirty_props__.children as Model[]).length = this.children.length - } + this.dirtyProps.children = this.children.map(e => { + if (e.isDirty()) { + return e.toModel() + } else { + //Dont need return model + return {} + } + }) return super.toModel() } - - onChildPropertyChanged(child: View) { - this.getDirtyChildrenModel()[this.children.indexOf(child)] = child.nativeViewModel - this.getDirtyChildrenModel().length = this.children.length - if (this.parent) { - this.parent.onChildPropertyChanged(this) - } - } - - isDirty() { - return super.isDirty() - } -} -export interface IStack extends IView { - gravity?: Gravity } -export class Stack extends Group implements IStack { - @Property - gravity?: Gravity -} - -export class Scroller extends View implements SuperView { - @Property - contentView?: View - - subviewById(id: string): View | undefined { - return this.contentView - } -} - -export class Root extends Stack { - -} -class LinearLayout extends Group { - @Property - space?: number - - @Property - gravity?: Gravity -} - -export interface IVLayout extends IView { - space?: number - gravity?: Gravity -} - -export class VLayout extends LinearLayout implements VLayout { -} - - -export interface IHLayout extends IView { - space?: number - gravity?: Gravity -} - -export class HLayout extends LinearLayout implements IHLayout { -} - -export interface IText extends IView { - text?: string - textColor?: Color - textSize?: number - maxLines?: number - textAlignment?: Gravity -} - -export class Text extends View implements IText { - @Property - text?: string - - @Property - textColor?: Color - - @Property - textSize?: number - - @Property - maxLines?: number - - @Property - textAlignment?: Gravity -} - -export interface IImage extends IView { - imageUrl?: string -} - -export class Image extends View implements IImage { - @Property - imageUrl?: string -} - - -export class SectionList extends View implements SuperView { - private cachedViews: Map = new Map - - subviewById(id: string): View | undefined { - return this.cachedViews.get(id) - } - @Property - sectionRowsCount: number[] = [] - - @Property - renderSectionHeader!: (sectionIdx: number) => View - - @Property - renderItem!: (sectionIdx: number, itemIdx: number) => View - - @Property - sectionHeaderSticky = true - - setupSectionRows(sectionCount: number, numberOfSection: (section: number) => number) { - this.sectionRowsCount = [...Array(sectionCount).keys()].map(e => numberOfSection(e)) - } - - private getItem(sectionIdx: number, itemIdx: number) { - let view = this.cachedViews.get(`${sectionIdx}:${itemIdx}`) - if (view === undefined) { - view = this.renderItem(sectionIdx, itemIdx) - this.cachedViews.set(`${sectionIdx}:${itemIdx}`, view) - } - return view - } - - private getSectionHeader(sectionIdx: number) { - let view = this.cachedViews.get(`${sectionIdx}:`) - if (view === undefined) { - view = this.renderSectionHeader(sectionIdx) - this.cachedViews.set(`${sectionIdx}:`, view) - } - return view - } - - @Property - private renderBunchedItems(items: Array<{ itemIdx: number, sectionIdx: number }>, - headers: number[]): { items: View[], headers: View[] } { - return { - items: items.map(e => this.getItem(e.sectionIdx, e.itemIdx)), - headers: headers.map(e => this.getSectionHeader(e)) - } - } -} - -export class Slide extends View implements SuperView { - @Property - pageCount = 0 - - @Property - renderPage!: (pageIdx: number) => View - - private cachedViews: Map = new Map - - subviewById(id: string): View | undefined { - return this.cachedViews.get(id) - } - private getPage(pageIdx: number) { - let view = this.cachedViews.get(`${pageIdx}`) - if (view === undefined) { - view = this.renderPage(pageIdx) - this.cachedViews.set(`${pageIdx}`, view) - } - return view - } - - @Property - private renderBunchedPages(pages: number[]): View[] { - return pages.map(e => this.getPage(e)) - } -} \ No newline at end of file diff --git a/js-framework/src/ui/widgets.ts b/js-framework/src/ui/widgets.ts new file mode 100644 index 00000000..0bd815d6 --- /dev/null +++ b/js-framework/src/ui/widgets.ts @@ -0,0 +1,52 @@ +/* + * Copyright [2019] [Doric.Pub] + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { IView, View, Property } from "./view" +import { Color } from "../util/color" +import { Gravity } from "../util/gravity" + +export interface IText extends IView { + text?: string + textColor?: Color + textSize?: number + maxLines?: number + textAlignment?: Gravity +} + +export class Text extends View implements IText { + @Property + text?: string + + @Property + textColor?: Color + + @Property + textSize?: number + + @Property + maxLines?: number + + @Property + textAlignment?: Gravity +} + +export interface IImage extends IView { + imageUrl?: string +} + +export class Image extends View implements IImage { + @Property + imageUrl?: string +} \ No newline at end of file