react-native-icon-switcher 0.0.0-stage → 0.1.1

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 (86) hide show
  1. package/IconSwitcher.podspec +20 -0
  2. package/LICENSE +20 -0
  3. package/README.md +252 -2
  4. package/android/build.gradle +51 -0
  5. package/android/src/main/AndroidManifest.xml +2 -0
  6. package/android/src/main/java/com/iconswitcher/IconSwitcher.kt +380 -0
  7. package/android/src/main/java/com/iconswitcher/IconSwitcherExceptions.kt +24 -0
  8. package/android/src/main/java/com/iconswitcher/IconSwitcherModule.kt +67 -0
  9. package/android/src/main/java/com/iconswitcher/IconSwitcherPackage.kt +30 -0
  10. package/android/src/test/AndroidManifest.xml +39 -0
  11. package/android/src/test/java/com/iconswitcher/IconSwitcherTest.kt +392 -0
  12. package/app.plugin.js +1 -0
  13. package/ios/ISIconSwitcher.h +49 -0
  14. package/ios/ISIconSwitcher.m +205 -0
  15. package/ios/IconSwitcher.h +5 -0
  16. package/ios/IconSwitcher.mm +100 -0
  17. package/jest/index.d.ts +31 -0
  18. package/jest/index.js +98 -0
  19. package/lib/module/NativeIconSwitcher.js +5 -0
  20. package/lib/module/NativeIconSwitcher.js.map +1 -0
  21. package/lib/module/config.js +6 -0
  22. package/lib/module/config.js.map +1 -0
  23. package/lib/module/errors.js +28 -0
  24. package/lib/module/errors.js.map +1 -0
  25. package/lib/module/index.js +69 -0
  26. package/lib/module/index.js.map +1 -0
  27. package/lib/module/package.json +1 -0
  28. package/lib/module/register.js +2 -0
  29. package/lib/module/register.js.map +1 -0
  30. package/lib/module/remote/index.js +119 -0
  31. package/lib/module/remote/index.js.map +1 -0
  32. package/lib/module/types.js +2 -0
  33. package/lib/module/types.js.map +1 -0
  34. package/lib/typescript/package.json +1 -0
  35. package/lib/typescript/src/NativeIconSwitcher.d.ts +18 -0
  36. package/lib/typescript/src/NativeIconSwitcher.d.ts.map +1 -0
  37. package/lib/typescript/src/config.d.ts +4 -0
  38. package/lib/typescript/src/config.d.ts.map +1 -0
  39. package/lib/typescript/src/errors.d.ts +7 -0
  40. package/lib/typescript/src/errors.d.ts.map +1 -0
  41. package/lib/typescript/src/index.d.ts +20 -0
  42. package/lib/typescript/src/index.d.ts.map +1 -0
  43. package/lib/typescript/src/register.d.ts +7 -0
  44. package/lib/typescript/src/register.d.ts.map +1 -0
  45. package/lib/typescript/src/remote/index.d.ts +17 -0
  46. package/lib/typescript/src/remote/index.d.ts.map +1 -0
  47. package/lib/typescript/src/types.d.ts +59 -0
  48. package/lib/typescript/src/types.d.ts.map +1 -0
  49. package/package.json +253 -4
  50. package/plugin/build/cli.d.ts +3 -0
  51. package/plugin/build/cli.js +89 -0
  52. package/plugin/build/core/assets.d.ts +80 -0
  53. package/plugin/build/core/assets.js +463 -0
  54. package/plugin/build/core/errors.d.ts +4 -0
  55. package/plugin/build/core/errors.js +11 -0
  56. package/plugin/build/core/validate.d.ts +6 -0
  57. package/plugin/build/core/validate.js +229 -0
  58. package/plugin/build/index.d.ts +6 -0
  59. package/plugin/build/index.js +134 -0
  60. package/plugin/build/load-config.d.ts +3 -0
  61. package/plugin/build/load-config.js +50 -0
  62. package/plugin/build/paths.d.ts +15 -0
  63. package/plugin/build/paths.js +153 -0
  64. package/plugin/build/sync.d.ts +12 -0
  65. package/plugin/build/sync.js +162 -0
  66. package/plugin/build/transforms/android.d.ts +5 -0
  67. package/plugin/build/transforms/android.js +212 -0
  68. package/plugin/build/transforms/errors.d.ts +4 -0
  69. package/plugin/build/transforms/errors.js +11 -0
  70. package/plugin/build/transforms/index.d.ts +4 -0
  71. package/plugin/build/transforms/index.js +12 -0
  72. package/plugin/build/transforms/ios.d.ts +4 -0
  73. package/plugin/build/transforms/ios.js +111 -0
  74. package/plugin/build/transforms/sampleConfigs.d.ts +3 -0
  75. package/plugin/build/transforms/sampleConfigs.js +33 -0
  76. package/plugin/build/transforms/types.d.ts +2 -0
  77. package/plugin/build/transforms/types.js +14 -0
  78. package/plugin/build/types.d.ts +61 -0
  79. package/plugin/build/types.js +5 -0
  80. package/src/NativeIconSwitcher.ts +17 -0
  81. package/src/config.ts +15 -0
  82. package/src/errors.ts +38 -0
  83. package/src/index.tsx +78 -0
  84. package/src/register.ts +4 -0
  85. package/src/remote/index.ts +142 -0
  86. package/src/types.ts +59 -0
@@ -0,0 +1,100 @@
1
+ #import "IconSwitcher.h"
2
+
3
+ #import "ISIconSwitcher.h"
4
+
5
+ #import <React/RCTBridgeModule.h>
6
+ #import <UIKit/UIKit.h>
7
+
8
+ using namespace facebook::react;
9
+
10
+ @implementation IconSwitcher {
11
+ ISIconSwitcher *_switcher;
12
+ BOOL _cachedIsSupported;
13
+ }
14
+
15
+ - (instancetype)init
16
+ {
17
+ if (self = [super init]) {
18
+ _switcher = [ISIconSwitcher defaultSwitcher];
19
+ _cachedIsSupported = UIApplication.sharedApplication.supportsAlternateIcons;
20
+ }
21
+ return self;
22
+ }
23
+
24
+ - (dispatch_queue_t)methodQueue
25
+ {
26
+ return dispatch_get_main_queue();
27
+ }
28
+
29
+ - (std::shared_ptr<TurboModule>)getTurboModule:(const ObjCTurboModule::InitParams &)params
30
+ {
31
+ return std::make_shared<NativeIconSwitcherSpecJSI>(params);
32
+ }
33
+
34
+ + (NSString *)moduleName
35
+ {
36
+ return @"IconSwitcher";
37
+ }
38
+
39
+ - (ModuleConstants<JS::NativeIconSwitcher::Constants>)constantsToExport
40
+ {
41
+ return [self getConstants];
42
+ }
43
+
44
+ - (ModuleConstants<JS::NativeIconSwitcher::Constants>)getConstants
45
+ {
46
+ NSArray<NSString *> *names = _switcher.iconNames;
47
+ std::vector<NSString *> iconNames;
48
+ iconNames.reserve(names.count);
49
+ for (NSString *name in names) {
50
+ iconNames.push_back(name);
51
+ }
52
+
53
+ return typedConstants<JS::NativeIconSwitcher::Constants>({
54
+ .isSupported = _cachedIsSupported,
55
+ .iconNames = iconNames,
56
+ });
57
+ }
58
+
59
+ - (void)getCurrent:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
60
+ {
61
+ resolve([_switcher currentIconName]);
62
+ }
63
+
64
+ - (void)set:(NSString *)name
65
+ resolve:(RCTPromiseResolveBlock)resolve
66
+ reject:(RCTPromiseRejectBlock)reject
67
+ {
68
+ [_switcher setIconName:name
69
+ completion:^(NSError *_Nullable error) {
70
+ if (error != nil) {
71
+ reject([self _rejectionCodeForError:error], error.localizedDescription, error);
72
+ return;
73
+ }
74
+ resolve(@{@"status" : @"applied"});
75
+ }];
76
+ }
77
+
78
+ - (void)applyPending:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject
79
+ {
80
+ resolve(@{@"status" : @"none"});
81
+ }
82
+
83
+ - (NSString *)_rejectionCodeForError:(NSError *)error
84
+ {
85
+ if (![error.domain isEqualToString:ISIconSwitcherErrorDomain]) {
86
+ return @"ERR_OS_REJECTED";
87
+ }
88
+
89
+ switch ((ISIconSwitcherErrorCode)error.code) {
90
+ case ISIconSwitcherErrorCodeUnsupported:
91
+ return @"ERR_UNSUPPORTED";
92
+ case ISIconSwitcherErrorCodeUnknownIcon:
93
+ return @"ERR_UNKNOWN_ICON";
94
+ case ISIconSwitcherErrorCodeOSRejected:
95
+ default:
96
+ return @"ERR_OS_REJECTED";
97
+ }
98
+ }
99
+
100
+ @end
@@ -0,0 +1,31 @@
1
+ import type { IconSwitcherErrorCode } from '../src/errors';
2
+
3
+ export class IconSwitcherError extends Error {
4
+ readonly code: IconSwitcherErrorCode;
5
+ constructor(code: IconSwitcherErrorCode, message?: string);
6
+ }
7
+
8
+ export type MockIconSwitcherState = {
9
+ isSupported: boolean;
10
+ iconNames: string[];
11
+ current: string;
12
+ setImpl: (name: string) => Promise<{ status: 'applied' | 'pending' }>;
13
+ applyPendingImpl: () => Promise<{ status: 'applied' | 'none' }>;
14
+ };
15
+
16
+ export declare const IconSwitcher: {
17
+ readonly isSupported: boolean;
18
+ list(): string[];
19
+ getCurrent(): Promise<string>;
20
+ set(name: string): Promise<{ status: 'applied' | 'pending' }>;
21
+ reset(): Promise<{ status: 'applied' | 'pending' }>;
22
+ applyPending(): Promise<{ status: 'applied' | 'none' }>;
23
+ };
24
+
25
+ export default IconSwitcher;
26
+
27
+ export declare function __setState(
28
+ partial: Partial<MockIconSwitcherState>
29
+ ): void;
30
+
31
+ export declare function __reset(): void;
package/jest/index.js ADDED
@@ -0,0 +1,98 @@
1
+ 'use strict';
2
+
3
+ /**
4
+ * Jest mock for `react-native-icon-switcher`.
5
+ *
6
+ * jest.mock(
7
+ * 'react-native-icon-switcher',
8
+ * () => require('react-native-icon-switcher/jest')
9
+ * );
10
+ */
11
+
12
+ class IconSwitcherError extends Error {
13
+ constructor(code, message) {
14
+ super(message ?? code);
15
+ this.name = 'IconSwitcherError';
16
+ this.code = code;
17
+ }
18
+ }
19
+
20
+ function defaultState() {
21
+ return {
22
+ isSupported: true,
23
+ iconNames: ['default', 'halloween'],
24
+ current: 'default',
25
+ setImpl: async () => ({ status: 'applied' }),
26
+ applyPendingImpl: async () => ({ status: 'none' }),
27
+ };
28
+ }
29
+
30
+ let state = defaultState();
31
+
32
+ function __setState(partial) {
33
+ state = { ...state, ...partial };
34
+ }
35
+
36
+ function __reset() {
37
+ state = defaultState();
38
+ }
39
+
40
+ function _assertKnownIcon(name) {
41
+ if (!state.iconNames.includes(name)) {
42
+ throw new IconSwitcherError('unknown_icon', `Unknown icon: ${name}`);
43
+ }
44
+ }
45
+
46
+ const IconSwitcher = {
47
+ get isSupported() {
48
+ return state.isSupported;
49
+ },
50
+
51
+ list() {
52
+ return [...state.iconNames];
53
+ },
54
+
55
+ async getCurrent() {
56
+ if (!state.isSupported) {
57
+ throw new IconSwitcherError(
58
+ 'unsupported',
59
+ 'Alternate app icons are not supported'
60
+ );
61
+ }
62
+ return state.current;
63
+ },
64
+
65
+ async set(name) {
66
+ if (!state.isSupported) {
67
+ throw new IconSwitcherError(
68
+ 'unsupported',
69
+ 'Alternate app icons are not supported'
70
+ );
71
+ }
72
+ _assertKnownIcon(name);
73
+ return state.setImpl(name);
74
+ },
75
+
76
+ async reset() {
77
+ return IconSwitcher.set('default');
78
+ },
79
+
80
+ async applyPending() {
81
+ if (!state.isSupported) {
82
+ throw new IconSwitcherError(
83
+ 'unsupported',
84
+ 'Alternate app icons are not supported'
85
+ );
86
+ }
87
+ return state.applyPendingImpl();
88
+ },
89
+ };
90
+
91
+ module.exports = {
92
+ __esModule: true,
93
+ default: IconSwitcher,
94
+ IconSwitcher,
95
+ IconSwitcherError,
96
+ __setState,
97
+ __reset,
98
+ };
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+
3
+ import { TurboModuleRegistry } from 'react-native';
4
+ export default TurboModuleRegistry.get('IconSwitcher');
5
+ //# sourceMappingURL=NativeIconSwitcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["TurboModuleRegistry","get"],"sourceRoot":"../../src","sources":["NativeIconSwitcher.ts"],"mappings":";;AACA,SAASA,mBAAmB,QAAQ,cAAc;AAelD,eAAeA,mBAAmB,CAACC,GAAG,CAAO,cAAc,CAAC","ignoreList":[]}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+
3
+ export function defineIcons(cfg) {
4
+ return cfg;
5
+ }
6
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["defineIcons","cfg"],"sourceRoot":"../../src","sources":["config.ts"],"mappings":";;AAYA,OAAO,SAASA,WAAWA,CAACC,GAAuB,EAAsB;EACvE,OAAOA,GAAG;AACZ","ignoreList":[]}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+
3
+ export class IconSwitcherError extends Error {
4
+ constructor(code, message) {
5
+ super(message ?? code);
6
+ this.name = 'IconSwitcherError';
7
+ this.code = code;
8
+ }
9
+ }
10
+ const _NATIVE_TO_JS = {
11
+ ERR_UNSUPPORTED: 'unsupported',
12
+ ERR_UNKNOWN_ICON: 'unknown_icon',
13
+ ERR_OS_REJECTED: 'os_rejected',
14
+ ERR_FOREGROUND: 'foreground'
15
+ };
16
+ export function mapNativeError(error) {
17
+ if (error instanceof IconSwitcherError) {
18
+ return error;
19
+ }
20
+ const code = typeof error === 'object' && error !== null && 'code' in error ? String(error.code) : undefined;
21
+ const mapped = code ? _NATIVE_TO_JS[code] : undefined;
22
+ if (mapped) {
23
+ const message = error instanceof Error ? error.message : undefined;
24
+ return new IconSwitcherError(mapped, message);
25
+ }
26
+ return new IconSwitcherError('os_rejected', error instanceof Error ? error.message : String(error));
27
+ }
28
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["IconSwitcherError","Error","constructor","code","message","name","_NATIVE_TO_JS","ERR_UNSUPPORTED","ERR_UNKNOWN_ICON","ERR_OS_REJECTED","ERR_FOREGROUND","mapNativeError","error","String","undefined","mapped"],"sourceRoot":"../../src","sources":["errors.ts"],"mappings":";;AAGA,OAAO,MAAMA,iBAAiB,SAASC,KAAK,CAAC;EAG3CC,WAAWA,CAACC,IAA2B,EAAEC,OAAgB,EAAE;IACzD,KAAK,CAACA,OAAO,IAAID,IAAI,CAAC;IACtB,IAAI,CAACE,IAAI,GAAG,mBAAmB;IAC/B,IAAI,CAACF,IAAI,GAAGA,IAAI;EAClB;AACF;AAEA,MAAMG,aAAoD,GAAG;EAC3DC,eAAe,EAAE,aAAa;EAC9BC,gBAAgB,EAAE,cAAc;EAChCC,eAAe,EAAE,aAAa;EAC9BC,cAAc,EAAE;AAClB,CAAC;AAED,OAAO,SAASC,cAAcA,CAACC,KAAc,EAAqB;EAChE,IAAIA,KAAK,YAAYZ,iBAAiB,EAAE;IACtC,OAAOY,KAAK;EACd;EACA,MAAMT,IAAI,GACR,OAAOS,KAAK,KAAK,QAAQ,IAAIA,KAAK,KAAK,IAAI,IAAI,MAAM,IAAIA,KAAK,GAC1DC,MAAM,CAAED,KAAK,CAAuBT,IAAI,CAAC,GACzCW,SAAS;EACf,MAAMC,MAAM,GAAGZ,IAAI,GAAGG,aAAa,CAACH,IAAI,CAAC,GAAGW,SAAS;EACrD,IAAIC,MAAM,EAAE;IACV,MAAMX,OAAO,GAAGQ,KAAK,YAAYX,KAAK,GAAGW,KAAK,CAACR,OAAO,GAAGU,SAAS;IAClE,OAAO,IAAId,iBAAiB,CAACe,MAAM,EAAEX,OAAO,CAAC;EAC/C;EACA,OAAO,IAAIJ,iBAAiB,CAC1B,aAAa,EACbY,KAAK,YAAYX,KAAK,GAAGW,KAAK,CAACR,OAAO,GAAGS,MAAM,CAACD,KAAK,CACvD,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+
3
+ import native from "./NativeIconSwitcher.js";
4
+ import { IconSwitcherError, mapNativeError } from "./errors.js";
5
+ function _constants() {
6
+ if (native == null) {
7
+ return {
8
+ isSupported: false,
9
+ iconNames: []
10
+ };
11
+ }
12
+ return native.getConstants();
13
+ }
14
+ function _rejectUnsupported() {
15
+ throw new IconSwitcherError('unsupported', 'Alternate app icons are not supported');
16
+ }
17
+ function _assertKnownIcon(name) {
18
+ if (!_constants().iconNames.includes(name)) {
19
+ throw new IconSwitcherError('unknown_icon', `Unknown icon: ${name}`);
20
+ }
21
+ }
22
+ const IconSwitcher = {
23
+ get isSupported() {
24
+ return _constants().isSupported;
25
+ },
26
+ list() {
27
+ return [..._constants().iconNames];
28
+ },
29
+ async getCurrent() {
30
+ if (native == null) {
31
+ _rejectUnsupported();
32
+ }
33
+ try {
34
+ const current = await native.getCurrent();
35
+ return current;
36
+ } catch (error) {
37
+ throw mapNativeError(error);
38
+ }
39
+ },
40
+ async set(name) {
41
+ if (!_constants().isSupported) {
42
+ _rejectUnsupported();
43
+ }
44
+ _assertKnownIcon(name);
45
+ try {
46
+ const result = await native.set(name);
47
+ return result;
48
+ } catch (error) {
49
+ throw mapNativeError(error);
50
+ }
51
+ },
52
+ async reset() {
53
+ return IconSwitcher.set('default');
54
+ },
55
+ async applyPending() {
56
+ if (native == null) {
57
+ _rejectUnsupported();
58
+ }
59
+ try {
60
+ const result = await native.applyPending();
61
+ return result;
62
+ } catch (error) {
63
+ throw mapNativeError(error);
64
+ }
65
+ }
66
+ };
67
+ export { IconSwitcher, IconSwitcherError };
68
+ export default IconSwitcher;
69
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["native","IconSwitcherError","mapNativeError","_constants","isSupported","iconNames","getConstants","_rejectUnsupported","_assertKnownIcon","name","includes","IconSwitcher","list","getCurrent","current","error","set","result","reset","applyPending"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,OAAOA,MAAM,MAAM,yBAAsB;AACzC,SAASC,iBAAiB,EAAEC,cAAc,QAAQ,aAAU;AAG5D,SAASC,UAAUA,CAAA,EAAkD;EACnE,IAAIH,MAAM,IAAI,IAAI,EAAE;IAClB,OAAO;MAAEI,WAAW,EAAE,KAAK;MAAEC,SAAS,EAAE;IAAG,CAAC;EAC9C;EACA,OAAOL,MAAM,CAACM,YAAY,CAAC,CAAC;AAC9B;AAEA,SAASC,kBAAkBA,CAAA,EAAU;EACnC,MAAM,IAAIN,iBAAiB,CACzB,aAAa,EACb,uCACF,CAAC;AACH;AAEA,SAASO,gBAAgBA,CAACC,IAAY,EAAQ;EAC5C,IAAI,CAACN,UAAU,CAAC,CAAC,CAACE,SAAS,CAACK,QAAQ,CAACD,IAAI,CAAC,EAAE;IAC1C,MAAM,IAAIR,iBAAiB,CAAC,cAAc,EAAE,iBAAiBQ,IAAI,EAAE,CAAC;EACtE;AACF;AAEA,MAAME,YAAY,GAAG;EACnB,IAAIP,WAAWA,CAAA,EAAY;IACzB,OAAOD,UAAU,CAAC,CAAC,CAACC,WAAW;EACjC,CAAC;EAEDQ,IAAIA,CAAA,EAAe;IACjB,OAAO,CAAC,GAAGT,UAAU,CAAC,CAAC,CAACE,SAAS,CAAC;EACpC,CAAC;EAED,MAAMQ,UAAUA,CAAA,EAAsB;IACpC,IAAIb,MAAM,IAAI,IAAI,EAAE;MAClBO,kBAAkB,CAAC,CAAC;IACtB;IACA,IAAI;MACF,MAAMO,OAAO,GAAG,MAAMd,MAAM,CAACa,UAAU,CAAC,CAAC;MACzC,OAAOC,OAAO;IAChB,CAAC,CAAC,OAAOC,KAAK,EAAE;MACd,MAAMb,cAAc,CAACa,KAAK,CAAC;IAC7B;EACF,CAAC;EAED,MAAMC,GAAGA,CAACP,IAAc,EAA8C;IACpE,IAAI,CAACN,UAAU,CAAC,CAAC,CAACC,WAAW,EAAE;MAC7BG,kBAAkB,CAAC,CAAC;IACtB;IACAC,gBAAgB,CAACC,IAAc,CAAC;IAChC,IAAI;MACF,MAAMQ,MAAM,GAAG,MAAMjB,MAAM,CAAEgB,GAAG,CAACP,IAAc,CAAC;MAChD,OAAOQ,MAAM;IACf,CAAC,CAAC,OAAOF,KAAK,EAAE;MACd,MAAMb,cAAc,CAACa,KAAK,CAAC;IAC7B;EACF,CAAC;EAED,MAAMG,KAAKA,CAAA,EAA+C;IACxD,OAAOP,YAAY,CAACK,GAAG,CAAC,SAAqB,CAAC;EAChD,CAAC;EAED,MAAMG,YAAYA,CAAA,EAA4C;IAC5D,IAAInB,MAAM,IAAI,IAAI,EAAE;MAClBO,kBAAkB,CAAC,CAAC;IACtB;IACA,IAAI;MACF,MAAMU,MAAM,GAAG,MAAMjB,MAAM,CAACmB,YAAY,CAAC,CAAC;MAC1C,OAAOF,MAAM;IACf,CAAC,CAAC,OAAOF,KAAK,EAAE;MACd,MAAMb,cAAc,CAACa,KAAK,CAAC;IAC7B;EACF;AACF,CAAC;AAED,SAASJ,YAAY,EAAEV,iBAAiB;AAExC,eAAeU,YAAY","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../src","sources":["register.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,119 @@
1
+ "use strict";
2
+
3
+ import { AppState, Platform } from 'react-native';
4
+ import IconSwitcher from "../index.js";
5
+ const STORAGE_KEY_APPLIED = 'icon-switcher:lastApplied';
6
+ const STORAGE_KEY_FAILED = 'icon-switcher:lastFailed';
7
+ const DEFAULT_RETRY_AFTER_MS = 24 * 60 * 60 * 1000;
8
+ function _createMemoryStorage() {
9
+ const data = new Map();
10
+ return {
11
+ getItem: async key => data.get(key) ?? null,
12
+ setItem: async (key, value) => {
13
+ data.set(key, value);
14
+ }
15
+ };
16
+ }
17
+ function _encodeFailed(name) {
18
+ return JSON.stringify({
19
+ name,
20
+ at: Date.now()
21
+ });
22
+ }
23
+ function _decodeFailed(raw) {
24
+ if (!raw || raw.length === 0) {
25
+ return null;
26
+ }
27
+ try {
28
+ const parsed = JSON.parse(raw);
29
+ if (typeof parsed.name === 'string' && typeof parsed.at === 'number') {
30
+ return {
31
+ name: parsed.name,
32
+ at: parsed.at
33
+ };
34
+ }
35
+ } catch {
36
+ // legacy: plain icon name with no timestamp — eligible for retry immediately
37
+ return {
38
+ name: raw,
39
+ at: 0
40
+ };
41
+ }
42
+ return null;
43
+ }
44
+ function _isFailedBlocked(failed, choice, retryAfterMs) {
45
+ if (!failed || failed.name !== choice) {
46
+ return false;
47
+ }
48
+ return Date.now() - failed.at < retryAfterMs;
49
+ }
50
+
51
+ /**
52
+ * Fetches the remote icon choice, validates it, and applies it via {@link IconSwitcher}.
53
+ * iOS: runs while the app is `active`. Android: calls `set` immediately (native may defer).
54
+ */
55
+ export async function syncIcon(options) {
56
+ const storage = options.storage ?? _createMemoryStorage();
57
+ const retryAfterMs = options.retryAfterMs ?? DEFAULT_RETRY_AFTER_MS;
58
+ const onError = options.onError;
59
+ let inFlight = false;
60
+ const run = async () => {
61
+ if (inFlight) {
62
+ return;
63
+ }
64
+ inFlight = true;
65
+ try {
66
+ const choice = await options.fetchChoice();
67
+ if (choice == null || choice === '') {
68
+ return;
69
+ }
70
+ if (!IconSwitcher.list().includes(choice)) {
71
+ return;
72
+ }
73
+ if (!IconSwitcher.isSupported) {
74
+ return;
75
+ }
76
+ const failedRaw = await storage.getItem(STORAGE_KEY_FAILED);
77
+ const failed = _decodeFailed(failedRaw);
78
+ if (_isFailedBlocked(failed, choice, retryAfterMs)) {
79
+ return;
80
+ }
81
+ const current = await IconSwitcher.getCurrent();
82
+ if (choice === current) {
83
+ await storage.setItem(STORAGE_KEY_APPLIED, choice);
84
+ return;
85
+ }
86
+ try {
87
+ const result = await IconSwitcher.set(choice);
88
+ if (result.status === 'pending') {
89
+ return;
90
+ }
91
+ await storage.setItem(STORAGE_KEY_APPLIED, choice);
92
+ await storage.setItem(STORAGE_KEY_FAILED, '');
93
+ } catch {
94
+ await storage.setItem(STORAGE_KEY_FAILED, _encodeFailed(choice));
95
+ }
96
+ } catch (error) {
97
+ onError?.(error);
98
+ } finally {
99
+ inFlight = false;
100
+ }
101
+ };
102
+ const runWhenActive = () => {
103
+ if (AppState.currentState === 'active') {
104
+ void run();
105
+ }
106
+ };
107
+ if (Platform.OS === 'ios') {
108
+ const subscription = AppState.addEventListener('change', state => {
109
+ if (state === 'active') {
110
+ void run();
111
+ }
112
+ });
113
+ runWhenActive();
114
+ return () => subscription.remove();
115
+ }
116
+ await run();
117
+ return () => {};
118
+ }
119
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["AppState","Platform","IconSwitcher","STORAGE_KEY_APPLIED","STORAGE_KEY_FAILED","DEFAULT_RETRY_AFTER_MS","_createMemoryStorage","data","Map","getItem","key","get","setItem","value","set","_encodeFailed","name","JSON","stringify","at","Date","now","_decodeFailed","raw","length","parsed","parse","_isFailedBlocked","failed","choice","retryAfterMs","syncIcon","options","storage","onError","inFlight","run","fetchChoice","list","includes","isSupported","failedRaw","current","getCurrent","result","status","error","runWhenActive","currentState","OS","subscription","addEventListener","state","remove"],"sourceRoot":"../../../src","sources":["remote/index.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../src","sources":["types.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"module"}
@@ -0,0 +1,18 @@
1
+ import type { TurboModule } from 'react-native';
2
+ export interface IconSwitcherConstants {
3
+ isSupported: boolean;
4
+ iconNames: string[];
5
+ }
6
+ export interface Spec extends TurboModule {
7
+ getConstants(): IconSwitcherConstants;
8
+ getCurrent(): Promise<string>;
9
+ set(name: string): Promise<{
10
+ status: string;
11
+ }>;
12
+ applyPending(): Promise<{
13
+ status: string;
14
+ }>;
15
+ }
16
+ declare const _default: Spec | null | undefined;
17
+ export default _default;
18
+ //# sourceMappingURL=NativeIconSwitcher.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"NativeIconSwitcher.d.ts","sourceRoot":"","sources":["../../../src/NativeIconSwitcher.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,MAAM,WAAW,qBAAqB;IACpC,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,MAAM,WAAW,IAAK,SAAQ,WAAW;IACvC,YAAY,IAAI,qBAAqB,CAAC;IACtC,UAAU,IAAI,OAAO,CAAC,MAAM,CAAC,CAAC;IAE9B,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IAC/C,YAAY,IAAI,OAAO,CAAC;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAC7C;;AAED,wBAA6D"}
@@ -0,0 +1,4 @@
1
+ import type { IconSwitcherConfig } from './types.js';
2
+ export type { AndroidAdaptiveIcon, HexColor, IconSource, IconSpec, IconSwitcherConfig, ImagePath, IosIconVariants, } from './types.js';
3
+ export declare function defineIcons(cfg: IconSwitcherConfig): IconSwitcherConfig;
4
+ //# sourceMappingURL=config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,YAAS,CAAC;AAElD,YAAY,EACV,mBAAmB,EACnB,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,kBAAkB,EAClB,SAAS,EACT,eAAe,GAChB,MAAM,YAAS,CAAC;AAEjB,wBAAgB,WAAW,CAAC,GAAG,EAAE,kBAAkB,GAAG,kBAAkB,CAEvE"}
@@ -0,0 +1,7 @@
1
+ export type IconSwitcherErrorCode = 'unsupported' | 'unknown_icon' | 'os_rejected' | 'foreground';
2
+ export declare class IconSwitcherError extends Error {
3
+ readonly code: IconSwitcherErrorCode;
4
+ constructor(code: IconSwitcherErrorCode, message?: string);
5
+ }
6
+ export declare function mapNativeError(error: unknown): IconSwitcherError;
7
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/errors.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,qBAAqB,GAC/B,aAAa,GAAG,cAAc,GAAG,aAAa,GAAG,YAAY,CAAC;AAEhE,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,QAAQ,CAAC,IAAI,EAAE,qBAAqB,CAAC;gBAEzB,IAAI,EAAE,qBAAqB,EAAE,OAAO,CAAC,EAAE,MAAM;CAK1D;AASD,wBAAgB,cAAc,CAAC,KAAK,EAAE,OAAO,GAAG,iBAAiB,CAiBhE"}
@@ -0,0 +1,20 @@
1
+ import { IconSwitcherError } from './errors.js';
2
+ import type { IconName } from './register.js';
3
+ declare const IconSwitcher: {
4
+ readonly isSupported: boolean;
5
+ list(): IconName[];
6
+ getCurrent(): Promise<IconName>;
7
+ set(name: IconName): Promise<{
8
+ status: "applied" | "pending";
9
+ }>;
10
+ reset(): Promise<{
11
+ status: "applied" | "pending";
12
+ }>;
13
+ applyPending(): Promise<{
14
+ status: "applied" | "none";
15
+ }>;
16
+ };
17
+ export { IconSwitcher, IconSwitcherError };
18
+ export type { IconName, Register } from './register.js';
19
+ export default IconSwitcher;
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAkB,MAAM,aAAU,CAAC;AAC7D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAY,CAAC;AAsB3C,QAAA,MAAM,YAAY;0BACG,OAAO;YAIlB,QAAQ,EAAE;kBAIE,OAAO,CAAC,QAAQ,CAAC;cAYrB,QAAQ,GAAG,OAAO,CAAC;QAAE,MAAM,EAAE,SAAS,GAAG,SAAS,CAAA;KAAE,CAAC;aAatD,OAAO,CAAC;QAAE,MAAM,EAAE,SAAS,GAAG,SAAS,CAAA;KAAE,CAAC;oBAInC,OAAO,CAAC;QAAE,MAAM,EAAE,SAAS,GAAG,MAAM,CAAA;KAAE,CAAC;CAW9D,CAAC;AAEF,OAAO,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAC;AAC3C,YAAY,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,eAAY,CAAC;AACrD,eAAe,YAAY,CAAC"}
@@ -0,0 +1,7 @@
1
+ /** Augment via `declare module 'react-native-icon-switcher' { interface Register { icons: ... } }`. */
2
+ export interface Register {
3
+ }
4
+ export type IconName = Register extends {
5
+ icons: infer T;
6
+ } ? T : string;
7
+ //# sourceMappingURL=register.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"register.d.ts","sourceRoot":"","sources":["../../../src/register.ts"],"names":[],"mappings":"AAAA,uGAAuG;AACvG,MAAM,WAAW,QAAQ;CAAG;AAE5B,MAAM,MAAM,QAAQ,GAAG,QAAQ,SAAS;IAAE,KAAK,EAAE,MAAM,CAAC,CAAA;CAAE,GAAG,CAAC,GAAG,MAAM,CAAC"}
@@ -0,0 +1,17 @@
1
+ export interface SyncIconStorage {
2
+ getItem(key: string): Promise<string | null>;
3
+ setItem(key: string, value: string): Promise<void>;
4
+ }
5
+ export interface SyncIconOptions {
6
+ fetchChoice: () => Promise<string | null | undefined>;
7
+ storage?: SyncIconStorage;
8
+ /** How long to skip re-applying a name after `set` failed. Default 24 h. */
9
+ retryAfterMs?: number;
10
+ onError?: (error: unknown) => void;
11
+ }
12
+ /**
13
+ * Fetches the remote icon choice, validates it, and applies it via {@link IconSwitcher}.
14
+ * iOS: runs while the app is `active`. Android: calls `set` immediately (native may defer).
15
+ */
16
+ export declare function syncIcon(options: SyncIconOptions): Promise<() => void>;
17
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/remote/index.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,eAAe;IAC9B,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7C,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACpD;AAED,MAAM,WAAW,eAAe;IAC9B,WAAW,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC,CAAC;IACtD,OAAO,CAAC,EAAE,eAAe,CAAC;IAC1B,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;CACpC;AA6CD;;;GAGG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAuE5E"}