652 lines
17 KiB
TypeScript
652 lines
17 KiB
TypeScript
|
import { ResourceItemType } from "@/Common/ResourceItem/ResourceItemType";
|
||
|
import { BaseEnumerator } from "@/Engine/CatanEngine/CoroutineV2/Core/BaseEnumerator";
|
||
|
import { TableManager } from "@/Engine/CatanEngine/TableV3/TableManager";
|
||
|
import CSSettingsV3 from "@/FormTable/CSSettingsV3";
|
||
|
import { ShopMycardTableRow, ShopShow2TableRow } from "@/FormTable/Tables/ShopTable";
|
||
|
import { Cocos } from "@/assets/VueScript/Cocos";
|
||
|
import { CocosVueScript } from "@/assets/VueScript/CocosVueScript";
|
||
|
import GameData_Cocos from "@/assets/VueScript/share/GameData_Cocos";
|
||
|
import { FriendRequest } from "@/define/Request/FriendRequest";
|
||
|
import { TxnRequest } from "@/define/Request/TxnRequest";
|
||
|
import { VIPLevelMapForChat } from "@/map";
|
||
|
import Player from "@/modules/player";
|
||
|
import { UserBindFlag } from "@/modules/player/define/userbind_flag";
|
||
|
import { ChatRoomRole, Games, ItemCodeList, ItemPropsType, ItemSize, PriceList, SelectorItemProps, StringContentType, TagTypes, TxnCenterData } from "@/types";
|
||
|
import liff from "@line/liff";
|
||
|
import axios, { AxiosResponse } from "axios";
|
||
|
import { isMobile } from "react-device-detect";
|
||
|
import * as Scroll from "react-scroll";
|
||
|
import stringWidth from "string-width";
|
||
|
import BusinessTypeSetting, { FolderName } from "../_BusinessTypeSetting/BusinessTypeSetting";
|
||
|
|
||
|
export const transArray = <T>(array: T[], split: number): T[][] => {
|
||
|
const newArr = [];
|
||
|
const copiedArr = array ? array?.slice() : [];
|
||
|
const length = copiedArr?.length;
|
||
|
for (let i = 0, j = 0; i < length; i += split, j++) {
|
||
|
newArr[j] = copiedArr.splice(0, split);
|
||
|
}
|
||
|
return newArr;
|
||
|
};
|
||
|
|
||
|
/** 去掉英文+百分比% */
|
||
|
export function onlyNumber(stringText: string): number {
|
||
|
const str = +stringText.replace(/[A-Za-z%]/g, "");
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
export function wordsLimit(limit: number, string: string) {
|
||
|
const length = string?.length;
|
||
|
const isOverLimit = length > limit;
|
||
|
const result = isOverLimit ? "..." : "";
|
||
|
return string?.substring(0, limit) + result;
|
||
|
}
|
||
|
|
||
|
export const capitalize = (str: string) =>
|
||
|
`${str.charAt(0).toUpperCase()}${str.slice(1)}`;
|
||
|
|
||
|
export function checkForUnique(str: string): boolean {
|
||
|
const chineseCharacterMatch =
|
||
|
/[\p{Unified_Ideograph}\u3006\u3007][\ufe00-\ufe0f\u{e0100}-\u{e01ef}]?/gmu;
|
||
|
const arr = str.match(chineseCharacterMatch);
|
||
|
if (arr === null) return true;
|
||
|
return !hasDuplicates(arr);
|
||
|
}
|
||
|
|
||
|
export function onlyChinese(str: string) {
|
||
|
const chineseCharacterMatch =
|
||
|
/[\p{Unified_Ideograph}\u3006\u3007][\ufe00-\ufe0f\u{e0100}-\u{e01ef}]?/gmu;
|
||
|
const arr = str.match(chineseCharacterMatch);
|
||
|
return arr.join("");
|
||
|
}
|
||
|
|
||
|
export function hasDuplicates(array: string[]): boolean {
|
||
|
return new Set(array).size !== array.length;
|
||
|
}
|
||
|
|
||
|
export function generatePriceList(
|
||
|
arr: [ID: number, ProductId: number, ShowMoney: number][],
|
||
|
items: { [id: string]: [ID: number, price: number] },
|
||
|
priceRef: ShopMycardTableRow[],
|
||
|
itemCodeList?: Map<number, ItemCodeList>,
|
||
|
): PriceList[] {
|
||
|
if (itemCodeList) {
|
||
|
arr = arr.filter((item) => itemCodeList.has(item[0]));
|
||
|
}
|
||
|
const MyCardPriceRefMap = new Map<number, number>(
|
||
|
priceRef.map((item) => [item.Id, item.Price]),
|
||
|
);
|
||
|
const newArr: [ID: number, ProductId: number, ShowMoney: number][] = [];
|
||
|
for (const item of Object.values(items)) {
|
||
|
arr.forEach((v: [ID: number, ProductId: number, ShowMoney: number]) => {
|
||
|
if (v[1] === item[0]) {
|
||
|
newArr.push(v);
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
return newArr
|
||
|
.map((item) => ({
|
||
|
ID: item[0],
|
||
|
points: item[2],
|
||
|
price: MyCardPriceRefMap.get(item[1]),
|
||
|
}))
|
||
|
.sort((a, b) => b.price - a.price);
|
||
|
}
|
||
|
|
||
|
/** 支付列表 */
|
||
|
export function generatePaymentList(
|
||
|
arr: string[],
|
||
|
priceRef: ShopShow2TableRow[],
|
||
|
): ShopShow2TableRow[] {
|
||
|
const newArr: ShopShow2TableRow[] = [];
|
||
|
for (const item of Object.values(priceRef)) {
|
||
|
arr.forEach((x) => {
|
||
|
if (item.Show && x === item.Key) newArr.push(item);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// priceRef.forEach((value: ShopShow2TableRow) => {
|
||
|
// arr.includes(value.Key);
|
||
|
// })
|
||
|
return newArr;
|
||
|
}
|
||
|
|
||
|
/** getQueryParameters */
|
||
|
export function getQueryParameters(v: string): string {
|
||
|
const queryParameters = new URLSearchParams(location.search);
|
||
|
return queryParameters.get(v);
|
||
|
}
|
||
|
|
||
|
export function createMap(obj: unknown) {
|
||
|
return new Map(Object.entries(obj));
|
||
|
}
|
||
|
|
||
|
export function isArray(itemCode: string | string[]): boolean {
|
||
|
return Array.isArray(itemCode);
|
||
|
}
|
||
|
|
||
|
export function formatTime(date: Date): string {
|
||
|
const hours = date.getHours();
|
||
|
const minutes = date.getMinutes();
|
||
|
const amPm = hours >= 12 ? "pm" : "am";
|
||
|
const formattedHours = hours % 12 === 0 ? 12 : hours % 12;
|
||
|
const formattedMinutes = minutes < 10 ? "0" + minutes : minutes;
|
||
|
return `${formattedHours}:${formattedMinutes} ${amPm}`;
|
||
|
}
|
||
|
|
||
|
export function getCurrentLocalTime() {
|
||
|
const date = new Date();
|
||
|
const utcTime = date.getTime();
|
||
|
return new Date(utcTime).toLocaleTimeString();
|
||
|
}
|
||
|
|
||
|
export function transferColorText(str: string): string {
|
||
|
const regex = /color=/g;
|
||
|
const replacement = "span style=color:";
|
||
|
const result = str.replace(regex, replacement);
|
||
|
const regex2 = /color>/g;
|
||
|
const replacement2 = "span>";
|
||
|
return result.replace(regex2, replacement2);
|
||
|
}
|
||
|
|
||
|
export function generateItemsData(
|
||
|
games: Map<string, number[]>,
|
||
|
favoriteGames: number[],
|
||
|
): ItemPropsType[] {
|
||
|
let itemsData: boolean | ItemPropsType[] = [];
|
||
|
const s = new Set(favoriteGames);
|
||
|
if (games.size) {
|
||
|
// @ts-ignore
|
||
|
for (const [gameID, [vendorID, id, VIPLimit, status, tag]] of games) {
|
||
|
const dataObj: ItemPropsType = {
|
||
|
id: gameID,
|
||
|
vendorID: vendorID.toString(),
|
||
|
img: {
|
||
|
url: `${BusinessTypeSetting.UseDownloadUrl}${FolderName.Game}${id}/b`,
|
||
|
},
|
||
|
size: ItemSize.small,
|
||
|
tag: tag as unknown as TagTypes,
|
||
|
lockBtn: VIPLimit,
|
||
|
like: s.has(id),
|
||
|
status,
|
||
|
};
|
||
|
|
||
|
itemsData.push(dataObj);
|
||
|
}
|
||
|
} else {
|
||
|
itemsData = [];
|
||
|
}
|
||
|
|
||
|
return itemsData;
|
||
|
}
|
||
|
|
||
|
export function generateItemsDataMap(games: Games): Map<string, number[]> {
|
||
|
const map = new Map();
|
||
|
for (const [gameID, value] of Object.entries(games)) {
|
||
|
map.set(gameID, value);
|
||
|
}
|
||
|
return map;
|
||
|
}
|
||
|
|
||
|
export function sortedGames(sorts: number[], map: Map<string, number[]>) {
|
||
|
const obj = new Map();
|
||
|
sorts?.forEach((gameID) => {
|
||
|
obj.set("" + gameID, map?.get("" + gameID));
|
||
|
});
|
||
|
return obj;
|
||
|
}
|
||
|
|
||
|
export function addPropertiesToDefaultItem(
|
||
|
games: any[],
|
||
|
selectedID: number,
|
||
|
): SelectorItemProps[] {
|
||
|
const index = games.findIndex((item) => parseInt(item.id) === selectedID);
|
||
|
const newGames = games.slice();
|
||
|
|
||
|
return newGames.map((g, i) =>
|
||
|
i === index
|
||
|
? { ...g, selected: true, defaultItem: true }
|
||
|
: {
|
||
|
...g,
|
||
|
selected: false,
|
||
|
defaultItem: false,
|
||
|
},
|
||
|
);
|
||
|
}
|
||
|
|
||
|
export function switchObjToMap(games: Games) {
|
||
|
// for (const [gameID, value] of Object.entries(games)) {
|
||
|
// map.set(gameID, value)
|
||
|
// }
|
||
|
return new Map(Object.entries(games));
|
||
|
}
|
||
|
|
||
|
export function hexToRgb(
|
||
|
hex: string,
|
||
|
// eslint-disable-next-line @typescript-eslint/typedef
|
||
|
result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex),
|
||
|
) {
|
||
|
const x = result ? result.map((i) => parseInt(i, 16)).slice(1) : null;
|
||
|
return {
|
||
|
r: x[0],
|
||
|
g: x[1],
|
||
|
b: x[2],
|
||
|
};
|
||
|
}
|
||
|
|
||
|
export function replaceBorderColor(string: string, color: string) {
|
||
|
const hasComma = string.includes(",");
|
||
|
if (hasComma) {
|
||
|
const result = string.split(",").map((s, i) => {
|
||
|
const index = s.indexOf("#");
|
||
|
const replaceStr = s.substring(index);
|
||
|
return s.replace(replaceStr, i === 0 ? "black" : color);
|
||
|
});
|
||
|
return result.join(",");
|
||
|
} else {
|
||
|
const index = string.indexOf("#");
|
||
|
const replaceStr = string.substring(index);
|
||
|
return string.replace(replaceStr, color);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export function generateMessage(message: string) {
|
||
|
return {
|
||
|
AID: "10000000063",
|
||
|
nickName: "masterkai",
|
||
|
profileIMG: "./img/png/avatar.png",
|
||
|
role: ChatRoomRole.player,
|
||
|
message: message,
|
||
|
created: getCurrentLocalTime(),
|
||
|
vip: VIPLevelMapForChat.get(4),
|
||
|
};
|
||
|
}
|
||
|
|
||
|
export function getVIPLevelFromStr(vipStr: string) {
|
||
|
const arr = vipStr.split(".");
|
||
|
const str = arr[0];
|
||
|
return str.at(-1);
|
||
|
}
|
||
|
|
||
|
interface Accumulator {
|
||
|
[AID: number]: {
|
||
|
AID: number;
|
||
|
nickName: string;
|
||
|
avatar: number;
|
||
|
role: number;
|
||
|
vip: number;
|
||
|
messages: {
|
||
|
message: string;
|
||
|
created: number;
|
||
|
}[];
|
||
|
};
|
||
|
}
|
||
|
|
||
|
export function sleep(ms: any): Promise<any> {
|
||
|
return new Promise((resolve) => setTimeout(resolve, ms));
|
||
|
}
|
||
|
|
||
|
export async function downloadJSON(formname: string) {
|
||
|
const patchUrl: string =
|
||
|
BusinessTypeSetting.UsePatch + BusinessTypeSetting.FolderUrlJson;
|
||
|
let fileUrl: string = `${patchUrl}${formname}.json`;
|
||
|
fileUrl = fileUrl + "?v=" + Date.now();
|
||
|
let resp: AxiosResponse<any, any> = null;
|
||
|
axios.get(fileUrl).then((res: AxiosResponse<any, any>) => {
|
||
|
loadJsonProcess(null, res, formname);
|
||
|
resp = res;
|
||
|
});
|
||
|
while (!resp) {
|
||
|
await sleep(0.1);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
function loadJsonProcess(
|
||
|
err: any,
|
||
|
res: AxiosResponse<any, any>,
|
||
|
formname: string,
|
||
|
) {
|
||
|
res["name"] = formname;
|
||
|
TableManager.AddJsonAsset(res.data);
|
||
|
}
|
||
|
|
||
|
export function getProfileImgUrl(avatar: number, aId: number) {
|
||
|
return avatar === 1
|
||
|
? `${BusinessTypeSetting.UseDownloadUrl}avatar/${aId}`
|
||
|
: "./img/common/DefaultAvatar.png";
|
||
|
}
|
||
|
|
||
|
export const CssStringContent = (
|
||
|
StringKey: number,
|
||
|
StringID: number | string,
|
||
|
): string => {
|
||
|
switch (StringKey) {
|
||
|
case StringContentType.String:
|
||
|
return StringID?.toString();
|
||
|
case StringContentType.CSSString:
|
||
|
return CSSettingsV3.prototype.CommonString(+StringID);
|
||
|
case StringContentType.CSSMailString:
|
||
|
return CSSettingsV3.prototype.CSSMailString(+StringID);
|
||
|
case StringContentType.CSSNetworkString:
|
||
|
return ""; // CSSettingsV3.Network.Priority[StringID][LanguageManager.GetMsgId()];
|
||
|
case StringContentType.HallString:
|
||
|
/* 廳管1~4 但表格是從2號位開始 */
|
||
|
return CSSettingsV3.prototype.LobbyString(1 + +StringID);
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
return;
|
||
|
};
|
||
|
|
||
|
export function txnDataTransformer(
|
||
|
arr: TxnRequest.TxnInfo[],
|
||
|
playerAid: number,
|
||
|
): TxnCenterData[] {
|
||
|
return arr.map(
|
||
|
([
|
||
|
sn,
|
||
|
time,
|
||
|
giver,
|
||
|
receiver,
|
||
|
status,
|
||
|
fee,
|
||
|
[[category, categoryId, quantity]],
|
||
|
]) => ({
|
||
|
serialNum: sn,
|
||
|
createdAt: time,
|
||
|
giverAid: giver[0],
|
||
|
giverName: giver[1],
|
||
|
isGiver: giver[0] === playerAid,
|
||
|
receiverAid: receiver[0],
|
||
|
receiverName: receiver[1],
|
||
|
status: +status,
|
||
|
quantity,
|
||
|
fee,
|
||
|
}),
|
||
|
);
|
||
|
}
|
||
|
|
||
|
export function calculatedReward(rewards: [number, number][]) {
|
||
|
const maximum = 6;
|
||
|
const result = [];
|
||
|
const couponType = ResourceItemType.Card_Coupon;
|
||
|
rewards.forEach(([type, quantity]) => {
|
||
|
if (type === couponType && quantity > maximum) {
|
||
|
const packNum = Math.floor(quantity / maximum);
|
||
|
const returnPack = Array.from({ length: packNum }, () => [
|
||
|
couponType,
|
||
|
maximum,
|
||
|
]);
|
||
|
const remainder = quantity % maximum;
|
||
|
const returnRemainder = remainder ? [couponType, remainder] : null;
|
||
|
if (returnRemainder) {
|
||
|
returnPack.push(returnRemainder);
|
||
|
}
|
||
|
returnPack.forEach((item) => result.push(item));
|
||
|
} else {
|
||
|
result.push([type, quantity]);
|
||
|
}
|
||
|
});
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
export const random = (min: number, max: number) =>
|
||
|
Math.floor(Math.random() * (max - min)) + min;
|
||
|
|
||
|
// Default color is a bright yellow
|
||
|
const DEFAULT_COLOR = "hsl(50deg, 100%, 50%)";
|
||
|
export const generateSparkle = (color = DEFAULT_COLOR) => {
|
||
|
return {
|
||
|
id: "" + random(10000, 99999),
|
||
|
createdAt: Date.now(),
|
||
|
// Bright yellow color:
|
||
|
color,
|
||
|
size: random(20, 60),
|
||
|
style: {
|
||
|
// Pick a random spot in the available space
|
||
|
top: random(0, 100) + "%",
|
||
|
left: random(0, 100) + "%",
|
||
|
// Float sparkles above sibling content
|
||
|
zIndex: 2,
|
||
|
},
|
||
|
};
|
||
|
};
|
||
|
|
||
|
export const range = (start, end, step = 1) => {
|
||
|
const output = [];
|
||
|
if (typeof end === "undefined") {
|
||
|
end = start;
|
||
|
start = 0;
|
||
|
}
|
||
|
for (let i = start; i < end; i += step) {
|
||
|
output.push(i);
|
||
|
}
|
||
|
return output;
|
||
|
};
|
||
|
|
||
|
export async function waitSetBusinessType() {
|
||
|
while (!BusinessTypeSetting.UseHost) {
|
||
|
await sleep(100);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 是否為好友
|
||
|
* @param {number} aId AID
|
||
|
*/
|
||
|
export function isMyFriend(aId: number): boolean {
|
||
|
let isTrue: boolean = false;
|
||
|
const playerData = Player.data.getState();
|
||
|
const lists: FriendRequest.ListFriendData = playerData.account.allowList;
|
||
|
for (let i = 0; i < lists.length; i++) {
|
||
|
const list: FriendRequest.SingleFriendData = lists[i];
|
||
|
if (list[0] === aId) {
|
||
|
isTrue = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return isTrue;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 是否為黑單
|
||
|
* @param {number} aId AID
|
||
|
*/
|
||
|
export function isMyDeny(aId: number): boolean {
|
||
|
let isTrue: boolean = false;
|
||
|
const playerData = Player.data.getState();
|
||
|
const lists: FriendRequest.ListFriendData = playerData.account.denyList;
|
||
|
for (let i = 0; i < lists.length; i++) {
|
||
|
const list: FriendRequest.SingleFriendData = lists[i];
|
||
|
if (list[0] === aId) {
|
||
|
isTrue = true;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
return isTrue;
|
||
|
}
|
||
|
|
||
|
export const sheetNameResourceTypeSwitcher = (
|
||
|
resourceType: ResourceItemType,
|
||
|
) => {
|
||
|
switch (resourceType) {
|
||
|
case ResourceItemType.Card_Coupon:
|
||
|
return "CouponSetting";
|
||
|
case ResourceItemType.Card:
|
||
|
return "Card1Setting";
|
||
|
default:
|
||
|
return "Card1Setting";
|
||
|
}
|
||
|
};
|
||
|
|
||
|
export function escapeCodesNToBr(v: string): string {
|
||
|
return v.replace(/\n/g, "<br>");
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* 切割顯示字串長度
|
||
|
* @param str
|
||
|
* @param showBytes 字元數(1中文2BYTES)
|
||
|
* @returns
|
||
|
*/
|
||
|
export function trimString(
|
||
|
str: string,
|
||
|
showBytes: number = 12,
|
||
|
ellipses: boolean = true,
|
||
|
): string {
|
||
|
if (!str) {
|
||
|
return str;
|
||
|
}
|
||
|
let bytes: number = stringWidth(str);
|
||
|
if (bytes <= showBytes) {
|
||
|
return str;
|
||
|
}
|
||
|
let byteAmount: number = 0;
|
||
|
let strLength: number = str.length;
|
||
|
for (let i: number = 0; i < strLength; i++) {
|
||
|
let word: string = str[i];
|
||
|
bytes = stringWidth(word);
|
||
|
byteAmount += bytes;
|
||
|
if (byteAmount > showBytes) {
|
||
|
let checkStr: string = str.substring(0, i + 1);
|
||
|
let checkByte: number = stringWidth(checkStr);
|
||
|
if (checkByte < showBytes) {
|
||
|
byteAmount = checkByte;
|
||
|
continue;
|
||
|
}
|
||
|
let result: string = str.substring(0, i);
|
||
|
if (ellipses) {
|
||
|
return result + "...";
|
||
|
} else {
|
||
|
return result;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
console.error("Trim Nickname Error.");
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
/** CommonEventType */
|
||
|
export enum CommonEventType {
|
||
|
/** Maintenance */
|
||
|
Maintenance,
|
||
|
/**ActivityReRender */
|
||
|
ActivityReRender,
|
||
|
}
|
||
|
|
||
|
|
||
|
export function responsiveText(characters: number): number {
|
||
|
if (characters <= 10) return 1.125;
|
||
|
if (characters > 10 && characters <= 20) return 0.9;
|
||
|
if (characters > 20) return 0.8;
|
||
|
}
|
||
|
|
||
|
export function discount(numberOff: number): number {
|
||
|
return (100 - numberOff) / 100;
|
||
|
}
|
||
|
|
||
|
/** 預載字體 */
|
||
|
export function PreloadFont(fonts: string[]): void {
|
||
|
// Check if API exists
|
||
|
if (document && document.fonts) {
|
||
|
// Do not block page loading
|
||
|
setTimeout(function (): void {
|
||
|
let successCount: number = 0;
|
||
|
for (let i: number = 0; i < fonts.length; i++) {
|
||
|
const font: string = fonts[i];
|
||
|
// eslint-disable-next-line no-loop-func
|
||
|
document.fonts.load(`16px ${font}`).then(() => {
|
||
|
// Make font using elements visible
|
||
|
successCount++;
|
||
|
if (successCount === fonts.length) {
|
||
|
document.documentElement.classList.add("font-loaded");
|
||
|
}
|
||
|
});
|
||
|
}
|
||
|
}, 0);
|
||
|
} else {
|
||
|
// Fallback if API does not exist
|
||
|
document.documentElement.classList.add("font-loaded");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// PWA
|
||
|
/** BeforeInstallPromptEvent */
|
||
|
export let deferredPrompt: any;
|
||
|
window.addEventListener("beforeinstallprompt", (e) => {
|
||
|
// Prevent Chrome 67 and earlier from automatically showing the prompt
|
||
|
e.preventDefault();
|
||
|
// Stash the event so it can be triggered later.
|
||
|
deferredPrompt = e;
|
||
|
// Update UI to notify the user they can add to home screen
|
||
|
Cocos.CocosEventListener.DispatchCallback(GameData_Cocos.CELT.PWAInitOK, e);
|
||
|
});
|
||
|
export function addToHomeScreen(): void {
|
||
|
if (isMobile) {
|
||
|
let url: string =
|
||
|
BusinessTypeSetting.UsePatch +
|
||
|
"addtohomescreen/index.html" +
|
||
|
"?v=" +
|
||
|
Date.now();
|
||
|
liff.openWindow({
|
||
|
url: url,
|
||
|
external: true,
|
||
|
});
|
||
|
} else {
|
||
|
if (deferredPrompt) {
|
||
|
// Show the prompt
|
||
|
deferredPrompt.prompt();
|
||
|
// Wait for the user to respond to the prompt
|
||
|
deferredPrompt.userChoice.then((choiceResult) => {
|
||
|
if (choiceResult.outcome === "accepted") {
|
||
|
// console.log("User accepted the A2HS prompt");
|
||
|
Cocos.CocosEventListener.DispatchCallback(GameData_Cocos.CELT.PWAInitOK, false);
|
||
|
} else {
|
||
|
// console.log("User dismissed the A2HS prompt");
|
||
|
}
|
||
|
deferredPrompt = null;
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
export function getArray(count: number): number[] {
|
||
|
const array: number[] = [];
|
||
|
for (let i: number = 0; i < count; i++) {
|
||
|
array.push(i);
|
||
|
}
|
||
|
return array;
|
||
|
}
|
||
|
|
||
|
/** 判斷登入並且Line綁定完 */
|
||
|
export function checkWait(): boolean {
|
||
|
const playerData = Player.data.getState();
|
||
|
const isLineBind: boolean = Player.hasUserBindFlag(UserBindFlag.LineBind);
|
||
|
if (!BaseEnumerator.isInit) {
|
||
|
return true;
|
||
|
} else if (!CocosVueScript.Instance || !CocosVueScript.Instance?.GetLoginData()) {
|
||
|
return true;
|
||
|
} else if (!playerData.account.role && !isLineBind) {
|
||
|
return true;
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
export function scrollToBottom(dynamicListHeight: number, duration: number = 200) {
|
||
|
Scroll.animateScroll.scrollTo(dynamicListHeight, {
|
||
|
duration: duration,
|
||
|
smooth: "easeInQuad",
|
||
|
containerId: "scrollableDiv",
|
||
|
offset: 50
|
||
|
});
|
||
|
}
|
||
|
|
||
|
export function Copy(serialNum: string) {
|
||
|
try {
|
||
|
navigator.clipboard.writeText(serialNum);
|
||
|
}
|
||
|
catch (error) {
|
||
|
console.error(error);
|
||
|
}
|
||
|
}
|