refactor: 应用参考工程代码模式,优化启动流程和架构
- 新增 SplashPage:启动页,2秒后跳转到 Index - 新增 MainPage:独立主页组件,含 Tab 导航 + 宽屏/窄屏自适应 - 简化 Index.ets:纯路由入口,初始化数据库,加载 MainPage - EntryAbility:加载 SplashPage 而非直接加载 Index - 新增 PageContext:NavPathStack 路由管理(参考工程模式) - 新增 BreakpointSystem:响应式断点系统 xs/sm/md/lg/xl - 新增 BaseViewModel:ViewModel 基类,含 attach/detach/dispose 生命周期 - 更新 common/Index.ets 导出新模块 - 更新 main_pages.json 注册 SplashPage 和 MainPage
This commit is contained in:
@ -3,3 +3,6 @@ export { GraphDatabase, RecallEntity, TimeRangeParams } from './src/main/ets/mod
|
|||||||
export { GraphMemoryService } from './src/main/ets/service/GraphMemoryService';
|
export { GraphMemoryService } from './src/main/ets/service/GraphMemoryService';
|
||||||
export { AIAgentService, ChatMessage, AgentResponse } from './src/main/ets/service/AIAgentService';
|
export { AIAgentService, ChatMessage, AgentResponse } from './src/main/ets/service/AIAgentService';
|
||||||
export { ImmersiveTabNavigation } from './src/main/ets/component/ImmersiveTabNavigation';
|
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';
|
||||||
|
|||||||
54
common/src/main/ets/routermanager/PageContext.ets
Normal file
54
common/src/main/ets/routermanager/PageContext.ets
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
47
common/src/main/ets/util/BreakpointSystem.ets
Normal file
47
common/src/main/ets/util/BreakpointSystem.ets
Normal file
@ -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<T> {
|
||||||
|
xs?: T;
|
||||||
|
sm: T;
|
||||||
|
md: T;
|
||||||
|
lg: T;
|
||||||
|
xl?: T;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class BreakpointType<T> {
|
||||||
|
private xs: T;
|
||||||
|
private sm: T;
|
||||||
|
private md: T;
|
||||||
|
private lg: T;
|
||||||
|
private xl: T;
|
||||||
|
|
||||||
|
public constructor(param: BreakpointTypes<T>) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
52
common/src/main/ets/viewmodel/BaseViewModel.ets
Normal file
52
common/src/main/ets/viewmodel/BaseViewModel.ets
Normal file
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,18 +1,34 @@
|
|||||||
import UIAbility from '@ohos.app.ability.UIAbility';
|
import { UIAbility, AbilityConstant, Want } from '@kit.AbilityKit';
|
||||||
import window from '@ohos.window';
|
import { window } from '@kit.ArkUI';
|
||||||
|
import { BusinessError } from '@kit.BasicServicesKit';
|
||||||
|
|
||||||
export default class EntryAbility extends UIAbility {
|
export default class EntryAbility extends UIAbility {
|
||||||
onCreate(want, launchParam) {
|
onCreate(want: Want, param: AbilityConstant.LaunchParam): void {
|
||||||
console.info('EntryAbility onCreate');
|
console.info('EntryAbility onCreate');
|
||||||
}
|
}
|
||||||
|
|
||||||
onDestroy() {
|
onDestroy(): void {
|
||||||
console.info('EntryAbility onDestroy');
|
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');
|
console.info('EntryAbility onWindowStageCreate');
|
||||||
windowStage.loadContent('pages/Index', (err, data) => {
|
windowStage.loadContent('pages/SplashPage', (err, data) => {
|
||||||
if (err.code) {
|
if (err.code) {
|
||||||
console.error('Failed to load the content. Cause: ' + JSON.stringify(err));
|
console.error('Failed to load the content. Cause: ' + JSON.stringify(err));
|
||||||
return;
|
return;
|
||||||
@ -21,15 +37,15 @@ export default class EntryAbility extends UIAbility {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
onWindowStageDestroy() {
|
onWindowStageDestroy(): void {
|
||||||
console.info('EntryAbility onWindowStageDestroy');
|
console.info('EntryAbility onWindowStageDestroy');
|
||||||
}
|
}
|
||||||
|
|
||||||
onForeground() {
|
onForeground(): void {
|
||||||
console.info('EntryAbility onForeground');
|
console.info('EntryAbility onForeground');
|
||||||
}
|
}
|
||||||
|
|
||||||
onBackground() {
|
onBackground(): void {
|
||||||
console.info('EntryAbility onBackground');
|
console.info('EntryAbility onBackground');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,19 +1,22 @@
|
|||||||
import { GraphDatabase } from '@ohos/common';
|
import { GraphDatabase } from '@ohos/common';
|
||||||
import { GraphPage } from '@ohos/graph';
|
import { MainPage } from './MainPage';
|
||||||
import { ChatPage } from '@ohos/chat';
|
|
||||||
import { SettingsPage } from '@ohos/settings';
|
|
||||||
import { ImmersiveTabNavigation } from '@ohos/common';
|
|
||||||
import display from '@ohos.display';
|
import display from '@ohos.display';
|
||||||
|
|
||||||
@Entry
|
@Entry
|
||||||
@Component
|
@Component
|
||||||
struct Index {
|
struct Index {
|
||||||
@State currentIndex: number = 0;
|
|
||||||
private db: GraphDatabase = new GraphDatabase();
|
private db: GraphDatabase = new GraphDatabase();
|
||||||
private displayCallback?: Callback<number>;
|
private displayCallback?: Callback<number>;
|
||||||
|
|
||||||
aboutToAppear() {
|
aboutToAppear() {
|
||||||
this.db.init(getContext(this));
|
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() {
|
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() {
|
build() {
|
||||||
Stack() {
|
MainPage({ db: this.db }).width('100%').height('100%');
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
104
products/phone/src/main/ets/pages/MainPage.ets
Normal file
104
products/phone/src/main/ets/pages/MainPage.ets
Normal file
@ -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%');
|
||||||
|
}
|
||||||
|
}
|
||||||
29
products/phone/src/main/ets/pages/SplashPage.ets
Normal file
29
products/phone/src/main/ets/pages/SplashPage.ets
Normal file
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,5 +1,7 @@
|
|||||||
{
|
{
|
||||||
"src": [
|
"src": [
|
||||||
|
"pages/SplashPage",
|
||||||
|
"pages/MainPage",
|
||||||
"pages/Index"
|
"pages/Index"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user