ToolsHelper.ets 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459
  1. import promptAction from '@ohos.promptAction';
  2. import { BusinessError, deviceInfo } from '@kit.BasicServicesKit';
  3. import { buffer, HashMap, util } from '@kit.ArkTS';
  4. import { DeviceInfo } from '../bean/DeviceInfo';
  5. import { common } from '@kit.AbilityKit';
  6. import { md5_hex } from '../util/md5';
  7. import { LogHelper } from '../../../../Index';
  8. export interface Btn {
  9. text?: string | Resource;
  10. color?: string | Resource;
  11. onClick?: () => void
  12. }
  13. export interface AlertOptions {
  14. title?: string,
  15. msg?: string,
  16. action?: Btn
  17. }
  18. export interface ConfirmOptions {
  19. title?: string
  20. msg?: string
  21. confirm?: Btn
  22. cancel?: Btn
  23. }
  24. export interface ListOptions<T> {
  25. title?: string
  26. cancel?: Btn
  27. autoCancel?: boolean
  28. index?: number
  29. alignment?: DialogAlignment
  30. values: Array<T>
  31. onSelected: (index: number, value: T) => void
  32. onError?: (msg: string) => void
  33. }
  34. interface ListItem {
  35. content: string
  36. }
  37. @Builder
  38. function customDialogBuilder<T>(option: ListOptions<T>, dialogTag: string) {
  39. Column() {
  40. Text(option.title)
  41. .fontSize(16)
  42. .fontColor('#00BE87')
  43. .textAlign(TextAlign.Center)
  44. .width('100%')
  45. .height(60)
  46. .backgroundColor('#F0FFFA')
  47. .borderRadius({
  48. topLeft: 10,
  49. topRight: 10
  50. })
  51. .visibility(option.title ? Visibility.Visible : Visibility.None)
  52. Column() {
  53. List() {
  54. ForEach(option.values, (item: T, index: number) => {
  55. ListItem() {
  56. Row() {
  57. Text(typeof item === "string" ? item : (item as ListItem).content)
  58. .fontSize(option.index === index ? 16 : 14)
  59. .fontWeight(option.index === index ? FontWeight.Bold : FontWeight.Normal)
  60. .maxLines(1)
  61. .width('70%')
  62. .ellipsisMode(EllipsisMode.CENTER)
  63. .textOverflow({
  64. overflow: TextOverflow.Ellipsis
  65. })
  66. .textAlign(TextAlign.Center)
  67. .align(Alignment.Center)
  68. .fontColor('#11102C')
  69. }
  70. .alignItems(VerticalAlign.Center)
  71. .justifyContent(FlexAlign.Center)
  72. .height(60)
  73. .width('100%')
  74. .onClick(() => {
  75. if (ToolsHelper.mapDialog.get(dialogTag)) {
  76. promptAction.closeCustomDialog(ToolsHelper.mapDialog.get(dialogTag))
  77. ToolsHelper.mapDialog.remove(dialogTag)
  78. }
  79. option.onSelected(index, item)
  80. })
  81. }
  82. }, (item: T) => typeof item === "string" ? item : (item as ListItem).content)
  83. }
  84. .listDirection(Axis.Vertical) // 排列方向
  85. .scrollBar(BarState.Off)
  86. .friction(0.6)
  87. .divider({
  88. strokeWidth: 1,
  89. color: '#F6F6F6',
  90. }) // 每行之间的分界线
  91. .edgeEffect(EdgeEffect.Spring) // 边缘效果设置为Spring
  92. .width('100%')
  93. .height(option.values === undefined ? '20%' : option.values.length < 5 ? option.values.length * 60 : 300)
  94. if (option.cancel) {
  95. Column() {
  96. Text(option.cancel.text ?? '取消')
  97. .fontSize(16)
  98. .fontColor(option.cancel.color ?? '#777777')
  99. .textAlign(TextAlign.Center)
  100. .width(325)
  101. .height(44)
  102. .backgroundColor('white')
  103. .borderRadius(22)
  104. .borderWidth(1)
  105. .borderColor('#D7D7D7')
  106. }
  107. .onClick(() => {
  108. if (ToolsHelper.mapDialog.get(dialogTag)) {
  109. promptAction.closeCustomDialog(ToolsHelper.mapDialog.get(dialogTag))
  110. ToolsHelper.mapDialog.remove(dialogTag)
  111. }
  112. option.cancel?.onClick && option.cancel.onClick()
  113. })
  114. .height(71)
  115. .width('100%')
  116. .alignItems(HorizontalAlign.Center)
  117. .justifyContent(FlexAlign.Center)
  118. }
  119. }.justifyContent(FlexAlign.End)
  120. }.justifyContent(FlexAlign.Start)
  121. }
  122. interface ThrottleInterface {
  123. startTime: number; //调用的时间
  124. timeoutNumber: number; //setTimeout的句柄
  125. }
  126. /**
  127. * 常用方法
  128. */
  129. export class ToolsHelper {
  130. private constructor() {
  131. }
  132. /**
  133. * 弹出Toast
  134. * @param msg
  135. */
  136. static log(...args: ESObject[]) {
  137. const k = ToolsHelper.getStackKey()?.split('/')
  138. LogHelper.info(`${k ? k[k.length-1].split('.')[0] : ''}::\n`, ...args)
  139. }
  140. /**
  141. * 弹出Toast
  142. * @param msg
  143. */
  144. static showMessage(msg: string) {
  145. console.info(msg);
  146. promptAction.showToast({
  147. message: msg,
  148. duration: 1500
  149. });
  150. }
  151. private static oTime: number = 0
  152. /**
  153. * 双击退出
  154. * @param msg
  155. */
  156. static doubleAndExit(event?: () => void) {
  157. const cTime = new Date().getTime()
  158. console.log('=====>', cTime)
  159. console.log('=====>', cTime - ToolsHelper.oTime)
  160. if (cTime - ToolsHelper.oTime > 800) {
  161. ToolsHelper.oTime = cTime
  162. ToolsHelper.showMessage('双击退出')
  163. } else {
  164. if (event) {
  165. event()
  166. } else {
  167. (getContext() as common.UIAbilityContext).terminateSelf()
  168. // getContext().getApplicationContext().killAllProcesses();
  169. }
  170. }
  171. return true
  172. }
  173. /**kio9
  174. * 弹出Alert弹窗
  175. * @param options
  176. */
  177. static showAlertDialog(options: AlertOptions) {
  178. try {
  179. promptAction.showDialog({
  180. alignment: DialogAlignment.Center,
  181. title: options.title,
  182. message: options.msg,
  183. buttons: [{
  184. text: options.action?.text ?? "确定",
  185. color: options.action?.color ?? "#000000",
  186. }]
  187. })
  188. .then(() => {
  189. options.action?.onClick && options.action?.onClick()
  190. })
  191. .catch((err: Error) => {
  192. // ToolsHelper.showMessage(err.message)
  193. })
  194. } catch (error) {
  195. let message = (error as BusinessError).message
  196. // ToolsHelper.showMessage(message)
  197. }
  198. }
  199. /**
  200. * 弹出Confirm弹窗
  201. * @param options
  202. */
  203. static showConfirmDialog(options: ConfirmOptions): Promise<void> {
  204. return new Promise((reject) => {
  205. try {
  206. promptAction.showDialog({
  207. alignment: 1,
  208. title: options.title,
  209. message: options.msg,
  210. buttons: [{
  211. text: options.cancel?.text ?? "取消",
  212. color: options.cancel?.color ?? "#666666",
  213. }, {
  214. text: options.confirm?.text ?? "确定",
  215. color: options.confirm?.color ?? "#000000",
  216. },]
  217. })
  218. .then((data) => {
  219. if (data.index === 0) {
  220. options.cancel?.onClick && options.cancel.onClick()
  221. } else {
  222. options.confirm?.onClick && options.confirm.onClick()
  223. }
  224. })
  225. .catch((err: Error) => {
  226. // ToolsHelper.showMessage(err.message)
  227. })
  228. } catch (error) {
  229. reject()
  230. // let message = (error as BusinessError).message
  231. // ToolsHelper.showMessage(message)
  232. }
  233. })
  234. }
  235. public static mapDialog = new HashMap<string, number>()
  236. /**
  237. * 弹出List弹窗
  238. * @param options values 如果是非string列表的话,需要存在content字段
  239. * @param p 调用页面,直接this 即可
  240. */
  241. static showListDialog<T = string>(options: ListOptions<T>, p: object) {
  242. let isSuccess: Array<number> = []
  243. options.values.forEach((item, index) => {
  244. if (typeof item !== 'string') {
  245. if (!(item as ListItem).content) {
  246. isSuccess.push(index)
  247. }
  248. }
  249. })
  250. if (isSuccess.length > 0) {
  251. options.onError && options.onError(`第(${isSuccess.join("、")})个数据中,没有content字段。`)
  252. } else {
  253. const dialogTag = ToolsHelper.getUuid()
  254. promptAction.openCustomDialog({
  255. cornerRadius: 0,
  256. autoCancel: options.autoCancel ?? false,
  257. width: '100%',
  258. // height: options.values === undefined ? '20%' :
  259. // options.values?.length < 8 ? `${options.values?.length / 16 * 100+10}%` : '50%',
  260. alignment: options.alignment ?? DialogAlignment.Bottom,
  261. builder: customDialogBuilder.bind(p, options, dialogTag),
  262. backgroundColor: 'white'
  263. }).then((dialogId: number) => {
  264. ToolsHelper.mapDialog.set(dialogTag, dialogId)
  265. })
  266. }
  267. }
  268. /**
  269. * 弹出自定义弹窗
  270. * @param alignment 弹窗在竖直方向上的对齐方式
  271. */
  272. static showCustomDialog(dialogTag: string, b: CustomBuilder, alignment?: DialogAlignment) {
  273. promptAction.openCustomDialog({
  274. alignment: alignment ?? DialogAlignment.Center,
  275. builder: b,
  276. cornerRadius: 3,
  277. width: '100%',
  278. }).then((dialogId: number) => {
  279. ToolsHelper.mapDialog.set(dialogTag, dialogId)
  280. }).catch((error: Error) => {
  281. console.log('>>>>>', JSON.stringify(error))
  282. })
  283. }
  284. /**
  285. * 关闭自定义弹窗
  286. * @param dialogTag 开启时的tag
  287. */
  288. static closeCustomDialog(dialogTag: string) {
  289. if (ToolsHelper.mapDialog.get(dialogTag)) {
  290. promptAction.closeCustomDialog(ToolsHelper.mapDialog.get(dialogTag))
  291. ToolsHelper.mapDialog.remove(dialogTag)
  292. }
  293. }
  294. static encryptStringToNumber(str: string): number {
  295. let result = 0;
  296. for (let i = 0; i < str.length; i++) {
  297. result = result * 256 + str.charCodeAt(i);
  298. }
  299. return result;
  300. }
  301. static decryptNumberToString(num: number): string {
  302. let result = '';
  303. while (num > 0) {
  304. result = String.fromCharCode(num & 255) + result;
  305. num >>>= 8;
  306. }
  307. return result.replace(/[\s\0]+$/, ''); // 移除结尾的空白字符
  308. }
  309. /**
  310. * 获取调用栈第一个类
  311. */
  312. static getStackKey() {
  313. let stack = new Error().stack
  314. if (stack) {
  315. let list = JSON.stringify(stack).split('\\n')
  316. let a = list[list.length-2].split(':')[0].split('(')[1]
  317. return a
  318. }
  319. return undefined
  320. }
  321. private static deviceInfo: DeviceInfo
  322. /**
  323. * 获取设备信息
  324. * @returns {@link DeviceInfo}
  325. */
  326. static getDeviceInfo() {
  327. if (!ToolsHelper.deviceInfo) {
  328. ToolsHelper.deviceInfo = new DeviceInfo()
  329. ToolsHelper.deviceInfo.ODID = deviceInfo.ODID
  330. ToolsHelper.deviceInfo.manufacture = deviceInfo.manufacture
  331. ToolsHelper.deviceInfo.productModel = deviceInfo.productModel
  332. ToolsHelper.deviceInfo.brand = deviceInfo.brand
  333. ToolsHelper.deviceInfo.osFullName = deviceInfo.osFullName
  334. ToolsHelper.logInfo()
  335. }
  336. return ToolsHelper.deviceInfo
  337. }
  338. private static logInfo() {
  339. // ToolsHelper.log('deviceType-----', deviceInfo.deviceType)
  340. // ToolsHelper.log('manufacture-----', deviceInfo.manufacture)
  341. // ToolsHelper.log('brand-----', deviceInfo.brand)
  342. // ToolsHelper.log('marketName-----', deviceInfo.marketName)
  343. // ToolsHelper.log('productSeries-----', deviceInfo.productSeries)
  344. // ToolsHelper.log('productModel-----', deviceInfo.productModel)
  345. // ToolsHelper.log('softwareModel-----', deviceInfo.softwareModel)
  346. // ToolsHelper.log('hardwareModel-----', deviceInfo.hardwareModel)
  347. // ToolsHelper.log('hardwareProfile-----', deviceInfo.hardwareProfile)
  348. // ToolsHelper.log('serial-----', deviceInfo.serial)
  349. // ToolsHelper.log('bootloaderVersion-----', deviceInfo.bootloaderVersion)
  350. // ToolsHelper.log('abiList-----', deviceInfo.abiList)
  351. // ToolsHelper.log('securityPatchTag-----', deviceInfo.securityPatchTag)
  352. // ToolsHelper.log('displayVersion-----', deviceInfo.displayVersion)
  353. // ToolsHelper.log('incrementalVersion-----', deviceInfo.incrementalVersion)
  354. // ToolsHelper.log('osReleaseType-----', deviceInfo.osReleaseType)
  355. // ToolsHelper.log('osFullName-----', deviceInfo.osFullName)
  356. // ToolsHelper.log('majorVersion-----', deviceInfo.majorVersion)
  357. // ToolsHelper.log('seniorVersion-----', deviceInfo.seniorVersion)
  358. // ToolsHelper.log('featureVersion-----', deviceInfo.featureVersion)
  359. // ToolsHelper.log('buildVersion-----', deviceInfo.buildVersion)
  360. // ToolsHelper.log('sdkApiVersion-----', deviceInfo.sdkApiVersion)
  361. // ToolsHelper.log('firstApiVersion-----', deviceInfo.firstApiVersion)
  362. // ToolsHelper.log('versionId-----', deviceInfo.versionId)
  363. // ToolsHelper.log('buildType-----', deviceInfo.buildType)
  364. // ToolsHelper.log('buildUser-----', deviceInfo.buildUser)
  365. // ToolsHelper.log('buildHost-----', deviceInfo.buildHost)
  366. // ToolsHelper.log('buildTime-----', deviceInfo.buildTime)
  367. // ToolsHelper.log('buildRootHash-----', deviceInfo.buildRootHash)
  368. // ToolsHelper.log('distributionOSName-----', deviceInfo.distributionOSName)
  369. // ToolsHelper.log('distributionOSVersion-----', deviceInfo.distributionOSVersion)
  370. // ToolsHelper.log('distributionOSApiVersion-----', deviceInfo.distributionOSApiVersion)
  371. // ToolsHelper.log('distributionOSApiName-----', deviceInfo.distributionOSApiName)
  372. // ToolsHelper.log('distributionOSReleaseType-----', deviceInfo.distributionOSReleaseType)
  373. }
  374. /**
  375. * 防抖动函数,调用后会延迟wait时间执行,当在wait时间内再次对同一函数调用,则会取消之前的定时器,重新定时
  376. * @param fun
  377. * @param wait
  378. */
  379. static debounceHold(fun: Function, wait: number = 1500) {
  380. let funcValue1 = ToolsHelper.getUniqueId(fun)
  381. let hash = md5_hex(funcValue1)
  382. if (ToolsHelper.setTimeOutMap.get(hash)) {
  383. clearTimeout(ToolsHelper.setTimeOutMap.get(hash)?.timeoutNumber)
  384. ToolsHelper.setTimeOutMap.delete(hash)
  385. }
  386. // ToolsHelper.checkTimeOutNumber()
  387. let timeoutNumber = setTimeout(() => {
  388. ToolsHelper.setTimeOutMap.get(hash) && clearTimeout(ToolsHelper.setTimeOutMap.get(hash)?.timeoutNumber)
  389. ToolsHelper.setTimeOutMap.delete(hash)
  390. // 执行函数调用
  391. fun()
  392. }, wait)
  393. ToolsHelper.setTimeOutMap.set(hash, {
  394. timeoutNumber: timeoutNumber,
  395. startTime: new Date().getTime(),
  396. })
  397. }
  398. static toString(arrayBuffer: ArrayBuffer) {
  399. let decoder = util.TextDecoder.create('utf-8');
  400. return decoder.decodeToString(new Uint8Array(arrayBuffer))
  401. }
  402. static stringToArrayBuffer(str: string): ArrayBuffer {
  403. let buf = buffer.from(str, 'utf-8'); // 使用 UTF-8 编码
  404. return buf.buffer;
  405. }
  406. private static setTimeOutMap: Map<string, ThrottleInterface> = new Map()
  407. private static uniqueIdMap = new WeakMap<Function, string>();
  408. public static getUuid() {
  409. return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
  410. let r = (Math.random() * 16) | 0, v = c == 'x' ? r : (r & 0x3) | 0x8;
  411. return v.toString(16);
  412. });
  413. }
  414. private static getUniqueId(fun: Function): string {
  415. // ToolsHelper.log('', ToolsHelper.getStackKey())
  416. if (!ToolsHelper.uniqueIdMap.has(fun)) {
  417. ToolsHelper.uniqueIdMap.set(fun, ToolsHelper.getUuid());
  418. }
  419. return ToolsHelper.uniqueIdMap.get(fun)!;
  420. }
  421. }