From aad2662abf1f5a63dbff992f2a9652d0f5563ab0 Mon Sep 17 00:00:00 2001 From: yuxiaofei9 Date: Thu, 24 Jul 2025 16:30:24 +0800 Subject: [PATCH] =?UTF-8?q?[feate]=E9=AB=98=E7=BA=A7=E7=BB=84=E4=BB=B6Prog?= =?UTF-8?q?ressButton1.2=E8=AF=AD=E6=B3=95=E6=95=B4=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: yuxiaofei9 --- advanced_ui_component_static/BUILD.gn | 1 + .../@ohos.arkui.advanced.ProgressButton.ets | 222 ++++++++++++++++++ .../progressbutton/BUILD.gn | 47 ++++ 3 files changed, 270 insertions(+) create mode 100644 advanced_ui_component_static/progressbutton/@ohos.arkui.advanced.ProgressButton.ets create mode 100644 advanced_ui_component_static/progressbutton/BUILD.gn diff --git a/advanced_ui_component_static/BUILD.gn b/advanced_ui_component_static/BUILD.gn index ec7d33dca8a..f589f14c35c 100644 --- a/advanced_ui_component_static/BUILD.gn +++ b/advanced_ui_component_static/BUILD.gn @@ -19,6 +19,7 @@ group("advanced_ui_component_static") { deps += [] if (!ace_engine_feature_wearable) { deps += [ + "progressbutton:progressButton", "swiperefresher:swipeRefresher", "splitlayout:splitLayout", ] diff --git a/advanced_ui_component_static/progressbutton/@ohos.arkui.advanced.ProgressButton.ets b/advanced_ui_component_static/progressbutton/@ohos.arkui.advanced.ProgressButton.ets new file mode 100644 index 00000000000..36f623c5ce0 --- /dev/null +++ b/advanced_ui_component_static/progressbutton/@ohos.arkui.advanced.ProgressButton.ets @@ -0,0 +1,222 @@ +/* + * Copyright (c) 2025 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 { + $r, Row, Area, Text, Color, Stack, Button, Length, Padding, Progress, Component, FontWeight, ResourceStr, ButtonType, + ClickEvent, HoverEffect, TextOverflow, ProgressType, ResourceColor, ButtonOptions, ProgressOptions, + CapsuleStyleOptions +} from '@ohos.arkui.component'; +import { State, PropRef, Watch } from '@ohos.arkui.stateManagement'; +import { LengthUnit, LengthMetrics } from '@ohos.arkui.node'; +import { Theme } from '@ohos.arkui.theme'; + +export interface ProgressButtonColorOptions { + progressColor?: ResourceColor; + borderColor?: ResourceColor; + textColor?: ResourceColor; + backgroundColor?: ResourceColor; +} + +const EMPTY_STRING: string = ''; +const MAX_PROGRESS: number = 100; +const MAX_PERCENTAGE: string = '100%'; +const MIN_PERCENTAGE: string = '0%'; +const TEXT_OPACITY: number = 0.4; +const BUTTON_NORMARL_WIDTH: number = 44; +const BUTTON_NORMARL_HEIGHT: number = 28; +const BUTTON_BORDER_RADIUS: number = 14; +const TEXT_ENABLE: number = 1.0; + +// Set the key value for the basic component of skin changing corresponding to progressButton +const PROGRESS_BUTTON_PROGRESS_KEY = 'progress_button_progress_key'; +const PROGRESS_BUTTON_PRIMARY_FONT_KEY = 'progress_button_primary_font_key'; +const PROGRESS_BUTTON_CONTAINER_BACKGROUND_COLOR_KEY = 'progress_button_container_background_color_key'; +const PROGRESS_BUTTON_EMPHASIZE_SECONDARY_BUTTON_KEY = 'progress_button_emphasize_secondary_button_key'; + +@Component +export struct ProgressButton { + @PropRef @Watch('getProgressContext') progress: number; + @State textProgress: string = EMPTY_STRING as string; + @PropRef content: ResourceStr = EMPTY_STRING as string; + @State @Watch('getLoadingProgress') isLoading: boolean = false; + progressButtonWidth?: Length = BUTTON_NORMARL_WIDTH as number; + clickCallback: () => void = () => {}; + @PropRef enable: boolean = true; + @PropRef colorOptions: ProgressButtonColorOptions | undefined = undefined; + @PropRef progressButtonRadius?: LengthMetrics | undefined = undefined; + @State progressColor: ResourceColor = '#330A59F7'; + @State containerBorderColor: ResourceColor = '#330A59F7'; + @State containerBackgroundColor: ResourceColor = $r('sys.color.ohos_id_color_foreground_contrary'); + @State textHeight?: Length = BUTTON_NORMARL_HEIGHT as number; + @State buttonBorderRadius?: number = BUTTON_BORDER_RADIUS as number; + + onWillApplyTheme(theme: Theme) { + this.progressColor = theme.colors.compEmphasizeSecondary; + this.containerBorderColor = theme.colors.compEmphasizeSecondary; + this.containerBackgroundColor = theme.colors.iconOnFourth; + } + + private getButtonProgress(): number { + if (this.progress < 0) { + return 0; + } else if (this.progress > MAX_PROGRESS) { + return MAX_PROGRESS; + } + return this.progress; + } + + private getProgressContext(propertyName: string) { + if (this.progress < 0) { + this.isLoading = false; + this.textProgress = MIN_PERCENTAGE; + } else if (this.progress >= MAX_PROGRESS) { + this.isLoading = false; + this.textProgress = MAX_PERCENTAGE; + } else { + this.isLoading = true; + this.textProgress = Math.floor(this.progress / MAX_PROGRESS * MAX_PROGRESS) + '%'; + } + } + + private getProgressButtonRadius(): LengthMetrics { + if (!this.progressButtonRadius || this.progressButtonRadius?.unit === LengthUnit.PERCENT) { + return LengthMetrics.vp(this.buttonBorderRadius!); + } else if ((this.progressButtonRadius as LengthMetrics).value < 0) { + return LengthMetrics.vp(0); + } else { + return this.progressButtonRadius as LengthMetrics; + } + } + + private getLoadingProgress(propertyName: string) { + if (this.isLoading) { + if (this.progress < 0) { + this.textProgress = MIN_PERCENTAGE; + } else if (this.progress >= MAX_PROGRESS) { + this.textProgress = MAX_PERCENTAGE; + } else { + this.textProgress = Math.floor(this.progress / MAX_PROGRESS * MAX_PROGRESS) + '%'; + } + } + } + + private toLengthString(value: LengthMetrics | undefined): string { + if (value === undefined) { + return ''; + } + const length: number = value.value; + let lengthString: string = ''; + switch (value.unit) { + case LengthUnit.PX: + lengthString = `${length}px`; + break; + case LengthUnit.FP: + lengthString = `${length}fp`; + break; + case LengthUnit.LPX: + lengthString = `${length}lpx`; + break; + case LengthUnit.PERCENT: + lengthString = `${length * 100}%`; + break; + case LengthUnit.VP: + lengthString = `${length}vp`; + break; + default: + lengthString = `${length}vp`; + break; + } + return lengthString; + } + + build() { + Button({ type: ButtonType.Normal } as ButtonOptions) { + Stack() { + Progress({ + value: this.getButtonProgress(), total: MAX_PROGRESS, type: ProgressType.Capsule + } as ProgressOptions) + .height(this.textHeight) + .constraintSize({ minHeight: BUTTON_NORMARL_HEIGHT }) + .borderRadius(this.buttonBorderRadius) + .width('100%') + .hoverEffect(HoverEffect.None) + .style({ + borderColor: this.colorOptions?.borderColor ? this.colorOptions?.borderColor : this.containerBorderColor, + borderRadius: this.getProgressButtonRadius() + } as CapsuleStyleOptions) + .clip(false) + .key(PROGRESS_BUTTON_PROGRESS_KEY) + .color(this.colorOptions?.progressColor ? this.colorOptions?.progressColor : this.progressColor) + Row() { + Text(this.isLoading ? this.textProgress : this.content) + .fontSize($r('sys.float.ohos_id_text_size_button3')) + .fontWeight(FontWeight.Medium) + .key(PROGRESS_BUTTON_PRIMARY_FONT_KEY) + .fontColor(this.colorOptions?.textColor ? this.colorOptions?.textColor : '#e6182431') + .maxLines(1) + .textOverflow({ overflow: TextOverflow.Ellipsis }) + .padding({ top: 4, left: 8, right: 8, bottom: 4 } as Padding) + .opacity(this.enable ? TEXT_ENABLE : TEXT_OPACITY) + .onAreaChange((oldValue: Area, newValue: Area) => { + if (!newValue.height || newValue.height === this.textHeight) { + return; + } + this.textHeight = + newValue.height as number > BUTTON_NORMARL_HEIGHT ? newValue.height as number : BUTTON_NORMARL_HEIGHT; + this.buttonBorderRadius = Number(this.textHeight as number) / 2; + }) + } + .constraintSize({ minHeight: BUTTON_NORMARL_HEIGHT }) + + Row() + .key(PROGRESS_BUTTON_CONTAINER_BACKGROUND_COLOR_KEY) + .backgroundColor(Color.Transparent) + .border({ + width: 1, + color: this.colorOptions?.borderColor ? this.colorOptions?.borderColor : this.containerBorderColor + }) + .height(this.textHeight) + .constraintSize({ minHeight: BUTTON_NORMARL_HEIGHT }) + .borderRadius(this.progressButtonRadius ? this.toLengthString(this.getProgressButtonRadius()) : + this.buttonBorderRadius) + .width('100%') + } + } + .borderRadius(this.progressButtonRadius ? this.toLengthString(this.getProgressButtonRadius()) : + this.buttonBorderRadius) + .clip(false) + .hoverEffect(HoverEffect.None) + .key(PROGRESS_BUTTON_EMPHASIZE_SECONDARY_BUTTON_KEY) + .backgroundColor(this.colorOptions?.backgroundColor ? + this.colorOptions?.backgroundColor : this.containerBackgroundColor) + .constraintSize({ minWidth: 44 }) + .padding({ top: 0, bottom: 0 } as Padding) + .width((!(this.progressButtonWidth as Length) || + (this.progressButtonWidth as number) < BUTTON_NORMARL_WIDTH as number) ? + BUTTON_NORMARL_WIDTH as number : this.progressButtonWidth as Length) + .stateEffect(this.enable) + .onClick((event?: ClickEvent) => { + if (!this.enable) { + return + } + if (this.progress < MAX_PROGRESS) { + this.isLoading = !this.isLoading + } + if (this.clickCallback) { + this.clickCallback(); + } + }) + } +} \ No newline at end of file diff --git a/advanced_ui_component_static/progressbutton/BUILD.gn b/advanced_ui_component_static/progressbutton/BUILD.gn new file mode 100644 index 00000000000..af5ffa614a7 --- /dev/null +++ b/advanced_ui_component_static/progressbutton/BUILD.gn @@ -0,0 +1,47 @@ +# Copyright (c) 2025 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("//build/config/components/ets_frontend/ets2abc_config.gni") +import("//build/ohos.gni") + +generate_static_abc("progress_button_ets_abc") { + base_url = "./" + files = [ "./@ohos.arkui.advanced.ProgressButton.ets" ] + ui_enable = "True" + is_boot_abc = "True" + device_dst_file = "/system/framework/progress_button_ets_abc.abc" + dst_file = target_out_dir + "/progress_button_ets_abc/modules_static.abc" + out_puts = [ target_out_dir + "/progress_button_ets_abc/modules_static.abc" ] +} + +ohos_copy("copy_progress_button_ets_abc") { + sources = [ + target_out_dir + "/progress_button_ets_abc/modules_static.abc" + ] + outputs = [ + target_out_dir + "/progress_button_ets_abc.abc" + ] + deps = [ ":progress_button_ets_abc" ] +} + +ohos_prebuilt_etc("progress_button_ets_abc_etc") { + source = "$target_out_dir/progress_button_ets_abc.abc" + module_install_dir = "framework" + subsystem_name = "arkui" + part_name = "ace_engine" + deps = [ ":copy_progress_button_ets_abc" ] +} + +group("progressButton"){ + deps = [":progress_button_ets_abc_etc"] +} \ No newline at end of file -- Gitee