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