回复
#HarmonyOS NEXT体验官# 体验HarmonyOS开发流程,开发一个记步app(二) 原创
RandomBoolean
发布于 2024-8-21 17:55
浏览
0收藏
接上一篇文章,本文将继续补充剩余部分。
首页源码已经贴过,下面介绍其他组件的封装。
TargetInformation
展示一言内容的组件,源码如下。
/*
* Copyright (c) 2023 Huawei Device Co., Ltd.
* Licensed under the Apache License,Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { CommonConstants } from '../common/constant/CommonConstant';
import { httpRequestGet } from '../common/utils/HttpUtil';
import ResponseResult from '../viewmodel/ResponseResult';
@Component
export default struct TargetInformation {
@Prop latestUpdateDate: string = '';
@Prop totalTasksNumber: number = 0;
@Prop completedTasksNumber: number = 0;
@State hitokoto: string = ''
@State hitokoto_from: string = ''
aboutToAppear(): void {
httpRequestGet(`https://v1.hitokoto.cn?c=d`).then((data: ESObject) => {
// this.dataArray = data.data || []
this.hitokoto = data.hitokoto
this.hitokoto_from = data.from
})
}
build() {
Column() {
this.TargetItem()
// this.OverallProgress()
}
.padding($r('app.float.target_padding'))
.width(CommonConstants.MAIN_BOARD_WIDTH)
.backgroundColor(Color.White)
.borderRadius(CommonConstants.TARGET_BORDER_RADIUS)
}
@Builder
TargetItem() {
Column() {
Text(this.hitokoto)
.fontSize($r('app.float.target_name_font'))
.fontWeight(CommonConstants.FONT_WEIGHT_LARGE)
.width(CommonConstants.TITLE_WIDTH)
Text(`@${this.hitokoto_from}`)
.opacityTextStyle()
.fontSize($r('app.float.target_desc_font'))
.margin({ top: $r('app.float.title_margin') })
}
.margin({ left: CommonConstants.TARGET_MARGIN_LEFT })
.alignItems(HorizontalAlign.Start)
}
@Builder
OverallProgress() {
Row() {
Column() {
Text($r('app.string.overall_progress'))
.fontSize($r('app.float.button_font'))
.fontColor($r('app.color.title_black_color'))
.fontWeight(CommonConstants.FONT_WEIGHT)
Row() {
Text($r('app.string.latest_updateTime'))
.opacityTextStyle()
Text(this.latestUpdateDate)
.opacityTextStyle()
}
.margin({ top: $r('app.float.text_margin') })
}
.alignItems(HorizontalAlign.Start)
Blank()
Stack() {
Row() {
Text(this.completedTasksNumber.toString())
.fontSize($r('app.float.progress_font'))
.fontWeight(CommonConstants.FONT_WEIGHT)
.fontColor($r('app.color.main_blue'))
Text(`/${this.totalTasksNumber}`)
.fontSize($r('app.float.progress_font'))
.fontWeight(CommonConstants.FONT_WEIGHT)
}
Progress({
value: this.completedTasksNumber,
total: this.totalTasksNumber,
type: ProgressType.Ring
})
.color($r('app.color.main_blue'))
.style({
strokeWidth: CommonConstants.STROKE_WIDTH
})
.width($r('app.float.progress_length'))
.height($r('app.float.progress_length'))
}
}
.width(CommonConstants.FULL_WIDTH)
.height($r('app.float.progress_length'))
.margin({ top: $r('app.float.progress_margin_top') })
}
}
/**
* Custom Transparent Text Styles
*/
@Extend(Text) function opacityTextStyle() {
.fontSize($r('app.float.text_font'))
.fontColor($r('app.color.title_black_color'))
.opacity(CommonConstants.OPACITY)
.fontWeight(CommonConstants.FONT_WEIGHT)
}
AddTargetDialog
添加目标的弹窗
源码如下,主要是一些表单的输入。
import { CommonConstants } from '../common/constant/CommonConstant';
@CustomDialog
export default struct AddTargetDialog {
@State subtaskName: string = '';
@State runNum: number = 0
private controller?: CustomDialogController;
onClickOk?: (value: string, runNum: number) => void;
build() {
Column() {
Text('添加目标🎯')
.width(CommonConstants.FULL_WIDTH)
.fontSize($r('app.float.secondary_title'))
.fontWeight(CommonConstants.FONT_WEIGHT)
.fontColor($r('app.color.title_black_color'))
.textAlign(TextAlign.Start)
TextInput({ placeholder: '请输入名称'})
.placeholderColor(Color.Grey)
.placeholderFont({ size: $r('app.float.list_font')})
.caretColor(Color.Blue)
.backgroundColor($r('app.color.input_background'))
.width(CommonConstants.FULL_WIDTH)
.height('60vp')
.margin({ top: CommonConstants.DIALOG_INPUT_MARGIN })
.fontSize($r('app.float.list_font'))
.fontColor($r('app.color.title_black_color'))
.onChange((value: string) => {
this.subtaskName = value;
})
TextInput({ placeholder: '请输入步数'})
.type(InputType.Number)
.placeholderColor(Color.Grey)
.placeholderFont({ size: $r('app.float.list_font')})
.caretColor(Color.Blue)
.backgroundColor($r('app.color.input_background'))
.width(CommonConstants.FULL_WIDTH)
.height('60vp')
.margin({ top: CommonConstants.DIALOG_INPUT_MARGIN })
.fontSize($r('app.float.list_font'))
.fontColor($r('app.color.title_black_color'))
.onChange((value: string) => {
this.runNum = Number(value);
})
Blank()
Row() {
Button($r('app.string.cancel_button'))
.dialogButtonStyle()
.onClick(() => {
this.controller?.close();
})
Divider()
.vertical(true)
Button($r('app.string.confirm_button'))
.dialogButtonStyle()
.onClick(() => {
if (this.onClickOk !== undefined) {
this.onClickOk(this.subtaskName, this.runNum);
}
})
}
.width(CommonConstants.DIALOG_OPERATION_WIDTH)
.height(CommonConstants.DIALOG_OPERATION_HEIGHT)
.justifyContent(FlexAlign.SpaceBetween)
}
.padding($r('app.float.dialog_padding'))
.height('300vp')
.width(CommonConstants.DIALOG_WIDTH)
.borderRadius(CommonConstants.DIALOG_BORDER_RADIUS)
.backgroundColor(Color.White)
}
}
/**
* Custom button style.
*/
@Extend(Button) function dialogButtonStyle() {
.fontSize($r('app.float.button_font'))
.height($r('app.float.dialog_btn_height'))
.width($r('app.float.dialog_btn_width'))
.backgroundColor(Color.White)
.fontColor($r('app.color.main_blue'))
}
TargetList
我的目标列表,源码如下,主要通过封装的getTasks方法,获取db数据。展示内容。
import TaskItemModel from '../viewmodel/TaskItemModel';
import TargetListItem from './TargetListItem';
import { CommonConstants } from '../common/constant/CommonConstant';
import DataModel from '../viewmodel/DataModel';
import { Task } from '../model/Task';
import { relationalStore } from '@kit.ArkData';
import { showToast } from '../utils/ToastUtils';
import { taskModel } from '../db/TaskModel';
import { emitter } from '@kit.BasicServicesKit';
@Component
export default struct TargetList {
@Consume overAllProgressChanged: boolean;
@State isEditMode: boolean = false;
@State selectArray: Array<boolean> = [];
@State clickIndex: number = CommonConstants.DEFAULT_CLICK_INDEX;
@State selectAll: boolean = false;
@Link targetData: Array<TaskItemModel>;
onAddClick?: () => void;
@State tasks: Array<Task> = new Array()
@Consume store: relationalStore.RdbStore
@State limit: number = 20
@State skip: number = 0
getTasks() {
taskModel.getTasks(this.store, (res: ESObject) => {
if (res && res.length > 0) {
this.tasks = this.tasks.concat(res)
}
}, (err: string) => {
showToast(err)
}, this.limit, this.skip)
}
aboutToAppear(): void {
setTimeout(() => {
this.getTasks()
}, 1000)
emitter.on("addTaskSuccess", () => {
this.tasks.length = 0
this.skip = 0
this.getTasks()
})
emitter.on('refresh', () => {
this.tasks.length = 0
this.skip = 0
this.getTasks()
})
}
build() {
Column() {
Row() {
Text('我的目标')
.fontSize($r('app.float.secondary_title'))
.fontWeight(CommonConstants.FONT_WEIGHT_LARGE)
.fontColor($r('app.color.title_black_color'))
Blank()
if (this.targetData.length > 0) {
if (this.isEditMode) {
Text($r('app.string.cancel_button'))
.operateTextStyle($r('app.color.main_blue'))
.margin({ left: $r('app.float.operate_button_margin') })
.onClick(() => {
this.selectAll = false;
this.isEditMode = false;
this.selectAllOrCancel(false);
})
Text($r('app.string.select_all_button'))
.operateTextStyle($r('app.color.main_blue'))
.margin({
left: $r('app.float.operate_button_margin')
})
Checkbox()
.select(this.isSelectAll())
.selectedColor($r('app.color.main_blue'))
.width(CommonConstants.CHECKBOX_WIDTH)
.onClick(() => {
this.selectAll = !this.selectAll;
this.selectAllOrCancel(this.selectAll);
})
} else {
Text($r('app.string.edit_button'))
.operateTextStyle($r('app.color.main_blue'))
.onClick(() => {
this.isEditMode = true;
this.selectAllOrCancel(false);
})
}
}
}
.width(CommonConstants.FULL_WIDTH)
.height($r('app.float.history_line_height'))
.padding({
left: $r('app.float.list_padding'),
right: $r('app.float.list_padding_right')
})
List({ space: CommonConstants.LIST_SPACE }) {
ForEach(this.tasks, (item: Task, index: number | undefined) => {
ListItem() {
TargetListItem({
taskItem: item,
index: index,
selectArr: $selectArray,
isEditMode: this.isEditMode,
clickIndex: $clickIndex
})
}
})
}
.edgeEffect(EdgeEffect.None)
.margin({ top: $r('app.float.list_margin_top') })
.width(CommonConstants.FULL_WIDTH)
.height(CommonConstants.LIST_HEIGHT)
Blank()
if (this.isEditMode) {
Button($r('app.string.delete_button'))
.opacity(this.isSelectRows() ? CommonConstants.NO_OPACITY : CommonConstants.OPACITY)
.enabled(this.isSelectRows() ? true : false)
.operateButtonStyle($r('app.color.main_red'))
.onClick(() => {
this.deleteSelected();
this.selectAllOrCancel(false);
this.selectAll = false;
})
} else {
Button('添加目标')
.operateButtonStyle($r('app.color.main_blue'))
.onClick(() => {
if (this.onAddClick !== undefined) {
this.onAddClick()
}
})
}
}
.width(CommonConstants.MAIN_BOARD_WIDTH)
.height(CommonConstants.FULL_HEIGHT)
.padding({ top: $r('app.float.operate_row_margin') })
}
/**
* Delete the selected item and exit the editing mode.
*/
deleteSelected() {
DataModel.deleteData(this.selectArray);
this.targetData = DataModel.getData();
this.overAllProgressChanged = !this.overAllProgressChanged;
this.isEditMode = false;
}
/**
* Select or deselect all.
*
* @param selectStatus true: Select all. Otherwise, deselect all.
*/
selectAllOrCancel(selectStatus: boolean) {
let newSelectArray: Array<boolean> = [];
this.targetData.forEach(() => {
newSelectArray.push(selectStatus);
});
this.selectArray = newSelectArray;
}
/**
* Whether to select all.
*/
isSelectAll(): boolean {
if (this.selectArray.length === 0) {
return false;
}
let deSelectCount: Length = this.selectArray.filter((selected: boolean) => selected === false).length;
if (deSelectCount === 0) {
this.selectAll = true;
return true;
}
this.selectAll = false;
return false;
}
/**
* Check whether there are selected rows.
*/
isSelectRows(): boolean {
return this.selectArray.filter((selected: boolean) => selected === true).length !== 0;
}
}
/**
* Custom text button style.
*/
@Extend(Text)
function operateTextStyle(color: Resource) {
.fontSize($r('app.float.text_button_font'))
.fontColor(color)
.lineHeight($r('app.float.text_line_height'))
.fontWeight(CommonConstants.FONT_WEIGHT)
}
/**
* Custom button style.
*/
@Extend(Button)
function operateButtonStyle(color: Resource) {
.width($r('app.float.button_width'))
.height($r('app.float.button_height'))
.fontSize($r('app.float.button_font'))
.fontWeight(CommonConstants.FONT_WEIGHT)
.fontColor(color)
.backgroundColor($r('app.color.button_background'))
}
接口的封装
在如图目录下创建文件
简单封装了一个接口请求,包含get和post。使用方式可以参考一言组件。
import { http } from '@kit.NetworkKit';
import ResponseResult from '../../viewmodel/ResponseResult';
import { promptAction } from '@kit.ArkUI';
const HTTP_READ_TIMEOUT = 10000
const HTTP_CODE_200 = 200
const SERVER_CODE_ERROR = 500
/**
* Initiates an HTTP request to a given URL.
*
* @param url URL for initiating an HTTP request.
* @param params Params for initiating an HTTP request.
*/
export function httpRequestGet(url: string): Promise<ResponseResult> {
let httpRequest = http.createHttp();
let responseResult = httpRequest.request(url, {
method: http.RequestMethod.GET,
readTimeout: HTTP_READ_TIMEOUT,
header: {
'Content-Type': 'application/json'
},
connectTimeout: HTTP_READ_TIMEOUT,
extraData: {}
});
let serverData: ResponseResult = new ResponseResult();
// Processes the data and returns.
return responseResult.then((value: http.HttpResponse) => {
if (value.responseCode === HTTP_CODE_200) {
// Obtains the returned data.
let result = `${value.result}`;
let resultJson: ResponseResult = JSON.parse(result);
return resultJson
} else {
serverData.msg = `网络请求失败,请稍后尝试!${value.responseCode}`;
}
return serverData;
}).catch(() => {
serverData.msg = '网络请求失败,请稍后尝试!';
return serverData;
})
}
export function httpRequestPost(url: string, data?: ESObject): Promise<ResponseResult> {
let httpRequest = http.createHttp();
let responseResult = httpRequest.request(url, {
method: http.RequestMethod.POST,
readTimeout: HTTP_READ_TIMEOUT,
header: {
'Content-Type': 'application/json'
},
connectTimeout: HTTP_READ_TIMEOUT,
extraData: data
});
let serverData: ResponseResult = new ResponseResult();
// Processes the data and returns.
return responseResult.then((value: http.HttpResponse) => {
if (value.responseCode === HTTP_CODE_200) {
// Obtains the returned data.
let result = `${value.result}`;
let resultJson: ResponseResult = JSON.parse(result);
serverData.data = resultJson.data;
serverData.code = resultJson.code;
serverData.msg = resultJson.msg;
if (resultJson.code === SERVER_CODE_ERROR) {
promptAction.showToast({
message: serverData.msg
})
}
} else {
serverData.msg = `网络请求失败,请稍后尝试!${value.responseCode}`;
promptAction.showToast({
message: serverData.msg
})
}
return serverData;
}).catch(() => {
serverData.msg = '网络请求失败,请稍后尝试!';
promptAction.showToast({
message: serverData.msg
})
return serverData;
})
}
©著作权归作者所有,如需转载,请注明出处,否则将追究法律责任
标签
赞
收藏
回复
相关推荐