ToolsHelper.ets 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361
  1. import promptAction from '@ohos.promptAction';
  2. import { BusinessError, deviceInfo } from '@kit.BasicServicesKit';
  3. import { HashMap } 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. values: Array<T>
  28. onSelected: (index: number, value: T) => void
  29. onError?: (msg: string) => void
  30. }
  31. interface ListItem {
  32. content: string
  33. }
  34. @Builder
  35. function customDialogBuilder<T>(option: ListOptions<T>, dialogTag: string) {
  36. Column() {
  37. Text(option.title)
  38. .fontSize(13)
  39. .textAlign(TextAlign.Center)
  40. .width('60%')
  41. .maxLines(2)
  42. .ellipsisMode(EllipsisMode.END)
  43. .textOverflow({
  44. overflow: TextOverflow.Ellipsis
  45. })
  46. .visibility(option.title ? Visibility.Visible : Visibility.None)
  47. List({ space: 20, initialIndex: 0 }) {
  48. ForEach(option.values, (item: T, index: number) => {
  49. ListItem() {
  50. Text(typeof item === "string" ? item : (item as ListItem).content)
  51. .width('100%')
  52. .fontSize(16)
  53. .textAlign(TextAlign.Center)
  54. .onClick(() => {
  55. if (ToolsHelper.mapDialog.get(dialogTag)) {
  56. promptAction.closeCustomDialog(ToolsHelper.mapDialog.get(dialogTag))
  57. ToolsHelper.mapDialog.remove(dialogTag)
  58. }
  59. option.onSelected(index, item)
  60. })
  61. }
  62. }, (item: string) => item)
  63. }
  64. .listDirection(Axis.Vertical) // 排列方向
  65. .scrollBar(BarState.Off)
  66. .friction(0.6)
  67. .divider({
  68. strokeWidth: 1,
  69. color: 0xEEEEEE,
  70. startMargin: 20,
  71. endMargin: 20
  72. }) // 每行之间的分界线
  73. .edgeEffect(EdgeEffect.Spring) // 边缘效果设置为Spring
  74. .width('100%')
  75. .height(option.values.length < 8 ? `${option.values.length / 16 * 100}%` : '50%')
  76. .margin({ top: 20 })
  77. }
  78. .padding({
  79. top: 20,
  80. bottom: 20,
  81. left: 20,
  82. right: 20
  83. })
  84. }
  85. interface ThrottleInterface {
  86. startTime: number; //调用的时间
  87. timeoutNumber: number; //setTimeout的句柄
  88. }
  89. /**
  90. * 常用方法
  91. */
  92. export class ToolsHelper {
  93. private constructor() {
  94. }
  95. /**
  96. * 弹出Toast
  97. * @param msg
  98. */
  99. static log(...args: ESObject[]) {
  100. const k = ToolsHelper.getStackKey()?.split('/')
  101. LogHelper.info(`${k ? k[k.length-1].split('.')[0] : ''}::\n`, ...args)
  102. }
  103. /**
  104. * 弹出Toast
  105. * @param msg
  106. */
  107. static showMessage(msg: string) {
  108. console.info(msg);
  109. promptAction.showToast({
  110. message: msg,
  111. duration: 1500
  112. });
  113. }
  114. private static oTime: number = 0
  115. /**
  116. * 双击退出
  117. * @param msg
  118. */
  119. static doubleAndExit(event?: () => void) {
  120. const cTime = new Date().getTime()
  121. console.log('=====>', cTime)
  122. console.log('=====>', cTime - ToolsHelper.oTime)
  123. if (cTime - ToolsHelper.oTime > 800) {
  124. ToolsHelper.oTime = cTime
  125. ToolsHelper.showMessage('双击退出')
  126. } else {
  127. if (event) {
  128. event()
  129. } else {
  130. (getContext() as common.UIAbilityContext).terminateSelf()
  131. // getContext().getApplicationContext().killAllProcesses();
  132. }
  133. }
  134. return true
  135. }
  136. /**kio9
  137. * 弹出Alert弹窗
  138. * @param options
  139. */
  140. static showAlertDialog(options: AlertOptions) {
  141. try {
  142. promptAction.showDialog({
  143. alignment: DialogAlignment.Center,
  144. title: options.title,
  145. message: options.msg,
  146. buttons: [{
  147. text: options.action?.text ?? "确定",
  148. color: options.action?.color ?? "#000000",
  149. }]
  150. })
  151. .then(() => {
  152. options.action?.onClick && options.action?.onClick()
  153. })
  154. .catch((err: Error) => {
  155. ToolsHelper.showMessage(err.message)
  156. })
  157. } catch (error) {
  158. let message = (error as BusinessError).message
  159. ToolsHelper.showMessage(message)
  160. }
  161. }
  162. /**
  163. * 弹出Confirm弹窗
  164. * @param options
  165. */
  166. static showConfirmDialog(options: ConfirmOptions): Promise<void> {
  167. return new Promise((reject) => {
  168. try {
  169. promptAction.showDialog({
  170. alignment: 1,
  171. title: options.title,
  172. message: options.msg,
  173. buttons: [{
  174. text: options.confirm?.text ?? "确定",
  175. color: options.confirm?.color ?? "#000000",
  176. }, {
  177. text: options.cancel?.text ?? "取消",
  178. color: options.cancel?.color ?? "#666666",
  179. }]
  180. })
  181. .then((data) => {
  182. if (data.index === 0) {
  183. options.confirm?.onClick && options.confirm.onClick()
  184. } else {
  185. options.cancel?.onClick && options.cancel.onClick()
  186. }
  187. })
  188. .catch((err: Error) => {
  189. ToolsHelper.showMessage(err.message)
  190. })
  191. } catch (error) {
  192. reject()
  193. let message = (error as BusinessError).message
  194. ToolsHelper.showMessage(message)
  195. }
  196. })
  197. }
  198. public static mapDialog = new HashMap<string, number>()
  199. /**
  200. * 弹出List弹窗
  201. * @param options values 如果是非string列表的话,需要存在content字段
  202. */
  203. static showListDialog<T = string>(options: ListOptions<T>, p: object) {
  204. let isSuccess: Array<number> = []
  205. options.values.forEach((item, index) => {
  206. if (typeof item !== 'string') {
  207. if (!(item as ListItem).content) {
  208. isSuccess.push(index)
  209. }
  210. }
  211. })
  212. if (isSuccess.length > 0) {
  213. options.onError && options.onError(`第(${isSuccess.join("、")})个数据中,没有content字段。`)
  214. } else {
  215. const dialogTag = ToolsHelper.getUuid()
  216. promptAction.openCustomDialog({
  217. alignment: 1,
  218. builder: customDialogBuilder.bind(p, options, dialogTag)
  219. }).then((dialogId: number) => {
  220. ToolsHelper.mapDialog.set(dialogTag, dialogId)
  221. })
  222. }
  223. }
  224. /**
  225. * 弹出自定义弹窗
  226. * @param alignment 弹窗在竖直方向上的对齐方式
  227. */
  228. static showCustomDialog(dialogTag: string, b: CustomBuilder, alignment?: DialogAlignment) {
  229. promptAction.openCustomDialog({
  230. alignment: alignment ?? DialogAlignment.Center,
  231. builder: b
  232. }).then((dialogId: number) => {
  233. ToolsHelper.mapDialog.set(dialogTag, dialogId)
  234. }).catch((error: Error) => {
  235. console.log('>>>>>', JSON.stringify(error))
  236. })
  237. }
  238. /**
  239. * 关闭自定义弹窗
  240. * @param dialogTag 开启时的tag
  241. */
  242. static closeCustomDialog(dialogTag: string) {
  243. if (ToolsHelper.mapDialog.get(dialogTag)) {
  244. promptAction.closeCustomDialog(ToolsHelper.mapDialog.get(dialogTag))
  245. ToolsHelper.mapDialog.remove(dialogTag)
  246. }
  247. }
  248. static encryptStringToNumber(str: string): number {
  249. let result = 0;
  250. for (let i = 0; i < str.length; i++) {
  251. result = result * 256 + str.charCodeAt(i);
  252. }
  253. return result;
  254. }
  255. static decryptNumberToString(num: number): string {
  256. let result = '';
  257. while (num > 0) {
  258. result = String.fromCharCode(num & 255) + result;
  259. num >>>= 8;
  260. }
  261. return result.replace(/[\s\0]+$/, ''); // 移除结尾的空白字符
  262. }
  263. /**
  264. * 获取调用栈第一个类
  265. */
  266. static getStackKey() {
  267. let stack = new Error().stack
  268. if (stack) {
  269. let list = JSON.stringify(stack).split('\\n')
  270. let a = list[list.length-2].split(':')[0].split('(')[1]
  271. return a
  272. }
  273. return undefined
  274. }
  275. private static deviceInfo: DeviceInfo
  276. /**
  277. * 获取设备信息
  278. * @returns {@link DeviceInfo}
  279. */
  280. static getDeviceInfo() {
  281. if (!ToolsHelper.deviceInfo) {
  282. ToolsHelper.deviceInfo = new DeviceInfo()
  283. ToolsHelper.deviceInfo.ODID = deviceInfo.ODID
  284. ToolsHelper.deviceInfo.manufacture = deviceInfo.manufacture
  285. ToolsHelper.deviceInfo.brand = deviceInfo.brand
  286. ToolsHelper.deviceInfo.osFullName = deviceInfo.osFullName
  287. }
  288. return ToolsHelper.deviceInfo
  289. }
  290. /**
  291. * 防抖动函数,调用后会延迟wait时间执行,当在wait时间内再次对同一函数调用,则会取消之前的定时器,重新定时
  292. * @param fun
  293. * @param wait
  294. */
  295. static debounceHold(fun: Function, wait: number = 1500) {
  296. let funcValue1 = ToolsHelper.getUniqueId(fun)
  297. let hash = md5_hex(funcValue1)
  298. if (ToolsHelper.setTimeOutMap.get(hash)) {
  299. clearTimeout(ToolsHelper.setTimeOutMap.get(hash)?.timeoutNumber)
  300. ToolsHelper.setTimeOutMap.delete(hash)
  301. }
  302. // ToolsHelper.checkTimeOutNumber()
  303. let timeoutNumber = setTimeout(() => {
  304. ToolsHelper.setTimeOutMap.get(hash) && clearTimeout(ToolsHelper.setTimeOutMap.get(hash)?.timeoutNumber)
  305. ToolsHelper.setTimeOutMap.delete(hash)
  306. // 执行函数调用
  307. fun()
  308. }, wait)
  309. ToolsHelper.setTimeOutMap.set(hash, {
  310. timeoutNumber: timeoutNumber,
  311. startTime: new Date().getTime(),
  312. })
  313. }
  314. private static setTimeOutMap: Map<string, ThrottleInterface> = new Map()
  315. private static uniqueIdMap = new WeakMap<Function, string>();
  316. public static getUuid() {
  317. return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => {
  318. let r = (Math.random() * 16) | 0, v = c == 'x' ? r : (r & 0x3) | 0x8;
  319. return v.toString(16);
  320. });
  321. }
  322. private static getUniqueId(fun: Function): string {
  323. // ToolsHelper.log(ToolsHelper.getStackKey())
  324. if (!ToolsHelper.uniqueIdMap.has(fun)) {
  325. ToolsHelper.uniqueIdMap.set(fun, ToolsHelper.getUuid());
  326. }
  327. return ToolsHelper.uniqueIdMap.get(fun)!;
  328. }
  329. }