diff --git a/common/Index.ets b/common/Index.ets index a5c974f..2e11e46 100644 --- a/common/Index.ets +++ b/common/Index.ets @@ -3,3 +3,6 @@ export { GraphDatabase, RecallEntity, TimeRangeParams } from './src/main/ets/mod export { GraphMemoryService } from './src/main/ets/service/GraphMemoryService'; export { AIAgentService, ChatMessage, AgentResponse } from './src/main/ets/service/AIAgentService'; export { ImmersiveTabNavigation } from './src/main/ets/component/ImmersiveTabNavigation'; +export { PageContext, RouterParam, IPageContext } from './src/main/ets/routermanager/PageContext'; +export { BreakpointType, BreakpointTypes, WidthBreakpoint } from './src/main/ets/util/BreakpointSystem'; +export { BaseViewModel, VMEvent } from './src/main/ets/viewmodel/BaseViewModel'; diff --git a/common/src/main/ets/routermanager/PageContext.ets b/common/src/main/ets/routermanager/PageContext.ets new file mode 100644 index 0000000..4b4ba34 --- /dev/null +++ b/common/src/main/ets/routermanager/PageContext.ets @@ -0,0 +1,54 @@ +export interface RouterParam { + routerName: string; + param?: object; +} + +export interface IPageContext { + openPage(data: RouterParam, animated?: boolean): void; + popPage(animated?: boolean): void; + replacePage(data: RouterParam, animated?: boolean): void; +} + +export class PageContext implements IPageContext { + private readonly pathStack: NavPathStack; + + constructor() { + this.pathStack = new NavPathStack(); + } + + public get navPathStack(): NavPathStack { + return this.pathStack; + } + + public replacePage(data: RouterParam, animated: boolean = true): void { + try { + this.pathStack.replacePath({ name: data.routerName, param: data.param }, animated); + } catch (err) { + console.error('Open Page ' + data.routerName + ' failed. ' + err.code + ' ' + err.message); + } + } + + public openPage(data: RouterParam, animated: boolean = true): void { + try { + this.pathStack.pushPath({ name: data.routerName, param: data.param }, animated); + } catch (err) { + console.error('Open Page ' + data.routerName + ' failed. ' + err.code + ' ' + err.message); + } + } + + public popPage(animated: boolean = true): void { + try { + this.pathStack.pop(animated); + } catch (err) { + console.error('Pop Page failed. ' + err.code + ' ' + err.message); + } + } + + public popPageByIndex(index: number, animated: boolean = true): void { + this.pathStack.popToIndex(index, animated); + } + + public clear(animated: boolean = true): void { + this.pathStack.clear(animated); + } +} diff --git a/common/src/main/ets/util/BreakpointSystem.ets b/common/src/main/ets/util/BreakpointSystem.ets new file mode 100644 index 0000000..219abee --- /dev/null +++ b/common/src/main/ets/util/BreakpointSystem.ets @@ -0,0 +1,47 @@ +export enum WidthBreakpoint { + WIDTH_XS = 'xs', + WIDTH_SM = 'sm', + WIDTH_MD = 'md', + WIDTH_LG = 'lg', + WIDTH_XL = 'xl' +} + +export interface BreakpointTypes { + xs?: T; + sm: T; + md: T; + lg: T; + xl?: T; +} + +export class BreakpointType { + private xs: T; + private sm: T; + private md: T; + private lg: T; + private xl: T; + + public constructor(param: BreakpointTypes) { + this.xs = param.xs ?? param.sm; + this.sm = param.sm; + this.md = param.md; + this.lg = param.lg; + this.xl = param.xl ?? param.lg; + } + + public getValue(currentBreakpoint: WidthBreakpoint): T { + if (currentBreakpoint === WidthBreakpoint.WIDTH_XS) { + return this.xs; + } + if (currentBreakpoint === WidthBreakpoint.WIDTH_SM) { + return this.sm; + } + if (currentBreakpoint === WidthBreakpoint.WIDTH_MD) { + return this.md; + } + if (currentBreakpoint === WidthBreakpoint.WIDTH_XL) { + return this.xl; + } + return this.lg; + } +} diff --git a/common/src/main/ets/viewmodel/BaseViewModel.ets b/common/src/main/ets/viewmodel/BaseViewModel.ets new file mode 100644 index 0000000..b60efc8 --- /dev/null +++ b/common/src/main/ets/viewmodel/BaseViewModel.ets @@ -0,0 +1,52 @@ +import { BreakpointType, WidthBreakpoint } from '../util/BreakpointSystem'; + +export interface VMEvent { +} + +export class BaseViewModel { + protected isAttached: boolean = false; + protected isDisposed: boolean = false; + protected currentBreakpoint: WidthBreakpoint = WidthBreakpoint.WIDTH_MD; + + attach(): void { + if (this.isAttached) { + return; + } + this.isAttached = true; + this.onAttach(); + } + + detach(): void { + if (!this.isAttached) { + return; + } + this.isAttached = false; + this.onDetach(); + } + + dispose(): void { + if (this.isDisposed) { + return; + } + this.isDisposed = true; + this.detach(); + this.onDispose(); + } + + protected onAttach(): void { + } + + protected onDetach(): void { + } + + protected onDispose(): void { + } + + public get attached(): boolean { + return this.isAttached; + } + + public get disposed(): boolean { + return this.isDisposed; + } +} diff --git a/products/phone/src/main/ets/entryability/EntryAbility.ets b/products/phone/src/main/ets/entryability/EntryAbility.ets index 6e60172..29799e4 100644 --- a/products/phone/src/main/ets/entryability/EntryAbility.ets +++ b/products/phone/src/main/ets/entryability/EntryAbility.ets @@ -1,18 +1,34 @@ -import UIAbility from '@ohos.app.ability.UIAbility'; -import window from '@ohos.window'; +import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit'; +import { window } from '@kit.ArkUI'; +import { BusinessError } from '@kit.BasicServicesKit'; export default class EntryAbility extends UIAbility { - onCreate(want, launchParam) { + onCreate(want: Want, param: AbilityConstant.LaunchParam): void { console.info('EntryAbility onCreate'); } - onDestroy() { + onDestroy(): void { console.info('EntryAbility onDestroy'); } - onWindowStageCreate(windowStage: window.WindowStage) { + onWindowStageCreate(windowStage: window.WindowStage): void { + const windowClass: window.Window = windowStage.getMainWindowSync(); + try { + windowClass.setWindowBackgroundColor('#00000000'); + } catch (e) { + console.error('Failed to set background color: ' + (e as BusinessError).message); + } + try { + windowClass.setWindowSystemBarProperties({ + statusBarColor: '#00000000', + navigationBarColor: '#00000000' + }); + } catch (e) { + console.error('Failed to set system bar properties: ' + (e as BusinessError).message); + } + console.info('EntryAbility onWindowStageCreate'); - windowStage.loadContent('pages/Index', (err, data) => { + windowStage.loadContent('pages/SplashPage', (err, data) => { if (err.code) { console.error('Failed to load the content. Cause: ' + JSON.stringify(err)); return; @@ -21,15 +37,15 @@ export default class EntryAbility extends UIAbility { }); } - onWindowStageDestroy() { + onWindowStageDestroy(): void { console.info('EntryAbility onWindowStageDestroy'); } - onForeground() { + onForeground(): void { console.info('EntryAbility onForeground'); } - onBackground() { + onBackground(): void { console.info('EntryAbility onBackground'); } } diff --git a/products/phone/src/main/ets/pages/Index.ets b/products/phone/src/main/ets/pages/Index.ets index 423f410..96318d0 100644 --- a/products/phone/src/main/ets/pages/Index.ets +++ b/products/phone/src/main/ets/pages/Index.ets @@ -1,19 +1,22 @@ import { GraphDatabase } from '@ohos/common'; -import { GraphPage } from '@ohos/graph'; -import { ChatPage } from '@ohos/chat'; -import { SettingsPage } from '@ohos/settings'; -import { ImmersiveTabNavigation } from '@ohos/common'; +import { MainPage } from './MainPage'; import display from '@ohos.display'; @Entry @Component struct Index { - @State currentIndex: number = 0; private db: GraphDatabase = new GraphDatabase(); private displayCallback?: Callback; aboutToAppear() { this.db.init(getContext(this)); + try { + this.displayCallback = (size: number): void => { + }; + display.on('change', this.displayCallback); + } catch (e) { + console.error('display.on error: ' + JSON.stringify(e)); + } } aboutToDisappear() { @@ -22,104 +25,7 @@ struct Index { } } - @Builder - tabContentBuilder() { - Column() { - if (this.currentIndex === 0) { - MainPage({ db: this.db }) - } else { - SettingsPage() - } - } - .width('100%') - .height('100%') - } - build() { - Stack() { - ImmersiveTabNavigation({ - currentIndex: this.currentIndex, - onTabChange: (index: number): void => { this.currentIndex = index; }, - contentBuilder: (): void => { this.tabContentBuilder(); } - }) - } - .width('100%') - .height('100%') - } -} - -@Component -struct MainPage { - @Prop db: GraphDatabase; - @State isWide: boolean = false; - - aboutToAppear() { - this.updateBreakpoint(); - try { - display.on('change', () => { - this.updateBreakpoint(); - }); - } catch (e) { - console.error('display.on error: ' + JSON.stringify(e)); - } - } - - private updateBreakpoint(): void { - try { - const defaultWindow = display.getDefaultDisplaySync(); - this.isWide = defaultWindow.width > 520; - } catch (e) { - console.error('updateBreakpoint error: ' + JSON.stringify(e)); - } - } - - build() { - if (this.isWide) { - Row() { - GraphPage({ db: this.db }) - .layoutWeight(1) - .height('100%') - .clip(true) - .borderRadius(12) - .margin({ left: 4, right: 2 }) - - ChatPage({ db: this.db }) - .width(380) - .height('100%') - .clip(true) - .borderRadius(12) - .margin({ left: 2, right: 4 }) - } - .width('100%') - .height('100%') - .padding(4) - .backgroundColor('#1A1B2E') - .backgroundBlurStyle(BlurStyle.Regular) - } else { - Column() { - Stack() { - GraphPage({ db: this.db }) - } - .height('55%') - .width('100%') - .clip(true) - .borderRadius(12) - .margin({ top: 2, left: 4, right: 4, bottom: 2 }) - - Stack() { - ChatPage({ db: this.db }) - } - .height('45%') - .width('100%') - .clip(true) - .borderRadius(12) - .margin({ top: 2, left: 4, right: 4, bottom: 2 }) - } - .width('100%') - .height('100%') - .padding(2) - .backgroundColor('#1A1B2E') - .backgroundBlurStyle(BlurStyle.Regular) - } + MainPage({ db: this.db }).width('100%').height('100%'); } } diff --git a/products/phone/src/main/ets/pages/MainPage.ets b/products/phone/src/main/ets/pages/MainPage.ets new file mode 100644 index 0000000..ea8b949 --- /dev/null +++ b/products/phone/src/main/ets/pages/MainPage.ets @@ -0,0 +1,104 @@ +import { GraphDatabase } from '@ohos/common'; +import { GraphPage } from '@ohos/graph'; +import { ChatPage } from '@ohos/chat'; +import { SettingsPage } from '@ohos/settings'; +import { ImmersiveTabNavigation } from '@ohos/common'; +import display from '@ohos.display'; + +@Component +export struct MainPage { + @Prop db: GraphDatabase; + @State isWide: boolean = false; + @State currentIndex: number = 0; + + aboutToAppear() { + this.updateBreakpoint(); + try { + display.on('change', () => { + this.updateBreakpoint(); + }); + } catch (e) { + console.error('display.on error: ' + JSON.stringify(e)); + } + } + + private updateBreakpoint(): void { + try { + const defaultWindow = display.getDefaultDisplaySync(); + this.isWide = defaultWindow.width > 520; + } catch (e) { + console.error('updateBreakpoint error: ' + JSON.stringify(e)); + } + } + + @Builder + tabContentBuilder() { + Column() { + if (this.currentIndex === 0) { + if (this.isWide) { + Row() { + GraphPage({ db: this.db }) + .layoutWeight(1) + .height('100%') + .clip(true) + .borderRadius(12) + .margin({ left: 4, right: 2 }); + ChatPage({ db: this.db }) + .width(380) + .height('100%') + .clip(true) + .borderRadius(12) + .margin({ left: 2, right: 4 }); + } + .width('100%') + .height('100%') + .padding(4) + .backgroundColor('#1A1B2E'); + } else { + Column() { + Stack() { + GraphPage({ db: this.db }) + } + .height('55%') + .width('100%') + .clip(true) + .borderRadius(12) + .margin({ top: 2, left: 4, right: 4, bottom: 2 }); + Stack() { + ChatPage({ db: this.db }) + } + .height('45%') + .width('100%') + .clip(true) + .borderRadius(12) + .margin({ top: 2, left: 4, right: 4, bottom: 2 }); + } + .width('100%') + .height('100%') + .padding(2) + .backgroundColor('#1A1B2E'); + } + } else { + SettingsPage() + } + } + .width('100%') + .height('100%'); + } + + build() { + Stack() { + ImmersiveTabNavigation({ + currentIndex: this.currentIndex, + onTabChange: (index: number): void => { + this.currentIndex = index; + }, + contentBuilder: (): void => { + this.tabContentBuilder(); + } + }) + } + .width('100%') + .height('100%'); + } +} diff --git a/products/phone/src/main/ets/pages/SplashPage.ets b/products/phone/src/main/ets/pages/SplashPage.ets new file mode 100644 index 0000000..386d617 --- /dev/null +++ b/products/phone/src/main/ets/pages/SplashPage.ets @@ -0,0 +1,29 @@ +import router from '@ohos.router'; + +@Entry +@Component +struct SplashPage { + aboutToAppear() { + setTimeout(() => { + router.replaceUrl({ url: 'pages/Index' }); + }, 2000); + } + + build() { + Column() { + Text('TrulyMEM') + .fontSize(48) + .fontWeight(FontWeight.Bold) + .fontColor(Color.White); + Text('True Human Memory') + .fontSize(20) + .fontColor(Color.White) + .margin({ top: 16 }); + } + .width('100%') + .height('100%') + .backgroundColor('#1A1B2E') + .justifyContent(FlexAlign.Center) + .alignItems(HorizontalAlign.Center); + } +} diff --git a/products/phone/src/main/resources/base/profile/main_pages.json b/products/phone/src/main/resources/base/profile/main_pages.json index 1898d94..2db95ae 100644 --- a/products/phone/src/main/resources/base/profile/main_pages.json +++ b/products/phone/src/main/resources/base/profile/main_pages.json @@ -1,5 +1,7 @@ { "src": [ + "pages/SplashPage", + "pages/MainPage", "pages/Index" ] }