1/* 2 * Copyright (c) 2023-2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16import { Theme } from '@ohos.arkui.theme'; 17 18const EMPTY_STRING: string = ''; 19const MAX_PROGRESS: number = 100; 20const MAX_PERCENTAGE: string = '100%'; 21const MIN_PERCENTAGE: string = '0%'; 22const TEXT_OPACITY: number = 0.4; 23const BUTTON_NORMARL_WIDTH: number = 44; 24const BUTTON_NORMARL_HEIGHT: number = 28; 25const BUTTON_BORDER_RADIUS: number = 14; 26const TEXT_ENABLE: number = 1.0; 27 28 29// Set the key value for the basic component of skin changing corresponding to progressButton 30const PROGRESS_BUTTON_PROGRESS_KEY = 'progress_button_progress_key'; 31const PROGRESS_BUTTON_PRIMARY_FONT_KEY = 'progress_button_primary_font_key'; 32const PROGRESS_BUTTON_CONTAINER_BACKGROUND_COLOR_KEY = 'progress_button_container_background_color_key'; 33const PROGRESS_BUTTON_EMPHASIZE_SECONDARY_BUTTON_KEY = 'progress_button_emphasize_secondary_button_key'; 34@Component 35export struct ProgressButton { 36 @Prop @Watch('getProgressContext') progress: number; 37 @State textProgress: string = EMPTY_STRING; 38 @Prop content: string = EMPTY_STRING; 39 @State @Watch('getLoadingProgress')isLoading: boolean = false; 40 progressButtonWidth?: Length = BUTTON_NORMARL_WIDTH; 41 clickCallback: () => void = () => {}; 42 @Prop enable: boolean = true; 43 44 @State progressColor: ResourceColor = '#330A59F7' 45 @State containerBorderColor: ResourceColor = '#330A59F7' 46 @State containerBackgroundColor: ResourceColor = $r('sys.color.ohos_id_color_foreground_contrary') 47 @State textHeight?: Length = BUTTON_NORMARL_HEIGHT; 48 @State buttonBorderRadius?: number = BUTTON_BORDER_RADIUS; 49 50 onWillApplyTheme(theme: Theme) { 51 this.progressColor = theme.colors.compEmphasizeSecondary; 52 this.containerBorderColor = theme.colors.compEmphasizeSecondary; 53 this.containerBackgroundColor = theme.colors.iconOnFourth; 54 } 55 56 private getButtonProgress(): number { 57 if (this.progress < 0) { 58 return 0 59 } else if (this.progress > MAX_PROGRESS) { 60 return MAX_PROGRESS 61 } 62 return this.progress 63 } 64 65 private getProgressContext() { 66 if (this.progress < 0) { 67 this.isLoading = false 68 this.textProgress = MIN_PERCENTAGE 69 } else if (this.progress >= MAX_PROGRESS) { 70 this.isLoading = false 71 this.textProgress = MAX_PERCENTAGE 72 } else { 73 this.isLoading = true 74 this.textProgress = Math.floor(this.progress / MAX_PROGRESS * MAX_PROGRESS).toString() + '%' 75 } 76 } 77 78 private getLoadingProgress() { 79 if (this.isLoading) { 80 if (this.progress < 0) { 81 this.textProgress = MIN_PERCENTAGE 82 } else if (this.progress >= MAX_PROGRESS) { 83 this.textProgress = MAX_PERCENTAGE 84 } else { 85 this.textProgress = Math.floor(this.progress / MAX_PROGRESS * MAX_PROGRESS).toString() + '%' 86 } 87 } 88 } 89 90 build() { 91 Button() { 92 Stack(){ 93 Progress({ value: this.getButtonProgress(), total: MAX_PROGRESS, 94 style: ProgressStyle.Capsule }) 95 .height(this.textHeight) 96 .constraintSize({ minHeight: BUTTON_NORMARL_HEIGHT }) 97 .borderRadius(this.buttonBorderRadius) 98 .width('100%') 99 .hoverEffect(HoverEffect.None) 100 .clip(false) 101 .enabled(this.enable) 102 .key(PROGRESS_BUTTON_PROGRESS_KEY) 103 .color(this.progressColor) 104 Row() { 105 Text(this.isLoading ? this.textProgress: this.content) 106 .fontSize($r('sys.float.ohos_id_text_size_button3')) 107 .fontWeight(FontWeight.Medium) 108 .key(PROGRESS_BUTTON_PRIMARY_FONT_KEY) 109 .maxLines(1) 110 .textOverflow({ overflow: TextOverflow.Ellipsis }) 111 .padding({ top: 4, left: 8, right: 8, bottom: 4}) 112 .opacity(this.enable ? TEXT_ENABLE : TEXT_OPACITY) 113 .onAreaChange((_, newValue)=>{ 114 if (!newValue.height || newValue.height === this.textHeight) { 115 return; 116 } 117 this.textHeight = newValue.height > BUTTON_NORMARL_HEIGHT ? newValue.height : BUTTON_NORMARL_HEIGHT; 118 this.buttonBorderRadius = Number(this.textHeight) / 2; 119 }) 120 } 121 .constraintSize({ minHeight: BUTTON_NORMARL_HEIGHT }) 122 Row() 123 .key(PROGRESS_BUTTON_CONTAINER_BACKGROUND_COLOR_KEY) 124 .backgroundColor(Color.Transparent) 125 .border({ width: 1, color: this.containerBorderColor}) 126 .height(this.textHeight) 127 .constraintSize({ minHeight: BUTTON_NORMARL_HEIGHT }) 128 .borderRadius(this.buttonBorderRadius) 129 .width('100%') 130 } 131 } 132 .borderRadius(this.buttonBorderRadius) 133 .clip(false) 134 .hoverEffect(HoverEffect.None) 135 .key(PROGRESS_BUTTON_EMPHASIZE_SECONDARY_BUTTON_KEY) 136 .backgroundColor(this.containerBackgroundColor) 137 .constraintSize({minWidth: 44}) 138 .padding({ top: 0, bottom: 0}) 139 .width((!this.progressButtonWidth || this.progressButtonWidth < BUTTON_NORMARL_WIDTH) ? 140 BUTTON_NORMARL_WIDTH : this.progressButtonWidth) 141 .stateEffect(this.enable) 142 .onClick(() => { 143 if (!this.enable) { 144 return 145 } 146 if (this.progress < MAX_PROGRESS) { 147 this.isLoading = !this.isLoading 148 } 149 this.clickCallback && this.clickCallback() 150 }) 151 } 152}