鸿蒙前进路上的又一成就——“必行录”应用上架!


让每一天更有质感的生活管理应用:LifeList

前言

大家好久不见啦,不知道还记得我嘛,我是云杰 。距离上次发文章已经3个月啦,这段时间里,一直在北京出差,白天在公司里紧锣密鼓赶项目进度,也是终于在10月底上线啦,进入了运维阶段。但是!作为刚毕业的大学生,晚上最是精力充沛!在这段时间里,华为激励活动很是感兴趣呀(money多多~~) 最近我上架了一款APP------必行录

在10月份的时候也是被华为审核打回------功能简单,后来也是加了一些功能才上架成功!

今天具体介绍一下------必行录

应用海报

核心卖点

  • 余生时钟与动态可视化,让时间"看得见"
  • 自定义清单与收藏,打造你的专属生活框架
  • 频率事件一键记录,生成"痕迹",回看每次坚持
  • 个人资料与头像管理,表达你自己的生活态度
  • 桌面卡片联动,选中事件直达更新
  • 媒体与传感器能力加持,更有温度的交互反馈
  • 图片选择、生成与分享,记录生活并与朋友共享

余生时钟

  • 实时计算年龄与人生统计,支持自定义退休年龄;动态 Canvas 时钟组件配合精致指针绘制。

  • 示例代码(函数级注释):

ts 复制代码
// 绘制主时钟:依次绘制背景、时针、分针、秒针与中心点
drawClock(context: CanvasRenderingContext2D, radius: number, canvasWidth: number, hour: number, minute: number,
  second: number, time: string) {
  this.drawBackGround(context, radius, canvasWidth);
  this.drawHour(context, radius, hour, minute);
  this.drawMinute(context, radius, minute);
  this.drawSecond(context, radius, second);
  this.drawDot(context);
}
ts 复制代码
// 启动时钟更新:按设定间隔刷新时间并重绘Canvas
public startClock(): void {
  if (this.intervalId !== 0) {
    this.stopClock();
  }
  this.intervalId = setInterval(() => {
    this.updateTime();
  }, this.updateInterval);
}

自定义清单与收藏

  • 支持创建、编辑、颜色选择、持久化;并提供默认清单模板提升开箱体验。

  • 示例代码(函数级注释):

ts 复制代码
// 添加收藏清单:避免重复ID,加入列表并持久化
public async addFavorite(favoriteData: UserSelectedFavoriteData): Promise<boolean> {
  const existingIndex = this.favoriteList.findIndex(item => item.id === favoriteData.id);
  if (existingIndex !== -1) {
    return false;
  }
  this.favoriteList.unshift(favoriteData);
  await this.saveFavoriteData();
  return true;
}
ts 复制代码
// 创建新清单:生成唯一ID,构建项目并保存为收藏
private async createNewChecklist(validItems: string[]): Promise<void> {
  const checklistId = Date.now().toString();
  const items: ChecklistItem[] = validItems.map((content, index) => {
    return new ChecklistItem(`${checklistId}_${index + 1}`, content.trim(), false);
  });
  const favoriteData = new UserSelectedFavoriteData(
    checklistId, this.title.trim(), this.colorOptions[this.selectedColorIndex].hex_code, items
  );
  await this.favoriteManager.addFavorite(favoriteData);
}

频率事件与痕迹记录

  • 用于记录"喝水/跑步"等日常高频行为;提供月/总计数,自动生成痕迹用于回顾。
  • 示例代码(函数级注释):
ts 复制代码
// 点击事件:更新月/总计数与最近点击时间,并写入痕迹
public async clickFrequencyEvent(eventId: string): Promise<void> {
  const event = this.frequencyEvents.find(e => e.id === eventId);
  const now = Date.now();
  const currentMonth = new Date().getMonth();
  const lastClickMonth = event.lastClickTime ? new Date(event.lastClickTime).getMonth() : -1;

  event.lastClickTime = now;
  event.totalCount += 1;
  if (currentMonth !== lastClickMonth) {
    event.monthlyCount = 1;
  } else {
    event.monthlyCount += 1;
  }

  await this.saveFrequencyEvents();
  await this.addToTrace(event, now);
}

个人资料与头像

  • 单例管理器整合验证、存储、事件分发;支持创建、更新、导入导出。
  • 示例代码(函数级注释):
ts 复制代码
// 创建用户资料:校验输入、持久化保存、更新内存并广播事件
async createProfile(name: string, motto: string, avatar?: Avatar): Promise<OperationResult<UserProfile>> {
  const nameValidation = UserProfileValidator.validateName(name);
  const mottoValidation = UserProfileValidator.validateMotto(motto);
  if (!nameValidation.isValid || !mottoValidation.isValid) {
    return { success: false, message: '输入校验失败' };
  }

  const profile = new UserProfile(name, motto, avatar);
  const saveResult = await this.storage.saveProfile(profile);
  if (!saveResult) {
    return { success: false, message: '保存用户资料失败' };
  }

  this.currentProfile = profile;
  this.emitEvent({ type: UserProfileEventType.PROFILE_CREATED, profile, timestamp: Date.now() });
  return { success: true, data: profile, message: '用户资料创建成功' };
}

桌面卡片联动

  • 卡片转正后自动保存卡片ID并提示打开事件选择;选中事件后,表单绑定数据推送,卡片实时更新。

  • 示例代码(函数级注释):

ts 复制代码
// 临时卡片转正:记录formId,推送"shouldOpen"标记驱动前端打开选择页
onCastToNormalForm(formId: string) {
  FormIdManager.context = this.context;
  FormIdManager.addFormId(formId);
  const payload = { formId: formId, shouldOpen: true };
  const binding = formBindingData.createFormBindingData(payload);
  formProvider.updateForm(formId, binding);
}
ts 复制代码
// 更新卡片绑定:组装选中事件的展示数据并推送到卡片
public static async updateSelectedEvent(formId: string, event: FrequencyEvent, guardianIcon: string): Promise<void> {
  const manager: FrequencyEventManager = FrequencyEventManager.getInstance();
  const lastClickText: string = manager.getLastClickTimeText(event.id);
  const payload: SelectedEventBindingData = {
    eventId: event.id,
    formId: formId,
    eventTitle: event.title,
    eventColor: event.color,
    guardianIcon: guardianIcon,
    monthlyCount: event.monthlyCount,
    lastClickTimeText: lastClickText
  };
  const binding = formBindingData.createFormBindingData(payload);
  await formProvider.updateForm(formId, binding);
}

媒体与传感器能力

  • 点击事件完成时,播放本地音频,提供触感震动反馈,让交互更生动。
  • 示例代码(函数级注释):
ts 复制代码
// 播放内置音频:按状态机推进(准备→播放→释放)
async start() {
  const avPlayer = await media.createAVPlayer();
  avPlayer.on('stateChange', state => {
    if (state === 'initialized') { avPlayer.prepare() }
    else if (state === 'prepared') { avPlayer.play() }
    else if (state === 'stopped') { avPlayer.release() }
  });
  let context = getContext(this) as common.UIAbilityContext;
  let fd = await context.resourceManager.getRawFd('music01.mp3');
  avPlayer.fdSrc = { fd: fd.fd, offset: fd.offset, length: fd.length };
}
ts 复制代码
// 触感反馈:触发一次70ms震动增强交互体验
vibrator() {
  vibrator.startVibration({ type: 'time', duration: 70 }, { id: 0, usage: 'alarm' });
}

图片选择、生成与分享

  • 支持多/单选图片;余生时钟可生成图片、保存至相册,并通过系统分享面板分享至社交平台。
  • 示例代码(函数级注释):
ts 复制代码
// 选择图片:多选模式返回URI列表,空选返回提示
static async pickImages(context: common.UIAbilityContext, config: ImagePickerConfig = { maxSelectNumber: 9, isMultiSelect: true }): Promise<ImagePickResult> {
  const photoSelectOptions = new picker.PhotoSelectOptions();
  photoSelectOptions.MIMEType = picker.PhotoViewMIMETypes.IMAGE_TYPE;
  photoSelectOptions.maxSelectNumber = config.maxSelectNumber;
  const photoPicker = new picker.PhotoViewPicker();
  const result = await photoPicker.select(photoSelectOptions);
  if (result && result.photoUris && result.photoUris.length > 0) {
    return { success: true, imageUris: result.photoUris };
  }
  return { success: false, imageUris: [], errorMessage: '未选择任何图片' };
}
ts 复制代码
// 生成并分享:生成余生时钟图片,唤起系统分享面板
private async handleShareClick(): Promise<void> {
  const context = getContext(this) as common.UIAbilityContext;
  const imageGenerator = new LifeClockImageGenerator(context);
  const imagePath = await imageGenerator.generateLifeClockImage('mainClockContent', {
    worldCups: this.lifeClockData.worldCups,
    summers: this.lifeClockData.summers,
    retirementYears: this.lifeClockData.retirementYears,
    weekends: this.lifeClockData.weekends
  });
  await this.shareLifeClockImage(imagePath);
}

总结与号召

  • LifeList 用更"艺术化"的方式,让时间、习惯与目标变得可视、可控、可复盘。无论是"余生时钟"的沉浸展示,还是"频率事件"的轻盈记录,亦或"自定义清单"的极致掌控,我们为每一位热爱生活的人,提供一个更懂你的日常系统。
  • 立即体验,让你今天的每一次选择都被认真记录。

关于青蓝逐码组织

如果你兴趣想要了解更多的鸿蒙应用开发细节和最新资讯甚至你想要做出一款属于自己的应用!欢迎在评论区留言或者私信,可以加入技术交流群。

相关推荐
爱笑的眼睛117 小时前
ArkTS接口与泛型在HarmonyOS应用开发中的深度应用
华为·harmonyos
大雷神9 小时前
【鸿蒙星光分享】HarmonyOS 语音朗读功能同步教程
华为·harmonyos
不凡的凡9 小时前
flutter 管理工具fvm
flutter·harmonyos
柒儿吖9 小时前
Electron for HarmonyOS_PC Swifty 密码管理器适配开源鸿蒙PC开发实践
javascript·electron·harmonyos
一只栖枝9 小时前
HarmonyOS 开发高级认证是什么?含金量高吗?
华为·华为认证·harmonyos·鸿蒙·考证
柒儿吖11 小时前
Electron for 鸿蒙PC - 菜单栏完整开发指南:从原生菜单到自定义菜单的实现
javascript·electron·harmonyos
A懿轩A11 小时前
【2025最新】最新HarmonyOS 6 DevEco Studio下载安装 详细步骤(带图展示)
华为·harmonyos
大雷神11 小时前
HarmonyOS文字书写功能实现指南
华为·harmonyos
进击的阿三姐11 小时前
鸿蒙个人开发者账号如何真机调试
华为·harmonyos
IT从业者张某某13 小时前
Qt-for-鸿蒙PC-TextEditorPro 多功能文本编辑器开源鸿蒙开发实践
qt·开源·harmonyos