react-native-ensys-camera-x 1.0.8 → 1.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -246,6 +246,13 @@ import {
|
|
|
246
246
|
AudioTile,
|
|
247
247
|
libraryPalette, // the shell's colours
|
|
248
248
|
wp, hp, ms, fs, // and its screen-scaling helpers
|
|
249
|
+
// Theme management
|
|
250
|
+
useCameraTheme, // hook: get the current theme with subscriptions to changes
|
|
251
|
+
useDarkOnlyTheme, // hook: get the dark theme (independent of global theme)
|
|
252
|
+
createCameraTheme, // create a custom theme from overrides
|
|
253
|
+
setGlobalCameraTheme, // change the active theme for all screens
|
|
254
|
+
getCurrentCameraTheme, // get the current theme (without subscriptions)
|
|
255
|
+
CameraThemeProvider, // context provider for theme
|
|
249
256
|
} from 'react-native-ensys-camera-x';
|
|
250
257
|
```
|
|
251
258
|
|
|
@@ -278,6 +285,114 @@ if (!result.cancelled) {
|
|
|
278
285
|
|
|
279
286
|
---
|
|
280
287
|
|
|
288
|
+
## Theming
|
|
289
|
+
|
|
290
|
+
The plugin ships with four built-in theme presets: `default`, `dark`, `light`, and `minimal`. You
|
|
291
|
+
can set the theme globally during configuration or override it per-screen.
|
|
292
|
+
|
|
293
|
+
### Set the theme globally
|
|
294
|
+
|
|
295
|
+
```tsx
|
|
296
|
+
import { configureCameraPlugin } from 'react-native-ensys-camera-x';
|
|
297
|
+
|
|
298
|
+
configureCameraPlugin({
|
|
299
|
+
theme: 'default', // 'default' | 'dark' | 'light' | 'minimal'
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
To switch themes at runtime:
|
|
304
|
+
|
|
305
|
+
```tsx
|
|
306
|
+
import { setGlobalCameraTheme } from 'react-native-ensys-camera-x';
|
|
307
|
+
|
|
308
|
+
setGlobalCameraTheme('dark'); // changes all screens immediately
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Override theme per-screen
|
|
312
|
+
|
|
313
|
+
Pass `theme` as a prop to any screen:
|
|
314
|
+
|
|
315
|
+
```tsx
|
|
316
|
+
<CameraMediaLibrary theme="dark" />
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
### Customize the theme
|
|
320
|
+
|
|
321
|
+
For deeper customization, pass a theme configuration object instead of a preset name:
|
|
322
|
+
|
|
323
|
+
```tsx
|
|
324
|
+
import { createCameraTheme } from 'react-native-ensys-camera-x';
|
|
325
|
+
|
|
326
|
+
const myTheme = createCameraTheme({
|
|
327
|
+
colors: {
|
|
328
|
+
primary: '#FF6B6B',
|
|
329
|
+
text: '#FFFFFF',
|
|
330
|
+
background: '#1A1A1A',
|
|
331
|
+
// ... other colors
|
|
332
|
+
},
|
|
333
|
+
components: {
|
|
334
|
+
cameraPreview: {
|
|
335
|
+
controlButtonBackground: 'rgba(0, 0, 0, 0.7)',
|
|
336
|
+
// ... other component overrides
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
configureCameraPlugin({ theme: myTheme });
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
### Dark-only theme for specific UI elements
|
|
345
|
+
|
|
346
|
+
Some UI elements (recording indicators, camera controls, audio players, media previews) should
|
|
347
|
+
always appear in dark mode regardless of the global theme setting. Use the `useDarkOnlyTheme()` hook
|
|
348
|
+
for these components:
|
|
349
|
+
|
|
350
|
+
```tsx
|
|
351
|
+
import { useDarkOnlyTheme } from 'react-native-ensys-camera-x';
|
|
352
|
+
|
|
353
|
+
export const MyCustomComponent = () => {
|
|
354
|
+
const theme = useDarkOnlyTheme(); // Always returns the dark theme
|
|
355
|
+
|
|
356
|
+
return (
|
|
357
|
+
<View style={{
|
|
358
|
+
backgroundColor: theme.colors.background,
|
|
359
|
+
color: theme.colors.text
|
|
360
|
+
}}>
|
|
361
|
+
{/* This component will always appear in dark mode */}
|
|
362
|
+
</View>
|
|
363
|
+
);
|
|
364
|
+
};
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
**Why use dark-only theme?** Some UI elements—particularly system-like overlays, control panels, and
|
|
368
|
+
status indicators—need to maintain visual consistency and contrast regardless of the app's theme
|
|
369
|
+
setting. The `useDarkOnlyTheme()` hook ensures these elements are never affected by theme changes.
|
|
370
|
+
|
|
371
|
+
### Access the current theme
|
|
372
|
+
|
|
373
|
+
To check the active theme in your components:
|
|
374
|
+
|
|
375
|
+
```tsx
|
|
376
|
+
import { useCameraTheme, getCurrentCameraTheme } from 'react-native-ensys-camera-x';
|
|
377
|
+
|
|
378
|
+
// In a component (with subscriptions to theme changes):
|
|
379
|
+
const theme = useCameraTheme();
|
|
380
|
+
|
|
381
|
+
// Outside a component (static access):
|
|
382
|
+
const theme = getCurrentCameraTheme();
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
### Theme presets
|
|
386
|
+
|
|
387
|
+
| Preset | Description |
|
|
388
|
+
| --- | --- |
|
|
389
|
+
| `default` | Professional dark theme with blue accents (recommended) |
|
|
390
|
+
| `dark` | Pure dark theme optimized for low-light environments |
|
|
391
|
+
| `light` | Light theme with professional appearance |
|
|
392
|
+
| `minimal` | Minimalist monochrome dark theme using white accents |
|
|
393
|
+
|
|
394
|
+
---
|
|
395
|
+
|
|
281
396
|
## Customizing icons
|
|
282
397
|
|
|
283
398
|
All icon customization happens in the **`CUSTOM_ICONS`** block of your `App.tsx`. Nothing else to
|
|
@@ -275,8 +275,10 @@ class CameraTheme(
|
|
|
275
275
|
val prefs = context.getSharedPreferences("CameraSettings", Context.MODE_PRIVATE)
|
|
276
276
|
val jsonString = prefs.getString("cameraTheme", null)
|
|
277
277
|
|
|
278
|
-
// Default palette (Dark)
|
|
279
|
-
|
|
278
|
+
// Default palette (Dark). Kept in a named val so the Light-theme
|
|
279
|
+
// guard below can revert to it: native Android screens never adopt
|
|
280
|
+
// a Light theme (see the light-theme check after parsing).
|
|
281
|
+
val defaultDarkColors = CameraThemeColors(
|
|
280
282
|
background = Color.parseColor("#000000"),
|
|
281
283
|
surface = Color.parseColor("#111827"),
|
|
282
284
|
surfaceMuted = Color.parseColor("#1F2937"),
|
|
@@ -295,6 +297,7 @@ class CameraTheme(
|
|
|
295
297
|
error = Color.parseColor("#FF5B5B"),
|
|
296
298
|
warning = Color.parseColor("#FBBF24")
|
|
297
299
|
)
|
|
300
|
+
var colors = defaultDarkColors
|
|
298
301
|
|
|
299
302
|
var typography = CameraThemeTypography("System", 18f, 16f, 13f, 14f)
|
|
300
303
|
var spacing = CameraThemeSpacing(4, 8, 12, 16, 20, 24)
|
|
@@ -362,6 +365,18 @@ class CameraTheme(
|
|
|
362
365
|
}
|
|
363
366
|
}
|
|
364
367
|
|
|
368
|
+
// Native Android screens stay Dark regardless of the host's
|
|
369
|
+
// light/dark switch: only the React Native surfaces follow the host
|
|
370
|
+
// into Light. If the resolved/persisted theme reads as Light (this
|
|
371
|
+
// can only happen for a theme persisted by an older build, since
|
|
372
|
+
// `setCameraTheme` no longer stores Light themes), revert the color
|
|
373
|
+
// palette to the Dark defaults. Typography/spacing/radius are left
|
|
374
|
+
// as configured because they aren't light/dark specific, so branded
|
|
375
|
+
// fonts and metrics survive. Dark themes are untouched.
|
|
376
|
+
if (!colors.isDark) {
|
|
377
|
+
colors = defaultDarkColors
|
|
378
|
+
}
|
|
379
|
+
|
|
365
380
|
// Flatten the theme's `components` section into per-component
|
|
366
381
|
// key→string maps consumed via componentColor()/componentValue().
|
|
367
382
|
val componentOverrides = mutableMapOf<String, Map<String, String>>()
|
|
@@ -1403,11 +1403,46 @@ class CustomCameraModule(
|
|
|
1403
1403
|
|
|
1404
1404
|
@ReactMethod
|
|
1405
1405
|
override fun setCameraTheme(theme: String, promise: Promise) {
|
|
1406
|
+
// Native Android screens must never switch to a Light theme: when the host
|
|
1407
|
+
// toggles Light, only the React Native surfaces follow. A Light theme push
|
|
1408
|
+
// is therefore NOT persisted natively, so the last Dark theme (or the Dark
|
|
1409
|
+
// default) is retained and native chrome stays Dark. Dark theme pushes —
|
|
1410
|
+
// including branded dark palettes — are saved as before, so Dark behavior is
|
|
1411
|
+
// unchanged. `CameraTheme.load()` applies the same guard defensively for any
|
|
1412
|
+
// Light theme persisted by an older build.
|
|
1413
|
+
if (isLightThemeJson(theme)) {
|
|
1414
|
+
// Re-read whatever Dark theme is already stored (no-op if unchanged) so a
|
|
1415
|
+
// subsequent load reflects the retained theme rather than the ignored push.
|
|
1416
|
+
CameraTheme.invalidate()
|
|
1417
|
+
promise.resolve(null)
|
|
1418
|
+
return
|
|
1419
|
+
}
|
|
1406
1420
|
saveSetting("cameraTheme", theme)
|
|
1407
1421
|
CameraTheme.invalidate()
|
|
1408
1422
|
promise.resolve(null)
|
|
1409
1423
|
}
|
|
1410
1424
|
|
|
1425
|
+
/**
|
|
1426
|
+
* Whether a `setCameraTheme` payload describes a Light theme, i.e. its
|
|
1427
|
+
* `colors.background` reads as light (relative luminance >= 0.5). Mirrors
|
|
1428
|
+
* [isColorDark] / the JS `isDarkTheme()` so the native/RN light-dark split
|
|
1429
|
+
* agrees. A payload with no parseable background is treated as NOT light, so
|
|
1430
|
+
* malformed themes fall through to the normal save path unchanged.
|
|
1431
|
+
*/
|
|
1432
|
+
private fun isLightThemeJson(theme: String): Boolean {
|
|
1433
|
+
if (!theme.trimStart().startsWith("{")) return false
|
|
1434
|
+
return try {
|
|
1435
|
+
val background = org.json.JSONObject(theme)
|
|
1436
|
+
.optJSONObject("colors")
|
|
1437
|
+
?.optString("background")
|
|
1438
|
+
?.takeIf { it.isNotEmpty() }
|
|
1439
|
+
?: return false
|
|
1440
|
+
!isColorDark(android.graphics.Color.parseColor(background))
|
|
1441
|
+
} catch (e: Exception) {
|
|
1442
|
+
false
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
|
|
1411
1446
|
@ReactMethod
|
|
1412
1447
|
override fun setCameraConfig(configJson: String, promise: Promise) {
|
|
1413
1448
|
saveSetting("cameraConfig", configJson)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-ensys-camera-x",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.10",
|
|
4
4
|
"description": "Full-screen native Android camera and media picker for React Native — photo/video capture, gallery multi-select, and an editor (crop, rotate, filters, stickers, emoji, text, drawing, trim) in one call. Fully white-labelled: every icon, colour and string is configurable.",
|
|
5
5
|
"source": "./src/index.tsx",
|
|
6
6
|
"main": "./lib/module/index.js",
|