@kontextso/sdk-react-native 2.2.0-rc.2 → 2.2.0-rc.4

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/dist/index.js CHANGED
@@ -124,6 +124,7 @@ var Format = ({ code, messageId, wrapper, ...otherParams }) => {
124
124
  const webViewRef = (0, import_react2.useRef)(null);
125
125
  const modalWebViewRef = (0, import_react2.useRef)(null);
126
126
  const modalInitTimeoutRef = (0, import_react2.useRef)(null);
127
+ const isModalInitRef = (0, import_react2.useRef)(false);
127
128
  const { height: windowHeight, width: windowWidth } = (0, import_react_native.useWindowDimensions)();
128
129
  const reset = () => {
129
130
  setHeight(0);
@@ -140,6 +141,7 @@ var Format = ({ code, messageId, wrapper, ...otherParams }) => {
140
141
  clearTimeout(modalInitTimeoutRef.current);
141
142
  modalInitTimeoutRef.current = null;
142
143
  }
144
+ isModalInitRef.current = false;
143
145
  setModalOpen(false);
144
146
  setModalLoaded(false);
145
147
  setModalShown(false);
@@ -221,7 +223,11 @@ var Format = ({ code, messageId, wrapper, ...otherParams }) => {
221
223
  break;
222
224
  case "open-component-iframe":
223
225
  setModalOpen(true);
224
- modalInitTimeoutRef.current = setTimeout(resetModal, message.data.timeout ?? 5e3);
226
+ modalInitTimeoutRef.current = setTimeout(() => {
227
+ if (!isModalInitRef.current) {
228
+ resetModal();
229
+ }
230
+ }, message.data.timeout ?? 5e3);
225
231
  break;
226
232
  }
227
233
  },
@@ -251,6 +257,7 @@ var Format = ({ code, messageId, wrapper, ...otherParams }) => {
251
257
  resetModal();
252
258
  break;
253
259
  case "init-component-iframe":
260
+ isModalInitRef.current = true;
254
261
  if (modalInitTimeoutRef.current) {
255
262
  clearTimeout(modalInitTimeoutRef.current);
256
263
  modalInitTimeoutRef.current = null;
@@ -260,6 +267,7 @@ var Format = ({ code, messageId, wrapper, ...otherParams }) => {
260
267
  case "error-component-iframe":
261
268
  case "error-iframe":
262
269
  resetModal();
270
+ context?.captureError(new Error("Processing modal iframe error"));
263
271
  break;
264
272
  case "click-iframe":
265
273
  if (message.data.url) {
@@ -315,7 +323,7 @@ var Format = ({ code, messageId, wrapper, ...otherParams }) => {
315
323
  }, 250);
316
324
  return () => clearInterval(interval);
317
325
  }, []);
318
- if (!context || !bid || !iframeUrl) {
326
+ if (!context || !bid || !iframeUrl || context.isDisabled) {
319
327
  return null;
320
328
  }
321
329
  const getWidth = () => {
@@ -331,38 +339,48 @@ var Format = ({ code, messageId, wrapper, ...otherParams }) => {
331
339
  return 0;
332
340
  };
333
341
  const content = /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
334
- /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native.Modal, { visible: modalOpen, transparent: true, onRequestClose: resetModal, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
335
- import_react_native.View,
342
+ /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
343
+ import_react_native.Modal,
336
344
  {
337
- style: {
338
- flex: 1,
339
- // Don't show the modal until the modal page is loaded and sends 'init-component-iframe' message back to SDK
340
- ...modalShown ? { opacity: 1, pointerEvents: "auto" } : { opacity: 0, pointerEvents: "none" }
341
- },
345
+ visible: modalOpen,
346
+ transparent: true,
347
+ onRequestClose: resetModal,
348
+ animationType: "slide",
349
+ statusBarTranslucent: true,
342
350
  children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
343
- frame_webview_default,
351
+ import_react_native.View,
344
352
  {
345
- ref: modalWebViewRef,
346
- iframeUrl: modalUrl,
347
- onMessage: onModalMessage,
348
353
  style: {
349
- backgroundColor: "transparent",
350
- height: "100%",
351
- width: "100%",
352
- borderWidth: 0
353
- },
354
- onError: () => {
355
- debug("modal-error");
356
- resetModal();
354
+ flex: 1,
355
+ // Don't show the modal until the modal page is loaded and sends 'init-component-iframe' message back to SDK
356
+ ...modalShown ? { opacity: 1, pointerEvents: "auto" } : { opacity: 0, pointerEvents: "none" }
357
357
  },
358
- onLoad: () => {
359
- debug("modal-load");
360
- setModalLoaded(true);
361
- }
358
+ children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
359
+ frame_webview_default,
360
+ {
361
+ ref: modalWebViewRef,
362
+ iframeUrl: modalUrl,
363
+ onMessage: onModalMessage,
364
+ style: {
365
+ backgroundColor: "transparent",
366
+ height: "100%",
367
+ width: "100%",
368
+ borderWidth: 0
369
+ },
370
+ onError: () => {
371
+ debug("modal-error");
372
+ resetModal();
373
+ },
374
+ onLoad: () => {
375
+ debug("modal-load");
376
+ setModalLoaded(true);
377
+ }
378
+ }
379
+ )
362
380
  }
363
381
  )
364
382
  }
365
- ) }),
383
+ ),
366
384
  /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(import_react_native.View, { style: containerStyles, ref: containerRef, children: /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
367
385
  frame_webview_default,
368
386
  {
@@ -372,7 +390,7 @@ var Format = ({ code, messageId, wrapper, ...otherParams }) => {
372
390
  style: {
373
391
  height: getHeight(),
374
392
  width: getWidth(),
375
- background: "transparent",
393
+ backgroundColor: "transparent",
376
394
  borderWidth: 0,
377
395
  ...iframeStyles
378
396
  },
@@ -407,6 +425,9 @@ var import_react_native_device_info = __toESM(require("react-native-device-info"
407
425
  var import_react_native2 = require("react-native");
408
426
  var NativeRNKontext_default = import_react_native2.TurboModuleRegistry.getEnforcing("RNKontext");
409
427
 
428
+ // package.json
429
+ var version = "2.2.0-rc.4";
430
+
410
431
  // src/context/AdsProvider.tsx
411
432
  var import_jsx_runtime4 = require("react/jsx-runtime");
412
433
  ErrorUtils.setGlobalHandler((error, isFatal) => {
@@ -418,41 +439,82 @@ ErrorUtils.setGlobalHandler((error, isFatal) => {
418
439
  });
419
440
  var getDevice = async () => {
420
441
  try {
421
- const os = import_react_native3.Platform.OS;
422
- const systemVersion = import_react_native_device_info.default.getSystemVersion();
423
- const model = import_react_native_device_info.default.getModel();
424
- const brand = import_react_native_device_info.default.getBrand();
425
- const deviceId = import_react_native_device_info.default.getDeviceId();
442
+ const powerState = await import_react_native_device_info.default.getPowerState();
426
443
  const deviceType = import_react_native_device_info.default.getDeviceType();
427
- const appBundleId = import_react_native_device_info.default.getBundleId();
428
- const appVersion = import_react_native_device_info.default.getVersion();
429
- let soundOn = false;
430
- try {
431
- soundOn = await NativeRNKontext_default.isSoundOn();
432
- } catch (error) {
433
- import_sdk_react2.log.warn("Failed to read output volume", error);
434
- }
435
- const rnv = import_react_native3.Platform.constants.reactNativeVersion;
436
- const reactNativeVersion = `${rnv.major}.${rnv.minor}.${rnv.patch}`;
444
+ const soundOn = await NativeRNKontext_default.isSoundOn();
445
+ const screen = import_react_native3.Dimensions.get("screen");
446
+ const mapDeviceTypeToHardwareType = () => {
447
+ switch (deviceType) {
448
+ case "Handset":
449
+ return "handset";
450
+ case "Tablet":
451
+ return "tablet";
452
+ case "Tv":
453
+ return "tv";
454
+ case "Desktop":
455
+ return "desktop";
456
+ default:
457
+ return "other";
458
+ }
459
+ };
437
460
  return {
438
- os,
439
- systemVersion,
440
- reactNativeVersion,
441
- model,
442
- brand,
443
- deviceId,
444
- deviceType,
445
- appBundleId,
446
- appVersion,
447
- soundOn
461
+ hardware: {
462
+ brand: import_react_native_device_info.default.getBrand(),
463
+ model: import_react_native_device_info.default.getModel(),
464
+ type: mapDeviceTypeToHardwareType()
465
+ // bootTime: Not available without native module
466
+ // sdCardAvailable: Not available without native module
467
+ },
468
+ audio: {
469
+ muted: soundOn
470
+ // volume: Requires react-native-volume-manager
471
+ // outputPluggedIn: Not available without native module
472
+ // outputType: Not available without native module
473
+ },
474
+ network: {
475
+ carrier: await import_react_native_device_info.default.getCarrier(),
476
+ userAgent: await import_react_native_device_info.default.getUserAgent()
477
+ // detail: Requires @react-native-community/netinfo
478
+ // type: Requires @react-native-community/netinfo
479
+ },
480
+ os: {
481
+ name: import_react_native3.Platform.OS,
482
+ version: import_react_native_device_info.default.getSystemVersion(),
483
+ locale: Intl.DateTimeFormat().resolvedOptions().locale,
484
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
485
+ },
486
+ screen: {
487
+ darkMode: import_react_native3.Appearance.getColorScheme() === "dark",
488
+ dpr: import_react_native3.PixelRatio.get(),
489
+ height: screen.height,
490
+ width: screen.width,
491
+ orientation: screen.width > screen.height ? "landscape" : "portrait"
492
+ },
493
+ power: {
494
+ batteryLevel: powerState.batteryLevel,
495
+ batteryState: powerState.batteryState,
496
+ lowPowerMode: powerState.lowPowerMode
497
+ }
448
498
  };
449
499
  } catch (error) {
450
500
  console.error(error);
501
+ return {};
451
502
  }
452
- return {};
453
503
  };
504
+ var getApp = async () => ({
505
+ bundleId: import_react_native_device_info.default.getBundleId(),
506
+ firstInstallTime: await import_react_native_device_info.default.getFirstInstallTime(),
507
+ lastUpdateTime: await import_react_native_device_info.default.getLastUpdateTime(),
508
+ startTime: await import_react_native_device_info.default.getStartupTime(),
509
+ version: import_react_native_device_info.default.getVersion()
510
+ });
511
+ var getSdk = async () => ({
512
+ name: "sdk-react-native",
513
+ platform: import_react_native3.Platform.OS === "ios" ? "ios" : "android",
514
+ version
515
+ });
454
516
  var AdsProvider = (props) => {
455
- return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_sdk_react2.AdsProviderInternal, { ...props, getDevice });
517
+ return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_sdk_react2.AdsProviderInternal, { ...props, getDevice, getSdk, getApp });
456
518
  };
457
519
  // Annotate the CommonJS export names for ESM import in node:
458
520
  0 && (module.exports = {
package/dist/index.mjs CHANGED
@@ -93,6 +93,7 @@ var Format = ({ code, messageId, wrapper, ...otherParams }) => {
93
93
  const webViewRef = useRef(null);
94
94
  const modalWebViewRef = useRef(null);
95
95
  const modalInitTimeoutRef = useRef(null);
96
+ const isModalInitRef = useRef(false);
96
97
  const { height: windowHeight, width: windowWidth } = useWindowDimensions();
97
98
  const reset = () => {
98
99
  setHeight(0);
@@ -109,6 +110,7 @@ var Format = ({ code, messageId, wrapper, ...otherParams }) => {
109
110
  clearTimeout(modalInitTimeoutRef.current);
110
111
  modalInitTimeoutRef.current = null;
111
112
  }
113
+ isModalInitRef.current = false;
112
114
  setModalOpen(false);
113
115
  setModalLoaded(false);
114
116
  setModalShown(false);
@@ -190,7 +192,11 @@ var Format = ({ code, messageId, wrapper, ...otherParams }) => {
190
192
  break;
191
193
  case "open-component-iframe":
192
194
  setModalOpen(true);
193
- modalInitTimeoutRef.current = setTimeout(resetModal, message.data.timeout ?? 5e3);
195
+ modalInitTimeoutRef.current = setTimeout(() => {
196
+ if (!isModalInitRef.current) {
197
+ resetModal();
198
+ }
199
+ }, message.data.timeout ?? 5e3);
194
200
  break;
195
201
  }
196
202
  },
@@ -220,6 +226,7 @@ var Format = ({ code, messageId, wrapper, ...otherParams }) => {
220
226
  resetModal();
221
227
  break;
222
228
  case "init-component-iframe":
229
+ isModalInitRef.current = true;
223
230
  if (modalInitTimeoutRef.current) {
224
231
  clearTimeout(modalInitTimeoutRef.current);
225
232
  modalInitTimeoutRef.current = null;
@@ -229,6 +236,7 @@ var Format = ({ code, messageId, wrapper, ...otherParams }) => {
229
236
  case "error-component-iframe":
230
237
  case "error-iframe":
231
238
  resetModal();
239
+ context?.captureError(new Error("Processing modal iframe error"));
232
240
  break;
233
241
  case "click-iframe":
234
242
  if (message.data.url) {
@@ -284,7 +292,7 @@ var Format = ({ code, messageId, wrapper, ...otherParams }) => {
284
292
  }, 250);
285
293
  return () => clearInterval(interval);
286
294
  }, []);
287
- if (!context || !bid || !iframeUrl) {
295
+ if (!context || !bid || !iframeUrl || context.isDisabled) {
288
296
  return null;
289
297
  }
290
298
  const getWidth = () => {
@@ -300,38 +308,48 @@ var Format = ({ code, messageId, wrapper, ...otherParams }) => {
300
308
  return 0;
301
309
  };
302
310
  const content = /* @__PURE__ */ jsxs(Fragment, { children: [
303
- /* @__PURE__ */ jsx2(Modal, { visible: modalOpen, transparent: true, onRequestClose: resetModal, children: /* @__PURE__ */ jsx2(
304
- View,
311
+ /* @__PURE__ */ jsx2(
312
+ Modal,
305
313
  {
306
- style: {
307
- flex: 1,
308
- // Don't show the modal until the modal page is loaded and sends 'init-component-iframe' message back to SDK
309
- ...modalShown ? { opacity: 1, pointerEvents: "auto" } : { opacity: 0, pointerEvents: "none" }
310
- },
314
+ visible: modalOpen,
315
+ transparent: true,
316
+ onRequestClose: resetModal,
317
+ animationType: "slide",
318
+ statusBarTranslucent: true,
311
319
  children: /* @__PURE__ */ jsx2(
312
- frame_webview_default,
320
+ View,
313
321
  {
314
- ref: modalWebViewRef,
315
- iframeUrl: modalUrl,
316
- onMessage: onModalMessage,
317
322
  style: {
318
- backgroundColor: "transparent",
319
- height: "100%",
320
- width: "100%",
321
- borderWidth: 0
322
- },
323
- onError: () => {
324
- debug("modal-error");
325
- resetModal();
323
+ flex: 1,
324
+ // Don't show the modal until the modal page is loaded and sends 'init-component-iframe' message back to SDK
325
+ ...modalShown ? { opacity: 1, pointerEvents: "auto" } : { opacity: 0, pointerEvents: "none" }
326
326
  },
327
- onLoad: () => {
328
- debug("modal-load");
329
- setModalLoaded(true);
330
- }
327
+ children: /* @__PURE__ */ jsx2(
328
+ frame_webview_default,
329
+ {
330
+ ref: modalWebViewRef,
331
+ iframeUrl: modalUrl,
332
+ onMessage: onModalMessage,
333
+ style: {
334
+ backgroundColor: "transparent",
335
+ height: "100%",
336
+ width: "100%",
337
+ borderWidth: 0
338
+ },
339
+ onError: () => {
340
+ debug("modal-error");
341
+ resetModal();
342
+ },
343
+ onLoad: () => {
344
+ debug("modal-load");
345
+ setModalLoaded(true);
346
+ }
347
+ }
348
+ )
331
349
  }
332
350
  )
333
351
  }
334
- ) }),
352
+ ),
335
353
  /* @__PURE__ */ jsx2(View, { style: containerStyles, ref: containerRef, children: /* @__PURE__ */ jsx2(
336
354
  frame_webview_default,
337
355
  {
@@ -341,7 +359,7 @@ var Format = ({ code, messageId, wrapper, ...otherParams }) => {
341
359
  style: {
342
360
  height: getHeight(),
343
361
  width: getWidth(),
344
- background: "transparent",
362
+ backgroundColor: "transparent",
345
363
  borderWidth: 0,
346
364
  ...iframeStyles
347
365
  },
@@ -369,13 +387,16 @@ var InlineAd_default = InlineAd;
369
387
 
370
388
  // src/context/AdsProvider.tsx
371
389
  import { AdsProviderInternal, log } from "@kontextso/sdk-react";
372
- import { Platform } from "react-native";
390
+ import { Platform, Dimensions, PixelRatio, Appearance } from "react-native";
373
391
  import DeviceInfo from "react-native-device-info";
374
392
 
375
393
  // src/NativeRNKontext.ts
376
394
  import { TurboModuleRegistry } from "react-native";
377
395
  var NativeRNKontext_default = TurboModuleRegistry.getEnforcing("RNKontext");
378
396
 
397
+ // package.json
398
+ var version = "2.2.0-rc.4";
399
+
379
400
  // src/context/AdsProvider.tsx
380
401
  import { jsx as jsx4 } from "react/jsx-runtime";
381
402
  ErrorUtils.setGlobalHandler((error, isFatal) => {
@@ -387,41 +408,82 @@ ErrorUtils.setGlobalHandler((error, isFatal) => {
387
408
  });
388
409
  var getDevice = async () => {
389
410
  try {
390
- const os = Platform.OS;
391
- const systemVersion = DeviceInfo.getSystemVersion();
392
- const model = DeviceInfo.getModel();
393
- const brand = DeviceInfo.getBrand();
394
- const deviceId = DeviceInfo.getDeviceId();
411
+ const powerState = await DeviceInfo.getPowerState();
395
412
  const deviceType = DeviceInfo.getDeviceType();
396
- const appBundleId = DeviceInfo.getBundleId();
397
- const appVersion = DeviceInfo.getVersion();
398
- let soundOn = false;
399
- try {
400
- soundOn = await NativeRNKontext_default.isSoundOn();
401
- } catch (error) {
402
- log.warn("Failed to read output volume", error);
403
- }
404
- const rnv = Platform.constants.reactNativeVersion;
405
- const reactNativeVersion = `${rnv.major}.${rnv.minor}.${rnv.patch}`;
413
+ const soundOn = await NativeRNKontext_default.isSoundOn();
414
+ const screen = Dimensions.get("screen");
415
+ const mapDeviceTypeToHardwareType = () => {
416
+ switch (deviceType) {
417
+ case "Handset":
418
+ return "handset";
419
+ case "Tablet":
420
+ return "tablet";
421
+ case "Tv":
422
+ return "tv";
423
+ case "Desktop":
424
+ return "desktop";
425
+ default:
426
+ return "other";
427
+ }
428
+ };
406
429
  return {
407
- os,
408
- systemVersion,
409
- reactNativeVersion,
410
- model,
411
- brand,
412
- deviceId,
413
- deviceType,
414
- appBundleId,
415
- appVersion,
416
- soundOn
430
+ hardware: {
431
+ brand: DeviceInfo.getBrand(),
432
+ model: DeviceInfo.getModel(),
433
+ type: mapDeviceTypeToHardwareType()
434
+ // bootTime: Not available without native module
435
+ // sdCardAvailable: Not available without native module
436
+ },
437
+ audio: {
438
+ muted: soundOn
439
+ // volume: Requires react-native-volume-manager
440
+ // outputPluggedIn: Not available without native module
441
+ // outputType: Not available without native module
442
+ },
443
+ network: {
444
+ carrier: await DeviceInfo.getCarrier(),
445
+ userAgent: await DeviceInfo.getUserAgent()
446
+ // detail: Requires @react-native-community/netinfo
447
+ // type: Requires @react-native-community/netinfo
448
+ },
449
+ os: {
450
+ name: Platform.OS,
451
+ version: DeviceInfo.getSystemVersion(),
452
+ locale: Intl.DateTimeFormat().resolvedOptions().locale,
453
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone
454
+ },
455
+ screen: {
456
+ darkMode: Appearance.getColorScheme() === "dark",
457
+ dpr: PixelRatio.get(),
458
+ height: screen.height,
459
+ width: screen.width,
460
+ orientation: screen.width > screen.height ? "landscape" : "portrait"
461
+ },
462
+ power: {
463
+ batteryLevel: powerState.batteryLevel,
464
+ batteryState: powerState.batteryState,
465
+ lowPowerMode: powerState.lowPowerMode
466
+ }
417
467
  };
418
468
  } catch (error) {
419
469
  console.error(error);
470
+ return {};
420
471
  }
421
- return {};
422
472
  };
473
+ var getApp = async () => ({
474
+ bundleId: DeviceInfo.getBundleId(),
475
+ firstInstallTime: await DeviceInfo.getFirstInstallTime(),
476
+ lastUpdateTime: await DeviceInfo.getLastUpdateTime(),
477
+ startTime: await DeviceInfo.getStartupTime(),
478
+ version: DeviceInfo.getVersion()
479
+ });
480
+ var getSdk = async () => ({
481
+ name: "sdk-react-native",
482
+ platform: Platform.OS === "ios" ? "ios" : "android",
483
+ version
484
+ });
423
485
  var AdsProvider = (props) => {
424
- return /* @__PURE__ */ jsx4(AdsProviderInternal, { ...props, getDevice });
486
+ return /* @__PURE__ */ jsx4(AdsProviderInternal, { ...props, getDevice, getSdk, getApp });
425
487
  };
426
488
  export {
427
489
  AdsProvider,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kontextso/sdk-react-native",
3
- "version": "2.2.0-rc.2",
3
+ "version": "2.2.0-rc.4",
4
4
  "description": "Kontext SDK for React Native",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -55,7 +55,7 @@
55
55
  "react-native-webview": "^13.15.0"
56
56
  },
57
57
  "dependencies": {
58
- "@kontextso/sdk-react": "^1.2.4"
58
+ "@kontextso/sdk-react": "^2.0.0"
59
59
  },
60
60
  "files": [
61
61
  "dist/*",
@@ -1,10 +1,9 @@
1
- 'use client'
2
-
3
- import type { AdsProviderProps, Device } from '@kontextso/sdk-react'
1
+ import type { AdsProviderProps, AppConfig, DeviceConfig, SDKConfig } from '@kontextso/sdk-react'
4
2
  import { AdsProviderInternal, log } from '@kontextso/sdk-react'
5
- import { Platform } from 'react-native'
6
- import DeviceInfo from 'react-native-device-info'
3
+ import { Platform, Dimensions, PixelRatio, Appearance } from 'react-native'
4
+ import DeviceInfo, { type DeviceType } from 'react-native-device-info'
7
5
  import KontextSDK from '../NativeRNKontext'
6
+ import { version } from '../../package.json'
8
7
 
9
8
  ErrorUtils.setGlobalHandler((error, isFatal) => {
10
9
  if (!isFatal) {
@@ -14,45 +13,88 @@ ErrorUtils.setGlobalHandler((error, isFatal) => {
14
13
  }
15
14
  })
16
15
 
17
- const getDevice = async (): Promise<Device> => {
16
+ const getDevice = async (): Promise<DeviceConfig> => {
18
17
  try {
19
- const os = Platform.OS
20
- const systemVersion = DeviceInfo.getSystemVersion()
21
- const model = DeviceInfo.getModel()
22
- const brand = DeviceInfo.getBrand()
23
- const deviceId = DeviceInfo.getDeviceId()
24
- const deviceType = DeviceInfo.getDeviceType()
25
- const appBundleId = DeviceInfo.getBundleId()
26
- const appVersion = DeviceInfo.getVersion()
18
+ const powerState = await DeviceInfo.getPowerState()
19
+ const deviceType = DeviceInfo.getDeviceType() as DeviceType
20
+ const soundOn = await KontextSDK.isSoundOn()
21
+ const screen = Dimensions.get('screen')
27
22
 
28
- let soundOn = false
29
- try {
30
- soundOn = await KontextSDK.isSoundOn()
31
- } catch (error) {
32
- log.warn('Failed to read output volume', error)
23
+ const mapDeviceTypeToHardwareType = (): DeviceConfig['hardware']['type'] => {
24
+ switch (deviceType) {
25
+ case 'Handset':
26
+ return 'handset'
27
+ case 'Tablet':
28
+ return 'tablet'
29
+ case 'Tv':
30
+ return 'tv'
31
+ case 'Desktop':
32
+ return 'desktop'
33
+ default:
34
+ return 'other'
35
+ }
33
36
  }
34
37
 
35
- const rnv = Platform.constants.reactNativeVersion
36
- const reactNativeVersion = `${rnv.major}.${rnv.minor}.${rnv.patch}`
37
-
38
38
  return {
39
- os,
40
- systemVersion,
41
- reactNativeVersion,
42
- model,
43
- brand,
44
- deviceId,
45
- deviceType,
46
- appBundleId,
47
- appVersion,
48
- soundOn,
39
+ hardware: {
40
+ brand: DeviceInfo.getBrand(),
41
+ model: DeviceInfo.getModel(),
42
+ type: mapDeviceTypeToHardwareType(),
43
+ // bootTime: Not available without native module
44
+ // sdCardAvailable: Not available without native module
45
+ },
46
+ audio: {
47
+ muted: soundOn,
48
+ // volume: Requires react-native-volume-manager
49
+ // outputPluggedIn: Not available without native module
50
+ // outputType: Not available without native module
51
+ },
52
+ network: {
53
+ carrier: await DeviceInfo.getCarrier(),
54
+ userAgent: await DeviceInfo.getUserAgent(),
55
+ // detail: Requires @react-native-community/netinfo
56
+ // type: Requires @react-native-community/netinfo
57
+ },
58
+ os: {
59
+ name: Platform.OS,
60
+ version: DeviceInfo.getSystemVersion(),
61
+ locale: Intl.DateTimeFormat().resolvedOptions().locale,
62
+ timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,
63
+ },
64
+ screen: {
65
+ darkMode: Appearance.getColorScheme() === 'dark',
66
+ dpr: PixelRatio.get(),
67
+ height: screen.height,
68
+ width: screen.width,
69
+ orientation: screen.width > screen.height ? 'landscape' : 'portrait',
70
+ },
71
+ power: {
72
+ batteryLevel: powerState.batteryLevel,
73
+ batteryState: powerState.batteryState,
74
+ lowPowerMode: powerState.lowPowerMode,
75
+ },
49
76
  }
50
77
  } catch (error) {
51
78
  console.error(error)
79
+ // @ts-expect-error
80
+ return {}
52
81
  }
53
- return {}
54
82
  }
55
83
 
84
+ const getApp = async (): Promise<AppConfig> => ({
85
+ bundleId: DeviceInfo.getBundleId(),
86
+ firstInstallTime: await DeviceInfo.getFirstInstallTime(),
87
+ lastUpdateTime: await DeviceInfo.getLastUpdateTime(),
88
+ startTime: await DeviceInfo.getStartupTime(),
89
+ version: DeviceInfo.getVersion(),
90
+ })
91
+
92
+ const getSdk = async (): Promise<SDKConfig> => ({
93
+ name: 'sdk-react-native',
94
+ platform: Platform.OS === 'ios' ? 'ios' : 'android',
95
+ version,
96
+ })
97
+
56
98
  export const AdsProvider = (props: AdsProviderProps) => {
57
- return <AdsProviderInternal {...props} getDevice={getDevice} />
99
+ return <AdsProviderInternal {...props} getDevice={getDevice} getSdk={getSdk} getApp={getApp} />
58
100
  }
@@ -294,7 +294,7 @@ const Format = ({ code, messageId, wrapper, ...otherParams }: FormatProps) => {
294
294
  return () => clearInterval(interval)
295
295
  }, [])
296
296
 
297
- if (!context || !bid || !iframeUrl) {
297
+ if (!context || !bid || !iframeUrl || context.isDisabled) {
298
298
  return null
299
299
  }
300
300