1/* 2 * Copyright (c) 2024 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 16class ArkThemeScopeItem { 17 elmtId: number; 18 owner: number; 19 name: string; 20 isInWhiteList?: boolean = undefined; 21} 22 23class ArkThemeScopeArray extends Array<ArkThemeScopeItem> { 24 binarySearch(elmtId: number): number { 25 let start = 0; 26 let end = this.length - 1; 27 while (start <= end) { 28 let mid = (start + end) >> 1; 29 if (this[mid].elmtId === elmtId) { 30 return mid; 31 } 32 if (elmtId < this[mid].elmtId) { 33 end = mid - 1; 34 } else { 35 start = mid + 1; 36 } 37 } 38 return -1; 39 } 40} 41 42/** 43 * Used to store elmtIds of the components that are in WithTheme container scope. 44 */ 45class ArkThemeScope { 46 /** 47 * elmtId of the CustomComponent which defines WithTheme container 48 */ 49 private ownerComponentId: number; 50 51 /** 52 * elmtId of the WithTheme container that defines theme scope 53 */ 54 private withThemeId: number; 55 56 /** 57 * WithTheme container options 58 */ 59 private withThemeOptions: WithThemeOptions; 60 61 /** 62 * Previous scope color mode before option change 63 */ 64 private prevColorMode: ThemeColorMode; 65 66 /** 67 * elmtIds of the components that are in this theme scope 68 */ 69 private components: ArkThemeScopeArray; 70 71 /** 72 * Theme instance associated with this Theme Scope 73 */ 74 private theme: ThemeInternal; 75 76 /** 77 * Initialize Theme Scope 78 * 79 * @param ownerComponentId elmtId of the CustomComponent which defines WithTheme container 80 * @param withThemeId elmtId of the WithTheme container that defines theme scope 81 * @param withThemeOptions WithTheme container options 82 * @param theme Theme instance associated with this Theme Scope 83 */ 84 constructor(ownerComponentId: number, withThemeId: number, withThemeOptions: WithThemeOptions, theme: ThemeInternal) { 85 this.ownerComponentId = ownerComponentId; 86 this.withThemeId = withThemeId; 87 this.withThemeOptions = withThemeOptions; 88 this.theme = theme; 89 this.prevColorMode = this.colorMode(); 90 } 91 92 /** 93 * Get elmtId of the CustomComponent which defines WithTheme container 94 * 95 * @returns elmtId as number 96 */ 97 getOwnerComponentId(): number { 98 return this.ownerComponentId; 99 } 100 101 /** 102 * Get elmtId of the WithTheme container that defines theme scope 103 * 104 * @returns elmtId as number 105 */ 106 getWithThemeId(): number { 107 return this.withThemeId; 108 } 109 110 /** 111 * Add component to the current theme scope by elmtId 112 * 113 * @param elmtId elmtId as number 114 * @param owner component owner id 115 * @param componentName component name 116 */ 117 addComponentToScope(elmtId: number, owner: number, componentName: string) { 118 if (this.isComponentInScope(elmtId)) { 119 return; 120 } 121 if (!this.components) { 122 this.components = new ArkThemeScopeArray(); 123 } 124 this.components.push({ elmtId: elmtId, owner: owner, name: componentName }); 125 } 126 127 /** 128 * Remove components from the current theme scope by elmtId 129 * 130 * @param elmtId elmtId as number 131 */ 132 removeComponentFromScope(elmtId: number) { 133 if (this.components) { 134 const index = this.components.binarySearch(elmtId); 135 if (index > -1) { 136 this.components.splice(index, 1); 137 } 138 } 139 } 140 141 /** 142 * Check whether the component with elmtId is in current theme scope 143 * 144 * @param elmtId elmtId as number 145 * @returns true if theme scope contains component, otherwise false 146 */ 147 isComponentInScope(elmtId: number): boolean { 148 return this.components && (this.components.binarySearch(elmtId) > -1); 149 } 150 151 /** 152 * Get all components elmtIds which are in current theme scope 153 * 154 * @returns array of elmIds as numbers 155 */ 156 componentsInScope(): Array<ArkThemeScopeItem> { 157 return this.components; 158 } 159 160 /** 161 * Get color mode of the current theme scope 162 * 163 * @returns DARK, Light or SYSTEM values 164 */ 165 colorMode(): ThemeColorMode { 166 return this.withThemeOptions.colorMode ?? ThemeColorMode.SYSTEM; 167 } 168 169 /** 170 * Get Custom Theme of the current theme scope 171 * 172 * @returns CustomTheme instance 173 */ 174 customTheme(): CustomTheme { 175 return this.withThemeOptions.theme ?? {}; 176 } 177 178 /** 179 * Get theme instance associated with this Theme Scope 180 * 181 * @returns theme instance 182 */ 183 getTheme(): ThemeInternal { 184 return this.theme; 185 } 186 187 /** 188 * Get WithTheme container options 189 * 190 * @returns WithThemeOptions instance 191 */ 192 options(): WithThemeOptions { 193 return this.withThemeOptions; 194 } 195 196 /** 197 * Update WithThemeOptions 198 * 199 * @param options WithThemeOptions instance 200 * @param theme Theme instance associated with this Theme Scope 201 */ 202 updateWithThemeOptions(options: WithThemeOptions, theme: ThemeInternal) { 203 this.prevColorMode = this.colorMode(); 204 this.withThemeOptions = options; 205 this.theme = theme; 206 } 207 208 /** 209 * Check whether scope color mode changed in last update 210 * 211 * @returns true if color mode changed, otherwise false 212 */ 213 isColorModeChanged() { 214 return this.prevColorMode !== this.colorMode(); 215 } 216}