1/* 2 * Copyright (c) 2022-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 { MathUtil } from './MathUtil'; 17import { Constants } from '../model/common/Constants'; 18import { Log } from './Log'; 19import { ScreenManager } from '../model/common/ScreenManager'; 20import prompt from '@system.prompt'; 21import type window from '@ohos.window'; 22import type { Action } from '../view/browserOperation/Action'; 23import { AlbumInfo } from '../model/browser/album/AlbumInfo'; 24import common from '@ohos.app.ability.common'; 25 26const TAG: string = 'common_UiUtil'; 27 28type Window = window.Window; 29 30export class UiUtil { 31 32 /** 33 * Status bar height 34 */ 35 static readonly STATUS_BAR_HEIGHT = 45; 36 37 /** 38 * Navigation bar height 39 */ 40 static readonly NAVI_BAR_HEIGHT = 45; 41 42 /** 43 * Hexadecimal Radix 44 */ 45 static readonly HEX_BASE = 16; 46 47 /** 48 * Maximum order of color 49 */ 50 static readonly MAX_COLOR_ORDER = 255; 51 public static readonly TOAST_DURATION = 3000; 52 /** 53 * 3-bit length hex color 54 */ 55 private static readonly HEX_COLOR_LENGTH_THREE = 3; 56 /** 57 * 8-bit length hex color 58 */ 59 private static readonly HEX_COLOR_LENGTH_EIGHT = 8; 60 /** 61 * Opacity length of hex color 62 */ 63 private static readonly HEX_COLOR_OPACITY_LENGTH = 2; 64 /** 65 * Hexadecimal array 66 */ 67 private static readonly HEX_ARRAY = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F']; 68 69 /** 70 * Set status bar color 71 * 72 * @param statusBarColor statusBarColor 73 */ 74 static setStatusBarColor(topWindow: Window): void { 75 topWindow.setSystemBarProperties({ navigationBarColor: '#FFF1F3F5', navigationBarContentColor: '#FF000000' }, 76 () => { 77 Log.info(TAG, 'setStatusBarColor done'); 78 }); 79 } 80 81 /** 82 * Gets the hexadecimal color with opacity 83 * 84 * @param color Original hex color 85 * @param opacity Opacity 86 * @returns Hex color with opacity 87 */ 88 static getHexOpacityColor(paramColor: string, paramOpacity: number): string { 89 let colorReg = /^\#([0-9a-fA-f]{3}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/; 90 // The input must be # the first 3-bit / 6-bit / 8-bit hex color 91 if (paramColor.match(colorReg) == null) { 92 Log.error(TAG, `getHexOpacityColor failed because of invalid input, color: ${paramColor}`); 93 return paramColor; 94 } 95 let color = paramColor.replace(/\#/g, '').toUpperCase(); 96 let opacity = MathUtil.clamp(0, 1, paramOpacity); 97 // If it is an abbreviated 3-digit color, complete the 3-digit characters to 6-digit characters 98 if (color.length === UiUtil.HEX_COLOR_LENGTH_THREE) { 99 let arr = color.split(''); 100 color = ''; 101 for (let i = 0; i < arr.length; i++) { 102 color += (arr[i] + arr[i]); 103 } 104 } 105 // If it is an 8-bit color, the original opacity will be removed 106 if (color.length === UiUtil.HEX_COLOR_LENGTH_EIGHT) { 107 color = color.slice(UiUtil.HEX_COLOR_OPACITY_LENGTH, color.length); 108 } 109 let opacityNum = Math.round(UiUtil.MAX_COLOR_ORDER * opacity); // rounding 110 let opacityStr = ''; 111 while (opacityNum > 0) { 112 let mod = opacityNum % UiUtil.HEX_BASE; 113 opacityNum = (opacityNum - mod) / UiUtil.HEX_BASE; 114 opacityStr = UiUtil.HEX_ARRAY[mod] + opacityStr; 115 } 116 if (opacityStr.length == 1) { 117 opacityStr = `0${opacityStr}`; 118 } 119 if (opacityStr.length == 0) { 120 opacityStr = '00'; 121 } 122 return `#${opacityStr + color}`; 123 } 124 125 /** 126 * Get the content of the resource reference 127 * 128 * @param resource resource reference 129 * @returns resource Corresponding content string 130 */ 131 static async getResourceString(resource: Resource): Promise<string> { 132 try { 133 Log.info(TAG, `getResourceString: ${JSON.stringify(resource)}`); 134 if (AppStorage.get('photosAbilityContext') === null || AppStorage.get('photosAbilityContext') === 'undefined') { 135 Log.error(TAG, 'getResourceString error: context is null'); 136 return null; 137 } 138 let context: common.UIAbilityContext = AppStorage.get<common.UIAbilityContext>('photosAbilityContext'); 139 let mgr: string = await context.resourceManager.getString(resource.id); 140 if (mgr) { 141 return mgr; 142 } else { 143 Log.error(TAG, `getResourceManager instance is none`); 144 return null; 145 } 146 } catch (error) { 147 Log.error(TAG, `getResourceString error: ${error}`); 148 return null; 149 } 150 } 151 152 /** 153 * Get the content of the resource reference 154 * 155 * @param resource resource reference 156 * @returns resource Corresponding content number 157 */ 158 static async getResourceNumber(resource: Resource): Promise<number> { 159 try { 160 Log.info(TAG, `getResourceNumber: ${JSON.stringify(resource)}`); 161 if (AppStorage.get('photosAbilityContext') === null || AppStorage.get('photosAbilityContext') === 'undefined') { 162 Log.error(TAG, 'getResourceNumber error: context is null'); 163 return null; 164 } 165 let context: common.UIAbilityContext = AppStorage.get<common.UIAbilityContext>('photosAbilityContext'); 166 let mgr: number = context.resourceManager.getNumber(resource.id); 167 if (mgr) { 168 return mgr; 169 } else { 170 Log.error(TAG, `getResourceNumber instance is none`); 171 return null; 172 } 173 } catch (error) { 174 Log.error(TAG, `getResourceNumber error: ${error}`); 175 return null; 176 } 177 } 178 179 static async showToast(resource: Resource): Promise<void> { 180 let message = await UiUtil.getResourceString(resource); 181 Log.debug(TAG, `showToast: ${message}`); 182 prompt.showToast({ 183 message: message, 184 duration: UiUtil.TOAST_DURATION, 185 bottom: '64vp' 186 }); 187 } 188 189 /** 190 * 获取相册封面宫格布局列的个数 191 * 192 * @param isSidebar 是否包含侧边栏 193 */ 194 static getAlbumGridCount(isSidebar: boolean): number { 195 Log.info(TAG, `get screen width is : ${ScreenManager.getInstance().getWinWidth()}`); 196 let sideBarWidth = isSidebar ? Constants.TAB_BAR_WIDTH : 0; 197 let contentWidth = ScreenManager.getInstance().getWinWidth() - sideBarWidth; 198 let maxCardWidth = Constants.ALBUM_SET_COVER_SIZE * Constants.GRID_MAX_SIZE_RATIO; 199 let gridColumnsCount = Math.max(Constants.DEFAULT_ALBUM_GRID_COLUMN_MIN_COUNT, 200 Math.ceil((contentWidth - Constants.ALBUM_SET_MARGIN * Constants.NUMBER_2 + Constants.ALBUM_SET_GUTTER) / 201 (maxCardWidth + Constants.ALBUM_SET_GUTTER))); 202 Log.info(TAG, `[getAlbumGridCount] contentWidth: ${contentWidth}, gridColumnsCount: ${gridColumnsCount}`); 203 return gridColumnsCount; 204 } 205 206 static resetGeometryTransitionParams(): void { 207 AppStorage.SetOrCreate<number>('geometryScale', 1); 208 AppStorage.SetOrCreate<number>('geometryOffsetX', 0); 209 AppStorage.SetOrCreate<number>('geometryOffsetY', 0); 210 AppStorage.SetOrCreate<number>('geometryOpacity', 1); 211 } 212 213 static updateGeometryTapInfo(geometryTapIndex: number, geometryTransitionString: string): void { 214 AppStorage.SetOrCreate<number>('placeholderIndex', geometryTapIndex); 215 AppStorage.SetOrCreate<string>('geometryTransitionBrowserId', 216 geometryTransitionString); 217 Log.debug(TAG, 'this.geometryTransitionId = ' + geometryTransitionString + 218 ', placeholderIndex = ' + geometryTapIndex); 219 } 220 221 static getRouterParams(params: Object): Object { 222 let fakeRouterParam: Object = AppStorage.Get('fakeRouterParam'); 223 AppStorage.Delete('fakeRouterParam'); 224 if (fakeRouterParam) { 225 Log.debug(TAG, 'fakeRouterParam = ' + JSON.stringify(fakeRouterParam)); 226 } 227 if (params) { 228 Log.debug(TAG, 'params = ' + JSON.stringify(params)); 229 } 230 return params ? params : fakeRouterParam; 231 } 232 233 static isActionArrayEqual(firstList: Array<Action>, secondList: Array<Action>): boolean { 234 if (firstList === secondList) { 235 return true; 236 } 237 if (firstList.length !== secondList.length) { 238 return false; 239 } 240 for (let index = 0; index < firstList.length; index++) { 241 if (!firstList[index].equals(secondList[index])) { 242 return false; 243 } 244 } 245 return true; 246 } 247 248 static getDisplayNameResourceByAlbumInfo(albumInfo: AlbumInfo): Resource { 249 let res: Resource = null; 250 if (albumInfo.isPhotoAlbum) { 251 return $r('app.string.album_photos'); 252 } else if (albumInfo.isFavorAlbum) { 253 return $r('app.string.album_favor'); 254 } else if (albumInfo.isVideoAlbum) { 255 return $r('app.string.album_video'); 256 } else if (albumInfo.isTrashAlbum) { 257 return $r('app.string.album_recycle'); 258 } else if (albumInfo.isScreenShotAlbum) { 259 return $r('app.string.album_screen_shot'); 260 } else { 261 return res; 262 } 263 } 264}