-
Notifications
You must be signed in to change notification settings - Fork 1
인증샷 촬영 기능 구현 #41
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
인증샷 촬영 기능 구현 #41
Changes from 15 commits
Commits
Show all changes
61 commits
Select commit
Hold shift + click to select a range
084eb6a
➕ Build: CameraX dependency 추가
chanho0908 3597ab5
✨Feat: 카메라 활영 버튼, 렌즈 전후면 토글 버튼 컴포저블 추가
chanho0908 4e001bd
✨Feat: 카메라 플래시 on/off SVG 추가
chanho0908 6f50885
✨Feat: cameraX 촬영 기능 구현
chanho0908 846a1ef
♻️ Refactor: 버전 카탈로그 주석 추가 및 위치 수정
chanho0908 7df1e27
♻️ Refactor: CameraControlBar에 noRippleClickable 적용
chanho0908 8c2818e
✨ Feat: 화면 닫기 아이콘 추가
chanho0908 b33218e
✨ Feat: 인증샷 촬용 상태를 표현하기 위한 객체 추가
chanho0908 d3a4a95
✨ Feat: 임시 이미지 추가
chanho0908 0fd6cf3
✨ Feat: 카메라 프리뷰 화면 구현
chanho0908 203fd84
✨ Feat: 카메라 촬영 가능 구현
chanho0908 df06bb4
♻️ Refactor: 할일 인증 화면 KtlintFormat 적용
chanho0908 6949feb
♻️ Refactor: CameraControlBar 컬포저블 수정
chanho0908 4f7972e
♻️ Refactor: 이미지 캡쳐후 저장 로직 수정
chanho0908 215fae3
✨ Feat: 카메라 렌즈 토글 기능 추가
chanho0908 1d1a933
♻️ Refactor: 잘못 커밋된 파일 수정
chanho0908 9268343
♻️ Refactor: 잘못된 패키지명 수정
chanho0908 c678149
✨ Feat: TaskCertificationGraph 추가
chanho0908 4146605
♻️ Refactor: 미완성 코드 제거
chanho0908 5fb89fe
♻️ Refactor: CaptureStatus에 @Immutable 추가
chanho0908 5f881aa
♻️ Refactor: 플래시 아이콘 이름 변경
chanho0908 41d90d6
✨ Feat: 카메라 클래스에 플래시 On/Off 기능 추가
chanho0908 7a50827
➕ Build: 미사용 dependency 제거
chanho0908 2b7534e
➕ Build: guava dependency 추가
chanho0908 8c61d1a
✨ Feat: UI 카메라 플래시 토글 기능 추가
chanho0908 f2947c7
♻️ Refactor: 토치 아이콘 변수명 수정
chanho0908 19c23fe
♻️ Refactor: 로깅 제거
chanho0908 9733fde
♻️ Refactor: 불필요한 lifecycleowner 제거
chanho0908 900c7cc
♻️ Refactor: 카메라 바인딩 책임을 UI로 이동
chanho0908 ac190dd
♻️ Refactor: 카메라 촬영 책임을 UI로 이동
chanho0908 753f3b8
♻️ Refactor: 임시 코드 제거
chanho0908 94ea778
♻️ Refactor: 카메라 렌즈 토글 책임을 UI로 이동
chanho0908 8deb072
♻️ Refactor: 사진 촬영 함수를 콜백에서 suspend로 변경
chanho0908 7cf1a78
♻️ Refactor:: LifecycleOwner import 수정
chanho0908 326c781
♻️ Refactor: 카메라 바인딩 책임을 UI로 이동
chanho0908 34442dd
♻️ Refactor: 카메라 촬영 책임을 UI로 이동
chanho0908 5706c1a
♻️ Refactor: 임시 코드 제거
chanho0908 ccfe5e0
♻️ Refactor: 카메라 렌즈 토글 책임을 UI로 이동
chanho0908 d56df8b
♻️ Refactor: 사진 촬영 함수를 콜백에서 suspend로 변경
chanho0908 b2f436e
♻️ Refactor:: LifecycleOwner import 수정
chanho0908 c6d7b0d
♻️ Refactor: 불필요한 lifecycleowner 제거
chanho0908 acaeec3
♻️ Refactor: 카메라 촬영 책임을 UI로 이동
chanho0908 0f480fd
♻️ Refactor: 불필요한 lifecycleowner 제거
chanho0908 0e22c51
♻️ Refactor: 카메라 촬영 책임을 UI로 이동
chanho0908 0450fef
♻️ Refactor: 카메라 플래시 토글 책임을 UI로 이동
chanho0908 a0255ea
♻️ Refactor: 사진 촬영시 에러 콜백 처리 방식 수정
chanho0908 e862959
♻️ Refactor: 임시 코드 제거
chanho0908 987840d
✨Merge branch 'feat/#38-task-certification' into feat/#38-task-certif…
chanho0908 1b1895b
✨Merge branch 'feat/#38-task-certification-torch' into feat/#38-task-…
chanho0908 c8b73b6
✨ Feat: 카메라 권한 로직 추가
chanho0908 1d628d7
✨Merge branch 'develop' into feat/#38-task-certification
chanho0908 3f55676
♻️ Refactor: 토치 토글 로직 함수, 변수명 수정
chanho0908 4f5b5fc
♻️ Refactor: 사진 촬영시 토치 off 함수명 하나로 수정
chanho0908 f7654f4
♻️ Refactor: 이미지 캡쳐 실패 sideEffect 명 수정
chanho0908 0658bd3
✨ Feat: 후면 카메라로 변경시 토치 Off 기능 추가
chanho0908 6d72767
♻️ Refactor: lifecycle의 coroutineScope에서 rememberCoroutineScope로 수정
chanho0908 170a413
♻️ Refactor: 람다 제거
chanho0908 d908bbf
♻️ Refactor: 카메라를 생명주기에 맞게 unbind 하도록 수정
chanho0908 342d989
♻️ Refactor: viewModel에 reduce 함수들의 prefix에 reduce 추가
chanho0908 6f6c4b5
♻️ Refactor: 전면 카메라일 때 토치 버튼 숨김 처리
chanho0908 af74717
♻️ Refactor: camera unbinding 메서드를 동기 방식으로 수정
chanho0908 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Some comments aren't visible on the classic Files Changed page.
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| /build |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,10 @@ | ||
| plugins { | ||
| alias(libs.plugins.twix.feature) | ||
| } | ||
|
|
||
| android { | ||
| namespace = "com.peto.task_certification" | ||
| } | ||
| dependencies { | ||
| implementation(libs.bundles.cameraX) | ||
| } | ||
Empty file.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| 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"> | ||
| <uses-permission android:name="android.permission.CAMERA"/> | ||
chanho0908 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| </manifest> | ||
119 changes: 119 additions & 0 deletions
119
...e/task-certification/src/main/java/com/peto/task_certification/TaskCertificationScreen.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,119 @@ | ||
| package com.peto.task_certification | ||
|
|
||
| import androidx.compose.foundation.background | ||
| import androidx.compose.foundation.layout.Column | ||
| import androidx.compose.foundation.layout.Spacer | ||
| import androidx.compose.foundation.layout.fillMaxSize | ||
| import androidx.compose.foundation.layout.height | ||
| import androidx.compose.runtime.Composable | ||
| import androidx.compose.runtime.CompositionLocalProvider | ||
| import androidx.compose.runtime.LaunchedEffect | ||
| import androidx.compose.runtime.getValue | ||
| import androidx.compose.ui.Alignment | ||
| import androidx.compose.ui.Modifier | ||
| import androidx.compose.ui.graphics.toArgb | ||
| import androidx.compose.ui.res.stringResource | ||
| import androidx.compose.ui.tooling.preview.Preview | ||
| import androidx.compose.ui.unit.dp | ||
| import androidx.lifecycle.compose.LocalLifecycleOwner | ||
| import androidx.lifecycle.compose.collectAsStateWithLifecycle | ||
| import com.peto.task_certification.component.CameraControlBar | ||
| import com.peto.task_certification.component.CameraPreviewBox | ||
| import com.peto.task_certification.component.TaskCertificationTopBar | ||
| import com.peto.task_certification.model.TaskCertificationIntent | ||
| import com.peto.task_certification.model.TaskCertificationUiState | ||
| import com.twix.designsystem.components.text.AppText | ||
| import com.twix.designsystem.theme.GrayColor | ||
| import com.twix.designsystem.theme.LocalStatusBarColor | ||
| import com.twix.designsystem.theme.StatusBarStyle | ||
| import com.twix.designsystem.theme.TwixTheme | ||
| import com.twix.domain.model.enums.AppTextStyle | ||
| import org.koin.androidx.compose.koinViewModel | ||
|
|
||
| @Composable | ||
| fun TaskCertificationRoute( | ||
| viewModel: TaskCertificationViewModel = koinViewModel(), | ||
| navigateToBack: () -> Unit, | ||
| ) { | ||
| val uiSate by viewModel.uiState.collectAsStateWithLifecycle() | ||
chanho0908 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| val lifecycleOwner = LocalLifecycleOwner.current | ||
|
|
||
| LaunchedEffect(Unit) { | ||
| viewModel.dispatch(TaskCertificationIntent.BindCamera(lifecycleOwner)) | ||
| } | ||
|
|
||
| CompositionLocalProvider( | ||
| LocalStatusBarColor provides | ||
| StatusBarStyle( | ||
| GrayColor.C500.toArgb(), | ||
| false, | ||
| ), | ||
| ) { | ||
| TaskCertificationScreen( | ||
| uiState = uiSate, | ||
| onClickClose = { | ||
| navigateToBack() | ||
| }, | ||
| onCaptureClick = { | ||
| viewModel.dispatch(TaskCertificationIntent.TakePicture) | ||
| }, | ||
| onToggleCameraClick = { | ||
| viewModel.dispatch(TaskCertificationIntent.ToggleCamera(lifecycleOwner)) | ||
| }, | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| @Composable | ||
| private fun TaskCertificationScreen( | ||
| uiState: TaskCertificationUiState, | ||
| onClickClose: () -> Unit, | ||
| onCaptureClick: () -> Unit, | ||
| onToggleCameraClick: () -> Unit, | ||
| ) { | ||
| Column( | ||
| Modifier | ||
| .fillMaxSize() | ||
| .background(GrayColor.C500), | ||
| horizontalAlignment = Alignment.CenterHorizontally, | ||
| ) { | ||
| TaskCertificationTopBar( | ||
| onClickClose = { onClickClose() }, | ||
| ) | ||
|
|
||
| Spacer(modifier = Modifier.height(24.26.dp)) | ||
|
|
||
| AppText( | ||
| text = stringResource(R.string.task_certification_title), | ||
| style = AppTextStyle.H2, | ||
| color = GrayColor.C100, | ||
| ) | ||
|
|
||
| Spacer(modifier = Modifier.height(40.dp)) | ||
|
|
||
| CameraPreviewBox( | ||
| captureStatus = uiState.capture, | ||
| previewRequest = uiState.preview, | ||
| ) | ||
|
|
||
| Spacer(modifier = Modifier.height(52.dp)) | ||
|
|
||
| CameraControlBar( | ||
| onCaptureClick = onCaptureClick, | ||
| onToggleCameraClick = onToggleCameraClick, | ||
| ) | ||
| } | ||
| } | ||
|
|
||
| @Preview | ||
| @Composable | ||
| fun TaskCertificationScreenPreview() { | ||
| TwixTheme { | ||
| TaskCertificationScreen( | ||
| uiState = TaskCertificationUiState(), | ||
| onClickClose = {}, | ||
| onCaptureClick = {}, | ||
| onToggleCameraClick = {}, | ||
| ) | ||
| } | ||
| } | ||
90 changes: 90 additions & 0 deletions
90
...ask-certification/src/main/java/com/peto/task_certification/TaskCertificationViewModel.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,90 @@ | ||
| package com.peto.task_certification | ||
|
|
||
| import android.net.Uri | ||
| import androidx.lifecycle.LifecycleOwner | ||
| import androidx.lifecycle.viewModelScope | ||
| import com.peto.task_certification.camera.Camera | ||
| import com.peto.task_certification.model.CameraPreview | ||
| import com.peto.task_certification.model.TaskCertificationIntent | ||
| import com.peto.task_certification.model.TaskCertificationSideEffect | ||
| import com.peto.task_certification.model.TaskCertificationUiState | ||
| import com.twix.ui.base.BaseViewModel | ||
| import kotlinx.coroutines.flow.launchIn | ||
| import kotlinx.coroutines.flow.map | ||
| import kotlinx.coroutines.flow.onEach | ||
| import kotlinx.coroutines.launch | ||
|
|
||
| class TaskCertificationViewModel( | ||
| private val camera: Camera, | ||
| ) : BaseViewModel<TaskCertificationUiState, TaskCertificationIntent, TaskCertificationSideEffect>( | ||
| TaskCertificationUiState(), | ||
| ) { | ||
| init { | ||
| camera.surfaceRequests | ||
| .map { request -> request?.let { CameraPreview(request) } } | ||
| .onEach { preview -> | ||
| reduce { copy(preview = preview) } | ||
| }.launchIn(viewModelScope) | ||
| } | ||
|
|
||
| override suspend fun handleIntent(intent: TaskCertificationIntent) { | ||
| when (intent) { | ||
| is TaskCertificationIntent.BindCamera -> { | ||
| bindCamera(intent.lifecycleOwner) | ||
| } | ||
|
|
||
| is TaskCertificationIntent.TakePicture -> { | ||
| takePicture() | ||
| } | ||
|
|
||
| is TaskCertificationIntent.ToggleCamera -> { | ||
| toggleCamera(intent.lifecycleOwner) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private fun takePicture() { | ||
| camera.takePicture( | ||
| onComplete = { | ||
| updateCapturedCImage(it) | ||
| unbindCamera() | ||
| }, | ||
| onFailure = { | ||
| onFailureCapture() | ||
| }, | ||
| ) | ||
| } | ||
|
|
||
| private fun onFailureCapture() { | ||
| viewModelScope.launch { | ||
| emitSideEffect(TaskCertificationSideEffect.ImageCaptureFailException) | ||
| } | ||
| } | ||
|
|
||
| private fun unbindCamera() { | ||
| viewModelScope.launch { | ||
| camera.unbind() | ||
| } | ||
| } | ||
|
|
||
| private fun bindCamera(lifecycleOwner: LifecycleOwner) { | ||
| viewModelScope.launch { | ||
| camera.bind(lifecycleOwner, uiState.value.lens) | ||
| } | ||
| } | ||
|
|
||
| private fun updateCapturedCImage(uri: Uri?) { | ||
| uri?.let { | ||
| reduce { updateCapturedCImage(uri) } | ||
| } ?: run { | ||
| viewModelScope.launch { | ||
| emitSideEffect(TaskCertificationSideEffect.ImageCaptureFailException) | ||
| } | ||
| } | ||
| } | ||
|
|
||
| private fun toggleCamera(lifecycleOwner: LifecycleOwner) { | ||
| reduce { toggleLens() } | ||
| bindCamera(lifecycleOwner) | ||
| } | ||
| } |
24 changes: 24 additions & 0 deletions
24
feature/task-certification/src/main/java/com/peto/task_certification/camera/Camera.kt
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| package com.peto.task_certification.camera | ||
|
|
||
| import android.net.Uri | ||
| import androidx.camera.core.CameraSelector | ||
| import androidx.camera.core.ImageCaptureException | ||
| import androidx.camera.core.SurfaceRequest | ||
| import androidx.lifecycle.LifecycleOwner | ||
| import kotlinx.coroutines.flow.StateFlow | ||
|
|
||
| interface Camera { | ||
| val surfaceRequests: StateFlow<SurfaceRequest?> | ||
|
|
||
| suspend fun bind( | ||
| lifecycleOwner: LifecycleOwner, | ||
| lens: CameraSelector, | ||
| ) | ||
|
|
||
| suspend fun unbind() | ||
|
|
||
| fun takePicture( | ||
| onComplete: (Uri?) -> Unit, | ||
| onFailure: (ImageCaptureException) -> Unit, | ||
| ) | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
namespace 값이 peto로 들어갔는데 다른 모듈들이랑 네이밍 맞춰주세요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
헉 꼼꼼하게 봐줘서 고마워 ! 👍
리뷰 반영 커밋 : 9268343
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NavGraph도 적용해놨어 !
리뷰 반영 커밋 : c678149