Peekaboo
🌄 Kotlin Multiplatform library for Compose Multiplatform, designed for seamless integration of an image picker feature in iOS and Android applications.
Install / Use
/learn @onseok/PeekabooREADME
peekaboo
<a href="https://mailchi.mp/kotlinweekly/kotlin-weekly-385"><img alt="Kotlin Weekly" src="https://img.shields.io/badge/Kotlin_Weekly-%23385-purple"/></a>
📂 Kotlin Multiplatform library for Compose Multiplatform, designed for seamless integration of an image picker feature in iOS and Android applications.
Getting started
Compose Multiplatform
peekaboo is based on Compose Multiplatform, currently targeting only iOS and Android. <br/>
Please note that it primarily focuses on these platforms, and additional platforms may be considered in the future. <br/>
When using peekaboo on Android, ensure that Google's Jetpack Compose version is compatible with peekaboo's Compose Multiplatform version. <br/>
Installation
The minimum supported Android SDK is 24 (Android 7.0).
In your commonMain configuration, add the desired dependency, either peekaboo-ui or peekaboo-image-picker, to your project. Both are available on Maven Central.
<br/>
Without Version Catalog
commonMain {
dependencies {
// peekaboo-ui
implementation("io.github.onseok:peekaboo-ui:$latest_version")
// peekaboo-image-picker
implementation("io.github.onseok:peekaboo-image-picker:$latest_version")
}
}
With Version Catalog
First, define the version in libs.versions.toml:
[versions]
peekaboo = "0.5.2"
[libraries]
peekaboo-ui = { module = "io.github.onseok:peekaboo-ui", version.ref = "peekaboo" }
peekaboo-image-picker = { module = "io.github.onseok:peekaboo-image-picker", version.ref = "peekaboo" }
Then, in your commonMain configuration, reference the defined version:
commonMain {
dependencies {
// peekaboo-ui
implementation(libs.peekaboo.ui)
// peekaboo-image-picker
implementation(libs.peekaboo.image.picker)
}
}
Artifacts
| Name | Description |
|-------------------------|-----------------------------------------------------------------------------|
| peekaboo-ui |Provides user-friendly UI elements, including a custom camera view for easy image capture, suitable for both iOS and Android platforms. |
| peekaboo-image-picker | Simplifies the process of selecting single or multiple images both in iOS and Android platforms. |
Usage
Xcode setup
In order to access the camera on iOS devices, it's essential to include a specific key-value pair in the Info.plist file of your iOS project. This key-value pair comprises a key that identifies the type of permission being requested and a value that provides a user-friendly description explaining why the app needs access to the camera.
Here's the key-value pair you should add to your Info.plist:
<key>Privacy - Camera Usage Description</key>
<string>This app uses camera for capturing photos.</string>
Custimizable Camera UI
PeekabooCamera is a composable function that provides a customizable camera UI within a Compose Multiplatform application.
Simple Camera UI
@Composable
fun CustomCameraView() {
val state = rememberPeekabooCameraState(onCapture = { /* Handle captured images */ })
PeekabooCamera(
state = state,
modifier = Modifier.fillMaxSize(),
permissionDeniedContent = {
// Custom UI content for permission denied scenario
},
)
}
Camera UI with overlay
@Composable
fun CustomCameraView() {
val state = rememberPeekabooCameraState(onCapture = { /* Handle captured images */ })
Box(modifier = Modifier.fillMaxSize()) {
PeekabooCamera(
state = state,
modifier = Modifier.fillMaxSize(),
permissionDeniedContent = {
// Custom UI content for permission denied scenario
},
)
// Draw here UI you need with provided state
YourCameraOverlay(
state = state,
modifier = Modifier.fillMaxSize(),
)
}
}
state: ThePeekabooCameraStateto control camera.permissionDeniedContent: An optionalcomposablelambda that provides content to be displayed when camera permission is denied. This allows users to define a custom UI to inform or guide the user when camera access has been denied. The content can be informative text, an image, a button to redirect the user to settings, or any othercomposablecontent. This lambda will be invoked within thePeekabooCameracomposable scope, replacing the camera preview with the user-defined UI.
Camera state
rememberPeekabooCameraState(
initialCameraMode: CameraMode = CameraMode.Back,
onCapture: (ByteArray?) -> Unit,
)
initialCameraMode: The initial camera mode (front or back). Default is [CameraMode.Back]. Changes does not affect state. To toggle use [PeekabooCameraState.toggleCamera]onCapture: A lambda called when a photo is captured, providing the photo as a ByteArray or null if the capture fails.PeekabooCameraState.isCameraReady: True if camera already available for showPeekabooCameraState.isCapturing: True if camera is in progress of capturePeekabooCameraState.cameraMode: Current camera mode (front or back)
Capturing an Image from Camera
| Android | iOS | |-----------------------------------------------------------------|---------------------------------------------------------| | <img src="https://github.com/onseok/onseok/assets/76798309/897a0104-2e8d-4339-90fb-2f61807aa56d" width="300" height="700"> | <img src="https://github.com/onseok/onseok/assets/76798309/fe414cc2-370a-4b0d-9558-c60e1fbbb4f7" width="300" height="700"> |
Toggling Camera Mode Between Front and Back
| Android | iOS | |-----------------------------------------------------------------|---------------------------------------------------------| | <img src="https://github.com/onseok/onseok/assets/76798309/477f49f8-389d-4ba6-a2d1-60155cab355e" width="300" height="700"> | <img src="https://github.com/onseok/onseok/assets/76798309/022da284-cf58-4ce0-9fc1-e592885f09b9" width="300" height="700"> |
Handling Denied Camera Permissions
| Android | iOS | |-----------------------------------------------------------------|---------------------------------------------------------| | <img src="https://github.com/onseok/onseok/assets/76798309/61511ec6-45b9-48bd-9267-fe9f2a086008" width="300" height="700"> | <img src="https://github.com/onseok/onseok/assets/76798309/604ed9d9-d6e0-47ac-9393-5cb627a4f13d" width="300" height="700"> |
Select Single Image
val scope = rememberCoroutineScope()
val singleImagePicker = rememberImagePickerLauncher(
selectionMode = SelectionMode.Single,
scope = scope,
onResult = { byteArrays ->
byteArrays.firstOrNull()?.let {
// Process the selected images' ByteArrays.
println(it)
}
}
)
Button(
onClick = {
singleImagePicker.launch()
}
) {
Text("Pick Single Image")
}
| Android | iOS | |-----------------------------------------------------------------|---------------------------------------------------------| | <img src="https://github.com/TEAM-PREAT/peekaboo/assets/76798309/03346992-cf2a-4424-88e5-fa53afd36eac" width="300" height="700"> | <img src="https://github.com/TEAM-PREAT/peekaboo/assets/76798309/7b562f6f-e5d5-4858-85b8-acf7196d646f" width="300" height="700"> |
Simply select the desired image with an intuitive interface.
<br/>Select Multiple Images
If you want to select multiple images, you can use SelectionMode.Multiple(). And you can set the maximum number of images to select.
If you didn't set max selection, the default value is maximum number that the system supports.
val scope = rememberCoroutineScope()
val multipleImagePicker = rememberImagePickerLauncher(
// Optional: Set a maximum selection limit, e.g., SelectionMode.Multiple(maxSelection = 5).
// Default: No limit, depends on system's maximum capacity.
selectionMode = SelectionMode.Multiple(maxSelection = 5),
scope = scope,
onResult = { byteArrays ->
byteArrays.forEach {
// Process the selected images' ByteArrays.
println(it)
}
}
)
Button(
onClick = {
multipleImagePicker.launch()
}
) {
Text("Pick Multiple Images")
}
| Android
