react-native-inapp-inspector 1.1.34 → 1.1.35

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 (75) hide show
  1. package/dist/commonjs/components/ConsoleLogCard.js +57 -56
  2. package/dist/commonjs/components/CopyButton.js +7 -1
  3. package/dist/commonjs/components/Inspector/BundleTab.js +19 -19
  4. package/dist/commonjs/components/Inspector/CrashDetail.js +16 -12
  5. package/dist/commonjs/components/Inspector/InspectorHeader.js +16 -16
  6. package/dist/commonjs/components/Inspector/MainScreen.js +6 -2
  7. package/dist/commonjs/components/Inspector/NetworkTab.js +97 -1
  8. package/dist/commonjs/components/Inspector/ReduxDetail.js +24 -19
  9. package/dist/commonjs/components/Inspector/ReduxTab.js +12 -8
  10. package/dist/commonjs/components/Inspector/SettingsPanel.js +1243 -673
  11. package/dist/commonjs/components/LogCard.js +27 -9
  12. package/dist/commonjs/components/MetaAccordion.js +42 -0
  13. package/dist/commonjs/components/NetworkIcons.d.ts +9 -0
  14. package/dist/commonjs/components/NetworkIcons.js +48 -1
  15. package/dist/commonjs/components/Toast.js +3 -3
  16. package/dist/commonjs/components/TouchableScale.d.ts +4 -2
  17. package/dist/commonjs/components/TouchableScale.js +4 -4
  18. package/dist/commonjs/constants/version.d.ts +1 -1
  19. package/dist/commonjs/constants/version.js +1 -1
  20. package/dist/commonjs/customHooks/analyticsLogger.d.ts +2 -0
  21. package/dist/commonjs/customHooks/analyticsLogger.js +10 -1
  22. package/dist/commonjs/customHooks/bundleAnalyzer.d.ts +2 -0
  23. package/dist/commonjs/customHooks/bundleAnalyzer.js +26 -17
  24. package/dist/commonjs/customHooks/consoleLogger.d.ts +2 -0
  25. package/dist/commonjs/customHooks/consoleLogger.js +10 -1
  26. package/dist/commonjs/customHooks/crashHandler.d.ts +2 -0
  27. package/dist/commonjs/customHooks/crashHandler.js +10 -1
  28. package/dist/commonjs/customHooks/networkLogger.d.ts +2 -0
  29. package/dist/commonjs/customHooks/networkLogger.js +12 -1
  30. package/dist/commonjs/customHooks/performanceTracker.d.ts +3 -1
  31. package/dist/commonjs/customHooks/performanceTracker.js +18 -4
  32. package/dist/commonjs/customHooks/reduxLogger.d.ts +2 -0
  33. package/dist/commonjs/customHooks/reduxLogger.js +10 -1
  34. package/dist/commonjs/i18n/locales/en.json +96 -28
  35. package/dist/commonjs/index.js +78 -34
  36. package/dist/commonjs/styles/AppColors.d.ts +28 -0
  37. package/dist/commonjs/styles/AppColors.js +30 -0
  38. package/dist/esm/components/ConsoleLogCard.js +58 -57
  39. package/dist/esm/components/CopyButton.js +7 -1
  40. package/dist/esm/components/Inspector/BundleTab.js +19 -19
  41. package/dist/esm/components/Inspector/CrashDetail.js +16 -12
  42. package/dist/esm/components/Inspector/InspectorHeader.js +16 -16
  43. package/dist/esm/components/Inspector/MainScreen.js +6 -2
  44. package/dist/esm/components/Inspector/NetworkTab.js +99 -3
  45. package/dist/esm/components/Inspector/ReduxDetail.js +24 -19
  46. package/dist/esm/components/Inspector/ReduxTab.js +12 -8
  47. package/dist/esm/components/Inspector/SettingsPanel.js +1246 -676
  48. package/dist/esm/components/LogCard.js +27 -9
  49. package/dist/esm/components/MetaAccordion.js +42 -0
  50. package/dist/esm/components/NetworkIcons.d.ts +9 -0
  51. package/dist/esm/components/NetworkIcons.js +38 -0
  52. package/dist/esm/components/Toast.js +3 -3
  53. package/dist/esm/components/TouchableScale.d.ts +4 -2
  54. package/dist/esm/components/TouchableScale.js +4 -4
  55. package/dist/esm/constants/version.d.ts +1 -1
  56. package/dist/esm/constants/version.js +1 -1
  57. package/dist/esm/customHooks/analyticsLogger.d.ts +2 -0
  58. package/dist/esm/customHooks/analyticsLogger.js +7 -0
  59. package/dist/esm/customHooks/bundleAnalyzer.d.ts +2 -0
  60. package/dist/esm/customHooks/bundleAnalyzer.js +23 -16
  61. package/dist/esm/customHooks/consoleLogger.d.ts +2 -0
  62. package/dist/esm/customHooks/consoleLogger.js +7 -0
  63. package/dist/esm/customHooks/crashHandler.d.ts +2 -0
  64. package/dist/esm/customHooks/crashHandler.js +7 -0
  65. package/dist/esm/customHooks/networkLogger.d.ts +2 -0
  66. package/dist/esm/customHooks/networkLogger.js +9 -0
  67. package/dist/esm/customHooks/performanceTracker.d.ts +3 -1
  68. package/dist/esm/customHooks/performanceTracker.js +15 -3
  69. package/dist/esm/customHooks/reduxLogger.d.ts +2 -0
  70. package/dist/esm/customHooks/reduxLogger.js +7 -0
  71. package/dist/esm/i18n/locales/en.json +96 -28
  72. package/dist/esm/index.js +64 -20
  73. package/dist/esm/styles/AppColors.d.ts +28 -0
  74. package/dist/esm/styles/AppColors.js +30 -0
  75. package/package.json +3 -2
@@ -1,5 +1,5 @@
1
- import React from 'react';
2
- import { Alert, Platform, ScrollView, Text, TouchableOpacity, View, } from 'react-native';
1
+ import React, { useMemo, useState, useEffect } from 'react';
2
+ import { Alert, Platform, ScrollView, StatusBar, Text, View, } from 'react-native';
3
3
  import Svg, { Path } from 'react-native-svg';
4
4
  import LinearGradient from 'react-native-linear-gradient';
5
5
  import { animateNextLayout, useInspector } from './InspectorContext';
@@ -12,32 +12,124 @@ import { isPersistentStorageAvailable } from '../../helpers/settingsStore';
12
12
  import { clearNetworkLogs } from '../../customHooks/networkLogger';
13
13
  import { clearConsoleLogs } from '../../customHooks/consoleLogger';
14
14
  import { clearAnalyticsEvents } from '../../customHooks/analyticsLogger';
15
- import { clearCrashRecords, } from '../../customHooks/crashHandler';
15
+ import { clearCrashRecords } from '../../customHooks/crashHandler';
16
+ import { clearCachedBundleAnalysis } from '../../customHooks/bundleAnalyzer';
17
+ import { clearPerformanceEvents } from '../../customHooks/performanceTracker';
16
18
  import { isReduxConnected } from '../../customHooks/reduxLogger';
17
19
  import { isAnalyticsConnected } from '../../customHooks/analyticsLogger';
18
20
  import { useTranslation } from '../../i18n';
19
- import { SignalIcon, TerminalIcon, AnalyticsIcon, SettingsIcon, SunIcon, MoonIcon, ScreenIcon, MotionIcon, LayersIcon, EyeIcon, CheckIcon, TrashIcon, WhiteBackNavigation, PackageIcon, ReduxIcon, PerformanceIcon, CrashIcon, ShieldAlertIcon, } from '../NetworkIcons';
21
+ import { SignalIcon, TerminalIcon, AnalyticsIcon, SettingsIcon, SunIcon, MoonIcon, ScreenIcon, MotionIcon, LayersIcon, EyeIcon, CheckIcon, TrashIcon, WhiteBackNavigation, PackageIcon, ReduxIcon, PerformanceIcon, CrashIcon, ShieldAlertIcon, ForwardChevronIcon, } from '../NetworkIcons';
20
22
  const SettingsPanel = () => {
21
23
  const { t } = useTranslation();
22
24
  const { settingsPage, setSettingsPage, settingsActiveSubTab, setSettingsActiveSubTab, tabVisibility, toggleTabVisibility, defaultTab, setDefaultTab, isDark, setIsDark, modalHeightPercent, setModalHeightPercent, modalAnimationType, setModalAnimationType, showDuplicateLogs, setShowDuplicateLogs, showConsoleLevels, setShowConsoleLevels, resetToDefaults, storage, logs, consoleLogs, analyticsEvents, reduxState, maxNetworkLogs, setMaxNetworkLogs, maxConsoleLogs, setMaxConsoleLogs, reduxAutoRefresh, setReduxAutoRefreshState, reduxExpandDepth, setReduxExpandDepth, switchActiveTab, setSelected, setSelectedEvent, setReduxState, crashRecords, maxCrashLogs, setMaxCrashLogs, } = useInspector();
23
25
  const isPersistent = isPersistentStorageAvailable();
24
- const headerTopPadding = Platform.OS === 'ios' && modalHeightPercent >= 95 ? 44 : 0;
26
+ // Safe Area & Status Bar Padding for All Device Form Factors
27
+ const statusBarHeight = Platform.OS === 'android' ? StatusBar.currentHeight || 24 : 44;
28
+ const headerTopPadding = modalHeightPercent >= 95 ? statusBarHeight : 0;
29
+ const allModules = [
30
+ {
31
+ key: 'apis',
32
+ label: 'APIs (Network)',
33
+ category: 'core',
34
+ icon: 'apis',
35
+ desc: 'HTTP/HTTPS requests, GraphQL, Axios & WebSocket inspector',
36
+ },
37
+ {
38
+ key: 'logs',
39
+ label: 'Console Logs',
40
+ category: 'core',
41
+ icon: 'logs',
42
+ desc: 'Terminal console logs, warnings, errors & stack traces',
43
+ },
44
+ {
45
+ key: 'performance',
46
+ label: 'Performance Tracker',
47
+ category: 'diagnostic',
48
+ icon: 'performance',
49
+ desc: '60 FPS monitor, Hermes memory telemetry & re-render profiler',
50
+ },
51
+ {
52
+ key: 'bundle',
53
+ label: 'Bundle Analyzer',
54
+ category: 'diagnostic',
55
+ icon: 'bundle',
56
+ desc: 'Metro packager dependencies, source maps & asset breakdown',
57
+ },
58
+ {
59
+ key: 'crash',
60
+ label: 'Crash Protection',
61
+ category: 'diagnostic',
62
+ icon: 'crash',
63
+ desc: 'Runtime exception guard, breadcrumbs & memory snapshot',
64
+ },
65
+ {
66
+ key: 'analytics',
67
+ label: 'Analytics Logger',
68
+ category: 'telemetry',
69
+ icon: 'analytics',
70
+ desc: 'Firebase & custom analytics events, user properties & params',
71
+ },
72
+ {
73
+ key: 'redux',
74
+ label: 'Redux Inspector',
75
+ category: 'telemetry',
76
+ icon: 'redux',
77
+ desc: 'Store state diffing, action history & reducer timeline',
78
+ },
79
+ ];
80
+ // Staged selection state for checkboxes before clicking "Save Changes"
81
+ const [stagedTabVisibility, setStagedTabVisibility] = useState(() => ({
82
+ apis: true,
83
+ logs: Boolean(tabVisibility?.logs),
84
+ analytics: Boolean(tabVisibility?.analytics),
85
+ redux: Boolean(tabVisibility?.redux),
86
+ bundle: Boolean(tabVisibility?.bundle),
87
+ performance: Boolean(tabVisibility?.performance),
88
+ crash: Boolean(tabVisibility?.crash),
89
+ }));
90
+ // Synchronize staged state with tabVisibility when tabVisibility updates
91
+ useEffect(() => {
92
+ setStagedTabVisibility({
93
+ apis: true,
94
+ logs: Boolean(tabVisibility?.logs),
95
+ analytics: Boolean(tabVisibility?.analytics),
96
+ redux: Boolean(tabVisibility?.redux),
97
+ bundle: Boolean(tabVisibility?.bundle),
98
+ performance: Boolean(tabVisibility?.performance),
99
+ crash: Boolean(tabVisibility?.crash),
100
+ });
101
+ }, [tabVisibility]);
102
+ const hasUnsavedChanges = useMemo(() => {
103
+ return allModules.some(m => Boolean(stagedTabVisibility[m.key]) !==
104
+ Boolean(tabVisibility?.[m.key]));
105
+ }, [stagedTabVisibility, tabVisibility, allModules]);
106
+ const stagedActiveCount = allModules.filter(m => m.key === 'apis' || Boolean(stagedTabVisibility[m.key])).length;
107
+ const handleSaveChanges = () => {
108
+ animateNextLayout();
109
+ allModules.forEach(m => {
110
+ if (m.key !== 'apis') {
111
+ const isStagedOn = Boolean(stagedTabVisibility[m.key]);
112
+ const isCurrentOn = Boolean(tabVisibility?.[m.key]);
113
+ if (isStagedOn !== isCurrentOn) {
114
+ toggleTabVisibility(m.key);
115
+ }
116
+ }
117
+ });
118
+ Alert.alert(t('settings.settingsSaved'), t('settings.settingsSavedDesc'));
119
+ };
25
120
  if (settingsPage === 'main') {
26
- const settingsTabs = [
27
- { key: 'apis', label: 'APIs', icon: 'apis' },
28
- { key: 'logs', label: 'Logs', icon: 'logs' },
29
- { key: 'analytics', label: 'Analytics', icon: 'analytics' },
30
- { key: 'redux', label: 'Redux', icon: 'redux' },
31
- { key: 'bundle', label: 'Bundle', icon: 'bundle' },
32
- { key: 'performance', label: 'Performance', icon: 'performance' },
33
- { key: 'crash', label: 'Crash', icon: 'crash' },
34
- ];
35
- return (<View style={{ flex: 1, backgroundColor: AppColors.grayBackground }}>
36
- {/* Settings Header with back button */}
121
+ return (<View style={{
122
+ flex: 1,
123
+ backgroundColor: AppColors.grayBackground,
124
+ }}>
125
+ {/* Modern Floating Gradient Header */}
37
126
  <LinearGradient colors={[AppColors.purple, AppColors.brandPurple]} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={styles.headerGradient}>
38
127
  <View style={{ paddingTop: headerTopPadding, width: '100%' }}>
39
- <View style={[styles.header, { paddingHorizontal: 16, gap: 12 }]}>
40
- <TouchableScale onPress={() => {
128
+ <View style={[
129
+ styles.header,
130
+ { paddingHorizontal: 16, paddingVertical: 12, gap: 12 },
131
+ ]}>
132
+ <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel={t('settings.back')} onPress={() => {
41
133
  animateNextLayout();
42
134
  setSettingsPage(null);
43
135
  switchActiveTab('apis');
@@ -46,223 +138,360 @@ const SettingsPanel = () => {
46
138
  borderRadius: 10,
47
139
  backgroundColor: `${AppColors.white}26`,
48
140
  borderWidth: 1,
49
- borderColor: `${AppColors.white}14`,
141
+ borderColor: `${AppColors.white}18`,
50
142
  }}>
51
- <WhiteBackNavigation color={AppColors.white} size={16}/>
52
- </TouchableScale>
53
- <View style={{ flex: 1 }}>
54
- <Text style={{
143
+ <WhiteBackNavigation color={AppColors.white} size={16}/>
144
+ </TouchableScale>
145
+
146
+ <View style={{ flex: 1 }}>
147
+ <View style={{
148
+ flexDirection: 'row',
149
+ alignItems: 'center',
150
+ gap: 8,
151
+ }}>
152
+ <Text style={{
55
153
  fontFamily: AppFonts.interBold,
56
154
  fontSize: 17,
57
155
  color: AppColors.white,
156
+ letterSpacing: -0.3,
157
+ lineHeight: 22,
58
158
  }}>
59
- Settings
60
- </Text>
61
- <Text style={{
159
+ {t('settings.mainTitle')}
160
+ </Text>
161
+ <View style={{
162
+ backgroundColor: `${AppColors.white}26`,
163
+ paddingHorizontal: 7,
164
+ paddingVertical: 2,
165
+ borderRadius: 12,
166
+ }}>
167
+ <Text style={{
168
+ fontFamily: AppFonts.interBold,
169
+ fontSize: 10,
170
+ color: AppColors.white,
171
+ lineHeight: 13,
172
+ }}>
173
+ {stagedActiveCount}/{allModules.length} Active
174
+ </Text>
175
+ </View>
176
+ </View>
177
+ <Text style={{
62
178
  fontFamily: AppFonts.interRegular,
63
179
  fontSize: 11,
64
- color: `${AppColors.white}BF`,
65
- marginTop: 1,
180
+ color: `${AppColors.white}CC`,
181
+ marginTop: 2,
182
+ lineHeight: 15,
66
183
  }}>
67
- Manage modules and preferences
68
- </Text>
69
- </View>
70
- <View style={{
71
- backgroundColor: `${AppColors.white}26`,
184
+ {t('settings.mainSubtitle')}
185
+ </Text>
186
+ </View>
187
+
188
+ <View style={{
189
+ backgroundColor: `${AppColors.white}22`,
72
190
  paddingHorizontal: 8,
73
191
  paddingVertical: 4,
74
192
  borderRadius: 8,
75
193
  borderWidth: 1,
76
194
  borderColor: `${AppColors.white}1A`,
77
195
  }}>
78
- <Text style={{
196
+ <Text style={{
79
197
  fontFamily: AppFonts.interBold,
80
198
  fontSize: 10.5,
81
199
  color: AppColors.white,
200
+ lineHeight: 14,
82
201
  }}>
83
- v{LIB_VERSION}
84
- </Text>
202
+ v{LIB_VERSION}
203
+ </Text>
204
+ </View>
85
205
  </View>
86
206
  </View>
87
- </View>
88
- </LinearGradient>
207
+ </LinearGradient>
89
208
 
90
- <ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16, gap: 12 }}>
91
- {/* Sub Tabs */}
209
+ <ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16, gap: 14 }} showsVerticalScrollIndicator={false}>
210
+ {/* Segmented Top Navigation Sub-Tabs */}
92
211
  <View style={{
93
212
  flexDirection: 'row',
94
213
  backgroundColor: AppColors.primaryLight,
95
- borderRadius: 10,
96
- padding: 3,
214
+ borderRadius: 12,
215
+ padding: 4,
97
216
  borderWidth: 1,
98
217
  borderColor: AppColors.grayBorderSecondary,
99
- marginBottom: 4,
218
+ shadowColor: AppColors.black,
219
+ shadowOpacity: 0.04,
220
+ shadowRadius: 4,
221
+ shadowOffset: { width: 0, height: 2 },
100
222
  }}>
101
- <TouchableOpacity onPress={() => {
223
+ <TouchableScale accessible={true} accessibilityRole="tab" accessibilityLabel={t('settings.modulesAndTools')} accessibilityState={{ selected: settingsActiveSubTab === 'module' }} onPress={() => {
102
224
  animateNextLayout();
103
225
  setSettingsActiveSubTab('module');
104
226
  }} style={{
105
227
  flex: 1,
106
- paddingVertical: 8,
228
+ paddingVertical: 9,
229
+ flexDirection: 'row',
107
230
  alignItems: 'center',
108
231
  justifyContent: 'center',
109
- borderRadius: 8,
232
+ gap: 6,
233
+ borderRadius: 9,
110
234
  backgroundColor: settingsActiveSubTab === 'module'
111
235
  ? AppColors.purple
112
236
  : 'transparent',
113
237
  }}>
238
+ <LayersIcon color={settingsActiveSubTab === 'module'
239
+ ? AppColors.white
240
+ : AppColors.grayText} size={13}/>
114
241
  <Text style={{
115
242
  fontFamily: AppFonts.interBold,
116
- fontSize: 12,
243
+ fontSize: 12.5,
244
+ lineHeight: 16,
117
245
  color: settingsActiveSubTab === 'module'
118
246
  ? AppColors.white
119
247
  : AppColors.grayText,
120
248
  }}>
121
- Module
249
+ {t('settings.modulesAndTools')}
122
250
  </Text>
123
- </TouchableOpacity>
124
- <TouchableOpacity onPress={() => {
251
+ </TouchableScale>
252
+
253
+ <TouchableScale accessible={true} accessibilityRole="tab" accessibilityLabel={t('settings.uiPreferences')} accessibilityState={{ selected: settingsActiveSubTab === 'ui' }} onPress={() => {
125
254
  animateNextLayout();
126
255
  setSettingsActiveSubTab('ui');
127
256
  }} style={{
128
257
  flex: 1,
129
- paddingVertical: 8,
258
+ paddingVertical: 9,
259
+ flexDirection: 'row',
130
260
  alignItems: 'center',
131
261
  justifyContent: 'center',
132
- borderRadius: 8,
262
+ gap: 6,
263
+ borderRadius: 9,
133
264
  backgroundColor: settingsActiveSubTab === 'ui'
134
265
  ? AppColors.purple
135
266
  : 'transparent',
136
267
  }}>
268
+ <ScreenIcon color={settingsActiveSubTab === 'ui'
269
+ ? AppColors.white
270
+ : AppColors.grayText} size={13}/>
137
271
  <Text style={{
138
272
  fontFamily: AppFonts.interBold,
139
- fontSize: 12,
273
+ fontSize: 12.5,
274
+ lineHeight: 16,
140
275
  color: settingsActiveSubTab === 'ui'
141
276
  ? AppColors.white
142
277
  : AppColors.grayText,
143
278
  }}>
144
- UI Preferences
279
+ {t('settings.uiPreferences')}
145
280
  </Text>
146
- </TouchableOpacity>
281
+ </TouchableScale>
147
282
  </View>
148
283
 
149
- {settingsActiveSubTab === 'module' ? (
150
- /* Tab list */
151
- <View style={{
152
- backgroundColor: AppColors.primaryLight,
284
+ {settingsActiveSubTab === 'module' ? (<View style={{ gap: 12 }}>
285
+ {/* Performance Advisory Banner */}
286
+ <View style={{
287
+ backgroundColor: `${AppColors.purple}0A`,
153
288
  borderRadius: 12,
289
+ padding: 12,
154
290
  borderWidth: 1,
155
- borderColor: AppColors.grayBorderSecondary,
156
- overflow: 'hidden',
157
- }}>
158
- {/* Table Header */}
159
- <View style={{
291
+ borderColor: `${AppColors.purple}20`,
160
292
  flexDirection: 'row',
161
293
  alignItems: 'center',
162
- paddingVertical: 8,
163
- paddingHorizontal: 14,
164
- backgroundColor: AppColors.grayBackground,
165
- borderBottomWidth: 1,
166
- borderBottomColor: AppColors.dividerColor,
167
- gap: 12,
294
+ gap: 10,
168
295
  }}>
169
- <Text style={{
170
- fontFamily: AppFonts.interBold,
171
- fontSize: 10,
172
- color: AppColors.grayTextWeak,
173
- letterSpacing: 0.6,
174
- flex: 1,
296
+ <View style={{
297
+ width: 32,
298
+ height: 32,
299
+ borderRadius: 8,
300
+ backgroundColor: `${AppColors.purple}14`,
301
+ alignItems: 'center',
302
+ justifyContent: 'center',
175
303
  }}>
176
- MODULE
177
- </Text>
178
- <Text style={{
304
+ <SignalIcon color={AppColors.purple} size={15}/>
305
+ </View>
306
+ <View style={{ flex: 1 }}>
307
+ <Text style={{
179
308
  fontFamily: AppFonts.interBold,
180
- fontSize: 10,
181
- color: AppColors.grayTextWeak,
182
- letterSpacing: 0.6,
183
- width: 90,
184
- textAlign: 'right',
185
- paddingRight: 4,
309
+ fontSize: 12,
310
+ color: AppColors.primaryBlack,
311
+ lineHeight: 16,
186
312
  }}>
187
- VISIBILITY
188
- </Text>
313
+ {t('settings.zeroOverheadTitle')}
314
+ </Text>
315
+ <Text style={{
316
+ fontFamily: AppFonts.interRegular,
317
+ fontSize: 10.5,
318
+ color: AppColors.grayText,
319
+ marginTop: 2,
320
+ lineHeight: 14,
321
+ }}>
322
+ {t('settings.zeroOverheadDesc')}
323
+ </Text>
324
+ </View>
189
325
  </View>
190
326
 
191
- {settingsTabs.map((tab, idx) => {
327
+ {/* Enhanced Individual Module Cards with Decorative Checkboxes */}
328
+ <View style={{ gap: 10 }}>
329
+ {allModules.map(moduleItem => {
192
330
  const isReduxAvail = isReduxConnected();
193
331
  const isAnalyticsAvail = isAnalyticsConnected();
194
- const isUnavailable = (tab.key === 'redux' && !isReduxAvail) ||
195
- (tab.key === 'analytics' && !isAnalyticsAvail);
196
- const isLocked = tab.key === 'apis' || isUnavailable;
197
- const isVisible = tab.key === 'apis' ||
198
- (Boolean(tabVisibility?.[tab.key]) && !isUnavailable);
199
- const isLast = idx === settingsTabs.length - 1;
200
- return (<View key={tab.key} style={{
332
+ const isUnavailable = (moduleItem.key === 'redux' && !isReduxAvail) ||
333
+ (moduleItem.key === 'analytics' && !isAnalyticsAvail);
334
+ const isLocked = moduleItem.key === 'apis' || isUnavailable;
335
+ const isChecked = moduleItem.key === 'apis' ||
336
+ (Boolean(stagedTabVisibility?.[moduleItem.key]) &&
337
+ !isUnavailable);
338
+ const liveStats = moduleItem.key === 'apis'
339
+ ? `${logs.length} requests • Limit: ${maxNetworkLogs}`
340
+ : moduleItem.key === 'logs'
341
+ ? `${consoleLogs.length} logs • Limit: ${maxConsoleLogs}`
342
+ : moduleItem.key === 'performance'
343
+ ? '60 FPS Target • Memory Telemetry'
344
+ : moduleItem.key === 'bundle'
345
+ ? 'Metro Packager • Dependency Map'
346
+ : moduleItem.key === 'crash'
347
+ ? `${crashRecords?.length || 0} crashes recorded • Crash Guard`
348
+ : moduleItem.key === 'analytics'
349
+ ? `${analyticsEvents.length} events logged`
350
+ : moduleItem.key === 'redux'
351
+ ? `${Object.keys(reduxState || {}).length} slices • Depth: ${reduxExpandDepth}`
352
+ : '';
353
+ return (<View key={moduleItem.key} style={{
354
+ backgroundColor: AppColors.primaryLight,
355
+ borderRadius: 14,
356
+ borderWidth: 1.5,
357
+ borderColor: isChecked
358
+ ? `${AppColors.purple}38`
359
+ : AppColors.grayBorderSecondary,
360
+ padding: 14,
361
+ gap: 10,
362
+ shadowColor: AppColors.black,
363
+ shadowOpacity: isChecked ? 0.04 : 0.02,
364
+ shadowRadius: 5,
365
+ shadowOffset: { width: 0, height: 2 },
366
+ }}>
367
+ {/* Top Row: Icon + Title & Badges + Checkbox */}
368
+ <View style={{
201
369
  flexDirection: 'row',
202
- alignItems: 'center',
203
- paddingVertical: 10,
204
- paddingHorizontal: 14,
205
- borderBottomWidth: isLast ? 0 : 1,
206
- borderBottomColor: AppColors.dividerColor,
207
- gap: 12,
370
+ alignItems: 'flex-start',
371
+ justifyContent: 'space-between',
372
+ gap: 10,
208
373
  }}>
209
- {/* Icon + Label fills remaining space */}
210
- <View style={{
374
+ {/* Tap Zone for Details/Settings */}
375
+ <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel={`${moduleItem.label} settings`} disabled={isUnavailable} onPress={() => {
376
+ animateNextLayout();
377
+ setSettingsPage(moduleItem.key);
378
+ }} style={{
211
379
  flex: 1,
212
380
  flexDirection: 'row',
213
- alignItems: 'center',
214
- gap: 8,
215
- flexWrap: 'wrap',
381
+ alignItems: 'flex-start',
382
+ gap: 10,
216
383
  }}>
217
- {/* Small icon tile */}
218
- <View style={{
219
- width: 20,
220
- height: 20,
221
- borderRadius: 6,
384
+ {/* Icon Tile */}
385
+ <View style={{
386
+ width: 36,
387
+ height: 36,
388
+ borderRadius: 10,
222
389
  backgroundColor: isLocked
223
- ? AppColors.grayBorderSecondary
224
- : AppColors.purpleShade50,
390
+ ? `${AppColors.grayBorderSecondary}4D`
391
+ : isChecked
392
+ ? `${AppColors.purple}14`
393
+ : AppColors.grayBackground,
225
394
  borderWidth: 1,
226
395
  borderColor: isLocked
227
396
  ? AppColors.dividerColor
228
- : `${AppColors.purple}33`,
397
+ : isChecked
398
+ ? `${AppColors.purple}33`
399
+ : AppColors.grayBorderSecondary,
229
400
  alignItems: 'center',
230
401
  justifyContent: 'center',
402
+ marginTop: 1,
231
403
  }}>
232
- {tab.icon === 'apis' && (<SignalIcon color={isLocked
233
- ? AppColors.grayTextWeak
234
- : AppColors.purple} size={11}/>)}
235
- {tab.icon === 'logs' && (<TerminalIcon color={isLocked
236
- ? AppColors.grayTextWeak
237
- : AppColors.purple} size={11}/>)}
238
- {tab.icon === 'analytics' && (<AnalyticsIcon color={isLocked
239
- ? AppColors.grayTextWeak
240
- : AppColors.purple} size={11}/>)}
241
- {tab.icon === 'redux' && (<ReduxIcon color={isLocked
242
- ? AppColors.grayTextWeak
243
- : AppColors.purple} size={11}/>)}
244
- {tab.icon === 'bundle' && (<PackageIcon color={isLocked
245
- ? AppColors.grayTextWeak
246
- : AppColors.purple} size={11}/>)}
247
- {tab.icon === 'performance' && (<PerformanceIcon color={isLocked
248
- ? AppColors.grayTextWeak
249
- : AppColors.purple} size={11}/>)}
250
- {tab.icon === 'crash' && (<CrashIcon color={isLocked
251
- ? AppColors.grayTextWeak
252
- : AppColors.purple} size={11}/>)}
253
- </View>
254
- {/* Label + Required badge */}
255
- <Text style={{
404
+ {moduleItem.icon === 'apis' && (<SignalIcon color={isChecked
405
+ ? AppColors.purple
406
+ : AppColors.grayTextWeak} size={16}/>)}
407
+ {moduleItem.icon === 'logs' && (<TerminalIcon color={isChecked
408
+ ? AppColors.purple
409
+ : AppColors.grayTextWeak} size={16}/>)}
410
+ {moduleItem.icon === 'performance' && (<PerformanceIcon color={isChecked
411
+ ? AppColors.purple
412
+ : AppColors.grayTextWeak} size={16}/>)}
413
+ {moduleItem.icon === 'bundle' && (<PackageIcon color={isChecked
414
+ ? AppColors.purple
415
+ : AppColors.grayTextWeak} size={16}/>)}
416
+ {moduleItem.icon === 'crash' && (<CrashIcon color={isChecked
417
+ ? AppColors.purple
418
+ : AppColors.grayTextWeak} size={16}/>)}
419
+ {moduleItem.icon === 'analytics' && (<AnalyticsIcon color={isChecked
420
+ ? AppColors.purple
421
+ : AppColors.grayTextWeak} size={16}/>)}
422
+ {moduleItem.icon === 'redux' && (<ReduxIcon color={isChecked
423
+ ? AppColors.purple
424
+ : AppColors.grayTextWeak} size={16}/>)}
425
+ </View>
426
+
427
+ {/* Titles & Status Pill */}
428
+ <View style={{ flex: 1, gap: 2 }}>
429
+ <View style={{
430
+ flexDirection: 'row',
431
+ alignItems: 'center',
432
+ gap: 6,
433
+ flexWrap: 'wrap',
434
+ }}>
435
+ <Text style={{
256
436
  fontFamily: AppFonts.interBold,
257
- fontSize: 13,
437
+ fontSize: 14,
438
+ lineHeight: 18,
258
439
  color: isLocked
259
440
  ? AppColors.grayText
260
441
  : AppColors.primaryBlack,
261
442
  }}>
262
- {tab.label}
263
- </Text>
264
- {/* Unavailable badge */}
265
- {isUnavailable && (<View style={{
443
+ {moduleItem.label}
444
+ </Text>
445
+
446
+ {/* Default Startup Tab Badge */}
447
+ {moduleItem.key === defaultTab &&
448
+ !isUnavailable && (<View style={{
449
+ flexDirection: 'row',
450
+ alignItems: 'center',
451
+ backgroundColor: `${AppColors.purple}14`,
452
+ borderRadius: 12,
453
+ paddingHorizontal: 5,
454
+ paddingVertical: 1.5,
455
+ borderWidth: 1,
456
+ borderColor: `${AppColors.purple}2E`,
457
+ gap: 3,
458
+ }}>
459
+ <View style={{
460
+ width: 4,
461
+ height: 4,
462
+ borderRadius: 2,
463
+ backgroundColor: AppColors.purple,
464
+ }}/>
465
+ <Text style={{
466
+ fontFamily: AppFonts.interBold,
467
+ fontSize: 8,
468
+ lineHeight: 11,
469
+ color: AppColors.purple,
470
+ letterSpacing: 0.4,
471
+ }}>
472
+ {t('settings.defaultBadge')}
473
+ </Text>
474
+ </View>)}
475
+
476
+ {/* Status Pill */}
477
+ {moduleItem.key === 'apis' ? (<View style={{
478
+ backgroundColor: `${AppColors.blue500}14`,
479
+ borderRadius: 4,
480
+ paddingHorizontal: 5,
481
+ paddingVertical: 1.5,
482
+ borderWidth: 1,
483
+ borderColor: `${AppColors.blue500}33`,
484
+ }}>
485
+ <Text style={{
486
+ fontFamily: AppFonts.interBold,
487
+ fontSize: 8,
488
+ lineHeight: 11,
489
+ color: AppColors.blue500,
490
+ letterSpacing: 0.3,
491
+ }}>
492
+ {t('settings.coreBadge')}
493
+ </Text>
494
+ </View>) : isUnavailable ? (<View style={{
266
495
  backgroundColor: `${AppColors.amber500}18`,
267
496
  borderRadius: 4,
268
497
  paddingHorizontal: 5,
@@ -270,181 +499,244 @@ const SettingsPanel = () => {
270
499
  borderWidth: 1,
271
500
  borderColor: `${AppColors.amber500}35`,
272
501
  }}>
273
- <Text style={{
502
+ <Text style={{
274
503
  fontFamily: AppFonts.interBold,
275
504
  fontSize: 8,
505
+ lineHeight: 11,
276
506
  color: AppColors.amber700,
277
507
  letterSpacing: 0.3,
278
508
  }}>
279
- {tab.key === 'redux'
509
+ {moduleItem.key === 'redux'
280
510
  ? t('settings.notConnectedBadge')
281
511
  : t('settings.notDetectedBadge')}
282
- </Text>
283
- </View>)}
284
- {/* #6 — badge marks the configured default tab */}
285
- {tab.key === defaultTab && !isUnavailable && (<View style={{
286
- flexDirection: 'row',
287
- alignItems: 'center',
288
- backgroundColor: `${AppColors.purple}14`,
289
- borderRadius: 20,
290
- paddingHorizontal: 6,
291
- paddingVertical: 2,
512
+ </Text>
513
+ </View>) : isChecked ? (<View style={{
514
+ backgroundColor: `${AppColors.liveGreen}18`,
515
+ borderRadius: 4,
516
+ paddingHorizontal: 5,
517
+ paddingVertical: 1.5,
292
518
  borderWidth: 1,
293
- borderColor: `${AppColors.purple}2E`,
294
- gap: 3,
519
+ borderColor: `${AppColors.liveGreen}38`,
295
520
  }}>
296
- <View style={{
297
- width: 4,
298
- height: 4,
299
- borderRadius: 2,
300
- backgroundColor: AppColors.purple,
301
- opacity: 0.7,
302
- }}/>
303
- <Text style={{
521
+ <Text style={{
304
522
  fontFamily: AppFonts.interBold,
305
- fontSize: 8.5,
306
- color: AppColors.purple,
307
- letterSpacing: 0.4,
523
+ fontSize: 8,
524
+ lineHeight: 11,
525
+ color: AppColors.green700,
526
+ letterSpacing: 0.3,
308
527
  }}>
309
- DEFAULT
310
- </Text>
311
- </View>)}
312
-
313
- {/* Settings gear icon next to label */}
314
- {!isUnavailable && (<TouchableScale onPress={() => {
315
- animateNextLayout();
316
- setSettingsPage(tab.key);
317
- }} hitSlop={8} style={{
318
- marginLeft: 4,
319
- padding: 4,
320
- borderRadius: 6,
321
- backgroundColor: AppColors.purpleShade50,
528
+ {t('settings.activeBadge')}
529
+ </Text>
530
+ </View>) : (<View style={{
531
+ backgroundColor: `${AppColors.grayTextWeak}18`,
532
+ borderRadius: 4,
533
+ paddingHorizontal: 5,
534
+ paddingVertical: 1.5,
322
535
  borderWidth: 1,
323
- borderColor: `${AppColors.purple}26`,
324
- alignItems: 'center',
325
- justifyContent: 'center',
536
+ borderColor: `${AppColors.grayTextWeak}2E`,
326
537
  }}>
327
- <SettingsIcon color={AppColors.purple} size={10}/>
328
- </TouchableScale>)}
329
- </View>
538
+ <Text style={{
539
+ fontFamily: AppFonts.interBold,
540
+ fontSize: 8,
541
+ lineHeight: 11,
542
+ color: AppColors.grayTextWeak,
543
+ letterSpacing: 0.3,
544
+ }}>
545
+ {t('settings.dormantBadge')}
546
+ </Text>
547
+ </View>)}
548
+ </View>
330
549
 
331
- {/* Visibility Switch in VISIBILITY column */}
332
- <View style={{
333
- width: 90,
334
- alignItems: 'flex-end',
335
- justifyContent: 'center',
550
+ <Text style={{
551
+ fontFamily: AppFonts.interRegular,
552
+ fontSize: 11,
553
+ color: AppColors.grayText,
554
+ lineHeight: 15,
555
+ marginTop: 1,
336
556
  }}>
337
- <TouchableScale disabled={isLocked} onPress={() => toggleTabVisibility(tab.key)} style={{
338
- width: 38,
339
- height: 22,
340
- borderRadius: 11,
341
- backgroundColor: isLocked
342
- ? AppColors.grayBackground
343
- : isVisible
344
- ? AppColors.purple
345
- : AppColors.grayBorderSecondary,
346
- borderWidth: isLocked ? 1.5 : 0,
557
+ {moduleItem.desc}
558
+ </Text>
559
+ </View>
560
+ </TouchableScale>
561
+
562
+ {/* Decorative Custom Checkbox */}
563
+ <TouchableScale accessible={true} accessibilityRole="checkbox" accessibilityLabel={`Select ${moduleItem.label}`} accessibilityState={{
564
+ checked: isChecked,
565
+ disabled: isLocked,
566
+ }} disabled={isLocked} onPress={() => {
567
+ if (isLocked)
568
+ return;
569
+ setStagedTabVisibility(prev => ({
570
+ ...prev,
571
+ [moduleItem.key]: !prev[moduleItem.key],
572
+ }));
573
+ }} style={{
574
+ width: 26,
575
+ height: 26,
576
+ borderRadius: 8,
577
+ borderWidth: isChecked ? 0 : 2,
347
578
  borderColor: isLocked
348
- ? AppColors.grayBorderSecondary
349
- : 'transparent',
350
- borderStyle: isLocked ? 'dashed' : 'solid',
351
- padding: 2,
352
- justifyContent: 'center',
353
- alignItems: isVisible ? 'flex-end' : 'flex-start',
354
- opacity: isLocked ? 0.9 : 1,
355
- }}>
356
- <View style={{
357
- width: 18,
358
- height: 18,
359
- borderRadius: 9,
360
- backgroundColor: isLocked
361
- ? AppColors.grayBorderSecondary
362
- : AppColors.white,
579
+ ? AppColors.dividerColor
580
+ : AppColors.grayBorderSecondary,
581
+ backgroundColor: moduleItem.key === 'apis'
582
+ ? `${AppColors.blue500}22`
583
+ : isChecked
584
+ ? AppColors.purple
585
+ : AppColors.grayBackground,
363
586
  alignItems: 'center',
364
587
  justifyContent: 'center',
365
- shadowColor: AppColors.black,
366
- shadowOpacity: isLocked ? 0 : 0.15,
367
- shadowRadius: 1.5,
588
+ shadowColor: isChecked
589
+ ? AppColors.purple
590
+ : 'transparent',
591
+ shadowOpacity: isChecked ? 0.3 : 0,
592
+ shadowRadius: 3,
368
593
  shadowOffset: { width: 0, height: 1 },
594
+ elevation: isChecked ? 2 : 0,
369
595
  }}>
370
- {isLocked && (<Svg width={10} height={10} viewBox="0 0 24 24" fill="none">
596
+ {moduleItem.key === 'apis' ? (<CheckIcon size={14} color={AppColors.blue500}/>) : isChecked ? (<CheckIcon size={14} color={AppColors.white}/>) : isLocked ? (<Svg width={10} height={10} viewBox="0 0 24 24" fill="none">
371
597
  <Path d="M7 10V7a5 5 0 0 1 10 0v3" stroke={AppColors.grayText} strokeWidth="2.2" strokeLinecap="round"/>
372
598
  <Path d="M5 10h14v9a1 1 0 0 1-1 1H6a1 1 0 0 1-1-1z" fill={AppColors.grayText}/>
373
- </Svg>)}
374
- </View>
375
- </TouchableScale>
376
- {isLocked && (<Text style={{
377
- fontFamily: AppFonts.interBold,
378
- fontSize: 7.5,
379
- color: isUnavailable
380
- ? AppColors.amber700
599
+ </Svg>) : null}
600
+ </TouchableScale>
601
+ </View>
602
+
603
+ {/* Card Footer: Live Stats + Configure Button */}
604
+ {!isUnavailable && (<View style={{
605
+ flexDirection: 'row',
606
+ alignItems: 'center',
607
+ justifyContent: 'space-between',
608
+ paddingTop: 8,
609
+ borderTopWidth: 1,
610
+ borderTopColor: AppColors.dividerColor,
611
+ }}>
612
+ {/* Live Info Pill */}
613
+ <View style={{
614
+ flexDirection: 'row',
615
+ alignItems: 'center',
616
+ gap: 6,
617
+ flex: 1,
618
+ }}>
619
+ <View style={{
620
+ width: 6,
621
+ height: 6,
622
+ borderRadius: 3,
623
+ backgroundColor: isChecked
624
+ ? AppColors.liveGreen
381
625
  : AppColors.grayTextWeak,
382
- letterSpacing: 0.3,
383
- marginTop: 3,
384
- textAlign: 'right',
626
+ }}/>
627
+ <Text style={{
628
+ fontFamily: AppFonts.interMedium,
629
+ fontSize: 11,
630
+ color: AppColors.grayText,
631
+ lineHeight: 14,
385
632
  }}>
386
- {tab.key === 'apis'
387
- ? t('settings.requiredBadge')
388
- : t('settings.readOnlyBadge')}
389
- </Text>)}
390
- </View>
391
- </View>);
633
+ {liveStats}
634
+ </Text>
635
+ </View>
636
+
637
+ {/* Sleek Configure Button */}
638
+ <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel={`Configure ${moduleItem.label} settings`} onPress={() => {
639
+ animateNextLayout();
640
+ setSettingsPage(moduleItem.key);
641
+ }} style={{
642
+ flexDirection: 'row',
643
+ alignItems: 'center',
644
+ gap: 5,
645
+ backgroundColor: `${AppColors.purple}12`,
646
+ paddingHorizontal: 10,
647
+ paddingVertical: 5,
648
+ borderRadius: 8,
649
+ borderWidth: 1,
650
+ borderColor: `${AppColors.purple}26`,
651
+ }}>
652
+ <SettingsIcon color={AppColors.purple} size={11}/>
653
+ <Text style={{
654
+ fontFamily: AppFonts.interBold,
655
+ fontSize: 11,
656
+ lineHeight: 14,
657
+ color: AppColors.purple,
658
+ }}>
659
+ {t('settings.configure')}
660
+ </Text>
661
+ <ForwardChevronIcon color={AppColors.purple} size={9}/>
662
+ </TouchableScale>
663
+ </View>)}
664
+ </View>);
392
665
  })}
666
+ </View>
393
667
  </View>) : (
394
- /* UI Preferences Section */
395
- <View style={{
668
+ /* UI Preferences Subtab */
669
+ <View style={{ gap: 14 }}>
670
+ {/* Section 1: Appearance */}
671
+ <View style={{
396
672
  backgroundColor: AppColors.primaryLight,
397
- borderRadius: 12,
673
+ borderRadius: 14,
398
674
  borderWidth: 1,
399
675
  borderColor: AppColors.grayBorderSecondary,
400
676
  overflow: 'hidden',
401
- }}>
402
- <View style={{
403
- flexDirection: 'row',
404
- alignItems: 'center',
405
- paddingVertical: 12,
406
- paddingHorizontal: 14,
677
+ padding: 14,
407
678
  gap: 12,
408
679
  }}>
409
- {/* Icon + Label */}
680
+ <Text style={{
681
+ fontFamily: AppFonts.interBold,
682
+ fontSize: 11,
683
+ lineHeight: 14,
684
+ color: AppColors.grayTextWeak,
685
+ letterSpacing: 0.8,
686
+ }}>
687
+ {t('settings.appearanceTheme')}
688
+ </Text>
689
+
410
690
  <View style={{
411
- flex: 1,
412
691
  flexDirection: 'row',
413
692
  alignItems: 'center',
414
- gap: 8,
693
+ justifyContent: 'space-between',
415
694
  }}>
416
695
  <View style={{
417
- width: 20,
418
- height: 20,
419
- borderRadius: 6,
696
+ flexDirection: 'row',
697
+ alignItems: 'center',
698
+ gap: 10,
699
+ flex: 1,
700
+ }}>
701
+ <View style={{
702
+ width: 32,
703
+ height: 32,
704
+ borderRadius: 8,
420
705
  backgroundColor: AppColors.purpleShade50,
421
- borderWidth: 1,
422
- borderColor: `${AppColors.purple}33`,
423
706
  alignItems: 'center',
424
707
  justifyContent: 'center',
425
708
  }}>
426
- {isDark ? (<SunIcon color={AppColors.purple} size={11}/>) : (<MoonIcon color={AppColors.purple} size={11}/>)}
427
- </View>
428
- <View style={{ flex: 1 }}>
429
- <Text style={{
709
+ {isDark ? (<SunIcon color={AppColors.purple} size={15}/>) : (<MoonIcon color={AppColors.purple} size={15}/>)}
710
+ </View>
711
+ <View style={{ flex: 1 }}>
712
+ <Text style={{
430
713
  fontFamily: AppFonts.interBold,
431
- fontSize: 13,
714
+ fontSize: 13.5,
715
+ lineHeight: 18,
432
716
  color: AppColors.primaryBlack,
433
717
  }}>
434
- Dark Theme
435
- </Text>
718
+ {t('settings.general.darkMode')}
719
+ </Text>
720
+ <Text style={{
721
+ fontFamily: AppFonts.interRegular,
722
+ fontSize: 11,
723
+ lineHeight: 15,
724
+ color: AppColors.grayText,
725
+ marginTop: 1,
726
+ }}>
727
+ {t('settings.general.darkModeDescription')}
728
+ </Text>
729
+ </View>
436
730
  </View>
437
- </View>
438
731
 
439
- {/* Toggle Switch */}
440
- <TouchableScale onPress={() => {
732
+ <TouchableScale accessible={true} accessibilityRole="switch" accessibilityLabel="Toggle Dark Theme" accessibilityState={{ checked: isDark }} onPress={() => {
441
733
  const newTheme = !isDark;
442
734
  setIsDark(newTheme);
443
735
  toggleGlobalTheme(newTheme);
444
736
  }} style={{
445
- width: 38,
446
- height: 22,
447
- borderRadius: 11,
737
+ width: 42,
738
+ height: 24,
739
+ borderRadius: 12,
448
740
  backgroundColor: isDark
449
741
  ? AppColors.purple
450
742
  : AppColors.grayBorderSecondary,
@@ -452,226 +744,243 @@ const SettingsPanel = () => {
452
744
  justifyContent: 'center',
453
745
  alignItems: isDark ? 'flex-end' : 'flex-start',
454
746
  }}>
455
- <View style={{
456
- width: 18,
457
- height: 18,
458
- borderRadius: 9,
747
+ <View style={{
748
+ width: 20,
749
+ height: 20,
750
+ borderRadius: 10,
459
751
  backgroundColor: AppColors.white,
460
752
  shadowColor: AppColors.black,
461
- shadowOpacity: 0.15,
462
- shadowRadius: 1.5,
753
+ shadowOpacity: 0.18,
754
+ shadowRadius: 2,
463
755
  shadowOffset: { width: 0, height: 1 },
464
756
  }}/>
465
- </TouchableScale>
757
+ </TouchableScale>
758
+ </View>
466
759
  </View>
467
760
 
468
- {/* Divider */}
469
- <View style={{
470
- height: 1,
471
- backgroundColor: AppColors.dividerColor,
472
- }}/>
473
-
474
- {/* Modal Height */}
761
+ {/* Section 2: Window & Layout */}
475
762
  <View style={{
476
- paddingVertical: 12,
477
- paddingHorizontal: 14,
763
+ backgroundColor: AppColors.primaryLight,
764
+ borderRadius: 14,
765
+ borderWidth: 1,
766
+ borderColor: AppColors.grayBorderSecondary,
767
+ overflow: 'hidden',
768
+ padding: 14,
769
+ gap: 14,
478
770
  }}>
479
- <View style={{
771
+ <Text style={{
772
+ fontFamily: AppFonts.interBold,
773
+ fontSize: 11,
774
+ lineHeight: 14,
775
+ color: AppColors.grayTextWeak,
776
+ letterSpacing: 0.8,
777
+ }}>
778
+ {t('settings.windowLayout')}
779
+ </Text>
780
+
781
+ {/* Modal Height */}
782
+ <View style={{ gap: 8 }}>
783
+ <View style={{
480
784
  flexDirection: 'row',
481
785
  alignItems: 'center',
482
- gap: 8,
786
+ gap: 10,
483
787
  }}>
484
- <View style={{
485
- width: 20,
486
- height: 20,
487
- borderRadius: 6,
788
+ <View style={{
789
+ width: 32,
790
+ height: 32,
791
+ borderRadius: 8,
488
792
  backgroundColor: AppColors.purpleShade50,
489
- borderWidth: 1,
490
- borderColor: `${AppColors.purple}33`,
491
793
  alignItems: 'center',
492
794
  justifyContent: 'center',
493
795
  }}>
494
- <ScreenIcon color={AppColors.purple} size={11}/>
495
- </View>
496
- <View style={{ flex: 1 }}>
497
- <Text style={{
796
+ <ScreenIcon color={AppColors.purple} size={15}/>
797
+ </View>
798
+ <View style={{ flex: 1 }}>
799
+ <Text style={{
498
800
  fontFamily: AppFonts.interBold,
499
- fontSize: 13,
801
+ fontSize: 13.5,
802
+ lineHeight: 18,
500
803
  color: AppColors.primaryBlack,
501
804
  }}>
502
- Modal Height
503
- </Text>
504
- <Text style={{
805
+ {t('settings.general.modalHeight')}
806
+ </Text>
807
+ <Text style={{
505
808
  fontFamily: AppFonts.interRegular,
506
809
  fontSize: 11,
810
+ lineHeight: 15,
507
811
  color: AppColors.grayText,
508
812
  marginTop: 1,
509
813
  }}>
510
- Height of the inspector panel relative to the screen
511
- </Text>
814
+ {t('settings.general.modalHeightDescription')}
815
+ </Text>
816
+ </View>
512
817
  </View>
513
- </View>
514
818
 
515
- {/* Segmented picker */}
516
- <View style={{
819
+ <View style={{
517
820
  flexDirection: 'row',
518
821
  backgroundColor: AppColors.grayBackground,
519
- borderRadius: 8,
520
- padding: 2.5,
521
- marginTop: 10,
822
+ borderRadius: 10,
823
+ padding: 3,
522
824
  borderWidth: 1,
523
825
  borderColor: AppColors.dividerColor,
524
826
  }}>
525
- {[50, 70, 90, 100].map(opt => {
827
+ {[50, 70, 90, 100].map(opt => {
526
828
  const isActive = modalHeightPercent === opt;
527
- return (<TouchableScale key={opt} onPress={() => setModalHeightPercent(opt)} style={{
829
+ return (<TouchableScale key={opt} accessible={true} accessibilityRole="button" accessibilityLabel={`Set window height to ${opt} percent`} accessibilityState={{ selected: isActive }} onPress={() => setModalHeightPercent(opt)} style={{
528
830
  flex: 1,
529
- paddingVertical: 6,
831
+ paddingVertical: 7,
530
832
  alignItems: 'center',
531
- borderRadius: 6,
833
+ borderRadius: 8,
532
834
  backgroundColor: isActive
533
835
  ? AppColors.purple
534
836
  : 'transparent',
535
837
  }}>
536
- <Text style={{
838
+ <Text style={{
537
839
  fontFamily: AppFonts.interBold,
538
- fontSize: 11,
539
- color: isActive ? AppColors.white : AppColors.grayText,
840
+ fontSize: 11.5,
841
+ lineHeight: 15,
842
+ color: isActive
843
+ ? AppColors.white
844
+ : AppColors.grayText,
540
845
  }}>
541
- {opt}%
542
- </Text>
543
- </TouchableScale>);
846
+ {opt}%
847
+ </Text>
848
+ </TouchableScale>);
544
849
  })}
850
+ </View>
545
851
  </View>
546
- </View>
547
852
 
548
- {/* Divider */}
549
- <View style={{
550
- height: 1,
551
- backgroundColor: AppColors.dividerColor,
552
- }}/>
853
+ <View style={{ height: 1, backgroundColor: AppColors.dividerColor }}/>
553
854
 
554
- {/* Modal Animation */}
555
- <View style={{
556
- paddingVertical: 12,
557
- paddingHorizontal: 14,
558
- }}>
559
- <View style={{
855
+ {/* Modal Animation */}
856
+ <View style={{ gap: 8 }}>
857
+ <View style={{
560
858
  flexDirection: 'row',
561
859
  alignItems: 'center',
562
- gap: 8,
860
+ gap: 10,
563
861
  }}>
564
- <View style={{
565
- width: 20,
566
- height: 20,
567
- borderRadius: 6,
862
+ <View style={{
863
+ width: 32,
864
+ height: 32,
865
+ borderRadius: 8,
568
866
  backgroundColor: AppColors.purpleShade50,
569
- borderWidth: 1,
570
- borderColor: `${AppColors.purple}33`,
571
867
  alignItems: 'center',
572
868
  justifyContent: 'center',
573
869
  }}>
574
- <MotionIcon color={AppColors.purple} size={11}/>
575
- </View>
576
- <View style={{ flex: 1 }}>
577
- <Text style={{
870
+ <MotionIcon color={AppColors.purple} size={15}/>
871
+ </View>
872
+ <View style={{ flex: 1 }}>
873
+ <Text style={{
578
874
  fontFamily: AppFonts.interBold,
579
- fontSize: 13,
875
+ fontSize: 13.5,
876
+ lineHeight: 18,
580
877
  color: AppColors.primaryBlack,
581
878
  }}>
582
- Modal Animation
583
- </Text>
584
- <Text style={{
879
+ {t('settings.general.modalAnimation')}
880
+ </Text>
881
+ <Text style={{
585
882
  fontFamily: AppFonts.interRegular,
586
883
  fontSize: 11,
884
+ lineHeight: 15,
587
885
  color: AppColors.grayText,
588
886
  marginTop: 1,
589
887
  }}>
590
- How the inspector panel enters and exits the screen
591
- </Text>
888
+ {t('settings.general.modalAnimationDescription')}
889
+ </Text>
890
+ </View>
592
891
  </View>
593
- </View>
594
892
 
595
- {/* Segmented picker */}
596
- <View style={{
893
+ <View style={{
597
894
  flexDirection: 'row',
598
895
  backgroundColor: AppColors.grayBackground,
599
- borderRadius: 8,
600
- padding: 2.5,
601
- marginTop: 10,
896
+ borderRadius: 10,
897
+ padding: 3,
602
898
  borderWidth: 1,
603
899
  borderColor: AppColors.dividerColor,
604
900
  }}>
605
- {([
901
+ {[
606
902
  { key: 'slide', label: 'Slide Up' },
607
903
  { key: 'fade', label: 'Fade' },
608
904
  { key: 'none', label: 'None' },
609
- ]).map(opt => {
905
+ ].map(opt => {
610
906
  const isActive = modalAnimationType === opt.key;
611
- return (<TouchableScale key={opt.key} onPress={() => setModalAnimationType(opt.key)} style={{
907
+ return (<TouchableScale key={opt.key} accessible={true} accessibilityRole="button" accessibilityLabel={`Set transition animation to ${opt.label}`} accessibilityState={{ selected: isActive }} onPress={() => setModalAnimationType(opt.key)} style={{
612
908
  flex: 1,
613
- paddingVertical: 6,
909
+ paddingVertical: 7,
614
910
  alignItems: 'center',
615
- borderRadius: 6,
911
+ borderRadius: 8,
616
912
  backgroundColor: isActive
617
913
  ? AppColors.purple
618
914
  : 'transparent',
619
915
  }}>
620
- <Text style={{
916
+ <Text style={{
621
917
  fontFamily: AppFonts.interBold,
622
- fontSize: 11,
623
- color: isActive ? AppColors.white : AppColors.grayText,
918
+ fontSize: 11.5,
919
+ lineHeight: 15,
920
+ color: isActive
921
+ ? AppColors.white
922
+ : AppColors.grayText,
624
923
  }}>
625
- {opt.label}
626
- </Text>
627
- </TouchableScale>);
924
+ {opt.label}
925
+ </Text>
926
+ </TouchableScale>);
628
927
  })}
928
+ </View>
629
929
  </View>
630
930
  </View>
631
931
 
632
- {/* Divider */}
932
+ {/* Section 3: Default Startup Tab */}
633
933
  <View style={{
634
- height: 1,
635
- backgroundColor: AppColors.dividerColor,
636
- }}/>
637
-
638
- {/* #6 — Default Tab */}
639
- <View style={{
640
- paddingVertical: 12,
641
- paddingHorizontal: 14,
934
+ backgroundColor: AppColors.primaryLight,
935
+ borderRadius: 14,
936
+ borderWidth: 1,
937
+ borderColor: AppColors.grayBorderSecondary,
938
+ overflow: 'hidden',
939
+ padding: 14,
940
+ gap: 12,
941
+ }}>
942
+ <Text style={{
943
+ fontFamily: AppFonts.interBold,
944
+ fontSize: 11,
945
+ lineHeight: 14,
946
+ color: AppColors.grayTextWeak,
947
+ letterSpacing: 0.8,
642
948
  }}>
949
+ {t('settings.startupDefault')}
950
+ </Text>
951
+
643
952
  <View style={{
644
953
  flexDirection: 'row',
645
954
  alignItems: 'center',
646
- gap: 8,
955
+ gap: 10,
647
956
  }}>
648
957
  <View style={{
649
- width: 20,
650
- height: 20,
651
- borderRadius: 6,
958
+ width: 32,
959
+ height: 32,
960
+ borderRadius: 8,
652
961
  backgroundColor: AppColors.purpleShade50,
653
- borderWidth: 1,
654
- borderColor: `${AppColors.purple}33`,
655
962
  alignItems: 'center',
656
963
  justifyContent: 'center',
657
964
  }}>
658
- <LayersIcon color={AppColors.purple} size={11}/>
965
+ <LayersIcon color={AppColors.purple} size={15}/>
659
966
  </View>
660
967
  <View style={{ flex: 1 }}>
661
968
  <Text style={{
662
969
  fontFamily: AppFonts.interBold,
663
- fontSize: 13,
970
+ fontSize: 13.5,
971
+ lineHeight: 18,
664
972
  color: AppColors.primaryBlack,
665
973
  }}>
666
- Default Tab
974
+ {t('settings.general.defaultOpeningTab')}
667
975
  </Text>
668
976
  <Text style={{
669
977
  fontFamily: AppFonts.interRegular,
670
978
  fontSize: 11,
979
+ lineHeight: 15,
671
980
  color: AppColors.grayText,
672
981
  marginTop: 1,
673
982
  }}>
674
- Tab shown when the inspector opens
983
+ {t('settings.general.defaultOpeningTabDesc')}
675
984
  </Text>
676
985
  </View>
677
986
  </View>
@@ -681,13 +990,15 @@ const SettingsPanel = () => {
681
990
  flexDirection: 'row',
682
991
  flexWrap: 'wrap',
683
992
  gap: 8,
684
- marginTop: 12,
993
+ marginTop: 4,
685
994
  }}>
686
- {settingsTabs
687
- .filter(tab => tab.key === 'apis' || tabVisibility?.[tab.key])
995
+ {allModules
996
+ .filter(tab => tab.key === 'apis' ||
997
+ stagedTabVisibility?.[tab.key] ||
998
+ tabVisibility?.[tab.key])
688
999
  .map(tab => {
689
1000
  const isActive = defaultTab === tab.key;
690
- return (<TouchableScale key={tab.key} onPress={() => setDefaultTab(tab.key)} style={{
1001
+ return (<TouchableScale key={tab.key} accessible={true} accessibilityRole="button" accessibilityLabel={`Set ${tab.label} as default tab`} accessibilityState={{ selected: isActive }} onPress={() => setDefaultTab(tab.key)} style={{
691
1002
  flexDirection: 'row',
692
1003
  alignItems: 'center',
693
1004
  gap: 8,
@@ -695,186 +1006,190 @@ const SettingsPanel = () => {
695
1006
  paddingHorizontal: 12,
696
1007
  borderRadius: 10,
697
1008
  borderWidth: 1.5,
698
- borderColor: isActive ? AppColors.purple : AppColors.grayBorderSecondary,
699
- backgroundColor: isActive ? `${AppColors.purple}0F` : AppColors.primaryLight,
1009
+ borderColor: isActive
1010
+ ? AppColors.purple
1011
+ : AppColors.grayBorderSecondary,
1012
+ backgroundColor: isActive
1013
+ ? `${AppColors.purple}0F`
1014
+ : AppColors.primaryLight,
700
1015
  minWidth: '47%',
701
1016
  flex: 1,
702
1017
  }}>
703
- <View style={{
704
- width: 22,
705
- height: 22,
706
- borderRadius: 6,
707
- backgroundColor: isActive ? AppColors.purple : AppColors.purpleShade50,
708
- alignItems: 'center',
709
- justifyContent: 'center',
710
- }}>
711
- {tab.icon === 'apis' && (<SignalIcon color={isActive ? AppColors.white : AppColors.purple} size={11}/>)}
712
- {tab.icon === 'logs' && (<TerminalIcon color={isActive ? AppColors.white : AppColors.purple} size={11}/>)}
713
- {tab.icon === 'analytics' && (<AnalyticsIcon color={isActive ? AppColors.white : AppColors.purple} size={11}/>)}
714
- {tab.icon === 'redux' && (<ReduxIcon color={isActive ? AppColors.white : AppColors.purple} size={11}/>)}
715
- {tab.icon === 'bundle' && (<PackageIcon color={isActive ? AppColors.white : AppColors.purple} size={11}/>)}
716
- {tab.icon === 'performance' && (<PerformanceIcon color={isActive ? AppColors.white : AppColors.purple} size={11}/>)}
717
- {tab.icon === 'crash' && (<CrashIcon color={isActive ? AppColors.white : AppColors.purple} size={11}/>)}
718
- </View>
719
1018
  <Text style={{
720
1019
  fontFamily: AppFonts.interBold,
721
- fontSize: 13,
722
- color: isActive ? AppColors.purple : AppColors.primaryBlack,
1020
+ fontSize: 12.5,
1021
+ lineHeight: 16,
1022
+ color: isActive
1023
+ ? AppColors.purple
1024
+ : AppColors.primaryBlack,
723
1025
  flex: 1,
724
1026
  }}>
725
- {tab.label}
1027
+ {tab.label}
726
1028
  </Text>
727
1029
  {isActive && (<View style={{
728
- width: 14,
729
- height: 14,
730
- borderRadius: 7,
1030
+ width: 16,
1031
+ height: 16,
1032
+ borderRadius: 8,
731
1033
  backgroundColor: AppColors.purple,
732
1034
  alignItems: 'center',
733
1035
  justifyContent: 'center',
734
1036
  }}>
735
- <CheckIcon size={8} color={AppColors.white}/>
1037
+ <CheckIcon size={9} color={AppColors.white}/>
736
1038
  </View>)}
737
1039
  </TouchableScale>);
738
1040
  })}
739
1041
  </View>
740
1042
  </View>
741
1043
 
742
- {/* Divider */}
1044
+ {/* Section 4: Log Deduplication & Levels */}
743
1045
  <View style={{
744
- height: 1,
745
- backgroundColor: AppColors.dividerColor,
746
- }}/>
1046
+ backgroundColor: AppColors.primaryLight,
1047
+ borderRadius: 14,
1048
+ borderWidth: 1,
1049
+ borderColor: AppColors.grayBorderSecondary,
1050
+ overflow: 'hidden',
1051
+ padding: 14,
1052
+ gap: 14,
1053
+ }}>
1054
+ <Text style={{
1055
+ fontFamily: AppFonts.interBold,
1056
+ fontSize: 11,
1057
+ lineHeight: 14,
1058
+ color: AppColors.grayTextWeak,
1059
+ letterSpacing: 0.8,
1060
+ }}>
1061
+ {t('settings.logFiltersDeduplication')}
1062
+ </Text>
747
1063
 
748
- {/* #9 — Show Duplicate Logs */}
749
- <View style={{
1064
+ {/* Show Duplicate Logs */}
1065
+ <View style={{
750
1066
  flexDirection: 'row',
751
1067
  alignItems: 'center',
752
- paddingVertical: 12,
753
- paddingHorizontal: 14,
754
- gap: 12,
1068
+ justifyContent: 'space-between',
755
1069
  }}>
756
- <View style={{
757
- flex: 1,
1070
+ <View style={{
758
1071
  flexDirection: 'row',
759
1072
  alignItems: 'center',
760
- gap: 8,
1073
+ gap: 10,
1074
+ flex: 1,
761
1075
  }}>
762
- <View style={{
763
- width: 20,
764
- height: 20,
765
- borderRadius: 6,
1076
+ <View style={{
1077
+ width: 32,
1078
+ height: 32,
1079
+ borderRadius: 8,
766
1080
  backgroundColor: AppColors.purpleShade50,
767
- borderWidth: 1,
768
- borderColor: `${AppColors.purple}33`,
769
1081
  alignItems: 'center',
770
1082
  justifyContent: 'center',
771
1083
  }}>
772
- <EyeIcon color={AppColors.purple} size={11}/>
773
- </View>
774
- <View style={{ flex: 1 }}>
775
- <Text style={{
1084
+ <EyeIcon color={AppColors.purple} size={15}/>
1085
+ </View>
1086
+ <View style={{ flex: 1 }}>
1087
+ <Text style={{
776
1088
  fontFamily: AppFonts.interBold,
777
- fontSize: 13,
1089
+ fontSize: 13.5,
1090
+ lineHeight: 18,
778
1091
  color: AppColors.primaryBlack,
779
1092
  }}>
780
- Show Duplicate Logs
781
- </Text>
782
- <Text style={{
1093
+ {t('settings.general.duplicateLogs')}
1094
+ </Text>
1095
+ <Text style={{
783
1096
  fontFamily: AppFonts.interRegular,
784
1097
  fontSize: 11,
1098
+ lineHeight: 15,
785
1099
  color: AppColors.grayText,
786
1100
  marginTop: 1,
787
1101
  }}>
788
- Off: repeated identical entries collapse into one row
789
- with a ×N count
790
- </Text>
1102
+ {t('settings.general.duplicateLogsDescription')}
1103
+ </Text>
1104
+ </View>
791
1105
  </View>
792
- </View>
793
1106
 
794
- {/* Toggle Switch */}
795
- <TouchableScale onPress={() => setShowDuplicateLogs(prev => !prev)} style={{
796
- width: 38,
797
- height: 22,
798
- borderRadius: 11,
1107
+ <TouchableScale accessible={true} accessibilityRole="switch" accessibilityLabel="Toggle show duplicate logs" accessibilityState={{ checked: showDuplicateLogs }} onPress={() => setShowDuplicateLogs(prev => !prev)} style={{
1108
+ width: 42,
1109
+ height: 24,
1110
+ borderRadius: 12,
799
1111
  backgroundColor: showDuplicateLogs
800
1112
  ? AppColors.purple
801
1113
  : AppColors.grayBorderSecondary,
802
1114
  padding: 2,
803
1115
  justifyContent: 'center',
804
- alignItems: showDuplicateLogs ? 'flex-end' : 'flex-start',
1116
+ alignItems: showDuplicateLogs
1117
+ ? 'flex-end'
1118
+ : 'flex-start',
805
1119
  }}>
806
- <View style={{
807
- width: 18,
808
- height: 18,
809
- borderRadius: 9,
1120
+ <View style={{
1121
+ width: 20,
1122
+ height: 20,
1123
+ borderRadius: 10,
810
1124
  backgroundColor: AppColors.white,
811
1125
  shadowColor: AppColors.black,
812
- shadowOpacity: 0.15,
813
- shadowRadius: 1.5,
1126
+ shadowOpacity: 0.18,
1127
+ shadowRadius: 2,
814
1128
  shadowOffset: { width: 0, height: 1 },
815
1129
  }}/>
816
- </TouchableScale>
817
- </View>
1130
+ </TouchableScale>
1131
+ </View>
818
1132
 
819
- {/* Divider */}
820
- <View style={{
821
- height: 1,
822
- backgroundColor: AppColors.dividerColor,
823
- }}/>
1133
+ <View style={{ height: 1, backgroundColor: AppColors.dividerColor }}/>
824
1134
 
825
- {/* Logs Console Levels */}
826
- <View style={{
827
- paddingVertical: 12,
828
- paddingHorizontal: 14,
829
- }}>
830
- <View style={{
1135
+ {/* Console Log Levels */}
1136
+ <View style={{ gap: 8 }}>
1137
+ <View style={{
831
1138
  flexDirection: 'row',
832
1139
  alignItems: 'center',
833
- gap: 8,
1140
+ gap: 10,
834
1141
  }}>
835
- <View style={{
836
- width: 20,
837
- height: 20,
838
- borderRadius: 6,
1142
+ <View style={{
1143
+ width: 32,
1144
+ height: 32,
1145
+ borderRadius: 8,
839
1146
  backgroundColor: AppColors.purpleShade50,
840
- borderWidth: 1,
841
- borderColor: `${AppColors.purple}33`,
842
1147
  alignItems: 'center',
843
1148
  justifyContent: 'center',
844
1149
  }}>
845
- <TerminalIcon color={AppColors.purple} size={11}/>
846
- </View>
847
- <View style={{ flex: 1 }}>
848
- <Text style={{
1150
+ <TerminalIcon color={AppColors.purple} size={15}/>
1151
+ </View>
1152
+ <View style={{ flex: 1 }}>
1153
+ <Text style={{
849
1154
  fontFamily: AppFonts.interBold,
850
- fontSize: 13,
1155
+ fontSize: 13.5,
1156
+ lineHeight: 18,
851
1157
  color: AppColors.primaryBlack,
852
1158
  }}>
853
- Logs Console Levels
854
- </Text>
855
- <Text style={{
1159
+ {t('settings.general.activeConsoleLogLevels')}
1160
+ </Text>
1161
+ <Text style={{
856
1162
  fontFamily: AppFonts.interRegular,
857
1163
  fontSize: 11,
1164
+ lineHeight: 15,
858
1165
  color: AppColors.grayText,
859
1166
  marginTop: 1,
860
1167
  }}>
861
- Toggle which log levels are visible in the Logs tab
862
- </Text>
1168
+ {t('settings.general.activeConsoleLogLevelsDesc')}
1169
+ </Text>
1170
+ </View>
863
1171
  </View>
864
- </View>
865
1172
 
866
- <View style={{
867
- flexDirection: 'row',
868
- gap: 8,
869
- marginTop: 10,
870
- }}>
871
- {([
872
- { key: 'info', label: 'Info', color: AppColors.blue500 },
873
- { key: 'warn', label: 'Warning', color: AppColors.amber500 },
874
- { key: 'error', label: 'Error', color: AppColors.errorColor },
875
- ]).map(level => {
1173
+ <View style={{ flexDirection: 'row', gap: 8, marginTop: 4 }}>
1174
+ {[
1175
+ {
1176
+ key: 'info',
1177
+ label: 'Info',
1178
+ color: AppColors.blue500,
1179
+ },
1180
+ {
1181
+ key: 'warn',
1182
+ label: 'Warning',
1183
+ color: AppColors.amber500,
1184
+ },
1185
+ {
1186
+ key: 'error',
1187
+ label: 'Error',
1188
+ color: AppColors.errorColor,
1189
+ },
1190
+ ].map(level => {
876
1191
  const isActive = showConsoleLevels[level.key];
877
- return (<TouchableScale key={level.key} onPress={() => setShowConsoleLevels(prev => ({
1192
+ return (<TouchableScale key={level.key} accessible={true} accessibilityRole="checkbox" accessibilityLabel={`Toggle ${level.label} logs`} accessibilityState={{ checked: isActive }} onPress={() => setShowConsoleLevels(prev => ({
878
1193
  ...prev,
879
1194
  [level.key]: !prev[level.key],
880
1195
  }))} style={{
@@ -884,112 +1199,113 @@ const SettingsPanel = () => {
884
1199
  justifyContent: 'center',
885
1200
  gap: 6,
886
1201
  paddingVertical: 8,
887
- borderRadius: 8,
1202
+ borderRadius: 9,
888
1203
  borderWidth: 1.5,
889
- borderColor: isActive ? level.color : AppColors.grayBorderSecondary,
890
- backgroundColor: isActive ? `${level.color}0D` : AppColors.primaryLight,
1204
+ borderColor: isActive
1205
+ ? level.color
1206
+ : AppColors.grayBorderSecondary,
1207
+ backgroundColor: isActive
1208
+ ? `${level.color}0D`
1209
+ : AppColors.primaryLight,
891
1210
  }}>
892
- <View style={{
1211
+ <View style={{
893
1212
  width: 8,
894
1213
  height: 8,
895
1214
  borderRadius: 4,
896
- backgroundColor: isActive ? level.color : AppColors.grayBorderSecondary,
1215
+ backgroundColor: isActive
1216
+ ? level.color
1217
+ : AppColors.grayBorderSecondary,
897
1218
  }}/>
898
- <Text style={{
1219
+ <Text style={{
899
1220
  fontFamily: AppFonts.interBold,
900
- fontSize: 11,
901
- color: isActive ? level.color : AppColors.grayText,
1221
+ fontSize: 11.5,
1222
+ lineHeight: 15,
1223
+ color: isActive
1224
+ ? level.color
1225
+ : AppColors.grayText,
902
1226
  }}>
903
- {level.label}
904
- </Text>
905
- </TouchableScale>);
1227
+ {level.label}
1228
+ </Text>
1229
+ </TouchableScale>);
906
1230
  })}
1231
+ </View>
907
1232
  </View>
908
1233
  </View>
909
1234
 
910
- {/* Divider */}
911
- <View style={{
912
- height: 1,
913
- backgroundColor: AppColors.dividerColor,
914
- }}/>
915
-
916
- {/* Reset Settings */}
1235
+ {/* Section 5: Reset Settings */}
917
1236
  <View style={{
1237
+ backgroundColor: AppColors.primaryLight,
1238
+ borderRadius: 14,
1239
+ borderWidth: 1,
1240
+ borderColor: `${AppColors.errorColor}33`,
1241
+ overflow: 'hidden',
1242
+ padding: 14,
918
1243
  flexDirection: 'row',
919
1244
  alignItems: 'center',
920
- paddingVertical: 12,
921
- paddingHorizontal: 14,
922
1245
  gap: 12,
923
1246
  }}>
924
1247
  <View style={{
925
- flex: 1,
926
- flexDirection: 'row',
927
- alignItems: 'center',
928
- gap: 8,
929
- }}>
930
- <View style={{
931
- width: 20,
932
- height: 20,
933
- borderRadius: 6,
1248
+ width: 34,
1249
+ height: 34,
1250
+ borderRadius: 9,
934
1251
  backgroundColor: `${AppColors.errorColor}14`,
935
- borderWidth: 1,
936
- borderColor: `${AppColors.errorColor}33`,
937
1252
  alignItems: 'center',
938
1253
  justifyContent: 'center',
939
1254
  }}>
940
- <TrashIcon color={AppColors.errorColor} size={11}/>
941
- </View>
942
- <View style={{ flex: 1 }}>
943
- <Text style={{
1255
+ <TrashIcon color={AppColors.errorColor} size={15}/>
1256
+ </View>
1257
+ <View style={{ flex: 1 }}>
1258
+ <Text style={{
944
1259
  fontFamily: AppFonts.interBold,
945
- fontSize: 13,
1260
+ fontSize: 13.5,
1261
+ lineHeight: 18,
946
1262
  color: AppColors.primaryBlack,
947
1263
  }}>
948
- Reset Settings
949
- </Text>
950
- <Text style={{
1264
+ {t('settings.resetSettings')}
1265
+ </Text>
1266
+ <Text style={{
951
1267
  fontFamily: AppFonts.interRegular,
952
1268
  fontSize: 11,
1269
+ lineHeight: 15,
953
1270
  color: AppColors.grayText,
954
1271
  marginTop: 1,
955
1272
  }}>
956
- Wipe custom configurations and load package defaults
957
- </Text>
958
- </View>
1273
+ {t('settings.resetSettingsDesc')}
1274
+ </Text>
959
1275
  </View>
960
1276
 
961
- <TouchableScale onPress={resetToDefaults} style={{
962
- paddingHorizontal: 10,
963
- paddingVertical: 5,
964
- borderRadius: 7,
1277
+ <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel="Reset all settings to default" onPress={resetToDefaults} style={{
1278
+ paddingHorizontal: 12,
1279
+ paddingVertical: 7,
1280
+ borderRadius: 8,
965
1281
  backgroundColor: `${AppColors.errorColor}14`,
966
1282
  borderWidth: 1,
967
- borderColor: `${AppColors.errorColor}33`,
1283
+ borderColor: `${AppColors.errorColor}38`,
968
1284
  }}>
969
1285
  <Text style={{
970
1286
  fontFamily: AppFonts.interBold,
971
- fontSize: 11,
1287
+ fontSize: 11.5,
1288
+ lineHeight: 15,
972
1289
  color: AppColors.errorColor,
973
1290
  }}>
974
- Reset
1291
+ {t('settings.reset')}
975
1292
  </Text>
976
1293
  </TouchableScale>
977
1294
  </View>
978
1295
  </View>)}
979
1296
 
980
-
981
- {/* Storage Status */}
1297
+ {/* Storage & Engine Status Card */}
982
1298
  <View style={{
983
- backgroundColor: isPersistentStorageAvailable()
984
- ? `${AppColors.liveGreen}14`
985
- : `${AppColors.amber600}14`,
1299
+ backgroundColor: isPersistent
1300
+ ? `${AppColors.liveGreen}12`
1301
+ : `${AppColors.amber600}12`,
986
1302
  borderRadius: 12,
987
1303
  borderWidth: 1,
988
- borderColor: isPersistentStorageAvailable()
1304
+ borderColor: isPersistent
989
1305
  ? `${AppColors.liveGreen}33`
990
1306
  : `${AppColors.amber600}33`,
991
1307
  padding: 12,
992
- marginTop: 16,
1308
+ marginBottom: 10,
993
1309
  flexDirection: 'row',
994
1310
  alignItems: 'center',
995
1311
  gap: 10,
@@ -998,32 +1314,106 @@ const SettingsPanel = () => {
998
1314
  width: 8,
999
1315
  height: 8,
1000
1316
  borderRadius: 4,
1001
- backgroundColor: isPersistentStorageAvailable() ? AppColors.green500 : AppColors.amber600,
1317
+ backgroundColor: isPersistent
1318
+ ? AppColors.green500
1319
+ : AppColors.amber600,
1002
1320
  }}/>
1003
1321
  <View style={{ flex: 1 }}>
1004
1322
  <Text style={{
1005
1323
  fontFamily: AppFonts.interBold,
1006
1324
  fontSize: 12,
1007
- color: isPersistentStorageAvailable() ? AppColors.green700 : AppColors.amber800,
1325
+ lineHeight: 16,
1326
+ color: isPersistent
1327
+ ? AppColors.green700
1328
+ : AppColors.amber800,
1008
1329
  }}>
1009
- {isPersistentStorageAvailable()
1010
- ? `Storage: Persistent (${storage ? 'Custom' : 'iOS Settings'})`
1011
- : 'Storage: Temporary (In-Memory)'}
1330
+ {isPersistent
1331
+ ? t('settings.general.storageStatusEnabled', {
1332
+ type: storage ? 'Custom Storage' : 'iOS NSUserDefaults',
1333
+ })
1334
+ : t('settings.general.storageStatusDisabled')}
1012
1335
  </Text>
1013
1336
  <Text style={{
1014
1337
  fontFamily: AppFonts.interRegular,
1015
1338
  fontSize: 10.5,
1016
- color: isPersistentStorageAvailable() ? AppColors.green800 : AppColors.amber800,
1339
+ lineHeight: 14,
1340
+ color: isPersistent
1341
+ ? AppColors.green800
1342
+ : AppColors.amber800,
1017
1343
  marginTop: 2,
1018
- opacity: 0.8,
1344
+ opacity: 0.85,
1019
1345
  }}>
1020
- {isPersistentStorageAvailable()
1021
- ? 'Your settings are saved across app restarts.'
1022
- : 'Settings reset when closed. To persist settings, pass a storage object to <NetworkInspector storage={...} />.'}
1346
+ {isPersistent
1347
+ ? t('settings.general.storageStatusEnabledDesc')
1348
+ : t('settings.general.storageStatusDisabledDesc')}
1023
1349
  </Text>
1024
1350
  </View>
1025
1351
  </View>
1026
1352
  </ScrollView>
1353
+
1354
+ {/* Bottom Sticky Action Bar for Save Changes */}
1355
+ {settingsActiveSubTab === 'module' && (<View style={{
1356
+ paddingHorizontal: 16,
1357
+ paddingTop: 12,
1358
+ paddingBottom: Platform.OS === 'ios' ? 26 : 14,
1359
+ backgroundColor: AppColors.primaryLight,
1360
+ borderTopWidth: 1,
1361
+ borderTopColor: AppColors.dividerColor,
1362
+ flexDirection: 'row',
1363
+ alignItems: 'center',
1364
+ gap: 12,
1365
+ shadowColor: AppColors.black,
1366
+ shadowOpacity: 0.08,
1367
+ shadowRadius: 8,
1368
+ shadowOffset: { width: 0, height: -3 },
1369
+ elevation: 8,
1370
+ }}>
1371
+ <View style={{ flex: 1 }}>
1372
+ <Text style={{
1373
+ fontFamily: AppFonts.interBold,
1374
+ fontSize: 13,
1375
+ lineHeight: 17,
1376
+ color: AppColors.primaryBlack,
1377
+ }}>
1378
+ {stagedActiveCount} of {allModules.length} Modules Active
1379
+ </Text>
1380
+ <Text style={{
1381
+ fontFamily: AppFonts.interRegular,
1382
+ fontSize: 11,
1383
+ lineHeight: 15,
1384
+ color: hasUnsavedChanges
1385
+ ? AppColors.purple
1386
+ : AppColors.grayText,
1387
+ marginTop: 1,
1388
+ }}>
1389
+ {hasUnsavedChanges
1390
+ ? t('settings.unsavedPending')
1391
+ : t('settings.allSynchronized')}
1392
+ </Text>
1393
+ </View>
1394
+
1395
+ <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel="Save Changes" onPress={handleSaveChanges} style={{
1396
+ flexDirection: 'row',
1397
+ alignItems: 'center',
1398
+ gap: 6,
1399
+ backgroundColor: hasUnsavedChanges
1400
+ ? AppColors.purple
1401
+ : `${AppColors.purple}22`,
1402
+ paddingHorizontal: 18,
1403
+ paddingVertical: 10,
1404
+ borderRadius: 10,
1405
+ }}>
1406
+ <CheckIcon size={14} color={hasUnsavedChanges ? AppColors.white : AppColors.purple}/>
1407
+ <Text style={{
1408
+ fontFamily: AppFonts.interBold,
1409
+ fontSize: 13,
1410
+ lineHeight: 17,
1411
+ color: hasUnsavedChanges ? AppColors.white : AppColors.purple,
1412
+ }}>
1413
+ {t('settings.saveChanges')}
1414
+ </Text>
1415
+ </TouchableScale>
1416
+ </View>)}
1027
1417
  </View>);
1028
1418
  }
1029
1419
  const goBackToMain = () => {
@@ -1057,6 +1447,7 @@ const SettingsPanel = () => {
1057
1447
  <Text style={{
1058
1448
  fontFamily: AppFonts.interBold,
1059
1449
  fontSize: 14,
1450
+ lineHeight: 18,
1060
1451
  color: AppColors.primaryBlack,
1061
1452
  }}>
1062
1453
  {opts.label}
@@ -1064,6 +1455,7 @@ const SettingsPanel = () => {
1064
1455
  {opts.description ? (<Text style={{
1065
1456
  fontFamily: AppFonts.interRegular,
1066
1457
  fontSize: 11,
1458
+ lineHeight: 15,
1067
1459
  color: AppColors.grayText,
1068
1460
  marginTop: 1,
1069
1461
  }}>
@@ -1095,6 +1487,7 @@ const SettingsPanel = () => {
1095
1487
  <Text style={{
1096
1488
  fontFamily: AppFonts.interBold,
1097
1489
  fontSize: 11,
1490
+ lineHeight: 14,
1098
1491
  color: isActive ? AppColors.white : AppColors.grayText,
1099
1492
  }}>
1100
1493
  {opts.picker.formatLabel
@@ -1110,22 +1503,21 @@ const SettingsPanel = () => {
1110
1503
  let icon = null;
1111
1504
  let rightInfo = '';
1112
1505
  if (settingsPage === 'apis') {
1113
- title = 'APIs Settings';
1506
+ title = t('settings.apis.title');
1114
1507
  icon = <SignalIcon color={AppColors.white} size={16}/>;
1115
- rightInfo = `Total: ${logs.length}`;
1116
- content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16 }}>
1508
+ rightInfo = t('settings.apis.total', { count: logs.length });
1509
+ content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16, gap: 12 }}>
1117
1510
  <View style={{
1118
1511
  backgroundColor: AppColors.primaryLight,
1119
1512
  padding: 16,
1120
- borderRadius: 12,
1513
+ borderRadius: 14,
1121
1514
  borderWidth: 1,
1122
1515
  borderColor: AppColors.grayBorderSecondary,
1123
- gap: 4,
1124
1516
  }}>
1125
1517
  {renderSettingRow({
1126
1518
  icon: <SignalIcon color={AppColors.purple} size={16}/>,
1127
- label: 'Max Request Logs',
1128
- description: 'How many network requests to keep in memory',
1519
+ label: t('settings.apis.maxRequestLogs'),
1520
+ description: t('settings.apis.maxRequestLogsDescription'),
1129
1521
  picker: {
1130
1522
  options: [50, 100, 200, 500],
1131
1523
  selectedValue: maxNetworkLogs,
@@ -1137,26 +1529,25 @@ const SettingsPanel = () => {
1137
1529
 
1138
1530
  <View style={{
1139
1531
  backgroundColor: AppColors.primaryLight,
1140
- borderRadius: 12,
1532
+ borderRadius: 14,
1141
1533
  borderWidth: 1,
1142
1534
  borderColor: AppColors.grayBorderSecondary,
1143
1535
  padding: 16,
1144
- marginTop: 12,
1145
1536
  }}>
1146
1537
  {renderSettingRow({
1147
1538
  icon: <TrashIcon color={AppColors.errorColor} size={16}/>,
1148
- label: 'Clear Network Logs',
1149
- description: `${logs.length} requests stored`,
1539
+ label: t('settings.apis.clearNetworkLogs'),
1540
+ description: t('settings.apis.clearNetworkLogsDescription', { count: logs.length }),
1150
1541
  isLast: true,
1151
1542
  onPress: () => {
1152
1543
  clearNetworkLogs();
1153
1544
  setSelected(null);
1154
- Alert.alert('Success', 'Network logs cleared.');
1545
+ Alert.alert(t('common.success'), t('settings.apis.networkLogsCleared'));
1155
1546
  },
1156
1547
  right: (<View style={{
1157
- paddingHorizontal: 10,
1158
- paddingVertical: 5,
1159
- borderRadius: 7,
1548
+ paddingHorizontal: 12,
1549
+ paddingVertical: 6,
1550
+ borderRadius: 8,
1160
1551
  backgroundColor: `${AppColors.errorColor}14`,
1161
1552
  borderWidth: 1,
1162
1553
  borderColor: `${AppColors.errorColor}33`,
@@ -1164,9 +1555,10 @@ const SettingsPanel = () => {
1164
1555
  <Text style={{
1165
1556
  fontFamily: AppFonts.interBold,
1166
1557
  fontSize: 11,
1558
+ lineHeight: 14,
1167
1559
  color: AppColors.errorColor,
1168
1560
  }}>
1169
- Clear
1561
+ {t('common.clear')}
1170
1562
  </Text>
1171
1563
  </View>),
1172
1564
  })}
@@ -1174,22 +1566,22 @@ const SettingsPanel = () => {
1174
1566
  </ScrollView>);
1175
1567
  }
1176
1568
  else if (settingsPage === 'logs') {
1177
- title = 'Logs Settings';
1569
+ title = t('settings.logs.title');
1178
1570
  icon = <TerminalIcon color={AppColors.white} size={16}/>;
1179
- rightInfo = `Total: ${consoleLogs.length}`;
1180
- content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16 }}>
1571
+ rightInfo = t('settings.logs.total', { count: consoleLogs.length });
1572
+ content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16, gap: 12 }}>
1181
1573
  <View style={{
1182
1574
  backgroundColor: AppColors.primaryLight,
1183
1575
  padding: 16,
1184
- borderRadius: 12,
1576
+ borderRadius: 14,
1185
1577
  borderWidth: 1,
1186
1578
  borderColor: AppColors.grayBorderSecondary,
1187
1579
  gap: 4,
1188
1580
  }}>
1189
1581
  {renderSettingRow({
1190
1582
  icon: <TerminalIcon color={AppColors.purple} size={16}/>,
1191
- label: 'Max Console Logs',
1192
- description: 'How many console messages to retain',
1583
+ label: t('settings.logs.maxConsoleLogs'),
1584
+ description: t('settings.logs.maxConsoleLogsDescription'),
1193
1585
  picker: {
1194
1586
  options: [100, 200, 500, 1000],
1195
1587
  selectedValue: maxConsoleLogs,
@@ -1200,10 +1592,11 @@ const SettingsPanel = () => {
1200
1592
  <Text style={{
1201
1593
  fontFamily: AppFonts.interBold,
1202
1594
  fontSize: 13,
1595
+ lineHeight: 17,
1203
1596
  color: AppColors.primaryBlack,
1204
- paddingTop: 4,
1597
+ paddingTop: 6,
1205
1598
  }}>
1206
- Log Levels
1599
+ {t('settings.logs.logLevels')}
1207
1600
  </Text>
1208
1601
  {['info', 'warn', 'error'].map(level => {
1209
1602
  const isLvlActive = showConsoleLevels?.[level];
@@ -1212,19 +1605,25 @@ const SettingsPanel = () => {
1212
1605
  : level === 'warn'
1213
1606
  ? AppColors.warningIconGold
1214
1607
  : AppColors.skyBlue;
1608
+ const label = level === 'info'
1609
+ ? t('settings.logs.showInfo')
1610
+ : level === 'warn'
1611
+ ? t('settings.logs.showWarn')
1612
+ : t('settings.logs.showError');
1613
+ const desc = level === 'info'
1614
+ ? t('settings.logs.showInfoDesc')
1615
+ : level === 'warn'
1616
+ ? t('settings.logs.showWarnDesc')
1617
+ : t('settings.logs.showErrorDesc');
1215
1618
  return renderSettingRow({
1216
1619
  icon: (<View style={{
1217
- width: 10,
1218
- height: 10,
1219
- borderRadius: 5,
1620
+ width: 12,
1621
+ height: 12,
1622
+ borderRadius: 6,
1220
1623
  backgroundColor: levelColor,
1221
1624
  }}/>),
1222
- label: `Show ${level.charAt(0).toUpperCase() + level.slice(1)} logs`,
1223
- description: level === 'info'
1224
- ? 'Informational messages'
1225
- : level === 'warn'
1226
- ? 'Warning messages'
1227
- : 'Error messages',
1625
+ label,
1626
+ description: desc,
1228
1627
  isLast: level === 'error',
1229
1628
  onPress: () => setShowConsoleLevels(prev => ({
1230
1629
  ...prev,
@@ -1252,25 +1651,24 @@ const SettingsPanel = () => {
1252
1651
 
1253
1652
  <View style={{
1254
1653
  backgroundColor: AppColors.primaryLight,
1255
- borderRadius: 12,
1654
+ borderRadius: 14,
1256
1655
  borderWidth: 1,
1257
1656
  borderColor: AppColors.grayBorderSecondary,
1258
1657
  padding: 16,
1259
- marginTop: 12,
1260
1658
  }}>
1261
1659
  {renderSettingRow({
1262
1660
  icon: <TrashIcon color={AppColors.errorColor} size={16}/>,
1263
- label: 'Clear Console Logs',
1264
- description: `${consoleLogs.length} logs stored`,
1661
+ label: t('settings.logs.clearConsoleLogs'),
1662
+ description: t('settings.logs.clearConsoleLogsDescription', { count: consoleLogs.length }),
1265
1663
  isLast: true,
1266
1664
  onPress: () => {
1267
1665
  clearConsoleLogs();
1268
- Alert.alert('Success', 'Console logs cleared.');
1666
+ Alert.alert(t('common.success'), t('settings.logs.consoleLogsCleared'));
1269
1667
  },
1270
1668
  right: (<View style={{
1271
- paddingHorizontal: 10,
1272
- paddingVertical: 5,
1273
- borderRadius: 7,
1669
+ paddingHorizontal: 12,
1670
+ paddingVertical: 6,
1671
+ borderRadius: 8,
1274
1672
  backgroundColor: `${AppColors.errorColor}14`,
1275
1673
  borderWidth: 1,
1276
1674
  borderColor: `${AppColors.errorColor}33`,
@@ -1278,9 +1676,10 @@ const SettingsPanel = () => {
1278
1676
  <Text style={{
1279
1677
  fontFamily: AppFonts.interBold,
1280
1678
  fontSize: 11,
1679
+ lineHeight: 14,
1281
1680
  color: AppColors.errorColor,
1282
1681
  }}>
1283
- Clear
1682
+ {t('common.clear')}
1284
1683
  </Text>
1285
1684
  </View>),
1286
1685
  })}
@@ -1288,47 +1687,45 @@ const SettingsPanel = () => {
1288
1687
  </ScrollView>);
1289
1688
  }
1290
1689
  else if (settingsPage === 'analytics') {
1291
- title = 'Analytics Settings';
1690
+ title = t('settings.analytics.title');
1292
1691
  icon = <AnalyticsIcon color={AppColors.white} size={16}/>;
1293
- rightInfo = `Events: ${analyticsEvents.length}`;
1294
- content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16 }}>
1692
+ rightInfo = t('settings.analytics.total', { count: analyticsEvents.length });
1693
+ content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16, gap: 12 }}>
1295
1694
  <View style={{
1296
1695
  backgroundColor: AppColors.primaryLight,
1297
1696
  padding: 16,
1298
- borderRadius: 12,
1697
+ borderRadius: 14,
1299
1698
  borderWidth: 1,
1300
1699
  borderColor: AppColors.grayBorderSecondary,
1301
- gap: 4,
1302
1700
  }}>
1303
1701
  {renderSettingRow({
1304
1702
  icon: <AnalyticsIcon color={AppColors.purple} size={16}/>,
1305
- label: 'Events Captured',
1306
- description: `${analyticsEvents.length} analytics events stored`,
1703
+ label: t('settings.analytics.maxAnalyticsEvents'),
1704
+ description: t('settings.analytics.maxAnalyticsEventsDescription', { count: analyticsEvents.length }),
1307
1705
  isLast: true,
1308
1706
  })}
1309
1707
  </View>
1310
1708
  <View style={{
1311
1709
  backgroundColor: AppColors.primaryLight,
1312
- borderRadius: 12,
1710
+ borderRadius: 14,
1313
1711
  borderWidth: 1,
1314
1712
  borderColor: AppColors.grayBorderSecondary,
1315
1713
  padding: 16,
1316
- marginTop: 12,
1317
1714
  }}>
1318
1715
  {renderSettingRow({
1319
1716
  icon: <TrashIcon color={AppColors.errorColor} size={16}/>,
1320
- label: 'Clear Analytics History',
1321
- description: 'Remove all captured events',
1717
+ label: t('settings.analytics.clearAnalyticsEvents'),
1718
+ description: t('settings.analytics.clearAnalyticsEventsDescription'),
1322
1719
  isLast: true,
1323
1720
  onPress: () => {
1324
1721
  clearAnalyticsEvents();
1325
1722
  setSelectedEvent(null);
1326
- Alert.alert('Success', 'Analytics events cleared.');
1723
+ Alert.alert(t('common.success'), t('settings.analytics.analyticsEventsCleared'));
1327
1724
  },
1328
1725
  right: (<View style={{
1329
- paddingHorizontal: 10,
1330
- paddingVertical: 5,
1331
- borderRadius: 7,
1726
+ paddingHorizontal: 12,
1727
+ paddingVertical: 6,
1728
+ borderRadius: 8,
1332
1729
  backgroundColor: `${AppColors.errorColor}14`,
1333
1730
  borderWidth: 1,
1334
1731
  borderColor: `${AppColors.errorColor}33`,
@@ -1336,9 +1733,10 @@ const SettingsPanel = () => {
1336
1733
  <Text style={{
1337
1734
  fontFamily: AppFonts.interBold,
1338
1735
  fontSize: 11,
1736
+ lineHeight: 14,
1339
1737
  color: AppColors.errorColor,
1340
1738
  }}>
1341
- Clear
1739
+ {t('common.clear')}
1342
1740
  </Text>
1343
1741
  </View>),
1344
1742
  })}
@@ -1346,22 +1744,22 @@ const SettingsPanel = () => {
1346
1744
  </ScrollView>);
1347
1745
  }
1348
1746
  else if (settingsPage === 'redux') {
1349
- title = 'Redux Settings';
1350
- icon = <TerminalIcon color={AppColors.white} size={16}/>;
1351
- rightInfo = `Reducers: ${Object.keys(reduxState || {}).length}`;
1352
- content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16 }}>
1747
+ title = t('settings.redux.title');
1748
+ icon = <ReduxIcon color={AppColors.white} size={16}/>;
1749
+ rightInfo = t('settings.redux.reducers', { count: Object.keys(reduxState || {}).length });
1750
+ content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16, gap: 12 }}>
1353
1751
  <View style={{
1354
1752
  backgroundColor: AppColors.primaryLight,
1355
1753
  padding: 16,
1356
- borderRadius: 12,
1754
+ borderRadius: 14,
1357
1755
  borderWidth: 1,
1358
1756
  borderColor: AppColors.grayBorderSecondary,
1359
1757
  gap: 4,
1360
1758
  }}>
1361
1759
  {renderSettingRow({
1362
- icon: <TerminalIcon color={AppColors.purple} size={16}/>,
1363
- label: 'Auto-refresh Store',
1364
- description: 'Automatically capture Redux store state updates',
1760
+ icon: <ReduxIcon color={AppColors.purple} size={16}/>,
1761
+ label: t('settings.redux.autoRefresh'),
1762
+ description: t('settings.redux.autoRefreshDescription'),
1365
1763
  onPress: () => setReduxAutoRefreshState(prev => !prev),
1366
1764
  right: (<View style={{
1367
1765
  width: 22,
@@ -1383,8 +1781,8 @@ const SettingsPanel = () => {
1383
1781
  <View style={{ height: 1, backgroundColor: AppColors.dividerColor }}/>
1384
1782
  {renderSettingRow({
1385
1783
  icon: <LayersIcon color={AppColors.purple} size={16}/>,
1386
- label: 'Default JSON Expand Depth',
1387
- description: 'Initial depth of Redux state tree to auto-expand',
1784
+ label: t('settings.redux.defaultJsonExpandDepth'),
1785
+ description: t('settings.redux.defaultJsonExpandDepthDescription'),
1388
1786
  picker: {
1389
1787
  options: [1, 2, 3, 5],
1390
1788
  selectedValue: reduxExpandDepth,
@@ -1396,27 +1794,26 @@ const SettingsPanel = () => {
1396
1794
 
1397
1795
  <View style={{
1398
1796
  backgroundColor: AppColors.primaryLight,
1399
- borderRadius: 12,
1797
+ borderRadius: 14,
1400
1798
  borderWidth: 1,
1401
1799
  borderColor: AppColors.grayBorderSecondary,
1402
1800
  padding: 16,
1403
- marginTop: 12,
1404
1801
  }}>
1405
1802
  {renderSettingRow({
1406
1803
  icon: <TrashIcon color={AppColors.errorColor} size={16}/>,
1407
- label: 'Clear Redux State',
1804
+ label: t('settings.redux.clearReduxState'),
1408
1805
  description: reduxState
1409
- ? 'Reset state snapshot in inspector'
1410
- : 'No store snapshot stored',
1806
+ ? t('settings.redux.clearReduxStateDescription')
1807
+ : t('settings.redux.clearReduxStateEmpty'),
1411
1808
  isLast: true,
1412
1809
  onPress: () => {
1413
1810
  setReduxState(null);
1414
- Alert.alert('Success', 'Redux state snapshot cleared.');
1811
+ Alert.alert(t('common.success'), t('settings.redux.reduxStateCleared'));
1415
1812
  },
1416
1813
  right: (<View style={{
1417
- paddingHorizontal: 10,
1418
- paddingVertical: 5,
1419
- borderRadius: 7,
1814
+ paddingHorizontal: 12,
1815
+ paddingVertical: 6,
1816
+ borderRadius: 8,
1420
1817
  backgroundColor: `${AppColors.errorColor}14`,
1421
1818
  borderWidth: 1,
1422
1819
  borderColor: `${AppColors.errorColor}33`,
@@ -1424,9 +1821,10 @@ const SettingsPanel = () => {
1424
1821
  <Text style={{
1425
1822
  fontFamily: AppFonts.interBold,
1426
1823
  fontSize: 11,
1824
+ lineHeight: 14,
1427
1825
  color: AppColors.errorColor,
1428
1826
  }}>
1429
- Clear
1827
+ {t('common.clear')}
1430
1828
  </Text>
1431
1829
  </View>),
1432
1830
  })}
@@ -1434,22 +1832,22 @@ const SettingsPanel = () => {
1434
1832
  </ScrollView>);
1435
1833
  }
1436
1834
  else if (settingsPage === 'crash') {
1437
- title = 'Crash Settings';
1835
+ title = t('settings.crash.title');
1438
1836
  icon = <CrashIcon color={AppColors.white} size={16}/>;
1439
1837
  rightInfo = `Total: ${crashRecords?.length || 0}`;
1440
- content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16 }}>
1838
+ content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16, gap: 12 }}>
1441
1839
  <View style={{
1442
1840
  backgroundColor: AppColors.primaryLight,
1443
1841
  padding: 16,
1444
- borderRadius: 12,
1842
+ borderRadius: 14,
1445
1843
  borderWidth: 1,
1446
1844
  borderColor: AppColors.grayBorderSecondary,
1447
1845
  gap: 4,
1448
1846
  }}>
1449
1847
  {renderSettingRow({
1450
1848
  icon: <LayersIcon color={AppColors.purple} size={16}/>,
1451
- label: 'Max Crash Logs',
1452
- description: 'How many crash records to preserve in history',
1849
+ label: t('settings.crash.maxCrashLogs'),
1850
+ description: t('settings.crash.maxCrashLogsDesc'),
1453
1851
  picker: {
1454
1852
  options: [25, 50, 100, 200],
1455
1853
  selectedValue: maxCrashLogs || 100,
@@ -1459,8 +1857,8 @@ const SettingsPanel = () => {
1459
1857
  <View style={{ height: 1, backgroundColor: AppColors.dividerColor }}/>
1460
1858
  {renderSettingRow({
1461
1859
  icon: <ShieldAlertIcon color={AppColors.greenColor} size={16}/>,
1462
- label: 'Global Crash Guard',
1463
- description: 'Intercepts native, JS, and render errors directly',
1860
+ label: t('settings.crash.globalGuard'),
1861
+ description: t('settings.crash.globalGuardDesc'),
1464
1862
  isLast: true,
1465
1863
  right: (<View style={{
1466
1864
  paddingHorizontal: 8,
@@ -1471,9 +1869,10 @@ const SettingsPanel = () => {
1471
1869
  <Text style={{
1472
1870
  fontFamily: AppFonts.interBold,
1473
1871
  fontSize: 10,
1872
+ lineHeight: 13,
1474
1873
  color: AppColors.greenColor,
1475
1874
  }}>
1476
- PROTECTED
1875
+ {t('settings.protectedBadge')}
1477
1876
  </Text>
1478
1877
  </View>),
1479
1878
  })}
@@ -1481,25 +1880,190 @@ const SettingsPanel = () => {
1481
1880
 
1482
1881
  <View style={{
1483
1882
  backgroundColor: AppColors.primaryLight,
1484
- borderRadius: 12,
1883
+ borderRadius: 14,
1485
1884
  borderWidth: 1,
1486
1885
  borderColor: AppColors.grayBorderSecondary,
1487
1886
  padding: 16,
1488
- marginTop: 12,
1489
1887
  }}>
1490
1888
  {renderSettingRow({
1491
1889
  icon: <TrashIcon color={AppColors.errorColor} size={16}/>,
1492
- label: 'Clear Crash History',
1493
- description: `${crashRecords?.length || 0} crash logs stored`,
1890
+ label: t('settings.crash.clearHistory'),
1891
+ description: t('settings.crash.clearHistoryDesc', { count: crashRecords?.length || 0 }),
1494
1892
  isLast: true,
1495
1893
  onPress: () => {
1496
1894
  clearCrashRecords();
1497
- Alert.alert('Success', 'Crash logs cleared.');
1895
+ Alert.alert(t('common.success'), t('settings.crash.historyCleared'));
1896
+ },
1897
+ right: (<View style={{
1898
+ paddingHorizontal: 12,
1899
+ paddingVertical: 6,
1900
+ borderRadius: 8,
1901
+ backgroundColor: `${AppColors.errorColor}14`,
1902
+ borderWidth: 1,
1903
+ borderColor: `${AppColors.errorColor}33`,
1904
+ }}>
1905
+ <Text style={{
1906
+ fontFamily: AppFonts.interBold,
1907
+ fontSize: 11,
1908
+ lineHeight: 14,
1909
+ color: AppColors.errorColor,
1910
+ }}>
1911
+ {t('common.clear')}
1912
+ </Text>
1913
+ </View>),
1914
+ })}
1915
+ </View>
1916
+ </ScrollView>);
1917
+ }
1918
+ else if (settingsPage === 'bundle') {
1919
+ title = t('settings.bundle.title');
1920
+ icon = <PackageIcon color={AppColors.white} size={16}/>;
1921
+ rightInfo = 'Metro';
1922
+ content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16, gap: 12 }}>
1923
+ <View style={{
1924
+ backgroundColor: AppColors.primaryLight,
1925
+ padding: 16,
1926
+ borderRadius: 14,
1927
+ borderWidth: 1,
1928
+ borderColor: AppColors.grayBorderSecondary,
1929
+ gap: 8,
1930
+ }}>
1931
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 10 }}>
1932
+ <View style={{
1933
+ width: 36,
1934
+ height: 36,
1935
+ borderRadius: 10,
1936
+ backgroundColor: AppColors.purpleShade50,
1937
+ alignItems: 'center',
1938
+ justifyContent: 'center',
1939
+ }}>
1940
+ <PackageIcon color={AppColors.purple} size={16}/>
1941
+ </View>
1942
+ <View style={{ flex: 1 }}>
1943
+ <Text style={{
1944
+ fontFamily: AppFonts.interBold,
1945
+ fontSize: 14,
1946
+ lineHeight: 18,
1947
+ color: AppColors.primaryBlack,
1948
+ }}>
1949
+ {t('settings.bundle.sourceBundler')}
1950
+ </Text>
1951
+ <Text style={{
1952
+ fontFamily: AppFonts.interRegular,
1953
+ fontSize: 11,
1954
+ lineHeight: 15,
1955
+ color: AppColors.grayText,
1956
+ marginTop: 1,
1957
+ }}>
1958
+ {t('settings.bundle.sourceBundlerDesc')}
1959
+ </Text>
1960
+ </View>
1961
+ </View>
1962
+ </View>
1963
+
1964
+ <View style={{
1965
+ backgroundColor: AppColors.primaryLight,
1966
+ borderRadius: 14,
1967
+ borderWidth: 1,
1968
+ borderColor: AppColors.grayBorderSecondary,
1969
+ padding: 16,
1970
+ }}>
1971
+ {renderSettingRow({
1972
+ icon: <TrashIcon color={AppColors.errorColor} size={16}/>,
1973
+ label: t('settings.bundle.clearCache'),
1974
+ description: t('settings.bundle.clearCacheDesc'),
1975
+ isLast: true,
1976
+ onPress: () => {
1977
+ clearCachedBundleAnalysis();
1978
+ Alert.alert(t('common.success'), t('settings.bundle.cacheCleared'));
1979
+ },
1980
+ right: (<View style={{
1981
+ paddingHorizontal: 12,
1982
+ paddingVertical: 6,
1983
+ borderRadius: 8,
1984
+ backgroundColor: `${AppColors.errorColor}14`,
1985
+ borderWidth: 1,
1986
+ borderColor: `${AppColors.errorColor}33`,
1987
+ }}>
1988
+ <Text style={{
1989
+ fontFamily: AppFonts.interBold,
1990
+ fontSize: 11,
1991
+ lineHeight: 14,
1992
+ color: AppColors.errorColor,
1993
+ }}>
1994
+ {t('common.clear')}
1995
+ </Text>
1996
+ </View>),
1997
+ })}
1998
+ </View>
1999
+ </ScrollView>);
2000
+ }
2001
+ else if (settingsPage === 'performance') {
2002
+ title = t('settings.performance.title');
2003
+ icon = <PerformanceIcon color={AppColors.white} size={16}/>;
2004
+ rightInfo = '60 FPS Target';
2005
+ content = (<ScrollView style={{ flex: 1 }} contentContainerStyle={{ padding: 16, gap: 12 }}>
2006
+ <View style={{
2007
+ backgroundColor: AppColors.primaryLight,
2008
+ padding: 16,
2009
+ borderRadius: 14,
2010
+ borderWidth: 1,
2011
+ borderColor: AppColors.grayBorderSecondary,
2012
+ gap: 8,
2013
+ }}>
2014
+ <View style={{ flexDirection: 'row', alignItems: 'center', gap: 10 }}>
2015
+ <View style={{
2016
+ width: 36,
2017
+ height: 36,
2018
+ borderRadius: 10,
2019
+ backgroundColor: AppColors.purpleShade50,
2020
+ alignItems: 'center',
2021
+ justifyContent: 'center',
2022
+ }}>
2023
+ <PerformanceIcon color={AppColors.purple} size={16}/>
2024
+ </View>
2025
+ <View style={{ flex: 1 }}>
2026
+ <Text style={{
2027
+ fontFamily: AppFonts.interBold,
2028
+ fontSize: 14,
2029
+ lineHeight: 18,
2030
+ color: AppColors.primaryBlack,
2031
+ }}>
2032
+ {t('settings.performance.frameMeasurement')}
2033
+ </Text>
2034
+ <Text style={{
2035
+ fontFamily: AppFonts.interRegular,
2036
+ fontSize: 11,
2037
+ lineHeight: 15,
2038
+ color: AppColors.grayText,
2039
+ marginTop: 1,
2040
+ }}>
2041
+ {t('settings.performance.frameMeasurementDesc')}
2042
+ </Text>
2043
+ </View>
2044
+ </View>
2045
+ </View>
2046
+
2047
+ <View style={{
2048
+ backgroundColor: AppColors.primaryLight,
2049
+ borderRadius: 14,
2050
+ borderWidth: 1,
2051
+ borderColor: AppColors.grayBorderSecondary,
2052
+ padding: 16,
2053
+ }}>
2054
+ {renderSettingRow({
2055
+ icon: <TrashIcon color={AppColors.errorColor} size={16}/>,
2056
+ label: t('settings.performance.clearEvents'),
2057
+ description: t('settings.performance.clearEventsDesc'),
2058
+ isLast: true,
2059
+ onPress: () => {
2060
+ clearPerformanceEvents();
2061
+ Alert.alert(t('common.success'), t('settings.performance.eventsCleared'));
1498
2062
  },
1499
2063
  right: (<View style={{
1500
- paddingHorizontal: 10,
1501
- paddingVertical: 5,
1502
- borderRadius: 7,
2064
+ paddingHorizontal: 12,
2065
+ paddingVertical: 6,
2066
+ borderRadius: 8,
1503
2067
  backgroundColor: `${AppColors.errorColor}14`,
1504
2068
  borderWidth: 1,
1505
2069
  borderColor: `${AppColors.errorColor}33`,
@@ -1507,29 +2071,33 @@ const SettingsPanel = () => {
1507
2071
  <Text style={{
1508
2072
  fontFamily: AppFonts.interBold,
1509
2073
  fontSize: 11,
2074
+ lineHeight: 14,
1510
2075
  color: AppColors.errorColor,
1511
2076
  }}>
1512
- Clear
2077
+ {t('common.clear')}
1513
2078
  </Text>
1514
2079
  </View>),
1515
2080
  })}
1516
2081
  </View>
1517
2082
  </ScrollView>);
1518
2083
  }
1519
- return (<View style={{ flex: 1, backgroundColor: AppColors.grayBackground }}>
2084
+ return (<View style={{
2085
+ flex: 1,
2086
+ backgroundColor: AppColors.grayBackground,
2087
+ }}>
1520
2088
  <LinearGradient colors={[AppColors.purple, AppColors.brandPurple]} start={{ x: 0, y: 0 }} end={{ x: 1, y: 0 }} style={styles.headerGradient}>
1521
2089
  <View style={{ paddingTop: headerTopPadding, width: '100%' }}>
1522
2090
  <View style={[styles.header, { paddingHorizontal: 16, gap: 12 }]}>
1523
- <TouchableScale onPress={goBackToMain} hitSlop={12} style={{
2091
+ <TouchableScale accessible={true} accessibilityRole="button" accessibilityLabel={t('settings.back')} onPress={goBackToMain} hitSlop={12} style={{
1524
2092
  padding: 8,
1525
2093
  borderRadius: 10,
1526
2094
  backgroundColor: `${AppColors.white}26`,
1527
2095
  borderWidth: 1,
1528
2096
  borderColor: `${AppColors.white}14`,
1529
2097
  }}>
1530
- <WhiteBackNavigation color={AppColors.white} size={16}/>
1531
- </TouchableScale>
1532
- {icon && (<View style={{
2098
+ <WhiteBackNavigation color={AppColors.white} size={16}/>
2099
+ </TouchableScale>
2100
+ {icon && (<View style={{
1533
2101
  width: 30,
1534
2102
  height: 30,
1535
2103
  borderRadius: 8,
@@ -1537,18 +2105,19 @@ const SettingsPanel = () => {
1537
2105
  alignItems: 'center',
1538
2106
  justifyContent: 'center',
1539
2107
  }}>
1540
- {icon}
1541
- </View>)}
1542
- <View style={{ flex: 1 }}>
1543
- <Text style={{
2108
+ {icon}
2109
+ </View>)}
2110
+ <View style={{ flex: 1 }}>
2111
+ <Text style={{
1544
2112
  fontFamily: AppFonts.interBold,
1545
2113
  fontSize: 17,
2114
+ lineHeight: 22,
1546
2115
  color: AppColors.white,
1547
2116
  }}>
1548
- {title}
1549
- </Text>
1550
- </View>
1551
- {rightInfo ? (<View style={{
2117
+ {title}
2118
+ </Text>
2119
+ </View>
2120
+ {rightInfo ? (<View style={{
1552
2121
  backgroundColor: `${AppColors.white}26`,
1553
2122
  paddingHorizontal: 8,
1554
2123
  paddingVertical: 4,
@@ -1556,17 +2125,18 @@ const SettingsPanel = () => {
1556
2125
  borderWidth: 1,
1557
2126
  borderColor: `${AppColors.white}1A`,
1558
2127
  }}>
1559
- <Text style={{
2128
+ <Text style={{
1560
2129
  fontFamily: AppFonts.interBold,
1561
2130
  fontSize: 11,
2131
+ lineHeight: 14,
1562
2132
  color: AppColors.white,
1563
2133
  }}>
1564
- {rightInfo}
1565
- </Text>
1566
- </View>) : null}
2134
+ {rightInfo}
2135
+ </Text>
2136
+ </View>) : null}
2137
+ </View>
1567
2138
  </View>
1568
- </View>
1569
- </LinearGradient>
2139
+ </LinearGradient>
1570
2140
  {content}
1571
2141
  </View>);
1572
2142
  };