實(shí)現(xiàn)打卡功能
首頁(yè)會(huì)展示當(dāng)前用戶已經(jīng)開啟的任務(wù)列表,每條任務(wù)會(huì)顯示對(duì)應(yīng)的任務(wù)名稱以及任務(wù)目標(biāo)、當(dāng)前任務(wù)完成情況。用戶只可對(duì)當(dāng)天任務(wù)進(jìn)行打卡操作,用戶可以根據(jù)需要對(duì)任務(wù)列表中相應(yīng)的任務(wù)進(jìn)行點(diǎn)擊打卡。如果任務(wù)列表中的每個(gè)任務(wù)都在當(dāng)天完成則為連續(xù)打卡一天,連續(xù)打卡多天會(huì)獲得成就徽章。打卡效果如下圖所示:
開發(fā)前請(qǐng)熟悉鴻蒙開發(fā)指導(dǎo)文檔:[qr23.cn/FBD4cY
]。
任務(wù)列表
使用List組件展示用戶當(dāng)前已經(jīng)開啟的任務(wù),每條任務(wù)對(duì)應(yīng)一個(gè)TaskCard組件,clickAction包裝了點(diǎn)擊和長(zhǎng)按事件,用戶點(diǎn)擊任務(wù)卡時(shí)會(huì)觸發(fā)彈起打卡彈窗,從而進(jìn)行打卡操作;長(zhǎng)按任務(wù)卡時(shí)會(huì)跳轉(zhuǎn)至任務(wù)編輯界面,對(duì)相應(yīng)的任務(wù)進(jìn)行編輯處理。代碼如下:
// HomeComponent.ets
// 任務(wù)列表
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生命周期中注冊(cè)SHOW_TASK_DETAIL_DIALOG的事件回調(diào)方法 ,當(dāng)通過(guò)emit觸發(fā)此事件時(shí)即觸發(fā)回調(diào)方法執(zhí)行。代碼如下:
// 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();
// 成就對(duì)話框
achievementDialog: CustomDialogController = new CustomDialogController({
builder: AchievementDialog(),
autoCancel: true,
customStyle: true
});
// 任務(wù)時(shí)鐘對(duì)話框
taskDialog: CustomDialogController = new CustomDialogController({
builder: TaskDetailDialog(),
autoCancel: true,
customStyle: true
});
aboutToAppear() {
Logger.debug('CustomDialogView', 'aboutToAppear');
// 成就對(duì)話框
this.broadCast.on(BroadCastType.SHOW_ACHIEVEMENT_DIALOG, (achievementLevel: number) = > {
Logger.debug('CustomDialogView', 'SHOW_ACHIEVEMENT_DIALOG');
this.achievementLevel = achievementLevel;
this.achievementDialog.open();
});
// 任務(wù)時(shí)鐘對(duì)話框
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() {
}
}
點(diǎn)擊任務(wù)卡片
點(diǎn)擊任務(wù)卡片會(huì)emit觸發(fā) “SHOW_TASK_DETAIL_DIALOG” 事件,同時(shí)把當(dāng)前任務(wù),以及確認(rèn)打卡回調(diào)方法傳遞下去。代碼如下:
// HomeComponent.ets
// 任務(wù)卡片事件
taskItemAction(item: TaskInfo, isClick: boolean): void {
...
if (isClick) {
// 點(diǎn)擊任務(wù)打卡
let callback: CustomDialogCallback = { confirmCallback: (taskTemp: TaskInfo) = > {
this.onConfirm(taskTemp)
}, cancelCallback: () = > {
} };
// 觸發(fā)彈出打卡彈窗事件 并透?jìng)鳟?dāng)前任務(wù)參數(shù)(item) 以及確認(rèn)打卡回調(diào)
this.broadCast.emit(BroadCastType.SHOW_TASK_DETAIL_DIALOG, [item, callback]);
} else {
// 長(zhǎng)按編輯任務(wù)
...
}
}
// 確認(rèn)打卡
onConfirm(task) {
this.homeStore.taskClock(task).then((res: AchievementInfo) = > {
// 打卡成功后 根據(jù)連續(xù)打卡情況判斷是否 彈出成就勛章 以及成就勛章級(jí)別
if (res.showAchievement) {
// 觸發(fā)彈出成就勛章SHOW_ACHIEVEMENT_DIALOG 事件, 并透?jìng)鲃渍骂愋图?jí)別
let achievementLevel = res.achievementLevel;
if (achievementLevel) {
this.broadCast.emit(BroadCastType.SHOW_ACHIEVEMENT_DIALOG, achievementLevel);
} else {
this.broadCast.emit(BroadCastType.SHOW_ACHIEVEMENT_DIALOG);
}
}
})
}
打卡彈窗組件TaskDetailDialog
打卡彈窗組件根據(jù)當(dāng)前任務(wù)的ID獲取任務(wù)名稱以及彈窗背景圖片資源。
打卡彈窗組件由兩個(gè)小組件構(gòu)成,代碼如下:
// TaskDetailDialog.ets
Column() {
// 展示任務(wù)的基本信息
TaskBaseInfo({
taskName: TaskMapById[this.currentTask?.taskID - 1].taskName // 根據(jù)當(dāng)前任務(wù)ID獲取任務(wù)名稱
});
// 打卡功能組件 (任務(wù)打卡、關(guān)閉彈窗)
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();
})
}
}
}
打卡接口調(diào)用
// HomeViewModel.ets
public async taskClock(taskInfo: TaskInfo) {
let taskItem = await this.updateTask(taskInfo);
let dateStr = this.selectedDayInfo?.dateStr;
// 更新任務(wù)失敗
if (!taskItem) {
return {
achievementLevel: 0,
showAchievement: false
} as AchievementInfo;
}
// 更新當(dāng)前時(shí)間的任務(wù)列表
this.selectedDayInfo.taskList = this.selectedDayInfo.taskList.map((item) = > {
return item.taskID === taskItem?.taskID ? taskItem : item;
});
let achievementLevel: number = 0;
if(taskItem.isDone) {
// 更新每日任務(wù)完成情況數(shù)據(jù)
let dayInfo = await this.updateDayInfo();
...
// 當(dāng)日任務(wù)完成數(shù)量等于總?cè)蝿?wù)數(shù)量時(shí) 累計(jì)連續(xù)打卡一天
// 更新成就勛章數(shù)據(jù) 判斷是否彈出獲得勛章彈出及勛章類型
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
// 更新當(dāng)天任務(wù)列表
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; // 任務(wù)步長(zhǎng)
let hasExceed = updateTask.isDone;
if (step === 0) { // 任務(wù)步長(zhǎng)為0 打卡一次即完成該任務(wù)
updateTask.isDone = true; // 打卡一次即完成該任務(wù)
updateTask.finValue = targetValue;
} else {
let value = Number(finValue) + step; // 任務(wù)步長(zhǎng)非0 打卡一次 步長(zhǎng)與上次打卡進(jìn)度累加
updateTask.isDone = updateTask.isDone || value >= Number(targetValue); // 判斷任務(wù)是否完成
updateTask.finValue = updateTask.isDone ? targetValue : `${value}`;
}
TaskInfoTableApi.updateDataByDate(updateTask, (res: number) = > { // 更新數(shù)據(jù)庫(kù)
if (!res || hasExceed) {
Logger.error('taskClock-updateTask', JSON.stringify(res));
reject(res);
}
resolve(updateTask);
})
})
}
審核編輯 黃宇
-
HarmonyOS
+關(guān)注
關(guān)注
79文章
1946瀏覽量
29731 -
OpenHarmony
+關(guān)注
關(guān)注
25文章
3545瀏覽量
15729 -
鴻蒙OS
+關(guān)注
關(guān)注
0文章
188瀏覽量
4336
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論