Skip to content

Commit 6e588b3

Browse files
committed
[#45][#110] feat: add InternalCameraScreen and update InternelCameraViewModel with capture functionality
1 parent bbecbe5 commit 6e588b3

File tree

23 files changed

+505
-165
lines changed

23 files changed

+505
-165
lines changed

app/src/main/AndroidManifest.xml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,13 @@
44
<!-- To use IP camera for external camera type-->
55
<!-- TODO: need to check to move this permission to presenter module -->
66
<uses-permission android:name="android.permission.INTERNET" />
7+
<uses-feature android:name="android.hardware.camera" />
8+
<uses-permission android:name="android.permission.CAMERA" />
9+
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" android:maxSdkVersion="32" />
10+
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
11+
android:maxSdkVersion="32" />
12+
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"
13+
android:maxSdkVersion="32" />
714

815
<application
916
android:name=".MainApplication"

data/src/main/java/com/foke/together/data/repository/AppPreferencesRepository.kt

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ class AppPreferencesRepository @Inject constructor(
8888
it.internalCameraCaptureMode
8989
}
9090

91-
override suspend fun setInterenalCameraCaptureMode(
91+
override suspend fun setInternalCameraCaptureMode(
9292
@IntRange(from = 0, to = 2) captureMode: Int
9393
) {
9494
appPreferences.updateData {
@@ -98,20 +98,6 @@ class AppPreferencesRepository @Inject constructor(
9898
}
9999
}
100100

101-
override fun getInternalCameraAspectRatio(): Flow<Int> =
102-
appPreferencesFlow.map {
103-
it.internalCameraAspectRatio
104-
}
105-
106-
override suspend fun setInterenalCameraAspectRatio(
107-
@IntRange(from = -1, to = 1) aspectRatio: Int
108-
) {
109-
appPreferences.updateData {
110-
it.toBuilder()
111-
.setInternalCameraAspectRatio(aspectRatio)
112-
.build()
113-
}
114-
}
115101

116102
override suspend fun clearAll() {
117103
appPreferences.updateData {

domain/src/main/java/com/foke/together/domain/interactor/CaptureWithInternalCameraUseCase.kt

Lines changed: 0 additions & 34 deletions
This file was deleted.

domain/src/main/java/com/foke/together/domain/interactor/GeneratePhotoFrameUseCaseV1.kt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.foke.together.domain.interactor
33
import android.content.Context
44
import android.graphics.Bitmap
55
import android.net.Uri
6+
import com.foke.together.domain.interactor.entity.CameraSourceType
67
import com.foke.together.domain.output.ImageRepositoryInterface
78
import com.foke.together.util.AppPolicy
89
import dagger.hilt.android.qualifiers.ApplicationContext
@@ -16,7 +17,7 @@ class GeneratePhotoFrameUseCaseV1 @Inject constructor(
1617
// 촬영한 이미지 리스트 관리
1718
// TODO: 추후 세션 관리와 엮어서 처리하기
1819
@Deprecated("Not in use")
19-
fun getCapturedImageListUri(): List<Uri> = imageRepositoryInterface.getCachedImageUriList()
20+
fun getCapturedImageListUri(sourceType: CameraSourceType): List<Uri> = imageRepositoryInterface.getCachedImageUriList(sourceType)
2021
@Deprecated("Not in use")
2122
suspend fun clearCapturedImageList() = imageRepositoryInterface.clearCacheDir()
2223

domain/src/main/java/com/foke/together/domain/interactor/GetInternalCameraAspectRatioUseCase.kt

Lines changed: 0 additions & 11 deletions
This file was deleted.
Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,26 +9,35 @@ import androidx.lifecycle.LifecycleOwner
99
import com.foke.together.domain.output.InternalCameraRepositoryInterface
1010
import javax.inject.Inject
1111

12-
class GetInternalCameraPreviewUseCase @Inject constructor(
12+
class InternalCameraUseCase @Inject constructor(
1313
private val internalCameraRepository: InternalCameraRepositoryInterface,
1414
) {
15-
suspend operator fun invoke(
15+
suspend fun initial(
1616
context: Context,
17-
previewView: PreviewView,
1817
lifecycleOwner: LifecycleOwner,
18+
previewView : PreviewView,
1919
cameraSelector: CameraSelector,
20-
imageAnalysis: ImageAnalysis?,
20+
imageAnalyzer: ImageAnalysis.Analyzer?,
2121
@IntRange(from = 0, to = 2) captureMode: Int,
2222
@IntRange(from = 0, to = 3) flashMode: Int,
23-
@IntRange(from = -1, to = 1) aspectRatio: Int
24-
) = internalCameraRepository.showCameraPreview(
23+
) = internalCameraRepository.initial(
2524
context = context,
2625
lifecycleOwner = lifecycleOwner,
27-
previewView = previewView,
28-
selector = cameraSelector,
29-
imageAnalysis = imageAnalysis,
3026
captureMode = captureMode,
3127
flashMode = flashMode,
32-
aspectRatio = aspectRatio
28+
selector = cameraSelector,
29+
imageAnalyzer = imageAnalyzer,
30+
previewView = previewView,
31+
)
32+
33+
suspend fun capture(
34+
context: Context,
35+
fileName : String,
36+
) = internalCameraRepository.capture(
37+
context = context,
38+
fileName = fileName
3339
)
40+
suspend fun release(
41+
context: Context
42+
) = internalCameraRepository.release(context)
3443
}

domain/src/main/java/com/foke/together/domain/output/AppPreferenceInterface.kt

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,14 +24,9 @@ interface AppPreferenceInterface {
2424
)
2525

2626
fun getInternalCameraCaptureMode(): Flow<Int>
27-
suspend fun setInterenalCameraCaptureMode(
27+
suspend fun setInternalCameraCaptureMode(
2828
@IntRange(from = 0, to = 2) captureMode: Int
2929
)
3030

31-
fun getInternalCameraAspectRatio(): Flow<Int>
32-
suspend fun setInterenalCameraAspectRatio(
33-
@IntRange(from = -1, to = 1) aspectRatio: Int
34-
)
35-
3631
suspend fun clearAll()
3732
}

domain/src/main/java/com/foke/together/domain/output/ImageRepositoryInterface.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,16 @@ package com.foke.together.domain.output
22

33
import android.graphics.Bitmap
44
import android.net.Uri
5+
import com.foke.together.domain.interactor.entity.CameraSourceType
56
import com.foke.together.domain.interactor.entity.CutFrameTypeV1
67

78
interface ImageRepositoryInterface {
89
fun getCutFrameType(): CutFrameTypeV1
910
suspend fun setCutFrameType(type: Int)
1011
// 촬영한 사진들 모음
1112
suspend fun cachingImage(image: Bitmap, fileName: String) : Uri
12-
fun getCachedImageUriList() : List<Uri>
13+
14+
fun getCachedImageUriList(sourceType: CameraSourceType) : List<Uri>
1315
suspend fun clearCacheDir()
1416

1517
// 완성된 프레임 모음

domain/src/main/java/com/foke/together/domain/output/InternalCameraRepositoryInterface.kt

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,20 +5,22 @@ import android.graphics.Bitmap
55
import androidx.annotation.IntRange
66
import androidx.camera.core.CameraSelector
77
import androidx.camera.core.ImageAnalysis
8-
import androidx.camera.core.ImageCapture
98
import androidx.camera.view.PreviewView
109
import androidx.lifecycle.LifecycleOwner
1110

1211
interface InternalCameraRepositoryInterface {
13-
suspend fun capture(context: Context): Result<Bitmap>
14-
suspend fun showCameraPreview(
12+
suspend fun capture(
13+
context: Context,
14+
fileName : String,
15+
)
16+
suspend fun initial(
1517
context: Context,
1618
lifecycleOwner: LifecycleOwner,
17-
previewView: PreviewView,
19+
previewView : PreviewView,
1820
selector : CameraSelector,
19-
imageAnalysis: ImageAnalysis?,
2021
@IntRange(from = 0, to = 2) captureMode: Int,
2122
@IntRange(from = 0, to = 3) flashMode: Int,
22-
@IntRange(from = -1, to = 1) aspectRatio: Int
23+
imageAnalyzer: ImageAnalysis.Analyzer?,
2324
)
25+
suspend fun release(context: Context)
2426
}

external/src/main/java/com/foke/together/external/repository/ImageRepository.kt

Lines changed: 52 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,20 @@ import android.content.Context
44
import android.graphics.Bitmap
55
import android.graphics.ImageDecoder
66
import android.net.Uri
7+
import android.provider.MediaStore
8+
import com.foke.together.domain.interactor.GetCameraSourceTypeUseCase
9+
import com.foke.together.domain.interactor.entity.CameraSourceType
710
import com.foke.together.domain.interactor.entity.CutFrameTypeV1
811
import com.foke.together.domain.output.ImageRepositoryInterface
912
import com.foke.together.util.AppPolicy
1013
import com.foke.together.util.ImageFileUtil
1114
import dagger.hilt.android.qualifiers.ApplicationContext
15+
import kotlinx.coroutines.flow.map
1216
import javax.inject.Inject
1317

1418
class ImageRepository @Inject constructor(
15-
@ApplicationContext private val context: Context
19+
@ApplicationContext private val context: Context,
20+
private val getCameraSourceTypeUseCase: GetCameraSourceTypeUseCase
1621
): ImageRepositoryInterface{
1722
private var cutFrameType: CutFrameTypeV1 = CutFrameTypeV1.MAKER_FAIRE
1823

@@ -25,12 +30,53 @@ class ImageRepository @Inject constructor(
2530
return ImageFileUtil.cacheBitmap(context, image, fileName)
2631
}
2732

28-
override fun getCachedImageUriList(): List<Uri> {
33+
override fun getCachedImageUriList(sourceType: CameraSourceType): List<Uri> {
2934
var uriList = mutableListOf<Uri>()
30-
context.cacheDir.listFiles().forEach {
31-
if(it.name.contains(AppPolicy.CAPTURED_FOUR_CUT_IMAGE_NAME)){
32-
// capture로 시작하는 파일만 반환
33-
uriList.add(Uri.fromFile(it))
35+
when(sourceType){
36+
CameraSourceType.EXTERNAL -> {
37+
context.cacheDir.listFiles().forEach {
38+
if(it.name.contains(AppPolicy.CAPTURED_FOUR_CUT_IMAGE_NAME)){
39+
// capture로 시작하는 파일만 반환
40+
uriList.add(Uri.fromFile(it))
41+
}
42+
}
43+
}
44+
CameraSourceType.INTERNAL -> {
45+
val projection = arrayOf(
46+
MediaStore.Images.Media._ID,
47+
MediaStore.Images.Media.DISPLAY_NAME,
48+
MediaStore.Images.Media.DATE_ADDED
49+
)
50+
val selection = "${MediaStore.Images.Media.RELATIVE_PATH} LIKE ?"
51+
val selectionArgs = arrayOf("%Pictures/4cuts/backup%")
52+
val sortOrder = "${MediaStore.Images.Media.DATE_ADDED} DESC"
53+
54+
val cursor = context.contentResolver.query(
55+
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
56+
projection,
57+
selection,
58+
selectionArgs,
59+
sortOrder
60+
)
61+
62+
cursor?.use {
63+
val idColumn = it.getColumnIndexOrThrow(MediaStore.Images.Media._ID)
64+
val latestUris = mutableListOf<Uri>()
65+
66+
var count = 0
67+
while (it.moveToNext() && count < AppPolicy.CAPTURE_COUNT) {
68+
val id = it.getLong(idColumn)
69+
val contentUri = Uri.withAppendedPath(
70+
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
71+
id.toString()
72+
)
73+
latestUris.add(contentUri)
74+
count++
75+
}
76+
77+
latestUris.reverse()
78+
uriList.addAll(latestUris)
79+
}
3480
}
3581
}
3682
return uriList

0 commit comments

Comments
 (0)