@quicktvui/web-renderer 1.0.0

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.
Files changed (56) hide show
  1. package/package.json +24 -0
  2. package/src/adapters/es3-video-player.js +828 -0
  3. package/src/components/Modal.js +119 -0
  4. package/src/components/QtAnimationView.js +678 -0
  5. package/src/components/QtBaseComponent.js +165 -0
  6. package/src/components/QtFastListView.js +1920 -0
  7. package/src/components/QtFlexView.js +799 -0
  8. package/src/components/QtImage.js +203 -0
  9. package/src/components/QtItemFrame.js +239 -0
  10. package/src/components/QtItemStoreView.js +93 -0
  11. package/src/components/QtItemView.js +125 -0
  12. package/src/components/QtListView.js +331 -0
  13. package/src/components/QtLoadingView.js +55 -0
  14. package/src/components/QtPageRootView.js +19 -0
  15. package/src/components/QtPlayMark.js +168 -0
  16. package/src/components/QtProgressBar.js +199 -0
  17. package/src/components/QtQRCode.js +78 -0
  18. package/src/components/QtReplaceChild.js +149 -0
  19. package/src/components/QtRippleView.js +166 -0
  20. package/src/components/QtSeekBar.js +409 -0
  21. package/src/components/QtText.js +679 -0
  22. package/src/components/QtTransitionImage.js +170 -0
  23. package/src/components/QtView.js +706 -0
  24. package/src/components/QtWebView.js +613 -0
  25. package/src/components/TabsView.js +420 -0
  26. package/src/components/ViewPager.js +206 -0
  27. package/src/components/index.js +24 -0
  28. package/src/components/plugins/TextV2Component.js +70 -0
  29. package/src/components/plugins/index.js +7 -0
  30. package/src/core/SceneBuilder.js +58 -0
  31. package/src/core/TVFocusManager.js +2014 -0
  32. package/src/core/asyncLocalStorage.js +175 -0
  33. package/src/core/autoProxy.js +165 -0
  34. package/src/core/componentRegistry.js +84 -0
  35. package/src/core/constants.js +6 -0
  36. package/src/core/index.js +8 -0
  37. package/src/core/moduleUtils.js +36 -0
  38. package/src/core/patches.js +958 -0
  39. package/src/core/templateBinding.js +666 -0
  40. package/src/index.js +246 -0
  41. package/src/modules/AndroidDevelopModule.js +101 -0
  42. package/src/modules/AndroidDeviceModule.js +341 -0
  43. package/src/modules/AndroidNetworkModule.js +178 -0
  44. package/src/modules/AndroidSharedPreferencesModule.js +100 -0
  45. package/src/modules/ESDeviceInfoModule.js +450 -0
  46. package/src/modules/ESGroupDataModule.js +195 -0
  47. package/src/modules/ESIJKAudioPlayerModule.js +477 -0
  48. package/src/modules/ESLocalStorageModule.js +100 -0
  49. package/src/modules/ESLogModule.js +65 -0
  50. package/src/modules/ESModule.js +106 -0
  51. package/src/modules/ESNetworkSpeedModule.js +117 -0
  52. package/src/modules/ESToastModule.js +172 -0
  53. package/src/modules/EsNativeModule.js +117 -0
  54. package/src/modules/FastListModule.js +101 -0
  55. package/src/modules/FocusModule.js +145 -0
  56. package/src/modules/RuntimeDeviceModule.js +176 -0
package/src/index.js ADDED
@@ -0,0 +1,246 @@
1
+ // Web Renderer Module
2
+ // Main entry point for web renderer components and utilities
3
+
4
+ // Core modules
5
+ export * from './core'
6
+
7
+ // Components
8
+ export * from './components'
9
+
10
+ // Create component registry for web renderer
11
+ import { HippyWebEngine } from '@hippy/web-renderer'
12
+ import { QtView, createNamedComponent } from './components/QtView'
13
+ import { QtText } from './components/QtText'
14
+ import { QtImage } from './components/QtImage'
15
+ import { QtTransitionImage } from './components/QtTransitionImage'
16
+ import { QtPageRootView } from './components/QtPageRootView'
17
+ import { QtFastListView } from './components/QtFastListView'
18
+ import { QtLoadingView } from './components/QtLoadingView'
19
+ import { QtAnimationView } from './components/QtAnimationView'
20
+ import { QtWebView } from './components/QtWebView'
21
+ import { QtQRCode } from './components/QtQRCode'
22
+ import { QtProgressBar } from './components/QtProgressBar'
23
+ import { QtSeekBar } from './components/QtSeekBar'
24
+ import { QtItemFrame } from './components/QtItemFrame'
25
+ import { QtItemStoreView } from './components/QtItemStoreView'
26
+ import { QtRippleView } from './components/QtRippleView'
27
+ import { QtFlexView } from './components/QtFlexView'
28
+ import { QtItemView } from './components/QtItemView'
29
+ import { TabsView } from './components/TabsView'
30
+ import { ViewPager } from './components/ViewPager'
31
+ import { Modal } from './components/Modal'
32
+ import { QtListView, QtListViewItem } from './components/QtListView'
33
+ import { QtPlayMark } from './components/QtPlayMark'
34
+ import { APP_NAME } from './core/constants'
35
+ import { ESModule } from './modules/ESModule'
36
+ import { ESLocalStorageModule } from './modules/ESLocalStorageModule'
37
+ import { EsNativeModule } from './modules/EsNativeModule'
38
+ import { AndroidSharedPreferencesModule } from './modules/AndroidSharedPreferencesModule'
39
+ import { AndroidDevelopModule } from './modules/AndroidDevelopModule'
40
+ import { AndroidNetworkModule } from './modules/AndroidNetworkModule'
41
+ import { ESToastModule } from './modules/ESToastModule'
42
+ import { RuntimeDeviceModule } from './modules/RuntimeDeviceModule'
43
+ import { ESIJKAudioPlayerModule } from './modules/ESIJKAudioPlayerModule'
44
+ import { ESLogModule } from './modules/ESLogModule'
45
+ import { FastListModule } from './modules/FastListModule'
46
+ import { FocusModule } from './modules/FocusModule'
47
+ import { ESDeviceInfoModule } from './modules/ESDeviceInfoModule'
48
+ import { ESGroupDataModule } from './modules/ESGroupDataModule'
49
+ import { TextV2Component } from './components/plugins'
50
+ import { IJKPlayerComponent } from './adapters/es3-video-player'
51
+ // Create named versions of base components
52
+ const QtViewNamed = createNamedComponent(QtView, 'View')
53
+ const QtTextNamed = createNamedComponent(QtText, 'Text')
54
+ const QtImageNamed = createNamedComponent(QtImage, 'Image')
55
+
56
+ // Component registry for HippyWebEngine
57
+ // ListView and ListViewItem are overridden with QtListView/QtListViewItem
58
+ // to support TV-specific features like fadingEdgeLength, horizontalFadingEdgeEnabled, etc.
59
+ export const quicktvuiComponents = {
60
+ // Core Hippy native components (overriding some defaults)
61
+ View: QtViewNamed,
62
+ Text: QtTextNamed,
63
+ Image: QtImageNamed,
64
+ // Override ListView and ListViewItem with TV-specific adapters
65
+ ListView: QtListView,
66
+ ListViewItem: QtListViewItem,
67
+ ScrollView: createNamedComponent(QtView, 'ScrollView'),
68
+ TextInput: createNamedComponent(QtView, 'TextInput'),
69
+ WebView: QtWebView,
70
+ ViewPager: createNamedComponent(QtView, 'ViewPager'),
71
+ FastListView: QtFastListView,
72
+ TextView: QtTextNamed,
73
+
74
+ // ESRouter native components
75
+ ESPageRouterView: createNamedComponent(QtView, 'ESPageRouterView'),
76
+ ESPageRootView: QtPageRootView,
77
+ ESSlotRootView: createNamedComponent(QtView, 'ESSlotRootView'),
78
+ ESSlotView: createNamedComponent(QtView, 'ESSlotView'),
79
+
80
+ // Loading component
81
+ LoadingViewComponent: QtLoadingView,
82
+
83
+ // Animation component
84
+ AnimationViewComponent: QtAnimationView,
85
+
86
+ // WebView component
87
+ ESWebViewComponent: QtWebView,
88
+
89
+ // X5WebView component (uses same implementation as WebView)
90
+ ESX5WebViewComponent: QtWebView,
91
+
92
+ // QR Code component
93
+ QrCodeComponent: QtQRCode,
94
+
95
+ // ProgressBar component
96
+ TVProgressBarViewComponent: QtProgressBar,
97
+
98
+ // SeekBar component
99
+ TVSeekBarViewComponent: QtSeekBar,
100
+
101
+ // GridView/List component - both use QtFastListView with spanCount
102
+ TVListViewComponent: QtFastListView,
103
+
104
+ // ItemFrame component (simple container for qt-poster)
105
+ ItemFrameComponent: QtItemFrame,
106
+
107
+ // ItemStoreView component (shared item templates for waterfall)
108
+ ItemStoreView: QtItemStoreView,
109
+
110
+ // RippleView component
111
+ RippleViewComponent: QtRippleView,
112
+
113
+ // FlexView component (for tv-flex / waterfall)
114
+ FastFlexView: QtFlexView,
115
+
116
+ // ItemView component (for tv-item / waterfall sections)
117
+ FastItemView: QtItemView,
118
+
119
+ // Tabs component (for qt-tabs)
120
+ TabsView: TabsView,
121
+
122
+ // RecyclerViewPager component (for qt-tabs content)
123
+ RecyclerViewPager: ViewPager,
124
+
125
+ // Modal component (for qt-dialog)
126
+ Modal: Modal,
127
+
128
+ // Plugin components
129
+ TextV2Component: TextV2Component,
130
+
131
+ // TransitionImage component (for img-transition)
132
+ TransitionImageComponent: QtTransitionImage,
133
+
134
+ // Video player component (IJKPlayer for web)
135
+ IJKPlayerComponent: IJKPlayerComponent,
136
+
137
+ // PlayMark component
138
+ ESPlayMarkViewComponent: QtPlayMark,
139
+ }
140
+
141
+ // Create and configure the web engine
142
+ export function createWebEngine() {
143
+ console.log('[Web Renderer] Creating HippyWebEngine...')
144
+
145
+ const engine = HippyWebEngine.create({
146
+ modules: {
147
+ ESModule,
148
+ ESLocalStorageModule,
149
+ EsNativeModule,
150
+ AndroidSharedPreferencesModule,
151
+ AndroidDevelopModule,
152
+ AndroidNetworkModule,
153
+ ESToastModule,
154
+ RuntimeDeviceModule,
155
+ ESIJKAudioPlayerModule,
156
+ ESLogModule,
157
+ FastListModule,
158
+ FocusModule,
159
+ ESDeviceInfoModule,
160
+ ESGroupDataModule,
161
+ },
162
+ components: quicktvuiComponents,
163
+ })
164
+
165
+ console.log('[Web Renderer] Engine created')
166
+
167
+ // Register ListView and ListViewItem (override Hippy's built-in)
168
+ // These support TV-specific features like fadingEdgeLength, horizontalFadingEdgeEnabled
169
+ engine.registerComponent('ListView', QtListView)
170
+ engine.registerComponent('ListViewItem', QtListViewItem)
171
+
172
+ // Override built-in Image component
173
+ engine.registerComponent('Image', QtImage)
174
+
175
+ // Register ESWebViewComponent
176
+ engine.registerComponent('ESWebViewComponent', QtWebView)
177
+
178
+ // Register ESX5WebViewComponent
179
+ engine.registerComponent('ESX5WebViewComponent', QtWebView)
180
+
181
+ // Register QrCodeComponent
182
+ engine.registerComponent('QrCodeComponent', QtQRCode)
183
+
184
+ // Register TVProgressBarViewComponent
185
+ engine.registerComponent('TVProgressBarViewComponent', QtProgressBar)
186
+
187
+ // Register TVSeekBarViewComponent
188
+ engine.registerComponent('TVSeekBarViewComponent', QtSeekBar)
189
+
190
+ // Register TVListViewComponent (for qt-grid-view) - uses QtFastListView
191
+ engine.registerComponent('TVListViewComponent', QtFastListView)
192
+
193
+ // Register ItemFrameComponent (simple container for qt-poster)
194
+ engine.registerComponent('ItemFrameComponent', QtItemFrame)
195
+
196
+ // Register ItemStoreView (shared item templates for waterfall)
197
+ engine.registerComponent('ItemStoreView', QtItemStoreView)
198
+
199
+ // Register RippleViewComponent
200
+ engine.registerComponent('RippleViewComponent', QtRippleView)
201
+
202
+ // Register FastFlexView (for tv-flex / waterfall)
203
+ engine.registerComponent('FastFlexView', QtFlexView)
204
+
205
+ // Register FastItemView (for tv-item / waterfall sections)
206
+ engine.registerComponent('FastItemView', QtItemView)
207
+
208
+ // Register TabsView (for qt-tabs)
209
+ engine.registerComponent('TabsView', TabsView)
210
+
211
+ // Register RecyclerViewPager (for qt-tabs content)
212
+ engine.registerComponent('RecyclerViewPager', ViewPager)
213
+
214
+ // Register Modal (for qt-dialog)
215
+ engine.registerComponent('Modal', Modal)
216
+
217
+ // Register Plugin components
218
+ engine.registerComponent('TextV2Component', TextV2Component)
219
+
220
+ // Register TransitionImageComponent
221
+ engine.registerComponent('TransitionImageComponent', QtTransitionImage)
222
+
223
+ // Register IJKPlayerComponent (video player)
224
+ engine.registerComponent('IJKPlayerComponent', IJKPlayerComponent)
225
+
226
+ // Register ESPlayMarkViewComponent (play mark animation)
227
+ engine.registerComponent('ESPlayMarkViewComponent', QtPlayMark)
228
+
229
+ return engine
230
+ }
231
+
232
+ // Start the web engine
233
+ export function startWebEngine(engine) {
234
+ engine.start({
235
+ id: 'app',
236
+ name: APP_NAME,
237
+ params: {
238
+ business: APP_NAME,
239
+ data: {},
240
+ },
241
+ })
242
+
243
+ console.log('[Web Renderer] Engine started')
244
+ }
245
+
246
+ export { APP_NAME }
@@ -0,0 +1,101 @@
1
+ /**
2
+ * ESDevelopModule - Web平台适配器
3
+ * 提供应用开发信息(版本号、包名、渠道等)
4
+ */
5
+
6
+ // 存储开发信息
7
+ let developInfo = null
8
+
9
+ function getPackageName() {
10
+ const g = globalThis
11
+ if (g && g.__CONFIG__ && g.__CONFIG__.packageName) {
12
+ return g.__CONFIG__.packageName
13
+ }
14
+ return 'web'
15
+ }
16
+
17
+ function ensureDevelopInfo() {
18
+ if (!developInfo) {
19
+ developInfo = {
20
+ versionCode: 1,
21
+ versionName: '1.0.0',
22
+ packageName: getPackageName(),
23
+ channel: 'web',
24
+ }
25
+ }
26
+ return developInfo
27
+ }
28
+
29
+ export class AndroidDevelopModule {
30
+ constructor(context) {
31
+ this.context = context
32
+ this.name = 'AndroidDevelopModule'
33
+ }
34
+
35
+ init(...args) {
36
+ const addon = args && args.length ? args[args.length - 1] : null
37
+ const info = ensureDevelopInfo()
38
+ if (addon && typeof addon.resolve === 'function') {
39
+ addon.resolve(info)
40
+ }
41
+ return info
42
+ }
43
+
44
+ destroy() {
45
+ developInfo = null
46
+ }
47
+
48
+ getDevelop(...args) {
49
+ const addon = args && args.length ? args[args.length - 1] : null
50
+ const info = ensureDevelopInfo()
51
+ if (addon && typeof addon.resolve === 'function') {
52
+ addon.resolve(info)
53
+ }
54
+ // 返回 Promise,与原生平台行为一致
55
+ return Promise.resolve(info)
56
+ }
57
+
58
+ getPackageName(...args) {
59
+ const addon = args && args.length ? args[args.length - 1] : null
60
+ const name = getPackageName()
61
+ if (addon && typeof addon.resolve === 'function') {
62
+ addon.resolve(name)
63
+ }
64
+ return name
65
+ }
66
+
67
+ getVersionName(...args) {
68
+ const addon = args && args.length ? args[args.length - 1] : null
69
+ const info = ensureDevelopInfo()
70
+ const value = info.versionName
71
+ if (addon && typeof addon.resolve === 'function') {
72
+ addon.resolve(value)
73
+ }
74
+ return value
75
+ }
76
+
77
+ getVersionCode(...args) {
78
+ const addon = args && args.length ? args[args.length - 1] : null
79
+ const info = ensureDevelopInfo()
80
+ const value = info.versionCode
81
+ if (addon && typeof addon.resolve === 'function') {
82
+ addon.resolve(value)
83
+ }
84
+ return value
85
+ }
86
+
87
+ getChannel(...args) {
88
+ const addon = args && args.length ? args[args.length - 1] : null
89
+ const info = ensureDevelopInfo()
90
+ const value = info.channel
91
+ if (addon && typeof addon.resolve === 'function') {
92
+ addon.resolve(value)
93
+ }
94
+ return value
95
+ }
96
+
97
+ // getVendor 是 getChannel 的别名
98
+ getVendor(...args) {
99
+ return this.getChannel(...args)
100
+ }
101
+ }
@@ -0,0 +1,341 @@
1
+ // Web platform adapter for AndroidDeviceModule
2
+ // Provides simulated device information for web browser environment
3
+
4
+ /**
5
+ * @typedef {Object} ESDeviceInfo
6
+ * @property {string} cid - Device ID
7
+ * @property {string} device_name - Device name
8
+ * @property {string} device_ip - Device IP address
9
+ * @property {string} eth_mac - Ethernet MAC address
10
+ * @property {string} wifi_mac - WiFi MAC address
11
+ * @property {number} total_memory - Total memory in bytes
12
+ * @property {number} avail_memory - Available memory in bytes
13
+ * @property {number} screen_width - Screen width in pixels
14
+ * @property {number} screen_height - Screen height in pixels
15
+ * @property {string} resolution - Screen resolution string
16
+ * @property {number} density - Screen density
17
+ * @property {number} density_dpi - Screen density DPI
18
+ * @property {number} scaled_density - Scaled density
19
+ * @property {string} build_version_release - Android version
20
+ * @property {string} build_model - Device model
21
+ * @property {string} build_brand - Device brand
22
+ * @property {string} build_device - Device name
23
+ * @property {string} build_board - Board name
24
+ * @property {string} build_product - Product name
25
+ * @property {string} build_hardware - Hardware name
26
+ * @property {string} build_manufacturer - Manufacturer name
27
+ */
28
+
29
+ const TV_WIDTH = 1920
30
+ const TV_HEIGHT = 1080
31
+
32
+ class AndroidDeviceModuleClass {
33
+ constructor() {
34
+ this.name = 'AndroidDeviceModule'
35
+ }
36
+
37
+ /**
38
+ * Get complete device information
39
+ * @returns {Promise<ESDeviceInfo>}
40
+ */
41
+ async getAndroidDevice() {
42
+ const screen = this._getScreenInfo()
43
+ return {
44
+ cid: this._generateDeviceId(),
45
+ device_name: 'Web Browser',
46
+ device_ip: await this._getLocalIP(),
47
+ eth_mac: '',
48
+ wifi_mac: this._generateMAC(),
49
+ total_memory: this._estimateTotalMemory(),
50
+ avail_memory: this._estimateAvailMemory(),
51
+ screen_width: screen.width,
52
+ screen_height: screen.height,
53
+ resolution: `${screen.width}x${screen.height}`,
54
+ density: screen.density,
55
+ density_dpi: screen.densityDpi,
56
+ scaled_density: screen.scaledDensity,
57
+ build_version_release: 'Web',
58
+ build_model: this._getBrowserInfo(),
59
+ build_brand: 'Web',
60
+ build_device: 'Browser',
61
+ build_board: 'Web',
62
+ build_product: 'quicktvui-web',
63
+ build_hardware: 'Web',
64
+ build_manufacturer: 'quicktvui',
65
+ }
66
+ }
67
+
68
+ /**
69
+ * Get Ethernet MAC address
70
+ * @returns {Promise<string>}
71
+ */
72
+ async getEthMac() {
73
+ return ''
74
+ }
75
+
76
+ /**
77
+ * Get WiFi MAC address
78
+ * @returns {Promise<string>}
79
+ */
80
+ async getWifiMac() {
81
+ return this._generateMAC()
82
+ }
83
+
84
+ /**
85
+ * Get total memory in bytes
86
+ * @returns {Promise<number>}
87
+ */
88
+ async getTotalMemory() {
89
+ return this._estimateTotalMemory()
90
+ }
91
+
92
+ /**
93
+ * Get available memory in bytes
94
+ * @returns {Promise<number>}
95
+ */
96
+ async getAvailableMemory() {
97
+ return this._estimateAvailMemory()
98
+ }
99
+
100
+ /**
101
+ * Get screen width
102
+ * @returns {Promise<number>}
103
+ */
104
+ async getScreenWidth() {
105
+ return this._getScreenInfo().width
106
+ }
107
+
108
+ /**
109
+ * Get screen height
110
+ * @returns {Promise<number>}
111
+ */
112
+ async getScreenHeight() {
113
+ return this._getScreenInfo().height
114
+ }
115
+
116
+ /**
117
+ * Get screen resolution string
118
+ * @returns {Promise<string>}
119
+ */
120
+ async getResolution() {
121
+ const screen = this._getScreenInfo()
122
+ return `${screen.width}x${screen.height}`
123
+ }
124
+
125
+ /**
126
+ * Get screen density
127
+ * @returns {Promise<number>}
128
+ */
129
+ async getDensity() {
130
+ return this._getScreenInfo().density
131
+ }
132
+
133
+ /**
134
+ * Get screen density DPI
135
+ * @returns {Promise<number>}
136
+ */
137
+ async getDensityDpi() {
138
+ return this._getScreenInfo().densityDpi
139
+ }
140
+
141
+ /**
142
+ * Get scaled density
143
+ * @returns {Promise<number>}
144
+ */
145
+ async getScaledDensity() {
146
+ return this._getScreenInfo().scaledDensity
147
+ }
148
+
149
+ /**
150
+ * Get Android version (simulated for web)
151
+ * @returns {Promise<string>}
152
+ */
153
+ async getBuildVersionRelease() {
154
+ return 'Web'
155
+ }
156
+
157
+ /**
158
+ * Get device model
159
+ * @returns {Promise<string>}
160
+ */
161
+ async getBuildModel() {
162
+ return this._getBrowserInfo()
163
+ }
164
+
165
+ /**
166
+ * Get device brand
167
+ * @returns {Promise<string>}
168
+ */
169
+ async getBuildBrand() {
170
+ return 'Web'
171
+ }
172
+
173
+ /**
174
+ * Get device name
175
+ * @returns {Promise<string>}
176
+ */
177
+ async getBuildDevice() {
178
+ return 'Browser'
179
+ }
180
+
181
+ /**
182
+ * Get board name
183
+ * @returns {Promise<string>}
184
+ */
185
+ async getBuildBoard() {
186
+ return 'Web'
187
+ }
188
+
189
+ /**
190
+ * Get product name
191
+ * @returns {Promise<string>}
192
+ */
193
+ async getBuildProduct() {
194
+ return 'quicktvui-web'
195
+ }
196
+
197
+ /**
198
+ * Get hardware name
199
+ * @returns {Promise<string>}
200
+ */
201
+ async getBuildHardware() {
202
+ return 'Web'
203
+ }
204
+
205
+ /**
206
+ * Get manufacturer name
207
+ * @returns {Promise<string>}
208
+ */
209
+ async getBuildManufacturer() {
210
+ return 'quicktvui'
211
+ }
212
+
213
+ // ============ Private helper methods ============
214
+
215
+ /**
216
+ * Get screen information
217
+ * @private
218
+ */
219
+ _getScreenInfo() {
220
+ if (typeof window === 'undefined') {
221
+ return {
222
+ width: TV_WIDTH,
223
+ height: TV_HEIGHT,
224
+ density: 1,
225
+ densityDpi: 160,
226
+ scaledDensity: 1,
227
+ }
228
+ }
229
+
230
+ const dpr = window.devicePixelRatio || 1
231
+ return {
232
+ width: TV_WIDTH,
233
+ height: TV_HEIGHT,
234
+ density: dpr,
235
+ densityDpi: Math.round(dpr * 160),
236
+ scaledDensity: dpr,
237
+ }
238
+ }
239
+
240
+ /**
241
+ * Generate a random device ID
242
+ * @private
243
+ */
244
+ _generateDeviceId() {
245
+ // Try to get from localStorage for persistence
246
+ if (typeof localStorage !== 'undefined') {
247
+ let cid = localStorage.getItem('__ES_DEVICE_ID__')
248
+ if (!cid) {
249
+ cid = 'web-' + Math.random().toString(36).substring(2, 15)
250
+ localStorage.setItem('__ES_DEVICE_ID__', cid)
251
+ }
252
+ return cid
253
+ }
254
+ return 'web-' + Math.random().toString(36).substring(2, 15)
255
+ }
256
+
257
+ /**
258
+ * Generate a fake MAC address
259
+ * @private
260
+ */
261
+ _generateMAC() {
262
+ const hexDigits = '0123456789ABCDEF'
263
+ let mac = ''
264
+ for (let i = 0; i < 6; i++) {
265
+ if (i > 0) mac += ':'
266
+ mac += hexDigits.charAt(Math.floor(Math.random() * 16))
267
+ mac += hexDigits.charAt(Math.floor(Math.random() * 16))
268
+ }
269
+ return mac
270
+ }
271
+
272
+ /**
273
+ * Get local IP (returns empty string as we can't detect it in browser)
274
+ * @private
275
+ */
276
+ async _getLocalIP() {
277
+ // WebRTC can sometimes detect local IP, but it's not reliable
278
+ // Return empty string for simplicity
279
+ return ''
280
+ }
281
+
282
+ /**
283
+ * Estimate total memory using Performance API
284
+ * @private
285
+ */
286
+ _estimateTotalMemory() {
287
+ if (typeof performance !== 'undefined' && performance.memory) {
288
+ return performance.memory.jsHeapSizeLimit || 1073741824 // 1GB default
289
+ }
290
+ return 1073741824 // 1GB default for web
291
+ }
292
+
293
+ /**
294
+ * Estimate available memory using Performance API
295
+ * @private
296
+ */
297
+ _estimateAvailMemory() {
298
+ if (typeof performance !== 'undefined' && performance.memory) {
299
+ const limit = performance.memory.jsHeapSizeLimit || 1073741824
300
+ const used = performance.memory.usedJSHeapSize || 0
301
+ return Math.max(0, limit - used)
302
+ }
303
+ return 536870912 // 512MB default
304
+ }
305
+
306
+ /**
307
+ * Get browser information
308
+ * @private
309
+ */
310
+ _getBrowserInfo() {
311
+ if (typeof navigator === 'undefined') {
312
+ return 'Unknown Browser'
313
+ }
314
+
315
+ const ua = navigator.userAgent
316
+ let browserName = 'Unknown Browser'
317
+
318
+ if (ua.indexOf('Firefox') > -1) {
319
+ browserName = 'Firefox'
320
+ } else if (ua.indexOf('Edg') > -1) {
321
+ browserName = 'Edge'
322
+ } else if (ua.indexOf('Chrome') > -1) {
323
+ browserName = 'Chrome'
324
+ } else if (ua.indexOf('Safari') > -1) {
325
+ browserName = 'Safari'
326
+ } else if (ua.indexOf('Opera') > -1 || ua.indexOf('OPR') > -1) {
327
+ browserName = 'Opera'
328
+ }
329
+
330
+ // Extract version
331
+ const match = ua.match(/(Firefox|Chrome|Safari|Edg|OPR)\/(\d+)/)
332
+ if (match) {
333
+ return `${match[1]} ${match[2]}`
334
+ }
335
+
336
+ return browserName
337
+ }
338
+ }
339
+
340
+ // Create singleton instance and export
341
+ export const AndroidDeviceModule = new AndroidDeviceModuleClass()