1/* 2 * Copyright (c) 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 16/// <reference path='./import.ts' /> 17 18class ArkRadioComponent extends ArkComponent implements RadioAttribute { 19 builder: WrappedBuilder<Object[]> | null = null; 20 radioNode: BuilderNode<[RadioConfiguration]> | null = null; 21 modifier: ContentModifier<RadioConfiguration>; 22 needRebuild: boolean = false; 23 constructor(nativePtr: KNode, classType?: ModifierType) { 24 super(nativePtr, classType); 25 } 26 allowChildCount(): number { 27 return 0; 28 } 29 initialize(value: Object[]): this { 30 if (!value.length) { 31 return this; 32 } 33 if (!isUndefined(value[0]) && !isNull(value[0]) && isObject(value[0])) { 34 modifierWithKey(this._modifiersWithKeys, RadioOptionsModifier.identity, RadioOptionsModifier, value[0]); 35 } else { 36 modifierWithKey(this._modifiersWithKeys, RadioOptionsModifier.identity, RadioOptionsModifier, undefined); 37 } 38 return this; 39 } 40 checked(value: boolean): this { 41 modifierWithKey(this._modifiersWithKeys, RadioCheckedModifier.identity, RadioCheckedModifier, value); 42 return this; 43 } 44 onChange(callback: (isChecked: boolean) => void): this { 45 modifierWithKey(this._modifiersWithKeys, RadioOnChangeModifier.identity, RadioOnChangeModifier,callback); 46 return this; 47 } 48 radioStyle(value: RadioStyle): this { 49 modifierWithKey(this._modifiersWithKeys, RadioStyleModifier.identity, RadioStyleModifier, value); 50 return this; 51 } 52 width(value: Length): this { 53 modifierWithKey(this._modifiersWithKeys, RadioWidthModifier.identity, RadioWidthModifier, value); 54 return this; 55 } 56 height(value: Length): this { 57 modifierWithKey(this._modifiersWithKeys, RadioHeightModifier.identity, RadioHeightModifier, value); 58 return this; 59 } 60 size(value: { width: Length; height: Length }): this { 61 modifierWithKey(this._modifiersWithKeys, RadioSizeModifier.identity, RadioSizeModifier, value); 62 return this; 63 } 64 hoverEffect(value: HoverEffect): this { 65 modifierWithKey(this._modifiersWithKeys, RadioHoverEffectModifier.identity, RadioHoverEffectModifier, value); 66 return this; 67 } 68 padding(value: Padding | Length): this { 69 modifierWithKey(this._modifiersWithKeys, RadioPaddingModifier.identity, RadioPaddingModifier, value); 70 return this; 71 } 72 responseRegion(value: Array<Rectangle> | Rectangle): this { 73 modifierWithKey(this._modifiersWithKeys, RadioResponseRegionModifier.identity, 74 RadioResponseRegionModifier, value); 75 return this; 76 } 77 contentModifier(value: ContentModifier<RadioConfiguration>): this { 78 modifierWithKey(this._modifiersWithKeys, RadioContentModifier.identity, RadioContentModifier, value); 79 return this; 80 } 81 setContentModifier(modifier: ContentModifier<RadioConfiguration>): this { 82 if (modifier === undefined || modifier === null) { 83 getUINativeModule().radio.setContentModifierBuilder(this.nativePtr, false); 84 return; 85 } 86 this.needRebuild = false; 87 if (this.builder !== modifier.applyContent()) { 88 this.needRebuild = true; 89 } 90 this.builder = modifier.applyContent(); 91 this.modifier = modifier; 92 getUINativeModule().radio.setContentModifierBuilder(this.nativePtr, this); 93 } 94 makeContentModifierNode(context: UIContext, radioConfiguration: RadioConfiguration): FrameNode | null { 95 radioConfiguration.contentModifier = this.modifier; 96 if (isUndefined(this.radioNode) || this.needRebuild) { 97 const xNode = globalThis.requireNapi('arkui.node'); 98 this.radioNode = new xNode.BuilderNode(context); 99 this.radioNode.build(this.builder, radioConfiguration); 100 this.needRebuild = false; 101 } else { 102 this.radioNode.update(radioConfiguration); 103 } 104 return this.radioNode.getFrameNode(); 105 } 106} 107 108class RadioOptionsModifier extends ModifierWithKey<RadioOptions> { 109 constructor(value: RadioOptions) { 110 super(value); 111 } 112 static identity: Symbol = Symbol('radioOptions'); 113 applyPeer(node: KNode, reset: boolean): void { 114 if (reset) { 115 getUINativeModule().radio.setRadioOptions(node, undefined, undefined, undefined); 116 } else { 117 getUINativeModule().radio.setRadioOptions(node, this.value.value, this.value.group, this.value.indicatorType); 118 } 119 } 120 121 checkObjectDiff(): boolean { 122 return !isBaseOrResourceEqual(this.stageValue.value, this.value.value) || 123 !isBaseOrResourceEqual(this.stageValue.group, this.value.group) || 124 !isBaseOrResourceEqual(this.stageValue.indicatorType, this.value.indicatorType); 125 } 126} 127 128class RadioCheckedModifier extends ModifierWithKey<boolean> { 129 constructor(value: boolean) { 130 super(value); 131 } 132 static identity: Symbol = Symbol('radioChecked'); 133 applyPeer(node: KNode, reset: boolean): void { 134 if (reset) { 135 getUINativeModule().radio.resetRadioChecked(node); 136 } else { 137 getUINativeModule().radio.setRadioChecked(node, this.value!); 138 } 139 } 140} 141 142class RadioStyleModifier extends ModifierWithKey<RadioStyle> { 143 constructor(value: RadioStyle) { 144 super(value); 145 } 146 static identity: Symbol = Symbol('radioStyle'); 147 applyPeer(node: KNode, reset: boolean): void { 148 if (reset) { 149 getUINativeModule().radio.resetRadioStyle(node); 150 } else { 151 getUINativeModule().radio.setRadioStyle( 152 node, this.value.checkedBackgroundColor, this.value.uncheckedBorderColor, this.value.indicatorColor); 153 } 154 } 155 156 checkObjectDiff(): boolean { 157 let checkedBackgroundColorEQ = 158 isBaseOrResourceEqual(this.stageValue.checkedBackgroundColor, 159 this.value.checkedBackgroundColor); 160 let uncheckedBorderColorEQ = 161 isBaseOrResourceEqual(this.stageValue.uncheckedBorderColor, 162 this.value.uncheckedBorderColor); 163 let indicatorColorEQ = 164 isBaseOrResourceEqual(this.stageValue.indicatorColor, 165 this.value.indicatorColor); 166 return !checkedBackgroundColorEQ || 167 !uncheckedBorderColorEQ || 168 !indicatorColorEQ; 169 } 170} 171 172class RadioWidthModifier extends ModifierWithKey<Length> { 173 constructor(value: Length) { 174 super(value); 175 } 176 static identity: Symbol = Symbol('radioWidth'); 177 applyPeer(node: KNode, reset: boolean): void { 178 if (reset) { 179 getUINativeModule().radio.resetRadioWidth(node); 180 } else { 181 getUINativeModule().radio.setRadioWidth(node, this.value); 182 } 183 } 184 185 checkObjectDiff(): boolean { 186 return !isBaseOrResourceEqual(this.stageValue, this.value); 187 } 188} 189 190class RadioHeightModifier extends ModifierWithKey<Length> { 191 constructor(value: Length) { 192 super(value); 193 } 194 static identity: Symbol = Symbol('radioHeight'); 195 applyPeer(node: KNode, reset: boolean): void { 196 if (reset) { 197 getUINativeModule().radio.resetRadioHeight(node); 198 } else { 199 getUINativeModule().radio.setRadioHeight(node, this.value); 200 } 201 } 202 203 checkObjectDiff(): boolean { 204 return !isBaseOrResourceEqual(this.stageValue, this.value); 205 } 206} 207 208class RadioSizeModifier extends ModifierWithKey<{ width: Length; height: Length }> { 209 constructor(value: { width: Length; height: Length }) { 210 super(value); 211 } 212 static identity: Symbol = Symbol('radioSize'); 213 applyPeer(node: KNode, reset: boolean): void { 214 if (reset) { 215 getUINativeModule().radio.resetRadioSize(node); 216 } else { 217 getUINativeModule().radio.setRadioSize(node, this.value.width, this.value.height); 218 } 219 } 220 221 checkObjectDiff(): boolean { 222 return !isBaseOrResourceEqual(this.stageValue.width, this.value.width) || 223 !isBaseOrResourceEqual(this.stageValue.height, this.value.height); 224 } 225} 226 227class RadioHoverEffectModifier extends ModifierWithKey<HoverEffect> { 228 constructor(value: HoverEffect) { 229 super(value); 230 } 231 static identity: Symbol = Symbol('radioHoverEffect'); 232 applyPeer(node: KNode, reset: boolean): void { 233 if (reset) { 234 getUINativeModule().radio.resetRadioHoverEffect(node); 235 } else { 236 getUINativeModule().radio.setRadioHoverEffect(node, this.value); 237 } 238 } 239 240 checkObjectDiff(): boolean { 241 return !isBaseOrResourceEqual(this.stageValue, this.value); 242 } 243} 244 245class RadioPaddingModifier extends ModifierWithKey<Padding | Length> { 246 constructor(value: Padding | Length) { 247 super(value); 248 } 249 static identity: Symbol = Symbol('radioPadding'); 250 applyPeer(node: KNode, reset: boolean): void { 251 if (reset) { 252 getUINativeModule().radio.resetRadioPadding(node); 253 } else { 254 let paddingTop: Length; 255 let paddingRight: Length; 256 let paddingBottom: Length; 257 let paddingLeft: Length; 258 if (this.value !== null && this.value !== undefined) { 259 if (isLengthType(this.value) || isResource(this.value)) { 260 paddingTop = <Length> this.value; 261 paddingRight = <Length> this.value; 262 paddingBottom = <Length> this.value; 263 paddingLeft = <Length> this.value; 264 } else { 265 paddingTop = (<Padding> this.value).top; 266 paddingRight = (<Padding> this.value).right; 267 paddingBottom = (<Padding> this.value).bottom; 268 paddingLeft = (<Padding> this.value).left; 269 } 270 } 271 getUINativeModule().radio.setRadioPadding(node, paddingTop, paddingRight, paddingBottom, paddingLeft); 272 } 273 } 274 275 checkObjectDiff(): boolean { 276 if (isResource(this.stageValue) && isResource(this.value)) { 277 return !isResourceEqual(this.stageValue, this.value); 278 } else if (!isResource(this.stageValue) && !isResource(this.value)) { 279 return !((this.stageValue as Padding).left === (this.value as Padding).left && 280 (this.stageValue as Padding).right === (this.value as Padding).right && 281 (this.stageValue as Padding).top === (this.value as Padding).top && 282 (this.stageValue as Padding).bottom === (this.value as Padding).bottom); 283 } else { 284 return true; 285 } 286 } 287} 288 289class RadioResponseRegionModifier extends ModifierWithKey<Array<Rectangle> | Rectangle> { 290 constructor(value: Array<Rectangle> | Rectangle) { 291 super(value); 292 } 293 static identity = Symbol('radioResponseRegion'); 294 applyPeer(node: KNode, reset: boolean): void { 295 if (reset) { 296 getUINativeModule().radio.resetRadioResponseRegion(node); 297 } else { 298 let responseRegion: (number | string | Resource)[] = []; 299 if (Array.isArray(this.value)) { 300 for (let i = 0; i < this.value.length; i++) { 301 responseRegion.push(this.value[i].x ?? 'PLACEHOLDER'); 302 responseRegion.push(this.value[i].y ?? 'PLACEHOLDER'); 303 responseRegion.push(this.value[i].width ?? 'PLACEHOLDER'); 304 responseRegion.push(this.value[i].height ?? 'PLACEHOLDER'); 305 } 306 } else { 307 responseRegion.push(this.value.x ?? 'PLACEHOLDER'); 308 responseRegion.push(this.value.y ?? 'PLACEHOLDER'); 309 responseRegion.push(this.value.width ?? 'PLACEHOLDER'); 310 responseRegion.push(this.value.height ?? 'PLACEHOLDER'); 311 } 312 getUINativeModule().radio.setRadioResponseRegion(node, responseRegion, responseRegion.length); 313 } 314 } 315 316 checkObjectDiff(): boolean { 317 if (Array.isArray(this.value) && Array.isArray(this.stageValue)) { 318 if (this.value.length !== this.stageValue.length) { 319 return true; 320 } else { 321 for (let i = 0; i < this.value.length; i++) { 322 if (!(isBaseOrResourceEqual(this.stageValue[i].x, this.value[i].x) && 323 isBaseOrResourceEqual(this.stageValue[i].y, this.value[i].y) && 324 isBaseOrResourceEqual(this.stageValue[i].width, this.value[i].width) && 325 isBaseOrResourceEqual(this.stageValue[i].height, this.value[i].height) 326 )) { 327 return true; 328 } 329 } 330 return false; 331 } 332 } else if (!Array.isArray(this.value) && !Array.isArray(this.stageValue)) { 333 return (!(isBaseOrResourceEqual(this.stageValue.x, this.value.x) && 334 isBaseOrResourceEqual(this.stageValue.y, this.value.y) && 335 isBaseOrResourceEqual(this.stageValue.width, this.value.width) && 336 isBaseOrResourceEqual(this.stageValue.height, this.value.height) 337 )); 338 } else { 339 return true; 340 } 341 } 342} 343 344class RadioContentModifier extends ModifierWithKey<ContentModifier<RadioConfiguration>> { 345 constructor(value: ContentModifier<RadioConfiguration>) { 346 super(value); 347 } 348 static identity: Symbol = Symbol('radioContentModifier'); 349 applyPeer(node: KNode, reset: boolean, component: ArkComponent): void { 350 let radioComponent = component as ArkRadioComponent; 351 radioComponent.setContentModifier(this.value); 352 } 353} 354class RadioOnChangeModifier extends ModifierWithKey<(isChecked: boolean) => void>{ 355 constructor(value:(isChecked: boolean) => void) { 356 super(value); 357 } 358 static identity: Symbol = Symbol('radioOnChange'); 359 applyPeer(node: KNode, reset: boolean): void { 360 if (reset) { 361 getUINativeModule().radio.resetRadioOnChange(node); 362 } else { 363 getUINativeModule().radio.setRadioOnChange(node, this.value); 364 } 365 } 366} 367 368// @ts-ignore 369globalThis.Radio.attributeModifier = function (modifier: ArkComponent): void { 370 attributeModifierFunc.call(this, modifier, (nativePtr: KNode) => { 371 return new ArkRadioComponent(nativePtr); 372 }, (nativePtr: KNode, classType: ModifierType, modifierJS: ModifierJS) => { 373 return new modifierJS.RadioModifier(nativePtr, classType); 374 }); 375}; 376 377// @ts-ignore 378globalThis.Radio.contentModifier = function (modifier): void { 379 const elmtId = ViewStackProcessor.GetElmtIdToAccountFor(); 380 let nativeNode = getUINativeModule().getFrameNodeById(elmtId); 381 let component = this.createOrGetNode(elmtId, () => { 382 return new ArkRadioComponent(nativeNode); 383 }); 384 component.setContentModifier(modifier); 385}; 386