HarmonyOS开发案例:【生活健康app之实现打卡功能】(2)
实现打卡功能
首页会展示当前用户已经开启的任务列表,每条任务会显示对应的任务名称以及任务目标、当前任务完成情况。用户只可对当天任务进行打卡操作,用户可以根据需要对任务列表中相应的任务进行点击打卡。如果任务列表中的每个任务都在当天完成则为连续打卡一天,连续打卡多天会获得成就徽章。打卡效果如下图所示:
开发前请熟悉鸿蒙开发指导文档:gitee.com/li-shizhen-skin/harmony-os/blob/master/README.md
点击或者复制转到。
任务列表
使用List组件展示用户当前已经开启的任务,每条任务对应一个TaskCard组件,clickAction包装了点击和长按事件,用户点击任务卡时会触发弹起打卡弹窗,从而进行打卡操作;长按任务卡时会跳转至任务编辑界面,对相应的任务进行编辑处理。代码如下:
// HomeComponent.ets
// 任务列表
ForEach(this.homeStore.getTaskListOfDay(), (item: TaskInfo) => {TaskCard({taskInfoStr: JSON.stringify(item),clickAction: (isClick: boolean) => this.taskItemAction(item, isClick)}).margin({ bottom: Const.DEFAULT_12 }).height($r('app.float.default_64'))
}, (item: TaskInfo) => JSON.stringify(item))
...
CustomDialogView() // 自定义弹窗中间件
自定义弹窗中间件CustomDialogView
在组件CustomDialogView的aboutToAppear生命周期中注册SHOW_TASK_DETAIL_DIALOG的事件回调方法 ,当通过emit触发此事件时即触发回调方法执行。代码如下:
// CustomDialogView.ets
export class CustomDialogCallback {confirmCallback: Function = () => {};cancelCallback: Function = () => {};
}@Component
export struct CustomDialogView {@State isShow: boolean = false;@Provide achievementLevel: number = 0;@Consume broadCast: BroadCast;@Provide currentTask: TaskInfo = TaskItem;@Provide dialogCallBack: CustomDialogCallback = new CustomDialogCallback();// 成就对话框achievementDialog: CustomDialogController = new CustomDialogController({builder: AchievementDialog(),autoCancel: true,customStyle: true});// 任务时钟对话框taskDialog: CustomDialogController = new CustomDialogController({builder: TaskDetailDialog(),autoCancel: true,customStyle: true});aboutToAppear() {Logger.debug('CustomDialogView', 'aboutToAppear');// 成就对话框this.broadCast.on(BroadCastType.SHOW_ACHIEVEMENT_DIALOG, (achievementLevel: number) => {Logger.debug('CustomDialogView', 'SHOW_ACHIEVEMENT_DIALOG');this.achievementLevel = achievementLevel;this.achievementDialog.open();});// 任务时钟对话框this.broadCast.on(BroadCastType.SHOW_TASK_DETAIL_DIALOG,(currentTask: TaskInfo, dialogCallBack: CustomDialogCallback) => {Logger.debug('CustomDialogView', 'SHOW_TASK_DETAIL_DIALOG');this.currentTask = currentTask || TaskItem;this.dialogCallBack = dialogCallBack;this.taskDialog.open();});}aboutToDisappear() {Logger.debug('CustomDialogView', 'aboutToDisappear');}build() {}
}
点击任务卡片
点击任务卡片会emit触发 “SHOW_TASK_DETAIL_DIALOG” 事件,同时把当前任务,以及确认打卡回调方法传递下去。代码如下:
// HomeComponent.ets
// 任务卡片事件
taskItemAction(item: TaskInfo, isClick: boolean): void {...if (isClick) {// 点击任务打卡let callback: CustomDialogCallback = { confirmCallback: (taskTemp: TaskInfo) => {this.onConfirm(taskTemp)}, cancelCallback: () => {} };// 触发弹出打卡弹窗事件 并透传当前任务参数(item) 以及确认打卡回调this.broadCast.emit(BroadCastType.SHOW_TASK_DETAIL_DIALOG, [item, callback]);} else {// 长按编辑任务...}
}
// 确认打卡
onConfirm(task) {this.homeStore.taskClock(task).then((res: AchievementInfo) => {// 打卡成功后 根据连续打卡情况判断是否 弹出成就勋章 以及成就勋章级别if (res.showAchievement) {// 触发弹出成就勋章SHOW_ACHIEVEMENT_DIALOG 事件, 并透传勋章类型级别let achievementLevel = res.achievementLevel;if (achievementLevel) {this.broadCast.emit(BroadCastType.SHOW_ACHIEVEMENT_DIALOG, achievementLevel);} else {this.broadCast.emit(BroadCastType.SHOW_ACHIEVEMENT_DIALOG);}}})
}
打卡弹窗组件TaskDetailDialog
打卡弹窗组件根据当前任务的ID获取任务名称以及弹窗背景图片资源。
打卡弹窗组件由两个小组件构成,代码如下:
// TaskDetailDialog.ets
Column() {// 展示任务的基本信息TaskBaseInfo({taskName: TaskMapById[this.currentTask?.taskID - 1].taskName // 根据当前任务ID获取任务名称});// 打卡功能组件 (任务打卡、关闭弹窗)TaskClock({confirm: () => {this.dialogCallBack.confirmCallback(this.currentTask);this.controller.close();},cancel: () => {this.controller.close();},showButton: this.showButton})
}
...
TaskBaseInfo组件代码如下:
// TaskDetailDialog.ets
@Component
struct TaskBaseInfo {taskName: string | Resource = '';build() {Column({ space: Const.DEFAULT_8 }) {Text(this.taskName).fontSize($r('app.float.default_22')).fontWeight(FontWeight.Bold).fontFamily($r('app.string.HarmonyHeiTi_Bold')).taskTextStyle().margin({left: $r('app.float.default_12')})}.position({ y: $r('app.float.default_267') })}
}
TaskClock组件代码如下:
// TaskDetailDialog.ets
@Component
struct TaskClock {confirm: Function = () => {};cancel: Function = () => {};showButton: boolean = false;build() {Column({ space: Const.DEFAULT_12 }) {Button() {Text($r('app.string.clock_in')).height($r('app.float.default_42')).fontSize($r('app.float.default_20')).fontWeight(FontWeight.Normal).textStyle()}.width($r('app.float.default_220')).borderRadius($r('app.float.default_24')).backgroundColor('rgba(255,255,255,0.40)').onClick(() => {GlobalContext.getContext().setObject('taskListChange', true);this.confirm();}).visibility(!this.showButton ? Visibility.None : Visibility.Visible)Text($r('app.string.got_it')).fontSize($r('app.float.default_14')).fontWeight(FontWeight.Regular).textStyle().onClick(() => {this.cancel();})}}
}
打卡接口调用
// HomeViewModel.ets
public async taskClock(taskInfo: TaskInfo) {let taskItem = await this.updateTask(taskInfo);let dateStr = this.selectedDayInfo?.dateStr;// 更新任务失败if (!taskItem) {return {achievementLevel: 0,showAchievement: false} as AchievementInfo;}// 更新当前时间的任务列表this.selectedDayInfo.taskList = this.selectedDayInfo.taskList.map((item) => {return item.taskID === taskItem?.taskID ? taskItem : item;});let achievementLevel: number = 0;if(taskItem.isDone) {// 更新每日任务完成情况数据let dayInfo = await this.updateDayInfo();... // 当日任务完成数量等于总任务数量时 累计连续打卡一天// 更新成就勋章数据 判断是否弹出获得勋章弹出及勋章类型if (dayInfo && dayInfo?.finTaskNum === dayInfo?.targetTaskNum) {achievementLevel = await this.updateAchievement(this.selectedDayInfo.dayInfo);}}...return {achievementLevel: achievementLevel,showAchievement: ACHIEVEMENT_LEVEL_LIST.includes(achievementLevel)} as AchievementInfo;
}`HarmonyOS与OpenHarmony鸿蒙文档籽料:mau123789是v直接拿`
// HomeViewModel.ets
// 更新当天任务列表
updateTask(task: TaskInfo): Promise<TaskInfo> {return new Promise((resolve, reject) => {let taskID = task.taskID;let targetValue = task.targetValue;let finValue = task.finValue;let updateTask = new TaskInfo(task.id, task.date, taskID, targetValue, task.isAlarm, task.startTime,task.endTime, task.frequency, task.isDone, finValue, task.isOpen);let step = TaskMapById[taskID - 1].step; // 任务步长let hasExceed = updateTask.isDone;if (step === 0) { // 任务步长为0 打卡一次即完成该任务updateTask.isDone = true; // 打卡一次即完成该任务updateTask.finValue = targetValue;} else {let value = Number(finValue) + step; // 任务步长非0 打卡一次 步长与上次打卡进度累加updateTask.isDone = updateTask.isDone || value >= Number(targetValue); // 判断任务是否完成updateTask.finValue = updateTask.isDone ? targetValue : `${value}`;}TaskInfoTableApi.updateDataByDate(updateTask, (res: number) => { // 更新数据库if (!res || hasExceed) {Logger.error('taskClock-updateTask', JSON.stringify(res));reject(res);}resolve(updateTask);})})
}
相关文章:

HarmonyOS开发案例:【生活健康app之实现打卡功能】(2)
实现打卡功能 首页会展示当前用户已经开启的任务列表,每条任务会显示对应的任务名称以及任务目标、当前任务完成情况。用户只可对当天任务进行打卡操作,用户可以根据需要对任务列表中相应的任务进行点击打卡。如果任务列表中的每个任务都在当天完成则为…...

Mockito框架,帮助创建模拟对象进行测试的利器
在现代软件开发中,单元测试作为确保代码质量和可靠性的重要环节,已逐渐成为开发流程中不可或缺的一部分。为了让单元测试更加灵活、独立,开发者们通常使用 Mocking(模拟)框架来替代真实对象,从而更好地模拟…...

Spring Boot的工作原理
文章目录 前言一、Spring Boot的核心原理二、Spring Boot的工作原理1.创建SpringApplication对象2.调用实例的run方法 总结 前言 在上一篇《初识SpringBoot并构建第一个SpringBoot项目》的学习后,我们对Spring Boot有了基本了解。现在,我们将通过学习Sp…...

单点登录和统一身份认证的区别
在工作过程中,总被问到单点登录和统一身份认证的问题。笔者打算尝试用更通俗的方式解释统一身份认证(Unified Identity Authentication)和单点登录(Single Sign-On,简称SSO)之间的区别。 1.定义࿱…...

革新机器人任务规划:TREE-PLANNER引领高效、准确的机器人动作生成新趋势
DeepVisionary 每日深度学习前沿科技推送&顶会论文分享,与你一起了解前沿深度学习信息! 引言 任务规划在机器人技术中扮演着至关重要的角色。它涉及到为机器人设计一系列中级动作(技能),使其能够完成复杂的高级任…...

【数据分析面试】42.用户流失预测模型搭建(资料数据分享)
题目 保持高的客户留存率可以稳定和提到企业的收入。因此,预测和防止客户流失是在业务中常见的一项数据分析任务。这次分享的数据集包括了电信行业、银行、人力资源和电商行业,涵盖了不同业务背景下的流失预测数据。 后台回复暗号(在本文末…...

5.13号模拟前端面试10问
1.介绍箭头函数和普通函数的区别 箭头函数和普通函数在JavaScript中有一些重要的区别。以下是关于这些区别的详细解释: 语法结构上的差异: 箭头函数使用更简洁的语法,它不需要使用function关键字,而是使用一个箭头(…...

学习使用jQuery将光标移动到textarea的末尾
学习使用jQuery将光标移动到textarea的末尾 代码 代码 $(document).ready(function(){var textarea $(#your-qipa-id); // 替换为你的textarea IDtextarea.focus(); // 将焦点设置到textarea// 获取textarea的值的长度var len textarea.val().length;// 使用setSelectionRan…...

【送书福利第七期】你好!Java(文末送书)
文章目录 编辑推荐内容简介作者简介目录前言/序言 编辑推荐 适读人群 :程序员;相关院校师生 本书以轻松幽默的语言,从零开始介绍Java语言。书名来源于编程语言中最经典的Hello World程序,寓意带读者从入门到精通。 书中每章都设有总结与扩展…...

申贷时,银行级大数据自己能查到吗?
随着金融风控的不断健全,大数据作为辅助的风控工具正在被越来越多的银行和机构使用。在进行申贷时,银行通常会进行大数据查询,以便评估申请人的信用状况。那么,这些大数据自己能查到吗?接下来本文就为大家详细介绍一下࿰…...

【SVN-TortoiseSVN】SVN 的简介与TortoiseSVN 安装使用教程
目录 🌞前言 🌊1. SVN 的简介 🌍1.1 SVN是什么 🌍1.2 SVN 工作原理 🌍1.3 TortoiseSVN 术语及定义 🌊2. TortoiseSVN 安装与汉化 🌊3. SVN 基本操作-TortoiseSVN 🌍3.1 浏览…...

5.13学习日志
Pytorch 神经网络基础 1.模型构造 1》层和块 块可以描述单个层,由多个层组成的组件或者模型本身 块由类表示,类的任何子类都必须定义一个将其输入转换为输出的前向传播函数。为了计算梯度,块必须具有反向传播函数 自定义块: …...

8种常见的CMD命令
1.怎么打开CMD窗口 步骤1:winr 步骤2:在弹出的窗口输入cmd,然后点击确认,就会出现一个cmd的窗口 2.CMD的8种常见命令 2.1盘符名称冒号 说明:切换盘的路径 打开CMD窗口这里默认的是C盘的Users的27823路径底下…...

版本控制工具之Git的基础使用教程
Git Git是一个分布式版本控制系统,由Linux之父Linus Torvalds 开发。它既可以用来管理和追踪计算机文件的变化,也是开发者协作编写代码的工具。 本文将介绍 Git 的基础原理、用法、操作等内容。 一、基础概念 1.1 版本控制系统 版本控制系统&#x…...

五子棋对战(网页版)
目录 一、项目背景 用户模块 匹配模块 对战模块 二、核心技术 三、相关知识 WebSocket 原理 报文格式 代码 服务器代码 客户端代码 四、项目创建 4.1、实现用户模块 编写数据库代码 数据库设计 配置MyBatis 创建实体类 创建UserMapper 创建UserMapper接口 实现UserMapper.xml 前…...

在 Ubuntu系统中,可以使用以下几种方法查看网络速率
1 使用终端命令:可以使用ifconfig命令查看网络接口的信息,包括网络接口名称、IP地址、子网掩码等。也可以使用nload命令查看网络流量和传输速率。 2 使用网络监控工具:例如nethogs,可以更加直观地查看网络吞吐量。 3 使用网络测…...

这是摆脱困境的最好方法
20多年前,我开始涉足创业,经历过的那种停滞感我都记不清了。这是这条职业道路上最常见的挣扎之一,而且很难摆脱。 卡住的城市是一个地方,任何有创造力的,自由职业者和好奇的人经常去。这是一个很难逃离的地方。 被困…...

OceanBase 中的ROWID与Oracle的差异与如何迁移
1. ROWID 1.1 OB和Oracle中rowid的区别 正如大家所知道的,OceanBase兼容Oracle的rowid特性,但在其生成规则上却存在不同,具体表现如下: OceanBase ● 定义:OceanBase(简称 OB)的rowid是通过…...

秋招后端开发面试题 - JVM运行时数据区
目录 运行时数据区前言面试题JVM 内存区域 / 运行时数据区?说一下 JDK1.6、1.7、1.8 内存区域的变化?为什么使用元空间替代永久代作为方法区的实现?Java 堆的内存分区了解吗?运行时常量池?字符串常量池了解吗ÿ…...

【YOLOv8改进[Backbone]】使用SCINet改进YOLOv8在黑暗环境的目标检测效果
目录 一 SCINet 1 本文方法 ① 权重共享的照明学习 ② 自校准模块 ③ 无监督训练损失 二 使用SCINet助力YOLOv8在黑暗环境的目标检测效果 1 整体修改 2 配置文件 3 训练 其他 一 SCINet 官方论文地址:https://arxiv.org/pdf/2204.10137 官方代码地址&…...

ASE docker related research
ASE 2022 Understanding and Predicting Docker Build Duration: An Empirical Study of Containerized Workflow of OSS Projects 理解和预测 Docker 构建持续时间:OSS 项目容器化工作流程的实证研究 Docker 构建是容器化工作流程的关键组成部分,它…...

maven .lastUpdated文件作用
现象 有时候我在用maven管理项目时会发现有些依赖报错,这时你可以看一下本地仓库中是否有.lastUpdated文件,也许与它有关。 原因 有这个文件就表示依赖下载过程中发生了错误导致依赖没成功下载,可能是网络原因,也有可能是远程…...

gtest的编译与使用
文章目录 gtest的编译与使用概述笔记CMake参数官方文档测试程序测试效果END gtest的编译与使用 概述 gTest是 googletest的缩写,如果直接找gTest项目,是找不到的。 库地址 https://github.com/google/googletest.git 迁出到本地后,切到最新…...

【 npm详解:从入门到精通】
文章目录 npm详解:从入门到精通1. [npm](https://www.npmjs.com/)的安装2. npm的基础用法2.1 初始化项目2.2 安装依赖2.3 卸载依赖2.4 更新依赖 3. npm的高级用法3.1 运行脚本3.2 使用npm scope3.3 使用npm link 4. npm资源5. 使用npm进行依赖树分析和可视化6. npm进…...

【Web后端】实现文件上传
表单必须使用post提交 ,enctype 必须是multipart/form-data在Servlet上填加注解 MultipartConfiglocation :默认情况下将存储文件的目录,默认值为“”。maxFileSize :允许上传文件的最大大小,其值以字节为单位。 默认值为-1L表示无…...

react 逻辑 AND 运算符 ()
在 React 组件中,当你想在条件为 true 时渲染一些 JSX 时,它经常会出现,或者什么都不渲染。使用 ,只有在以下情况下才能有条件地呈现复选标记:&&isPackedtrue return (<li className"item">{…...

Redis详解(二)
事务 什么是事务? 事务是一个单独的隔离操作:事务中的所有命令都会序列化、按顺序地执行。事务在执行的过程中,不会被其他客户端发送来的命令请求所打断。 事务是一个原子操作:事务中的命令要么全部被执行,要么全部都…...

嵌入式:基于STM32的智能家居照明控制系统
在智能家居系统中,自动照明控制不仅提高了居住舒适度,还有助于节能减排。本教程旨在引导读者通过使用STM32微控制器来开发一个智能照明控制系统。该系统能够根据环境光线自动调整室内照明的亮度,并支持通过简单的用户界面手动控制光线。 一、…...

三种基本排序-冒泡,选择,二分
闲话不多说,直接上代码,简明易懂,条理清晰,交互性强,尽善尽美 码住,建议copy下来: 先上二分法吧,稍复杂点的,代码多一些,用了函数调用 二分排序࿱…...

windows查找重复的物理地址
单独查询所有物理(mac)地址(cmd执行):arp -a 查找同一局域网下重复的mac,打开power shell执行以下命令: Get-NetNeighbor | Where-Object { $_.State -eq "Reachable" } | Select-O…...