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 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 = app.expo.updates
844
- delete app.expo.updates
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
- app.expo.updates = app.expo.extra
861
- delete app.expo.extra
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", // 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
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": { // add telegram ids to listenReport Error
13
+ "errorReport": { // add telegram ids to listenReport Error
14
14
  "telegramIds": [
15
15
  "111111111"
16
16
  ]
17
17
  },
18
- "group_id":'1,2', // string separated comma
19
- "isDebug": 1, // optional: display console on esp.log('any message'), don't use it for automatic detect the environment (production / development)
20
- "salt": "CHANGE_INTO_YOUR_OWN_SALT", // SALT form config.php in your website
21
- "notification": 1, // optional: to determine is this application have notification or not
22
- "exludeModules":[], // optional: to delete module when listed
23
- "firebase": { // https://console.firebase.google.com - download google-services.json
24
- "apiKey": "FIREBASE_Web_API_Key", // Eg. AIzaSyAvVyNeXI3RTo7Tl5LCBSZ-mu92VpbPBK8Y
25
- "authDomain": "FIREBASE_authDomain", // Eg. project-6495177974885932998.firebaseapp.com
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":[], // untuk custom theme jika diperlukan,silahkan lihat module LibTheme untuk cara peggunaannya
33
- "fonts":{
34
- "fontName":"fontName.ttf or .otf", // taruh file font di assets/fonts/ jika ingin custom fonts. bisa lebih dari 1
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
- AsyncStorage.setItem(`${config?.domain}error`, JSON.stringify(_e));
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
- AsyncStorage.getItem(config?.domain + 'error').then((e: any) => {
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
- AsyncStorage.removeItem(config.domain + 'error')
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: string): any {
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?: string, ...params: string[]): any {
82
- let out: any = esp._config();
85
+ config<T = ConfigType>(param?: keyof ConfigType, ...params: string[]): T {
86
+ let out: any = this._config();
83
87
  if (param) {
84
- var _params = [param, ...params]
85
- if (_params.length > 0)
86
- for (let i = 0; i < _params.length; i++) {
87
- const key = _params[i];
88
- if (out?.hasOwnProperty?.(key)) {
89
- out = out[key];
90
- } else {
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
- return out;
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: string, langName: string, ...stringToBe: string[]): string {
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(): string {
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
- var config = {
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
- render: (props: T) => any,
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 sync: any = undefined
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
- if (o?.useAutoSync && sync && Array.isArray(value))
56
- sync?.(value.filter((item: any) => item.synced != 1))
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
- sync = UseTasks()((item) => new Promise((next) => {
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
- })[0]
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 && sync)
163
- sync?.(newValue.filter((item: any) => item.synced != 1))
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): void {
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 [state] = useState()
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
+ }
@@ -3,10 +3,10 @@
3
3
  import { update } from "immhelper";
4
4
 
5
5
  export default class m {
6
- _value = undefined
6
+ #value = undefined
7
7
 
8
8
  constructor(array: any) {
9
- this._value = array
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._value = update(array, spec)
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._value, value, ...values)
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._value, value, ...values)
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._value, index, deleteCount, value, ...values)
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._value, index, ...indexs)
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._value, value)
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._value, callback)
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._value, deepCopy(obj1))
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._value
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "esoftplay",
3
- "version": "0.0.140",
3
+ "version": "0.0.141",
4
4
  "description": "embedding data from esoftplay framework (web based) into mobile app",
5
5
  "main": "cache/index.js",
6
6
  "types": "../../index.d.ts",
package/persist.ts CHANGED
@@ -1,43 +1,46 @@
1
- import AsyncStorage from '@react-native-async-storage/async-storage';
2
- import { useLayoutEffect, useState } from 'react';
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
- let setter = new Set<Function>()
6
- export default function usePersistState(key: string, def?: any): any[] {
7
- const [state, setState] = useState(def || undefined)
8
-
9
- function set(value: any) {
10
- if (value == undefined)
11
- AsyncStorage.removeItem(key)
12
- else
13
- AsyncStorage.setItem(key, JSON.stringify(value));
14
- setter.forEach((c) => c?.(value))
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
- function updater(callback?: (a?: typeof def) => void) {
18
- AsyncStorage.getItem(key).then((v: string | undefined) => {
19
- if (v) {
20
- const json = JSON.parse(v)
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
- if (callback) callback(def)
25
- set(def)
27
+ valueRef.current = value;
26
28
  }
27
- })
28
- }
29
29
 
30
- function del() {
31
- AsyncStorage.removeItem(key)
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
- useLayoutEffect(() => {
35
- setter.add(setState)
36
- updater()
38
+ useEffect(() => {
39
+ isMountedRef.current = true;
37
40
  return () => {
38
- setter.delete(setState)
39
- }
40
- }, [])
41
+ isMountedRef.current = false;
42
+ };
43
+ }, []);
41
44
 
42
- return [state, set, updater, del]
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 trigger;
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
  }