Skip to content

Commit

Permalink
Merge pull request #6 from lemoncloud-io/develop
Browse files Browse the repository at this point in the history
Compose 유틸리티 모듈 추가
  • Loading branch information
raine-lemon authored Aug 28, 2024
2 parents 3fb2815 + c49c240 commit 8fe9424
Show file tree
Hide file tree
Showing 12 changed files with 310 additions and 5 deletions.
14 changes: 9 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@

## Module

| module | description |
|------------------------------|---------------------------|
| android-component | android component 유틸리티 |
| ui-architecture | mvi 기반 architecture 인터페이스 |
| util-compose (Not Implement) | compose 유틸리티 |
| module | description |
|-------------------|---------------------------|
| android-component | android component 유틸리티 |
| ui-architecture | mvi 기반 architecture 인터페이스 |
| util-compose | compose 유틸리티 |

### UI-Architecture

Expand All @@ -21,6 +21,10 @@

안드로이드 컴포넌트 제어 라이브러리 안드로이드 컴포넌트 초기화, 설정 및 컴포넌트간의 통신과 같은 작업을 수행합니다.

### Compose-Util

안드로이드 `Compose` 에서 사용되는 유틸리티 집합 라이브러리

## 초기화

최초로 프로젝트를 다운받은 후 `./init_lint_settings.sh` 를 실행해주세요. commit changes 에 대한 lint를 자동적으로 수행합니다.
Expand Down
1 change: 1 addition & 0 deletions compose-util/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
3 changes: 3 additions & 0 deletions compose-util/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Compose-Util
안드로이드 `Compose` 에서 사용되는 유틸리티 집합
여러 디바이스 및 환경을 대응하는 `Preview` 집합 및 `Modifier` 확장자 관련한 유틸리티 등이 존재합니다.
12 changes: 12 additions & 0 deletions compose-util/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
plugins {
alias(libs.plugins.lemon.android.library)
alias(libs.plugins.lemon.android.library.compose)
alias(libs.plugins.lemon.android.compose.ext)
alias(libs.plugins.lemon.android.feature)
alias(libs.plugins.lemon.android.kotlin)
}

android {
namespace = "io.lemon.core.compose.util"
group = "io.lemon.core"
}
Empty file added compose-util/consumer-rules.pro
Empty file.
21 changes: 21 additions & 0 deletions compose-util/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
4 changes: 4 additions & 0 deletions compose-util/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

</manifest>
103 changes: 103 additions & 0 deletions compose-util/src/main/java/io/lemon/core/compose/util/Modifier.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package io.lemon.core.compose.util

import androidx.compose.foundation.Indication
import androidx.compose.foundation.clickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableLongStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.composed
import androidx.compose.ui.semantics.Role
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch

/**
* Click interaction 이 연속적으로 발생하는 것을 방지하는 확장자
*/
fun Modifier.throttleClickable(
onClick: () -> Unit,
enabled: Boolean = true,
onClickLabel: String? = null,
role: Role? = null,
coroutineDispatcher: CoroutineDispatcher = Dispatchers.Main,
throttleTime: Long = 250L,
) = composed {
val coroutineScope = rememberCoroutineScope { coroutineDispatcher }
var lastEmissionTime: Long by remember { mutableLongStateOf(0L) }

clickable(
onClick = {
val currentTime = System.currentTimeMillis()
if (currentTime - lastEmissionTime >= throttleTime) {
coroutineScope.launch {
lastEmissionTime = currentTime
onClick()
}
}
lastEmissionTime = currentTime
},
enabled = enabled,
onClickLabel = onClickLabel,
role = role,
)
}

/**
* Click interaction 이 연속적으로 발생하는 것을 방지하는 확장자
*/
fun Modifier.throttleClickable(
onClick: () -> Unit,
interactionSource: MutableInteractionSource = MutableInteractionSource(),
indication: Indication? = null,
enabled: Boolean = true,
onClickLabel: String? = null,
role: Role? = null,
coroutineDispatcher: CoroutineDispatcher = Dispatchers.Main,
throttleTime: Long = 250L,
) = composed {
val coroutineScope = rememberCoroutineScope { coroutineDispatcher }
var lastEmissionTime: Long by remember { mutableLongStateOf(0L) }

noRippleClickable(
onClick = {
val currentTime = System.currentTimeMillis()
if (currentTime - lastEmissionTime >= throttleTime) {
coroutineScope.launch {
lastEmissionTime = currentTime
onClick()
}
}
lastEmissionTime = currentTime
},
interactionSource = remember { interactionSource },
indication = indication,
enabled = enabled,
onClickLabel = onClickLabel,
role = role
)
}

/**
* Click interaction 중 발생하는 시각 이펙트를 제거하는 확장자
*/
fun Modifier.noRippleClickable(
onClick: () -> Unit,
interactionSource: MutableInteractionSource = MutableInteractionSource(),
indication: Indication? = null,
enabled: Boolean = true,
onClickLabel: String? = null,
role: Role? = null,
) = composed {
clickable(
interactionSource = remember { interactionSource },
indication = indication,
enabled = enabled,
onClickLabel = onClickLabel,
onClick = onClick,
role = role
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package io.lemon.core.compose.util.preview

import android.content.res.Configuration
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview

/**
* A ComponentPreview annotation for displaying a @[Composable] method in a component.
*/
@Retention(AnnotationRetention.BINARY)
@Target(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.FUNCTION)
@Preview(name = "Night", group = "Component", uiMode = Configuration.UI_MODE_NIGHT_YES)
@Preview(name = "Day", group = "Component", uiMode = Configuration.UI_MODE_NIGHT_NO)
annotation class ComponentPreview
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package io.lemon.core.compose.util.preview

import android.content.res.Configuration
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Devices.FOLDABLE
import androidx.compose.ui.tooling.preview.Devices.TABLET
import androidx.compose.ui.tooling.preview.Preview

/**
* A PhoneDevicePreview annotation for displaying a @[Composable] method in a component using a phone device.
*/
@Retention(AnnotationRetention.BINARY)
@Target(
AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.FUNCTION
)
@Preview(
name = "Android Large Night",
group = "Phone Device",
device = "spec:width=412dp,height=846dp,dpi=480",
showSystemUi = true,
uiMode = Configuration.UI_MODE_NIGHT_YES
)
@Preview(
name = "Android Large Day",
group = "Phone Device",
device = "spec:width=412dp,height=846dp,dpi=480",
showSystemUi = true,
uiMode = Configuration.UI_MODE_NIGHT_NO
)
@Preview(
name = "Android Small Night",
group = "Phone Device",
device = "spec:width=360dp,height=640dp,dpi=480",
showSystemUi = true,
uiMode = Configuration.UI_MODE_NIGHT_YES
)
@Preview(
name = "Android Small Day",
group = "Phone Device",
device = "spec:width=360dp,height=640dp,dpi=480",
showSystemUi = true,
uiMode = Configuration.UI_MODE_NIGHT_NO
)
annotation class PhoneDevicePreview

/**
* A FoldableDevicePreview annotation for displaying a @[Composable] method in a component using a foldable device.
*/
@Retention(AnnotationRetention.BINARY)
@Target(
AnnotationTarget.ANNOTATION_CLASS,
AnnotationTarget.FUNCTION
)
@Preview(
name = "Foldable Night",
group = "Foldable Device",
device = FOLDABLE,
showSystemUi = true,
uiMode = Configuration.UI_MODE_NIGHT_YES,
)
@Preview(
name = "Foldable Day",
group = "Foldable Device",
device = FOLDABLE,
showSystemUi = true,
uiMode = Configuration.UI_MODE_NIGHT_NO
)
annotation class FoldableDevicePreview

/**
* A TabletDevicePreview annotation for displaying a @[Composable] method in a component using a tablet device.
*/
@Retention(AnnotationRetention.BINARY)
@Target(
AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.FUNCTION
)
@Preview(
name = "Tablet Night",
group = "Tablet Device",
device = "spec:width=1280dp,height=800dp,dpi=240",
showSystemUi = true,
uiMode = Configuration.UI_MODE_NIGHT_YES
)
@Preview(
name = "Tablet Day",
group = "Tablet Device",
device = TABLET,
showSystemUi = true,
uiMode = Configuration.UI_MODE_NIGHT_NO
)
annotation class TabletDevicePreview

/**
* A MultiDevicePreview annotation for displaying a @[Composable] method in a component using the screen sizes of three different reference devices.
*/

@PhoneDevicePreview
@FoldableDevicePreview
@TabletDevicePreview
annotation class MultiDevicePreview
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package io.lemon.core.compose.util.preview

import android.content.res.Configuration
import androidx.compose.runtime.Composable
import androidx.compose.ui.tooling.preview.Preview

/**
* A LandscapeDevicePreview annotation for displaying a @[Composable] method in a component using a phone device in landscape mode.
*/
@Retention(AnnotationRetention.BINARY)
@Target(
AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.FUNCTION
)
@Preview(
name = "Landscape Android Large Night",
group = "Landscape Phone Device",
device = "spec:width=412dp,height=846dp,dpi=480,orientation=landscape",
showSystemUi = true,
uiMode = Configuration.UI_MODE_NIGHT_YES
)
@Preview(
name = "Landscape Android Large Day",
group = "Landscape Phone Device",
device = "spec:width=412dp,height=846dp,dpi=480,orientation=landscape",
showSystemUi = true,
uiMode = Configuration.UI_MODE_NIGHT_NO
)
@Preview(
name = "Landscape Android Small Night",
group = "Landscape Phone Device",
device = "spec:width=360dp,height=640dp,dpi=480,orientation=landscape",
showSystemUi = true,
uiMode = Configuration.UI_MODE_NIGHT_YES
)
@Preview(
name = "Landscape Android Small Day",
group = "Landscape Phone Device",
device = "spec:width=360dp,height=640dp,dpi=480,orientation=landscape",
showSystemUi = true,
uiMode = Configuration.UI_MODE_NIGHT_NO
)
annotation class LandscapeDevicePreview
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ dependencyResolutionManagement {

include(":sample")
include(":android-component")
include(":compose-util")
include(":ui-architecture")

0 comments on commit 8fe9424

Please sign in to comment.