1/* 2 * Copyright (c) 2023-2025 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 16if (!('finalizeConstruction' in ViewPU.prototype)) { 17 Reflect.set(ViewPU.prototype, 'finalizeConstruction', () => { }); 18} 19const LengthMetrics = requireNapi('arkui.node').LengthMetrics; 20const LengthUnit = requireNapi('arkui.node').LengthUnit; 21const EMPTY_STRING = ''; 22const MAX_PROGRESS = 100; 23const MAX_PERCENTAGE = '100%'; 24const MIN_PERCENTAGE = '0%'; 25const TEXT_OPACITY = 0.4; 26const BUTTON_NORMARL_WIDTH = 44; 27const BUTTON_NORMARL_HEIGHT = 28; 28const BUTTON_BORDER_RADIUS = 14; 29const TEXT_ENABLE = 1.0; 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'; 34export class ProgressButton extends ViewPU { 35 constructor(h1, i1, j1, k1 = -1, l1 = undefined, m1) { 36 super(h1, j1, k1, m1); 37 if (typeof l1 === 'function') { 38 this.paramsGenerator_ = l1; 39 } 40 this.__progress = new SynchedPropertySimpleOneWayPU(i1.progress, this, 'progress'); 41 this.__textProgress = new ObservedPropertySimplePU(EMPTY_STRING, this, 'textProgress'); 42 this.__content = new SynchedPropertyObjectOneWayPU(i1.content, this, 'content'); 43 this.__isLoading = new ObservedPropertySimplePU(false, this, 'isLoading'); 44 this.progressButtonWidth = BUTTON_NORMARL_WIDTH; 45 this.clickCallback = () => { }; 46 this.__enable = new SynchedPropertySimpleOneWayPU(i1.enable, this, 'enable'); 47 this.__colorOptions = new SynchedPropertyObjectOneWayPU(i1.colorOptions, this, 'colorOptions'); 48 this.__progressButtonRadius = new SynchedPropertyObjectOneWayPU(i1.progressButtonRadius, this, 'progressButtonRadius'); 49 this.__progressColor = new ObservedPropertyObjectPU('#330A59F7', this, 'progressColor'); 50 this.__containerBorderColor = new ObservedPropertyObjectPU('#330A59F7', this, 'containerBorderColor'); 51 this.__containerBackgroundColor = new ObservedPropertyObjectPU({ 'id': -1, 'type': 10001, params: ['sys.color.ohos_id_color_foreground_contrary'], 'bundleName': '__harDefaultBundleName__', 'moduleName': '__harDefaultModuleName__' }, this, 'containerBackgroundColor'); 52 this.__textHeight = new ObservedPropertyObjectPU(BUTTON_NORMARL_HEIGHT, this, 'textHeight'); 53 this.__buttonBorderRadius = new ObservedPropertySimplePU(BUTTON_BORDER_RADIUS, this, 'buttonBorderRadius'); 54 this.setInitiallyProvidedValue(i1); 55 this.declareWatch('progress', this.getProgressContext); 56 this.declareWatch('isLoading', this.getLoadingProgress); 57 this.finalizeConstruction(); 58 } 59 setInitiallyProvidedValue(g1) { 60 if (g1.textProgress !== undefined) { 61 this.textProgress = g1.textProgress; 62 } 63 if (g1.content === undefined) { 64 this.__content.set(EMPTY_STRING); 65 } 66 if (g1.isLoading !== undefined) { 67 this.isLoading = g1.isLoading; 68 } 69 if (g1.progressButtonWidth !== undefined) { 70 this.progressButtonWidth = g1.progressButtonWidth; 71 } 72 if (g1.clickCallback !== undefined) { 73 this.clickCallback = g1.clickCallback; 74 } 75 if (g1.enable === undefined) { 76 this.__enable.set(true); 77 } 78 if (g1.colorOptions === undefined) { 79 this.__colorOptions.set(undefined); 80 } 81 if (g1.progressButtonRadius === undefined) { 82 this.__progressButtonRadius.set(undefined); 83 } 84 if (g1.progressColor !== undefined) { 85 this.progressColor = g1.progressColor; 86 } 87 if (g1.containerBorderColor !== undefined) { 88 this.containerBorderColor = g1.containerBorderColor; 89 } 90 if (g1.containerBackgroundColor !== undefined) { 91 this.containerBackgroundColor = g1.containerBackgroundColor; 92 } 93 if (g1.textHeight !== undefined) { 94 this.textHeight = g1.textHeight; 95 } 96 if (g1.buttonBorderRadius !== undefined) { 97 this.buttonBorderRadius = g1.buttonBorderRadius; 98 } 99 } 100 updateStateVars(f1) { 101 this.__progress.reset(f1.progress); 102 this.__content.reset(f1.content); 103 this.__enable.reset(f1.enable); 104 this.__colorOptions.reset(f1.colorOptions); 105 this.__progressButtonRadius.reset(f1.progressButtonRadius); 106 } 107 purgeVariableDependenciesOnElmtId(e1) { 108 this.__progress.purgeDependencyOnElmtId(e1); 109 this.__textProgress.purgeDependencyOnElmtId(e1); 110 this.__content.purgeDependencyOnElmtId(e1); 111 this.__isLoading.purgeDependencyOnElmtId(e1); 112 this.__enable.purgeDependencyOnElmtId(e1); 113 this.__colorOptions.purgeDependencyOnElmtId(e1); 114 this.__progressButtonRadius.purgeDependencyOnElmtId(e1); 115 this.__progressColor.purgeDependencyOnElmtId(e1); 116 this.__containerBorderColor.purgeDependencyOnElmtId(e1); 117 this.__containerBackgroundColor.purgeDependencyOnElmtId(e1); 118 this.__textHeight.purgeDependencyOnElmtId(e1); 119 this.__buttonBorderRadius.purgeDependencyOnElmtId(e1); 120 } 121 aboutToBeDeleted() { 122 this.__progress.aboutToBeDeleted(); 123 this.__textProgress.aboutToBeDeleted(); 124 this.__content.aboutToBeDeleted(); 125 this.__isLoading.aboutToBeDeleted(); 126 this.__enable.aboutToBeDeleted(); 127 this.__colorOptions.aboutToBeDeleted(); 128 this.__progressButtonRadius.aboutToBeDeleted(); 129 this.__progressColor.aboutToBeDeleted(); 130 this.__containerBorderColor.aboutToBeDeleted(); 131 this.__containerBackgroundColor.aboutToBeDeleted(); 132 this.__textHeight.aboutToBeDeleted(); 133 this.__buttonBorderRadius.aboutToBeDeleted(); 134 SubscriberManager.Get().delete(this.id__()); 135 this.aboutToBeDeletedInternal(); 136 } 137 get progress() { 138 return this.__progress.get(); 139 } 140 set progress(d1) { 141 this.__progress.set(d1); 142 } 143 get textProgress() { 144 return this.__textProgress.get(); 145 } 146 set textProgress(c1) { 147 this.__textProgress.set(c1); 148 } 149 get content() { 150 return this.__content.get(); 151 } 152 set content(b1) { 153 this.__content.set(b1); 154 } 155 get isLoading() { 156 return this.__isLoading.get(); 157 } 158 set isLoading(a1) { 159 this.__isLoading.set(a1); 160 } 161 get enable() { 162 return this.__enable.get(); 163 } 164 set enable(z) { 165 this.__enable.set(z); 166 } 167 get colorOptions() { 168 return this.__colorOptions.get(); 169 } 170 set colorOptions(y) { 171 this.__colorOptions.set(y); 172 } 173 get progressButtonRadius() { 174 return this.__progressButtonRadius.get(); 175 } 176 set progressButtonRadius(x) { 177 this.__progressButtonRadius.set(x); 178 } 179 get progressColor() { 180 return this.__progressColor.get(); 181 } 182 set progressColor(w) { 183 this.__progressColor.set(w); 184 } 185 get containerBorderColor() { 186 return this.__containerBorderColor.get(); 187 } 188 set containerBorderColor(v) { 189 this.__containerBorderColor.set(v); 190 } 191 get containerBackgroundColor() { 192 return this.__containerBackgroundColor.get(); 193 } 194 set containerBackgroundColor(u) { 195 this.__containerBackgroundColor.set(u); 196 } 197 get textHeight() { 198 return this.__textHeight.get(); 199 } 200 set textHeight(t) { 201 this.__textHeight.set(t); 202 } 203 get buttonBorderRadius() { 204 return this.__buttonBorderRadius.get(); 205 } 206 set buttonBorderRadius(s) { 207 this.__buttonBorderRadius.set(s); 208 } 209 onWillApplyTheme(r) { 210 this.progressColor = r.colors.compEmphasizeSecondary; 211 this.containerBorderColor = r.colors.compEmphasizeSecondary; 212 this.containerBackgroundColor = r.colors.iconOnFourth; 213 } 214 getButtonProgress() { 215 if (this.progress < 0) { 216 return 0; 217 } 218 else if (this.progress > MAX_PROGRESS) { 219 return MAX_PROGRESS; 220 } 221 return this.progress; 222 } 223 getProgressContext() { 224 if (this.progress < 0) { 225 this.isLoading = false; 226 this.textProgress = MIN_PERCENTAGE; 227 } 228 else if (this.progress >= MAX_PROGRESS) { 229 this.isLoading = false; 230 this.textProgress = MAX_PERCENTAGE; 231 } 232 else { 233 this.isLoading = true; 234 this.textProgress = Math.floor(this.progress / MAX_PROGRESS * MAX_PROGRESS).toString() + '%'; 235 } 236 } 237 getProgressButtonRadius() { 238 if (!this.progressButtonRadius || this.progressButtonRadius.unit === LengthUnit.PERCENT) { 239 return LengthMetrics.vp(this.buttonBorderRadius); 240 } 241 else if (this.progressButtonRadius.value < 0) { 242 return LengthMetrics.vp(0); 243 } 244 else { 245 return this.progressButtonRadius; 246 } 247 } 248 getLoadingProgress() { 249 if (this.isLoading) { 250 if (this.progress < 0) { 251 this.textProgress = MIN_PERCENTAGE; 252 } 253 else if (this.progress >= MAX_PROGRESS) { 254 this.textProgress = MAX_PERCENTAGE; 255 } 256 else { 257 this.textProgress = Math.floor(this.progress / MAX_PROGRESS * MAX_PROGRESS).toString() + '%'; 258 } 259 } 260 } 261 toLengthString(o) { 262 if (o === void (0)) { 263 return ''; 264 } 265 const p = o.value; 266 let q = ''; 267 switch (o.unit) { 268 case LengthUnit.PX: 269 q = `${p}px`; 270 break; 271 case LengthUnit.FP: 272 q = `${p}fp`; 273 break; 274 case LengthUnit.LPX: 275 q = `${p}lpx`; 276 break; 277 case LengthUnit.PERCENT: 278 q = `${p * 100}%`; 279 break; 280 case LengthUnit.VP: 281 q = `${p}vp`; 282 break; 283 default: 284 q = `${p}vp`; 285 break; 286 } 287 return q; 288 } 289 initialRender() { 290 this.observeComponentCreation2((m, n) => { 291 Button.createWithChild(); 292 Button.borderRadius(this.progressButtonRadius ? this.toLengthString(this.getProgressButtonRadius()) : 293 this.buttonBorderRadius); 294 Button.clip(false); 295 Button.hoverEffect(HoverEffect.None); 296 Button.key(PROGRESS_BUTTON_EMPHASIZE_SECONDARY_BUTTON_KEY); 297 Button.backgroundColor(this.colorOptions?.backgroundColor 298 ? this.colorOptions?.backgroundColor 299 : this.containerBackgroundColor); 300 Button.constraintSize({ minWidth: 44 }); 301 Button.padding({ top: 0, bottom: 0 }); 302 Button.width((!this.progressButtonWidth || this.progressButtonWidth < BUTTON_NORMARL_WIDTH) ? 303 BUTTON_NORMARL_WIDTH : this.progressButtonWidth); 304 Button.stateEffect(this.enable); 305 Button.onClick(() => { 306 if (!this.enable) { 307 return; 308 } 309 if (this.progress < MAX_PROGRESS) { 310 this.isLoading = !this.isLoading; 311 } 312 this.clickCallback && this.clickCallback(); 313 }); 314 }, Button); 315 this.observeComponentCreation2((k, l) => { 316 Stack.create(); 317 }, Stack); 318 this.observeComponentCreation2((i, j) => { 319 Progress.create({ value: this.getButtonProgress(), total: MAX_PROGRESS, 320 style: ProgressStyle.Capsule }); 321 Progress.height(ObservedObject.GetRawObject(this.textHeight)); 322 Progress.constraintSize({ minHeight: BUTTON_NORMARL_HEIGHT }); 323 Progress.borderRadius(this.buttonBorderRadius); 324 Progress.width('100%'); 325 Progress.hoverEffect(HoverEffect.None); 326 Progress.style({ 327 borderColor: this.colorOptions?.borderColor ? this.colorOptions?.borderColor : this.containerBorderColor, 328 borderRadius: this.getProgressButtonRadius() 329 }); 330 Progress.clip(false); 331 Progress.key(PROGRESS_BUTTON_PROGRESS_KEY); 332 Progress.color(this.colorOptions?.progressColor ? this.colorOptions?.progressColor : this.progressColor); 333 }, Progress); 334 this.observeComponentCreation2((g, h) => { 335 Row.create(); 336 Row.constraintSize({ minHeight: BUTTON_NORMARL_HEIGHT }); 337 }, Row); 338 this.observeComponentCreation2((c, d) => { 339 Text.create(this.isLoading ? this.textProgress : this.content); 340 Text.fontSize({ 'id': -1, 'type': 10002, params: ['sys.float.ohos_id_text_size_button3'], 'bundleName': '__harDefaultBundleName__', 'moduleName': '__harDefaultModuleName__' }); 341 Text.fontWeight(FontWeight.Medium); 342 Text.key(PROGRESS_BUTTON_PRIMARY_FONT_KEY); 343 Text.fontColor(this.colorOptions?.textColor); 344 Text.maxLines(1); 345 Text.textOverflow({ overflow: TextOverflow.Ellipsis }); 346 Text.padding({ top: 4, left: 8, right: 8, bottom: 4 }); 347 Text.opacity(this.enable ? TEXT_ENABLE : TEXT_OPACITY); 348 Text.onAreaChange((e, f) => { 349 if (!f.height || f.height === this.textHeight) { 350 return; 351 } 352 this.textHeight = f.height > BUTTON_NORMARL_HEIGHT ? f.height : BUTTON_NORMARL_HEIGHT; 353 this.buttonBorderRadius = Number(this.textHeight) / 2; 354 }); 355 }, Text); 356 Text.pop(); 357 Row.pop(); 358 this.observeComponentCreation2((a, b) => { 359 Row.create(); 360 Row.key(PROGRESS_BUTTON_CONTAINER_BACKGROUND_COLOR_KEY); 361 Row.backgroundColor(Color.Transparent); 362 Row.border({ 363 width: 1, 364 color: this.colorOptions?.borderColor ? this.colorOptions?.borderColor : this.containerBorderColor 365 }); 366 Row.height(ObservedObject.GetRawObject(this.textHeight)); 367 Row.constraintSize({ minHeight: BUTTON_NORMARL_HEIGHT }); 368 Row.borderRadius(this.progressButtonRadius ? this.toLengthString(this.getProgressButtonRadius()) : 369 this.buttonBorderRadius); 370 Row.width('100%'); 371 }, Row); 372 Row.pop(); 373 Stack.pop(); 374 Button.pop(); 375 } 376 rerender() { 377 this.updateDirtyElements(); 378 } 379} 380 381export default { ProgressButton };