day-piece-camera
Overview and capabilities
day-piece-camera adds a live camera preview and JPEG photo capture to a Day app.
Day is a Rust framework for building applications
from a shared codebase using each platform's native UI toolkit. A piece is a UI
component you place in a layout; a part provides a capability without drawing UI.
Day's day command builds and packages the Rust code, resources, and native platform
code together. Cargo.toml declares Rust dependencies; Day.toml configures the app
and its target platforms.
The camera() piece supports front/back camera switching, reactive session control,
a capture trigger, and signals reporting session state and the latest photo. A
signal is observable state: changing one updates the UI that reads it. A
trigger is an event you fire, such as a shutter press.
Photos are files in the app's cache directory, with a path, width, and height in
Photo. Photo::bytes() reads a file into Arc<Vec<u8>>, which can be displayed
with Day's day::async_image. The crate does not save to the photo library;
move or copy captures to persistent storage if the app needs to keep them.
Platform support and limitations
| Day target | Implementation | Limitations |
|---|---|---|
ios-uikit |
AVFoundation capture sessions, preview and photo output | Physical device required for capture; the iOS Simulator reports Unavailable. Below iOS 17, the preview is fixed portrait. |
android-material |
CameraX (androidx.camera), preview and image capture; architecture guide |
Requires a usable camera and permission; the emulator's virtual camera supports the capture path. |
harmony-arkui |
ArkUI surface and OpenHarmony native camera API (OH_Camera) |
Compiles and links, but is unverified on hardware. |
| Desktop, web, mock | No camera renderer | The piece becomes a placeholder; support() returns Unsupported. |
day_piece_camera::support() reports whether a renderer was compiled in, not whether
hardware or permission is available. Read CameraState at runtime: Idle,
Starting, Running, Unavailable, Denied, or Error(String). Torch, zoom, and
video recording are not exposed.
Add it to a Day project
Start with a Day app (the demo shows its complete structure). Add this to
its Cargo.toml:
[]
= "0.1"
Add an app-specific camera explanation to Day.toml, merging it into any existing
[permissions] table:
[]
= "Take photos to attach to your notes."
Alternatively, use camera = true and supply permission_camera in the app's
translation catalogs, as the demo does. The crate declares the permission it uses;
Day generates the Android, iOS, and HarmonyOS permission entries. iOS and HarmonyOS
builds require the app's explanation.
Return this piece from your app's UI-building function or place it in a layout:
use *;
use ;
.auto_request() opts into the system permission prompt when the session is first
wanted. Without it, request permission yourself through day-part-permissions;
an undecided permission leaves the camera idle. .active(signal) starts/stops the
session, .facing(signal) switches cameras, and removing the piece stops its session.
Gate camera navigation with support() on apps that also target desktop or web.
With the chosen target configured in your app and its platform SDK installed, run
day build -p android-material or day launch -p ios-uikit. Day reads the crate's backend
metadata and enables its matching feature; you do not need to forward camera
features in your app. Use Day's build pipeline to include the native sources.
Architecture and dependencies
Dependency links below lead to upstream source repositories or official API documentation. Version requirements describe this checkout's Cargo.toml, not necessarily the newest upstream releases.
src/lib.rs defines the portable piece, properties, commands, permission
checks, and event decoding. Reactive changes become CameraPatch commands (Start,
Stop, Capture, Facing). Native callbacks become Day custom events that update
the app's state and photo signals on the UI thread. Platform renderers register at
link time through linkme.
| Layer | Dependencies and responsibility |
|---|---|
| Shared Rust | day-core for the piece/tree, day-spec for types/events, day-pieces for builders, day-reactive for bindings, day-part-permissions for permission checks, log for diagnostics, linkme for registration. |
| iOS | Optional day-toolkit-uikit, objc2 0.6 and objc2-ui-kit 0.3. A Swift shim calls system AVFoundation; Day stages it into the app's Swift build. |
| Android | Optional day-toolkit-material provides the JNI/backend boundary. Gradle adds CameraX camera-core, camera-camera2, camera-lifecycle, and camera-view, each at 1.5.1, plus their transitive dependencies. |
| HarmonyOS | Optional day-toolkit-arkui and build dependency cc 1. build.rs compiles the C++ camera shim; the native implementation links ohcamera, ohimage, and native_window. Day stages the ArkTS surface code. |
| Tests | day-mock supplies the headless test backend. |
The iOS shim configures the session on a serial queue and reports on the main queue.
Android owns a separate camera lifecycle so navigating away releases this
viewfinder's use cases. HarmonyOS connects an ArkTS XComponent surface to the NDK
camera and encodes captured images as JPEG. See the design and
platform sources for the command protocol and resource ownership.
Compatibility and development
This checkout requires Rust 1.89 or newer and declares compatibility with Day 0.5 in
Cargo.toml. The crate is consumed from Git, not crates.io. Its Day
dependencies use https://github.com/daybrite/day.git without a branch, tag, or
revision. Use the same source in your app and keep its Cargo.lock to record the
resolved revisions. Mixing Day source URLs or refs can introduce duplicate framework
crates and incompatible types.
For a local framework checkout, run day patch --local ../day from this repository
(adjust the path when running from demo/). The demo depends on this crate
by path and is a complete integration example.
Run cargo test for the host-side checks. From demo/, run
day launch -p android-material --script dayscript/camera.yaml for the walkthrough.
The separate dayscript/camera-capture.yaml takes a photo and needs the permission granted
first, since Day scripts cannot dismiss the OS permission dialog: day launch -p android-material --grant camera --script dayscript/camera-capture.yaml marks it on the emulator before the app
starts. CI launches that way on its Android leg and runs the capture script there on every
push, beside the walkthrough on the iOS Simulator and the HarmonyOS emulator. Validate capture on a real iPhone and on the intended HarmonyOS
hardware before relying on those paths.