Skip to content

Commit

Permalink
Merge pull request #8 from TEAM-PREAT/chore/apply-spotless
Browse files Browse the repository at this point in the history
[chore/apply-spotless] Integrate spotless with ktlint and update CI configuration
  • Loading branch information
onseok authored Dec 10, 2023
2 parents 04619b9 + 68fb342 commit 8aaca11
Show file tree
Hide file tree
Showing 20 changed files with 200 additions and 144 deletions.
31 changes: 31 additions & 0 deletions .github/workflows/ci_check.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
name: Check CI

on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
workflow_dispatch:

concurrency:
group: ci-${{ github.ref }}
cancel-in-progress: true

jobs:
code-formatting-and-tests:
runs-on: macos-latest
steps:
- uses: actions/checkout@v4

- name: Setup JDK 17
uses: actions/setup-java@v4
with:
java-version: 17
distribution: zulu
cache: gradle

- name: Check Spotless
run: ./gradlew spotlessCheck

- name: Run Common Tests
run: ./gradlew cleanAllTests allTests
2 changes: 1 addition & 1 deletion build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
id("root.publication")
//trick: for the same plugin versions in all sub-modules
// trick: for the same plugin versions in all sub-modules
alias(libs.plugins.androidApplication).apply(false)
alias(libs.plugins.androidLibrary).apply(false)
alias(libs.plugins.kotlinAndroid).apply(false)
Expand Down
2 changes: 1 addition & 1 deletion convention-plugins/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ plugins {

dependencies {
implementation(libs.nexus.publish)
}
}
2 changes: 1 addition & 1 deletion convention-plugins/settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ dependencyResolutionManagement {
from(files("../gradle/libs.versions.toml"))
}
}
}
}
18 changes: 12 additions & 6 deletions convention-plugins/src/main/kotlin/module.publication.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,21 @@ publishing {
// Configure all publications
publications.withType<MavenPublication> {
// Stub javadoc.jar artifact
artifact(tasks.register("${name}JavadocJar", Jar::class) {
archiveClassifier.set("javadoc")
archiveAppendix.set(this@withType.name)
})
artifact(
tasks.register("${name}JavadocJar", Jar::class) {
archiveClassifier.set("javadoc")
archiveAppendix.set(this@withType.name)
},
)

// Provide artifacts information required by Maven Central
pom {
name.set("peekaboo")
description.set("Kotlin Multiplatform library for Compose Multiplatform, designed for seamless integration of an image picker feature in iOS and Android applications.")
description.set(
"Kotlin Multiplatform library for Compose Multiplatform, " +
"designed for seamless integration of an image picker feature in iOS " +
"and Android applications.",
)
url.set("https://github.com/TEAM-PREAT/peekaboo")

licenses {
Expand Down Expand Up @@ -61,4 +67,4 @@ signing {
tasks.withType<AbstractPublishToMaven>().configureEach {
val signingTasks = tasks.withType<Sign>()
mustRunAfter(signingTasks)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,4 @@ import androidx.compose.ui.graphics.asImageBitmap

actual fun ByteArray.toImageBitmap(): ImageBitmap {
return BitmapFactory.decodeByteArray(this, 0, size).asImageBitmap()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,9 @@ internal fun isSystemPickerAvailable(): Boolean {
}

@SuppressLint("NewApi", "ClassVerificationFailure")
internal fun getMaxItems() = if (isSystemPickerAvailable()) {
MediaStore.getPickImagesMaxLimit()
} else {
Integer.MAX_VALUE
}
internal fun getMaxItems() =
if (isSystemPickerAvailable()) {
MediaStore.getPickImagesMaxLimit()
} else {
Integer.MAX_VALUE
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,17 @@ actual fun rememberImagePickerLauncher(
onResult: (List<ByteArray>) -> Unit,
): ImagePickerLauncher {
return when (selectionMode) {
SelectionMode.Single -> pickSingleImage(
selectionMode = selectionMode,
onResult = onResult
)
SelectionMode.Single ->
pickSingleImage(
selectionMode = selectionMode,
onResult = onResult,
)

is SelectionMode.Multiple -> pickMultipleImages(
selectionMode = selectionMode,
onResult = onResult
)
is SelectionMode.Multiple ->
pickMultipleImages(
selectionMode = selectionMode,
onResult = onResult,
)
}
}

Expand All @@ -35,27 +37,28 @@ private fun pickSingleImage(
): ImagePickerLauncher {
val context = LocalContext.current

val singleImagePickerLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.PickVisualMedia(),
onResult = { uri ->
uri?.let {
with(context.contentResolver) {
openInputStream(uri)?.use {
onResult(listOf(it.readBytes()))
val singleImagePickerLauncher =
rememberLauncherForActivityResult(
contract = ActivityResultContracts.PickVisualMedia(),
onResult = { uri ->
uri?.let {
with(context.contentResolver) {
openInputStream(uri)?.use {
onResult(listOf(it.readBytes()))
}
}
}
}
}
)
},
)

return remember {
ImagePickerLauncher(
selectionMode = selectionMode,
onLaunch = {
singleImagePickerLauncher.launch(
PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)
PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly),
)
}
},
)
}
}
Expand All @@ -66,34 +69,37 @@ fun pickMultipleImages(
onResult: (List<ByteArray>) -> Unit,
): ImagePickerLauncher {
val context = LocalContext.current
val maxSelection = if (selectionMode.maxSelection == INFINITY) {
getMaxItems()
} else {
selectionMode.maxSelection
}
val maxSelection =
if (selectionMode.maxSelection == INFINITY) {
getMaxItems()
} else {
selectionMode.maxSelection
}

val multipleImagePickerLauncher = rememberLauncherForActivityResult(
contract = ActivityResultContracts.PickMultipleVisualMedia(maxSelection),
onResult = { uriList ->
val imageBytesList = uriList.mapNotNull { uri ->
context.contentResolver.openInputStream(uri)?.use { inputStream ->
inputStream.readBytes()
val multipleImagePickerLauncher =
rememberLauncherForActivityResult(
contract = ActivityResultContracts.PickMultipleVisualMedia(maxSelection),
onResult = { uriList ->
val imageBytesList =
uriList.mapNotNull { uri ->
context.contentResolver.openInputStream(uri)?.use { inputStream ->
inputStream.readBytes()
}
}
if (imageBytesList.isNotEmpty()) {
onResult(imageBytesList)
}
}
if (imageBytesList.isNotEmpty()) {
onResult(imageBytesList)
}
}
)
},
)

return remember {
ImagePickerLauncher(
selectionMode = selectionMode,
onLaunch = {
multipleImagePickerLauncher.launch(
PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly)
PickVisualMediaRequest(ActivityResultContracts.PickVisualMedia.ImageOnly),
)
}
},
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@ package com.preat.peekaboo.image.picker

import androidx.compose.ui.graphics.ImageBitmap

expect fun ByteArray.toImageBitmap(): ImageBitmap
expect fun ByteArray.toImageBitmap(): ImageBitmap
Original file line number Diff line number Diff line change
Expand Up @@ -7,20 +7,22 @@ import kotlinx.coroutines.CoroutineScope
expect fun rememberImagePickerLauncher(
selectionMode: SelectionMode = SelectionMode.Single,
scope: CoroutineScope?,
onResult: (List<ByteArray>) -> Unit
onResult: (List<ByteArray>) -> Unit,
): ImagePickerLauncher

sealed class SelectionMode {
data object Single : SelectionMode()

data class Multiple(val maxSelection: Int = INFINITY) : SelectionMode()

companion object {
const val INFINITY = 0
}
}

expect class ImagePickerLauncher(
selectionMode: SelectionMode,
onLaunch: () -> Unit
onLaunch: () -> Unit,
) {
fun launch()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,4 @@ import androidx.compose.ui.graphics.ImageBitmap
import androidx.compose.ui.graphics.toComposeImageBitmap
import org.jetbrains.skia.Image

actual fun ByteArray.toImageBitmap(): ImageBitmap =
Image.makeFromEncoded(this).toComposeImageBitmap()
actual fun ByteArray.toImageBitmap(): ImageBitmap = Image.makeFromEncoded(this).toComposeImageBitmap()
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,36 @@ import platform.posix.memcpy
actual fun rememberImagePickerLauncher(
selectionMode: SelectionMode,
scope: CoroutineScope?,
onResult: (List<ByteArray>) -> Unit
onResult: (List<ByteArray>) -> Unit,
): ImagePickerLauncher {

@OptIn(ExperimentalForeignApi::class)
val delegate = object : NSObject(), PHPickerViewControllerDelegateProtocol {
override fun picker(picker: PHPickerViewController, didFinishPicking: List<*>) {
picker.dismissViewControllerAnimated(flag = true, completion = null)
@Suppress("UNCHECKED_CAST")
val results = didFinishPicking as List<PHPickerResult>
val delegate =
object : NSObject(), PHPickerViewControllerDelegateProtocol {
override fun picker(
picker: PHPickerViewController,
didFinishPicking: List<*>,
) {
picker.dismissViewControllerAnimated(flag = true, completion = null)
@Suppress("UNCHECKED_CAST")
val results = didFinishPicking as List<PHPickerResult>

for (result in results) {
result.itemProvider.loadDataRepresentationForTypeIdentifier(
typeIdentifier = "public.image"
) { nsData, _ ->
scope?.launch(Dispatchers.Main) {
val data = mutableListOf<ByteArray>()
nsData?.let {
val bytes = ByteArray(it.length.toInt())
memcpy(bytes.refTo(0), it.bytes, it.length)
data.add(bytes)
for (result in results) {
result.itemProvider.loadDataRepresentationForTypeIdentifier(
typeIdentifier = "public.image",
) { nsData, _ ->
scope?.launch(Dispatchers.Main) {
val data = mutableListOf<ByteArray>()
nsData?.let {
val bytes = ByteArray(it.length.toInt())
memcpy(bytes.refTo(0), it.bytes, it.length)
data.add(bytes)
}
onResult(data.toList())
}
onResult(data.toList())
}
}
}
}
}

return remember {
ImagePickerLauncher(
Expand All @@ -57,31 +60,35 @@ actual fun rememberImagePickerLauncher(
UIApplication.sharedApplication.keyWindow?.rootViewController?.presentViewController(
pickerController,
true,
null
null,
)
}
},
)
}
}

private fun createPHPickerViewController(
delegate: PHPickerViewControllerDelegateProtocol,
selection: SelectionMode
selection: SelectionMode,
): PHPickerViewController {
val pickerViewController = PHPickerViewController(
configuration = when (selection) {
is SelectionMode.Multiple -> PHPickerConfiguration().apply {
setSelectionLimit(selectionLimit = selection.maxSelection.toLong())
setFilter(filter = PHPickerFilter.imagesFilter)
setSelection(selection = PHPickerConfigurationSelectionOrdered)
}
SelectionMode.Single -> PHPickerConfiguration().apply {
setSelectionLimit(selectionLimit = 1)
setFilter(filter = PHPickerFilter.imagesFilter)
setSelection(selection = PHPickerConfigurationSelectionOrdered)
}
}
)
val pickerViewController =
PHPickerViewController(
configuration =
when (selection) {
is SelectionMode.Multiple ->
PHPickerConfiguration().apply {
setSelectionLimit(selectionLimit = selection.maxSelection.toLong())
setFilter(filter = PHPickerFilter.imagesFilter)
setSelection(selection = PHPickerConfigurationSelectionOrdered)
}
SelectionMode.Single ->
PHPickerConfiguration().apply {
setSelectionLimit(selectionLimit = 1)
setFilter(filter = PHPickerFilter.imagesFilter)
setSelection(selection = PHPickerConfigurationSelectionOrdered)
}
},
)
pickerViewController.delegate = delegate
return pickerViewController
}
Expand All @@ -93,4 +100,4 @@ actual class ImagePickerLauncher actual constructor(
actual fun launch() {
onLaunch()
}
}
}
Loading

0 comments on commit 8aaca11

Please sign in to comment.