esoftplay 0.0.140 → 0.0.141
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/build.js +2 -0
- package/bin/cli.js +8 -5
- package/bin/router.js +44 -1
- package/config.json +26 -24
- package/error.ts +4 -5
- package/esp.ts +20 -16
- package/global.ts +27 -14
- package/mmkv.ts +3 -0
- package/modules/lib/custom.tsx +45 -0
- package/modules/lib/object.ts +64 -38
- package/package.json +1 -1
- package/persist.ts +35 -32
- package/subscribe.ts +2 -6
package/bin/build.js
CHANGED
|
@@ -227,6 +227,7 @@ if (fs.existsSync(packjson)) {
|
|
|
227
227
|
"compilerOptions": {\n\
|
|
228
228
|
"allowSyntheticDefaultImports": true,\n\
|
|
229
229
|
"experimentalDecorators": true,\n\
|
|
230
|
+
"resolveJsonModule": true, \n\
|
|
230
231
|
"forceConsistentCasingInFileNames": true,\n\
|
|
231
232
|
"importHelpers": true,\n\
|
|
232
233
|
"jsx": "react-native",\n\
|
|
@@ -319,6 +320,7 @@ export default UserIndex`;
|
|
|
319
320
|
'react-native-gesture-handler',
|
|
320
321
|
'react-native-awesome-gallery',
|
|
321
322
|
'react-native-fast-image',
|
|
323
|
+
'react-native-keyboard-controller',
|
|
322
324
|
'react-native-mmkv',
|
|
323
325
|
'react-native-pan-pinch-view',
|
|
324
326
|
'react-native-reanimated',
|
package/bin/cli.js
CHANGED
|
@@ -87,6 +87,7 @@ switch (args[0]) {
|
|
|
87
87
|
break
|
|
88
88
|
case "b":
|
|
89
89
|
case "build":
|
|
90
|
+
buildPrepare(false)
|
|
90
91
|
buildPrepare(true)
|
|
91
92
|
build()
|
|
92
93
|
break;
|
|
@@ -540,7 +541,7 @@ function publish(notes) {
|
|
|
540
541
|
let ajson = readToJSON(appjson)
|
|
541
542
|
if (ajson.expo.hasOwnProperty("updates"))
|
|
542
543
|
if (ajson.expo.updates.hasOwnProperty('url') && !ajson.expo.updates.url.includes("https://u.expo.dev")) {
|
|
543
|
-
if (!fs.existsSync('./code-signing')){
|
|
544
|
+
if (!fs.existsSync('./code-signing')) {
|
|
544
545
|
consoleError("./code-signing not found!")
|
|
545
546
|
return
|
|
546
547
|
}
|
|
@@ -840,8 +841,9 @@ function devClientPre(file) {
|
|
|
840
841
|
}
|
|
841
842
|
let app = JSON.parse(txt)
|
|
842
843
|
app.expo.name = app.expo.name.includes("DC-") ? app.expo.name : ("DC-" + app.expo.name)
|
|
843
|
-
app.expo.extra
|
|
844
|
-
|
|
844
|
+
// if (!app.expo.extra && app.expo.update)
|
|
845
|
+
// app.expo.extra = app.expo.updates
|
|
846
|
+
// delete app.expo.updates
|
|
845
847
|
fs.writeFileSync(file, JSON.stringify(app, undefined, 2))
|
|
846
848
|
} else {
|
|
847
849
|
consoleError(file)
|
|
@@ -857,8 +859,9 @@ function devClientPos(file) {
|
|
|
857
859
|
}
|
|
858
860
|
let app = JSON.parse(txt)
|
|
859
861
|
app.expo.name = app.expo.name.replace("DC-", "")
|
|
860
|
-
|
|
861
|
-
|
|
862
|
+
// if (app.expo.extra)
|
|
863
|
+
// app.expo.updates = app.expo.extra
|
|
864
|
+
// delete app.expo.extra
|
|
862
865
|
fs.writeFileSync(file, JSON.stringify(app, undefined, 2))
|
|
863
866
|
} else {
|
|
864
867
|
consoleError(file)
|
package/bin/router.js
CHANGED
|
@@ -141,7 +141,9 @@ if (!fs.existsSync(pathAsset)) {
|
|
|
141
141
|
listDir(pathAsset);
|
|
142
142
|
var Assets = "";
|
|
143
143
|
var pLength = pathAsset.length - 1;
|
|
144
|
+
let dFiles = []
|
|
144
145
|
assets.forEach(File => {
|
|
146
|
+
dFiles.push(File.substr(pLength))
|
|
145
147
|
Assets += "\t\tcase \"" + File.substr(pLength) + "\":\n" +
|
|
146
148
|
"\t\t\tOut = require(\"../../../" + File + "\");\n" +
|
|
147
149
|
"\t\t\tbreak;\n";
|
|
@@ -154,12 +156,18 @@ Text = 'function assets(File) {' + "\n\t" +
|
|
|
154
156
|
'return Out;' + "\n" +
|
|
155
157
|
'}' + "\n" +
|
|
156
158
|
'module.exports = assets;';
|
|
157
|
-
if (isChange(tmpDir + "assets.js", Text))
|
|
159
|
+
if (isChange(tmpDir + "assets.js", Text)) {
|
|
160
|
+
fs.writeFile(tmpDir + "assets.d.ts", `export type EspAssets = ${dFiles.map((x) => "\"" + x + "\"").join(" | ")}`, { flag: "w" }, (err) => {
|
|
161
|
+
if (err) {
|
|
162
|
+
return console.log(err);
|
|
163
|
+
}
|
|
164
|
+
})
|
|
158
165
|
fs.writeFile(tmpDir + "assets.js", Text, { flag: 'w' }, function (err) {
|
|
159
166
|
if (err) {
|
|
160
167
|
return console.log(err);
|
|
161
168
|
}
|
|
162
169
|
});
|
|
170
|
+
}
|
|
163
171
|
|
|
164
172
|
/* CREATE INDEX.D.TS */
|
|
165
173
|
function createIndex() {
|
|
@@ -429,4 +437,39 @@ export interface EspArgsInterface {
|
|
|
429
437
|
return console.log(err);
|
|
430
438
|
}
|
|
431
439
|
});
|
|
440
|
+
|
|
441
|
+
function readToJSON(path) {
|
|
442
|
+
var txt = fs.readFileSync(path, 'utf8');
|
|
443
|
+
let isJSON = txt.startsWith('{') || txt.startsWith('[')
|
|
444
|
+
return isJSON ? JSON.parse(txt) : txt
|
|
445
|
+
}
|
|
446
|
+
const espConfig = readToJSON("./config.json")
|
|
447
|
+
const presets = {
|
|
448
|
+
timezone: "",
|
|
449
|
+
protocol: "",
|
|
450
|
+
uri: "",
|
|
451
|
+
url: "",
|
|
452
|
+
content: "",
|
|
453
|
+
webviewOpen: "",
|
|
454
|
+
webviewClose: "",
|
|
455
|
+
api: "",
|
|
456
|
+
data: "",
|
|
457
|
+
home: {
|
|
458
|
+
member: "",
|
|
459
|
+
public: ""
|
|
460
|
+
},
|
|
461
|
+
group_id: 0,
|
|
462
|
+
langIds: [],
|
|
463
|
+
theme: [],
|
|
464
|
+
comment_login: 1,
|
|
465
|
+
notification: 0,
|
|
466
|
+
...espConfig.config
|
|
467
|
+
}
|
|
468
|
+
if (isChange(tmpDir + "config.json", JSON.stringify(presets))) {
|
|
469
|
+
fs.writeFile(tmpDir + "config.json", JSON.stringify(presets), { flag: 'w' }, function (err) {
|
|
470
|
+
if (err) {
|
|
471
|
+
return console.log(err);
|
|
472
|
+
}
|
|
473
|
+
});
|
|
474
|
+
}
|
|
432
475
|
}
|
package/config.json
CHANGED
|
@@ -1,38 +1,40 @@
|
|
|
1
1
|
{
|
|
2
2
|
"config": {
|
|
3
3
|
"timezone": "Asia/Jakarta",
|
|
4
|
-
"protocol": "http",
|
|
5
|
-
"domain": "esoftplay.com",
|
|
6
|
-
"api": "api",
|
|
7
|
-
"data": "data",
|
|
8
|
-
"uri": "/",
|
|
9
|
-
"home": {
|
|
10
|
-
"member": "content/member",
|
|
11
|
-
"public": "content"
|
|
4
|
+
"protocol": "http", // http or https
|
|
5
|
+
"domain": "esoftplay.com", // naked domain to website
|
|
6
|
+
"api": "api", // optional: subdomain to access web API
|
|
7
|
+
"data": "data", // optional: subdomain to access web content / article
|
|
8
|
+
"uri": "/", // relatif path to main website
|
|
9
|
+
"home": { // define the frontpage for module/task
|
|
10
|
+
"member": "content/member", // when user has been logged in
|
|
11
|
+
"public": "content" // when user not login yet
|
|
12
12
|
},
|
|
13
|
-
"errorReport": {
|
|
13
|
+
"errorReport": { // add telegram ids to listenReport Error
|
|
14
14
|
"telegramIds": [
|
|
15
15
|
"111111111"
|
|
16
16
|
]
|
|
17
17
|
},
|
|
18
|
-
"group_id":'1,
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
"
|
|
22
|
-
"
|
|
23
|
-
"
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
"group_id":'1,
|
|
19
|
+
2', // string separated comma
|
|
20
|
+
"isDebug": 1, // optional: display console on esp.log('any message'), don't use it for automatic detect the environment (production / development)
|
|
21
|
+
"salt": "CHANGE_INTO_YOUR_OWN_SALT", // SALT form config.php in your website
|
|
22
|
+
"notification": 1, // optional: to determine is this application have notification or not
|
|
23
|
+
"exludeModules": [],
|
|
24
|
+
"excludePackages": [], // optional: to delete module when listed
|
|
25
|
+
"firebase": { // https://console.firebase.google.com - download google-services.json
|
|
26
|
+
"apiKey": "FIREBASE_Web_API_Key", // Eg. AIzaSyAvVyNeXI3RTo7Tl5LCBSZ-mu92VpbPBK8Y
|
|
27
|
+
"authDomain": "FIREBASE_authDomain", // Eg. project-6495177974885932998.firebaseapp.com
|
|
26
28
|
"databaseURL": "FIREBASE_Database_URL", // Eg. https://project-6495177974885932998.firebaseio.com/
|
|
27
29
|
"storageBucket": "FIREBASE_Storage_URL" // Eg. test://project-6495177974885932998.appspot.com/
|
|
28
30
|
},
|
|
29
|
-
"experienceId":"@esp/appslug",
|
|
30
|
-
"iosClientId":"Ios Client id untuk keperluan google login",
|
|
31
|
-
"facebookAppId":"APP ID dari Aplikasi yang didaftarkan di Facebook Developer",
|
|
32
|
-
"theme":[],
|
|
33
|
-
"fonts":{
|
|
34
|
-
"fontName":"fontName.ttf or .otf",
|
|
35
|
-
"fontName2":"fontName2.ttf or .otf"
|
|
31
|
+
"experienceId": "@esp/appslug",
|
|
32
|
+
"iosClientId": "Ios Client id untuk keperluan google login",
|
|
33
|
+
"facebookAppId": "APP ID dari Aplikasi yang didaftarkan di Facebook Developer",
|
|
34
|
+
"theme": [], // untuk custom theme jika diperlukan,silahkan lihat module LibTheme untuk cara peggunaannya
|
|
35
|
+
"fonts": {
|
|
36
|
+
"fontName": "fontName.ttf or .otf", // taruh file font di assets/fonts/ jika ingin custom fonts. bisa lebih dari 1
|
|
37
|
+
"fontName2": "fontName2.ttf or .otf"
|
|
36
38
|
}
|
|
37
39
|
}
|
|
38
40
|
}
|
package/error.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import AsyncStorage from '@react-native-async-storage/async-storage';
|
|
2
1
|
import Constants from 'expo-constants';
|
|
3
2
|
import { Platform } from 'react-native';
|
|
4
3
|
import { LibCurl } from './cache/lib/curl/import';
|
|
5
4
|
import { UserClass } from './cache/user/class/import';
|
|
6
5
|
import esp from './esp';
|
|
6
|
+
import FastStorage from './mmkv';
|
|
7
7
|
import { default as UserRoutes } from './modules/user/routes';
|
|
8
8
|
let pack = require('../../package.json');
|
|
9
9
|
let app = require('../../app.json');
|
|
@@ -35,7 +35,7 @@ export function setError(error?: any) {
|
|
|
35
35
|
time: getTime()
|
|
36
36
|
};
|
|
37
37
|
try {
|
|
38
|
-
|
|
38
|
+
FastStorage.setItem(`${config?.domain}error`, JSON.stringify(_e));
|
|
39
39
|
} catch (e) {
|
|
40
40
|
console.error(e);
|
|
41
41
|
}
|
|
@@ -87,7 +87,6 @@ export function sendTm(message: string, chat_id?: string, bot?: string, res?: (r
|
|
|
87
87
|
let config = esp?.config?.()
|
|
88
88
|
_chatids = Object.values(config?.errorReport?.telegramIds)
|
|
89
89
|
}
|
|
90
|
-
console.log(_chatids)
|
|
91
90
|
_chatids.forEach((cid: string) => {
|
|
92
91
|
let post = {
|
|
93
92
|
text: message,
|
|
@@ -101,7 +100,7 @@ export function sendTm(message: string, chat_id?: string, bot?: string, res?: (r
|
|
|
101
100
|
|
|
102
101
|
export function getError() {
|
|
103
102
|
let config = esp?.config?.()
|
|
104
|
-
|
|
103
|
+
FastStorage.getItem(config?.domain + 'error').then((e: any) => {
|
|
105
104
|
if (e) {
|
|
106
105
|
let _e = JSON.parse(e)
|
|
107
106
|
let msg = [
|
|
@@ -137,7 +136,7 @@ export function getError() {
|
|
|
137
136
|
});
|
|
138
137
|
}
|
|
139
138
|
// });
|
|
140
|
-
|
|
139
|
+
FastStorage.removeItem(config.domain + 'error')
|
|
141
140
|
}
|
|
142
141
|
})
|
|
143
142
|
}
|
package/esp.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { EspAssets } from 'esoftplay/cache/assets';
|
|
2
|
+
import cacheConfig from 'esoftplay/cache/config.json';
|
|
1
3
|
import { LibLocale } from 'esoftplay/cache/lib/locale/import';
|
|
2
4
|
import { EspRouterPropertyInterface } from 'esoftplay/cache/properties';
|
|
3
5
|
import { EspRouterInterface } from 'esoftplay/cache/routers';
|
|
@@ -6,6 +8,8 @@ import { LogBox, Platform } from 'react-native';
|
|
|
6
8
|
import 'react-native-reanimated';
|
|
7
9
|
import './oneplusfixfont';
|
|
8
10
|
|
|
11
|
+
type ConfigType = typeof cacheConfig
|
|
12
|
+
|
|
9
13
|
const ignoreWarns = [
|
|
10
14
|
"Setting a timer for a long period of time",
|
|
11
15
|
"VirtualizedLists should never be nested inside plain ScrollViews with the same orientation",
|
|
@@ -71,28 +75,28 @@ const esp = {
|
|
|
71
75
|
appjson(): any {
|
|
72
76
|
return esp.mergeDeep(app, conf)
|
|
73
77
|
},
|
|
74
|
-
assets(path:
|
|
78
|
+
assets(path: EspAssets): any {
|
|
75
79
|
const _assets = require('./cache/assets')
|
|
76
80
|
return _assets(path)
|
|
77
81
|
},
|
|
78
82
|
versionName(): string {
|
|
79
83
|
return (Platform.OS == 'android' ? Constants?.expoConfig?.android?.versionCode : Constants?.expoConfig?.ios?.buildNumber) + '-' + esp.config('publish_id')
|
|
80
84
|
},
|
|
81
|
-
config(param?:
|
|
82
|
-
let out: any =
|
|
85
|
+
config<T = ConfigType>(param?: keyof ConfigType, ...params: string[]): T {
|
|
86
|
+
let out: any = this._config();
|
|
83
87
|
if (param) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
out = {};
|
|
92
|
-
}
|
|
88
|
+
const _params = [param, ...params];
|
|
89
|
+
for (let i = 0; i < _params.length; i++) {
|
|
90
|
+
const key = _params[i];
|
|
91
|
+
if (out && typeof out === 'object' && out.hasOwnProperty(key)) {
|
|
92
|
+
out = out[key];
|
|
93
|
+
} else {
|
|
94
|
+
return {} as T; // Return empty object if key doesn't exist
|
|
93
95
|
}
|
|
96
|
+
}
|
|
94
97
|
}
|
|
95
|
-
|
|
98
|
+
|
|
99
|
+
return out as T;
|
|
96
100
|
},
|
|
97
101
|
isDebug(message: string): boolean {
|
|
98
102
|
if (!lconf) {
|
|
@@ -116,7 +120,7 @@ const esp = {
|
|
|
116
120
|
return out;
|
|
117
121
|
}
|
|
118
122
|
},
|
|
119
|
-
lang(moduleTask:
|
|
123
|
+
lang<T extends keyof EspRouterInterface>(moduleTask: T, langName: string, ...stringToBe: string[]): string {
|
|
120
124
|
let string = LibLocale.stateLang().get()?.[esp.langId()]?.[moduleTask]?.[langName]
|
|
121
125
|
if (!string) {
|
|
122
126
|
string = esp.assets("locale/id.json")?.[moduleTask]?.[langName]
|
|
@@ -155,7 +159,7 @@ const esp = {
|
|
|
155
159
|
const properties = require('./cache/properties')
|
|
156
160
|
return properties(modtast.join("/"));
|
|
157
161
|
},
|
|
158
|
-
_config():
|
|
162
|
+
_config(): typeof cacheConfig {
|
|
159
163
|
app = esp.mergeDeep(app, conf)
|
|
160
164
|
var msg = ''
|
|
161
165
|
if (!app.hasOwnProperty('config')) {
|
|
@@ -172,7 +176,7 @@ const esp = {
|
|
|
172
176
|
throw error;
|
|
173
177
|
}
|
|
174
178
|
|
|
175
|
-
|
|
179
|
+
const config = {
|
|
176
180
|
// default config
|
|
177
181
|
timezone: "Asia/Jakarta",
|
|
178
182
|
protocol: "http",
|
package/global.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import esp from 'esoftplay/esp';
|
|
2
2
|
import * as R from 'react';
|
|
3
|
+
import { createDebounce } from './timeout';
|
|
3
4
|
|
|
4
5
|
export interface useGlobalReturn<T> {
|
|
5
6
|
useState: () => [T, (newState: T | ((newState: T) => T)) => void, () => T],
|
|
@@ -7,7 +8,7 @@ export interface useGlobalReturn<T> {
|
|
|
7
8
|
set: (x: T | ((old: T) => T)) => void,
|
|
8
9
|
reset: () => void,
|
|
9
10
|
listen: (cb: (value: T) => void) => () => void
|
|
10
|
-
sync: () => void,
|
|
11
|
+
sync: () => () => void,
|
|
11
12
|
connect: (props: useGlobalConnect<T>) => any,
|
|
12
13
|
useSelector: (selector: (state: T) => any) => any;
|
|
13
14
|
}
|
|
@@ -15,6 +16,7 @@ export interface useGlobalReturn<T> {
|
|
|
15
16
|
export interface useGlobalAutoSync {
|
|
16
17
|
url: string,
|
|
17
18
|
post: (item: any) => Object,
|
|
19
|
+
delayInMs?: number,
|
|
18
20
|
isSyncing?: (isSync: boolean) => void
|
|
19
21
|
}
|
|
20
22
|
|
|
@@ -31,7 +33,8 @@ export interface useGlobalOption {
|
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
export interface useGlobalConnect<T> {
|
|
34
|
-
|
|
36
|
+
selector?: (props: T) => any,
|
|
37
|
+
render: (props: Partial<T> | T) => any,
|
|
35
38
|
}
|
|
36
39
|
export let userDataReset: Function[] = []
|
|
37
40
|
let timeoutFinish: NodeJS.Timeout
|
|
@@ -42,7 +45,7 @@ export default function useGlobalState<T>(initValue: T, o?: useGlobalOption): us
|
|
|
42
45
|
let value: T = initValue;
|
|
43
46
|
let listener = new Set<Function>()
|
|
44
47
|
let loaded = -1
|
|
45
|
-
let
|
|
48
|
+
let taskSync: any = undefined
|
|
46
49
|
|
|
47
50
|
if (o?.persistKey) {
|
|
48
51
|
STORAGE = o?.inFastStorage ? require('esoftplay/mmkv').default : (o?.inFile ? (require('esoftplay/storage').default) : (require('@react-native-async-storage/async-storage').default))
|
|
@@ -52,14 +55,24 @@ export default function useGlobalState<T>(initValue: T, o?: useGlobalOption): us
|
|
|
52
55
|
}
|
|
53
56
|
|
|
54
57
|
function _sync() {
|
|
55
|
-
|
|
56
|
-
|
|
58
|
+
const debounce = createDebounce()
|
|
59
|
+
if (o?.useAutoSync && taskSync && Array.isArray(value)) {
|
|
60
|
+
debounce.set(taskSync[0]?.(value.filter((item: any) => item.synced != 1)), 16)
|
|
61
|
+
}
|
|
62
|
+
return () => {
|
|
63
|
+
if (o?.useAutoSync && taskSync && Array.isArray(value)) {
|
|
64
|
+
taskSync?.[1]?.()
|
|
65
|
+
debounce.set(taskSync[0]?.(value.filter((item: any) => item.synced != 1)), 16)
|
|
66
|
+
}
|
|
67
|
+
}
|
|
57
68
|
}
|
|
58
69
|
|
|
59
70
|
if (o?.useAutoSync) {
|
|
60
71
|
const LibCurl = esp.mod("lib/curl")
|
|
61
72
|
const UseTasks = esp.mod("use/tasks")
|
|
62
|
-
|
|
73
|
+
taskSync = UseTasks()((item) => new Promise((next) => {
|
|
74
|
+
const debounce = createDebounce()
|
|
75
|
+
const delayInMs = o?.useAutoSync?.delayInMs || 0
|
|
63
76
|
const { isOnline, isInternetReachable } = esp.mod("lib/net_status").state().get()
|
|
64
77
|
if (isOnline && isInternetReachable) {
|
|
65
78
|
if (o?.useAutoSync) {
|
|
@@ -74,18 +87,18 @@ export default function useGlobalState<T>(initValue: T, o?: useGlobalOption): us
|
|
|
74
87
|
return old
|
|
75
88
|
}
|
|
76
89
|
})
|
|
77
|
-
next
|
|
90
|
+
debounce.set(next, delayInMs)
|
|
78
91
|
}, () => {
|
|
79
|
-
next
|
|
92
|
+
debounce.set(next, delayInMs)
|
|
80
93
|
}
|
|
81
94
|
)
|
|
82
95
|
}
|
|
83
96
|
} else {
|
|
84
|
-
next
|
|
97
|
+
debounce.set(next, delayInMs)
|
|
85
98
|
}
|
|
86
99
|
}), () => {
|
|
87
100
|
o?.useAutoSync?.isSyncing?.(false)
|
|
88
|
-
})
|
|
101
|
+
})
|
|
89
102
|
}
|
|
90
103
|
|
|
91
104
|
function loadFromDisk() {
|
|
@@ -159,8 +172,8 @@ export default function useGlobalState<T>(initValue: T, o?: useGlobalOption): us
|
|
|
159
172
|
}
|
|
160
173
|
if (o?.listener)
|
|
161
174
|
o.listener(newValue)
|
|
162
|
-
if (o?.useAutoSync &&
|
|
163
|
-
|
|
175
|
+
if (o?.useAutoSync && taskSync)
|
|
176
|
+
taskSync?.[0]?.(newValue.filter((item: any) => item.synced != 1))
|
|
164
177
|
if (listener.size > 0) {
|
|
165
178
|
listener.forEach((fun) => fun?.(newValue))
|
|
166
179
|
}
|
|
@@ -174,7 +187,7 @@ export default function useGlobalState<T>(initValue: T, o?: useGlobalOption): us
|
|
|
174
187
|
set(initValue)
|
|
175
188
|
}
|
|
176
189
|
|
|
177
|
-
function useSelector(se: (state: T) => any):
|
|
190
|
+
function useSelector(se: (state: T) => any): Partial<T> | T {
|
|
178
191
|
loadFromDisk()
|
|
179
192
|
|
|
180
193
|
let [l, s] = R.useState<any>(se(value));
|
|
@@ -225,7 +238,7 @@ export default function useGlobalState<T>(initValue: T, o?: useGlobalOption): us
|
|
|
225
238
|
};
|
|
226
239
|
|
|
227
240
|
function _connect(props: useGlobalConnect<T>): any {
|
|
228
|
-
const
|
|
241
|
+
const state = props.selector ? useSelector(props.selector) : useState()[0]
|
|
229
242
|
const children = props.render(state)
|
|
230
243
|
return children ? R.cloneElement(children) : null
|
|
231
244
|
}
|
package/mmkv.ts
CHANGED
|
@@ -3,6 +3,9 @@ import { MMKV } from 'react-native-mmkv';
|
|
|
3
3
|
const storage = new MMKV()
|
|
4
4
|
|
|
5
5
|
const FastStorage = {
|
|
6
|
+
getItemSync(key: string): string {
|
|
7
|
+
return storage.getString(key)
|
|
8
|
+
},
|
|
6
9
|
getItem(key: string): Promise<string | undefined | null> {
|
|
7
10
|
return new Promise((r) => r(storage.getString(key)))
|
|
8
11
|
},
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
// withHooks
|
|
2
|
+
|
|
3
|
+
import esp from 'esoftplay/esp';
|
|
4
|
+
import React, { useEffect, useRef } from 'react';
|
|
5
|
+
import { Linking, Pressable, Text, View } from 'react-native';
|
|
6
|
+
import WebView from 'react-native-webview';
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
export interface LibCustomArgs {
|
|
10
|
+
|
|
11
|
+
}
|
|
12
|
+
export interface LibCustomProps {
|
|
13
|
+
|
|
14
|
+
}
|
|
15
|
+
export default function m(props: LibCustomProps): any {
|
|
16
|
+
const LibIcon = useRef(esp.mod("lib/icon")).current
|
|
17
|
+
|
|
18
|
+
const { url, title } = esp.mod("lib/navigation").getArgsAll(props)
|
|
19
|
+
|
|
20
|
+
useEffect(() => {
|
|
21
|
+
if (!String(url).startsWith("http")) {
|
|
22
|
+
Linking.openURL(url)
|
|
23
|
+
esp.mod("lib/navigation").back()
|
|
24
|
+
}
|
|
25
|
+
}, [])
|
|
26
|
+
|
|
27
|
+
if (String(url).startsWith("http"))
|
|
28
|
+
return (
|
|
29
|
+
<View style={{ flex: 1 }} >
|
|
30
|
+
<View style={[{ height: 60 + esp.mod("lib/style").STATUSBAR_HEIGHT, paddingTop: esp.mod("lib/style").STATUSBAR_HEIGHT, backgroundColor: "#fff", flexDirection: 'row', alignItems: 'center', marginBottom: 3 }, esp.mod("lib/style").elevation(3)]} >
|
|
31
|
+
<Pressable onPress={() => esp.mod("lib/navigation").back()} style={{ height: 60, width: 60, alignItems: 'center', justifyContent: 'center' }} >
|
|
32
|
+
<LibIcon name='arrow-left' />
|
|
33
|
+
</Pressable>
|
|
34
|
+
<Text style={{ fontWeight: "bold", marginLeft: 0 }}>{title ? title : ""}</Text>
|
|
35
|
+
</View>
|
|
36
|
+
<WebView
|
|
37
|
+
style={{ flex: 1 }}
|
|
38
|
+
source={{ uri: url }}
|
|
39
|
+
startInLoadingState={true}
|
|
40
|
+
/>
|
|
41
|
+
</View>
|
|
42
|
+
)
|
|
43
|
+
else
|
|
44
|
+
return null
|
|
45
|
+
}
|
package/modules/lib/object.ts
CHANGED
|
@@ -3,10 +3,10 @@
|
|
|
3
3
|
import { update } from "immhelper";
|
|
4
4
|
|
|
5
5
|
export default class m {
|
|
6
|
-
|
|
6
|
+
#value = undefined
|
|
7
7
|
|
|
8
8
|
constructor(array: any) {
|
|
9
|
-
this
|
|
9
|
+
this.#value = array
|
|
10
10
|
this.value = this.value.bind(this)
|
|
11
11
|
this.push = this.push.bind(this)
|
|
12
12
|
this.unset = this.unset.bind(this)
|
|
@@ -27,40 +27,48 @@ export default class m {
|
|
|
27
27
|
spec = { [pathToUpdate]: [command, ...allValues] }
|
|
28
28
|
else
|
|
29
29
|
spec = [command, ...allValues]
|
|
30
|
-
this
|
|
30
|
+
this.#value = update(array, spec)
|
|
31
31
|
return this
|
|
32
32
|
}
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
push(value?: any, ...values: any[]): (cursor?: string | number, ...cursors: (string | number)[]) => this {
|
|
36
|
-
return this.cursorBuilder("push", this
|
|
36
|
+
return this.cursorBuilder("push", this.#value, value, ...values)
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
unshift(value?: any, ...values: any[]): (cursor?: string | number, ...cursors: (string | number)[]) => this {
|
|
40
|
-
return this.cursorBuilder("unshift", this
|
|
40
|
+
return this.cursorBuilder("unshift", this.#value, value, ...values)
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
splice(index: number, deleteCount: number, value?: any, ...values: any[]): (cursor?: string | number, ...cursors: (string | number)[]) => this {
|
|
44
|
-
return this.cursorBuilder("splice", this
|
|
44
|
+
return this.cursorBuilder("splice", this.#value, index, deleteCount, value, ...values)
|
|
45
45
|
}
|
|
46
46
|
unset(index: number | string, ...indexs: (string | number)[]): (cursor?: string | number, ...cursors: (string | number)[]) => this {
|
|
47
|
-
return this.cursorBuilder("unset", this
|
|
47
|
+
return this.cursorBuilder("unset", this.#value, index, ...indexs)
|
|
48
48
|
}
|
|
49
49
|
|
|
50
50
|
set(value: any): (cursor?: string | number, ...cursors: (string | number)[]) => this {
|
|
51
|
-
return this.cursorBuilder("set", this
|
|
51
|
+
return this.cursorBuilder("set", this.#value, value)
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
update(callback: (lastValue: any) => any): (cursor?: string | number, ...cursors: (string | number)[]) => this {
|
|
55
|
-
return this.cursorBuilder("batch", this
|
|
55
|
+
return this.cursorBuilder("batch", this.#value, callback)
|
|
56
56
|
}
|
|
57
57
|
|
|
58
58
|
assign(obj1: any): (cursor?: string | number, ...cursors: (string | number)[]) => this {
|
|
59
|
-
return this.cursorBuilder("assign", this
|
|
59
|
+
return this.cursorBuilder("assign", this.#value, deepCopy(obj1))
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
removeKeys(deletedItemKeys: string[]): (cursor?: string | number, ...cursors: (string | number)[]) => this {
|
|
63
|
+
return this.cursorBuilder("batch", this.#value, (arr: any) => _removeKeys(arr, deletedItemKeys))
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
replaceItem<T>(filter: (item: T, index: number) => boolean, newItem: T): (cursor?: string | number, ...cursors: (string | number)[]) => this {
|
|
67
|
+
return this.cursorBuilder("batch", this.#value, (arr: any) => _replaceItem(arr, filter, newItem))
|
|
60
68
|
}
|
|
61
69
|
|
|
62
70
|
value(): any {
|
|
63
|
-
return this
|
|
71
|
+
return this.#value
|
|
64
72
|
}
|
|
65
73
|
|
|
66
74
|
static push(array: any, value?: any, ...values: any[]): (cursor?: string | number, ...cursors: (string | number)[]) => any {
|
|
@@ -69,6 +77,12 @@ export default class m {
|
|
|
69
77
|
static unshift(array: any, value?: any, ...values: any[]): (cursor?: string | number, ...cursors: (string | number)[]) => any {
|
|
70
78
|
return cursorBuilder("unshift", array, value, ...values)
|
|
71
79
|
}
|
|
80
|
+
static removeKeys(arrayOrObj: any, deletedItemKeys: string[]): (cursor?: string | number, ...cursors: (string | number)[]) => any {
|
|
81
|
+
return cursorBuilder("batch", arrayOrObj, (arrOrObj: any) => _removeKeys(arrOrObj, deletedItemKeys))
|
|
82
|
+
}
|
|
83
|
+
static replaceItem<T>(arrayOrObj: any, filter: (item: T, index: number) => boolean, newItem: T): (cursor?: string | number, ...cursors: (string | number)[]) => any {
|
|
84
|
+
return cursorBuilder("batch", arrayOrObj, (arrOrObj: any) => _replaceItem(arrOrObj, filter, newItem))
|
|
85
|
+
}
|
|
72
86
|
static splice(array: any, index: number, deleteCount: number, value?: any, ...values: any[]): (cursor?: string | number, ...cursors: (string | number)[]) => any {
|
|
73
87
|
return cursorBuilder("splice", array, index, deleteCount, value, ...values)
|
|
74
88
|
}
|
|
@@ -84,32 +98,6 @@ export default class m {
|
|
|
84
98
|
static assign(obj: any, obj1: any): (cursor?: string | number, ...cursors: (string | number)[]) => any {
|
|
85
99
|
return cursorBuilder("assign", obj, deepCopy(obj1))
|
|
86
100
|
}
|
|
87
|
-
|
|
88
|
-
// static deepMerge(obj: any, obj1: any) {
|
|
89
|
-
// return (cursor?: string | number, ...cursors: (string | number)[]) => {
|
|
90
|
-
// function mergeDeep(target: any, source: any): any {
|
|
91
|
-
// const isObject = (obj) => obj && typeof obj === 'object';
|
|
92
|
-
// if (!isObject(target) || !isObject(source)) {
|
|
93
|
-
// return source;
|
|
94
|
-
// }
|
|
95
|
-
// Object.keys(source).forEach(key => {
|
|
96
|
-
// const targetValue = target[key];
|
|
97
|
-
// const sourceValue = source[key];
|
|
98
|
-
// if (Array.isArray(targetValue) && Array.isArray(sourceValue)) {
|
|
99
|
-
// target[key] = targetValue.concat(sourceValue);
|
|
100
|
-
// } else if (isObject(targetValue) && isObject(sourceValue)) {
|
|
101
|
-
// target[key] = mergeDeep(Object.assign({}, targetValue), sourceValue);
|
|
102
|
-
// } else {
|
|
103
|
-
// target[key] = sourceValue;
|
|
104
|
-
// }
|
|
105
|
-
// });
|
|
106
|
-
// return target;
|
|
107
|
-
// }
|
|
108
|
-
// const allCursors = [cursor, ...cursors].filter((x) => x != undefined)
|
|
109
|
-
// let addressedObj = obj[cursor]
|
|
110
|
-
// return mergeDeep(addressedObj, obj1)
|
|
111
|
-
// }
|
|
112
|
-
// }
|
|
113
101
|
}
|
|
114
102
|
|
|
115
103
|
function cursorBuilder(command: string, array: any, value: any, ...values: any[]): (cursor?: string | number, ...cursors: (string | number)[]) => any {
|
|
@@ -126,8 +114,46 @@ function cursorBuilder(command: string, array: any, value: any, ...values: any[]
|
|
|
126
114
|
}
|
|
127
115
|
|
|
128
116
|
|
|
117
|
+
function _removeKeys(objOrArr: any, keysToRemove: string[]) {
|
|
118
|
+
if (Array.isArray(objOrArr)) {
|
|
119
|
+
return objOrArr.map(obj => {
|
|
120
|
+
let newObj = { ...obj };
|
|
121
|
+
keysToRemove.forEach(key => {
|
|
122
|
+
delete newObj[key];
|
|
123
|
+
});
|
|
124
|
+
return newObj;
|
|
125
|
+
});
|
|
126
|
+
} else {
|
|
127
|
+
let newObj = { ...objOrArr };
|
|
128
|
+
keysToRemove.forEach(key => {
|
|
129
|
+
delete newObj[key];
|
|
130
|
+
});
|
|
131
|
+
return newObj;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function _replaceItem(data: any, predicate: (item: any, index: number) => boolean, newItem: any) {
|
|
136
|
+
if (Array.isArray(data)) {
|
|
137
|
+
return data.map((item, index) => {
|
|
138
|
+
if (predicate(item, index)) {
|
|
139
|
+
return newItem;
|
|
140
|
+
}
|
|
141
|
+
return item;
|
|
142
|
+
});
|
|
143
|
+
} else if (typeof data === 'object' && data !== null) {
|
|
144
|
+
let newData = { ...data };
|
|
145
|
+
Object.keys(newData).forEach((key, index) => {
|
|
146
|
+
if (predicate(newData[key], index)) {
|
|
147
|
+
newData[key] = newItem;
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
return newData;
|
|
151
|
+
} else
|
|
152
|
+
return data
|
|
153
|
+
}
|
|
154
|
+
|
|
129
155
|
|
|
130
|
-
function deepCopy(o) {
|
|
156
|
+
function deepCopy(o: any) {
|
|
131
157
|
switch (typeof o) {
|
|
132
158
|
case 'object':
|
|
133
159
|
if (o === null) return null;
|
package/package.json
CHANGED
package/persist.ts
CHANGED
|
@@ -1,43 +1,46 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import FastStorage from 'esoftplay/mmkv';
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
3
|
|
|
4
|
+
type usePersistStateReturn<T> = [T, (newState: T | ((newState: T) => T)) => void, () => T];
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
6
|
+
export default function usePersistState<T = any>(persistKey: string, defaultValue?: T): usePersistStateReturn<T> {
|
|
7
|
+
const isMountedRef = useRef<boolean>(true);
|
|
8
|
+
const storedValue = FastStorage.getItemSync(persistKey);
|
|
9
|
+
let parsedValue: T | undefined;
|
|
10
|
+
if (storedValue) {
|
|
11
|
+
try {
|
|
12
|
+
parsedValue = JSON.parse(storedValue);
|
|
13
|
+
} catch (e) {
|
|
14
|
+
parsedValue = defaultValue;
|
|
15
|
+
}
|
|
16
|
+
} else {
|
|
17
|
+
parsedValue = defaultValue;
|
|
15
18
|
}
|
|
19
|
+
const valueRef = useRef<T>(parsedValue as T);
|
|
20
|
+
const [, rerender] = useState({});
|
|
16
21
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (
|
|
20
|
-
|
|
21
|
-
if (callback) callback(json)
|
|
22
|
-
set(json)
|
|
22
|
+
const updateState = useCallback((value: T | ((prevState: T) => T)) => {
|
|
23
|
+
if (isMountedRef.current) {
|
|
24
|
+
if (typeof value === 'function') {
|
|
25
|
+
valueRef.current = (value as (prevState: T) => T)(valueRef.current);
|
|
23
26
|
} else {
|
|
24
|
-
|
|
25
|
-
set(def)
|
|
27
|
+
valueRef.current = value;
|
|
26
28
|
}
|
|
27
|
-
})
|
|
28
|
-
}
|
|
29
29
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
30
|
+
if (valueRef.current != undefined)
|
|
31
|
+
FastStorage.setItem(persistKey, JSON.stringify(valueRef.current))
|
|
32
|
+
else
|
|
33
|
+
FastStorage.removeItem(persistKey)
|
|
34
|
+
rerender({});
|
|
35
|
+
}
|
|
36
|
+
}, []);
|
|
33
37
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
updater()
|
|
38
|
+
useEffect(() => {
|
|
39
|
+
isMountedRef.current = true;
|
|
37
40
|
return () => {
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
}, [])
|
|
41
|
+
isMountedRef.current = false;
|
|
42
|
+
};
|
|
43
|
+
}, []);
|
|
41
44
|
|
|
42
|
-
return [
|
|
45
|
+
return [valueRef.current, updateState, () => valueRef.current];
|
|
43
46
|
}
|
package/subscribe.ts
CHANGED
|
@@ -22,10 +22,6 @@ export default function useGlobalSubscriber(defaultValue?: any): useGlobalSubscr
|
|
|
22
22
|
value = defaultValue;
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
-
const trigger = (newValue?: any) => {
|
|
26
|
-
notify(newValue);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
25
|
function useSubscribe(func: Function) {
|
|
30
26
|
React.useLayoutEffect(() => {
|
|
31
27
|
subscribers.add(func)
|
|
@@ -35,7 +31,7 @@ export default function useGlobalSubscriber(defaultValue?: any): useGlobalSubscr
|
|
|
35
31
|
}
|
|
36
32
|
}, [])
|
|
37
33
|
|
|
38
|
-
return
|
|
34
|
+
return notify;
|
|
39
35
|
}
|
|
40
36
|
|
|
41
37
|
function notify(newValue?: any) {
|
|
@@ -51,6 +47,6 @@ export default function useGlobalSubscriber(defaultValue?: any): useGlobalSubscr
|
|
|
51
47
|
getValue,
|
|
52
48
|
useSubscribe,
|
|
53
49
|
reset,
|
|
54
|
-
trigger
|
|
50
|
+
trigger: notify
|
|
55
51
|
};
|
|
56
52
|
}
|