import { router } from '@kit.ArkUI'; import { AccountViewModel } from '../viewmodel/AccountViewModel'; import { Account } from '../model/Account'; import { AccountCard } from '../view/components/AccountCard'; import { TOTPGenerator } from '../common/utils/TOTPGenerator'; import { StorageUtil } from '../common/utils/StorageUtil'; import { hilog } from '@kit.PerformanceAnalysisKit'; import { AppConstants } from '../common/constants/AppConstants'; import { pasteboard } from '@kit.BasicServicesKit'; import { promptAction } from '@kit.ArkUI'; /** * 账户列表主页面 */ @Entry @Component struct AccountListPage { @State accounts: Account[] = []; @State codes: Map = new Map(); @State progress: number = 0; @State remainingSeconds: number = 30; @State searchText: string = ''; private viewModel: AccountViewModel = new AccountViewModel(); private timer: number = -1; async aboutToAppear(): Promise { // 初始化存储 try { await StorageUtil.init(getContext(this)); hilog.info(AppConstants.LOG_DOMAIN, AppConstants.LOG_TAG, 'Storage initialized'); } catch (error) { hilog.error(AppConstants.LOG_DOMAIN, AppConstants.LOG_TAG, 'Failed to init storage: %{public}s', JSON.stringify(error)); } // 设置更新回调 this.viewModel.setUpdateCallback(() => { this.updateAccounts(); }); // 加载账户 await this.viewModel.loadAccounts(); this.updateAccounts(); // 启动定时器更新验证码 this.startTimer(); } aboutToDisappear(): void { this.stopTimer(); } /** * 页面显示时重新加载账户 * 处理从添加/编辑页面返回的情况 */ onPageShow(): void { // 重新加载账户数据 this.viewModel.loadAccounts(); } /** * 更新账户列表 */ private updateAccounts(): void { if (this.searchText) { this.accounts = this.viewModel.searchAccounts(this.searchText); } else { this.accounts = this.viewModel.getAccounts(); } } /** * 启动定时器 */ private startTimer(): void { // 立即生成一次验证码 this.generateAllCodes(); // 每秒更新一次 this.timer = setInterval(() => { this.updateProgress(); this.generateAllCodes(); }, 1000); } /** * 停止定时器 */ private stopTimer(): void { if (this.timer !== -1) { clearInterval(this.timer); this.timer = -1; } } /** * 更新进度 */ private updateProgress(): void { this.progress = TOTPGenerator.getProgress(); this.remainingSeconds = TOTPGenerator.getRemainingSeconds(); } /** * 生成所有账户的验证码 */ private async generateAllCodes(): Promise { for (const account of this.accounts) { try { const code = await this.viewModel.generateCode(account); this.codes.set(account.id, code); } catch (error) { hilog.error(AppConstants.LOG_DOMAIN, AppConstants.LOG_TAG, 'Failed to generate code: %{public}s', JSON.stringify(error)); } } } /** * 复制验证码到剪贴板 */ private copyToClipboard(account: Account): void { const code = this.codes.get(account.id) || '------'; if (code !== '------') { const pasteData = pasteboard.createData(pasteboard.MIMETYPE_TEXT_PLAIN, code); const systemPasteboard = pasteboard.getSystemPasteboard(); systemPasteboard.setData(pasteData); } } /** * 删除账户 */ private async deleteAccount(account: Account): Promise { promptAction.showDialog({ title: $r('app.string.delete_confirm'), buttons: [ { text: $r('app.string.cancel'), color: $r('app.color.text_secondary') }, { text: $r('app.string.delete'), color: $r('app.color.danger_color') } ] }).then(async (result) => { if (result.index === 1) { await this.viewModel.deleteAccount(account.id); this.updateAccounts(); } }); } /** * 编辑账户 */ private editAccount(account: Account): void { router.pushUrl({ url: 'pages/AccountDetailPage', params: { accountId: account.id } }); } /** * 添加账户 */ private addAccount(): void { router.pushUrl({ url: 'pages/AddAccountPage' }); } build() { Column() { // 顶部导航栏 Row() { Text($r('app.string.app_name')) .fontSize($r('app.float.title_large')) .fontColor($r('app.color.text_primary')) .fontWeight(FontWeight.Bold) Blank() // 添加按钮 Button({ type: ButtonType.Circle }) { Text('+') .fontSize(28) .fontColor($r('app.color.card_background')) } .width(40) .height(40) .backgroundColor($r('app.color.primary_color')) .onClick(() => { this.addAccount(); }) } .width('100%') .padding({ left: $r('app.float.spacing_large'), right: $r('app.float.spacing_large'), top: $r('app.float.spacing_large'), bottom: $r('app.float.spacing_medium') }) // 搜索框 if (this.accounts.length > 0) { Search({ placeholder: $r('app.string.search') }) .margin({ left: $r('app.float.spacing_large'), right: $r('app.float.spacing_large'), bottom: $r('app.float.spacing_medium') }) .onChange((value: string) => { this.searchText = value; this.updateAccounts(); }) } // 账户列表 if (this.accounts.length === 0) { // 空状态 Column({ space: 12 }) { Text($r('app.string.no_accounts')) .fontSize($r('app.float.body_large')) .fontColor($r('app.color.text_secondary')) Text($r('app.string.no_accounts_tip')) .fontSize($r('app.float.body_medium')) .fontColor($r('app.color.text_tertiary')) } .width('100%') .layoutWeight(1) .justifyContent(FlexAlign.Center) } else { // 账户列表 List({ space: 12 }) { ForEach(this.accounts, (account: Account) => { ListItem() { AccountCard({ account: account, code: this.codes.get(account.id) || '------', progress: this.progress, remainingSeconds: this.remainingSeconds, onCopy: (acc: Account) => { this.copyToClipboard(acc); }, onEdit: (acc: Account) => { this.editAccount(acc); }, onDelete: (acc: Account) => { this.deleteAccount(acc); } }) } }, (account: Account) => account.id) } .width('100%') .layoutWeight(1) .padding({ left: $r('app.float.spacing_large'), right: $r('app.float.spacing_large') }) } } .width('100%') .height('100%') .backgroundColor($r('app.color.background_color')) } }