Skip to content

Commit 2ca5da4

Browse files
committed
feat: implement internal camera functionality with capture and preview use cases [#45]
1 parent 8bea38c commit 2ca5da4

File tree

18 files changed

+419
-149
lines changed

18 files changed

+419
-149
lines changed

data/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ dependencies {
4949
implementation(libs.datastore.preferences.core)
5050
implementation(libs.protobuf.javalite)
5151

52+
// camerax
53+
implementation(libs.camerax.core)
5254
// test
5355
testImplementation(libs.junit)
5456
androidTestImplementation(libs.androidx.junit)

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

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.foke.together.data.repository
22

3+
import androidx.annotation.IntRange
4+
import androidx.camera.core.CameraSelector
35
import androidx.datastore.core.DataStore
46
import com.foke.together.AppPreferences
57
import com.foke.together.CameraSource
@@ -53,6 +55,64 @@ class AppPreferencesRepository @Inject constructor(
5355
}
5456
}
5557

58+
override fun getInternalCameraLensFacing(): Flow<Int> =
59+
appPreferencesFlow.map{
60+
it.internalCameraLensFacing
61+
}
62+
63+
override suspend fun setInternalCameraLensFacing(lensFacing: Int) {
64+
appPreferences.updateData {
65+
it.toBuilder()
66+
.setInternalCameraLensFacing(lensFacing)
67+
.build()
68+
}
69+
}
70+
71+
override fun getInterenalCameraFlashMode(): Flow<Int> =
72+
appPreferencesFlow.map{
73+
it.internalCameraFlashMode
74+
}
75+
76+
override suspend fun setInterenalCameraFlashMode(
77+
@IntRange(from = 0, to = 3) flashMode: Int
78+
) {
79+
appPreferences.updateData {
80+
it.toBuilder()
81+
.setInternalCameraFlashMode(flashMode)
82+
.build()
83+
}
84+
}
85+
86+
override fun getInternalCameraCaptureMode(): Flow<Int> =
87+
appPreferencesFlow.map {
88+
it.internalCameraCaptureMode
89+
}
90+
91+
override suspend fun setInterenalCameraCaptureMode(
92+
@IntRange(from = 0, to = 2) captureMode: Int
93+
) {
94+
appPreferences.updateData {
95+
it.toBuilder()
96+
.setInternalCameraCaptureMode(captureMode)
97+
.build()
98+
}
99+
}
100+
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+
}
115+
56116
override suspend fun clearAll() {
57117
appPreferences.updateData {
58118
it.toBuilder().clear().build()

data/src/main/proto/app_preferences.proto

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,11 @@ message AppPreferences {
1515
CameraSource camera_source = 10;
1616
string external_camera_ip = 11;
1717

18+
int32 internal_camera_lens_facing = 20;
19+
int32 internal_camera_flash_mode = 21;
20+
int32 internal_camera_capture_mode = 22;
21+
int32 internal_camera_aspect_ratio = 23;
22+
1823
// TODO: sample code. remove later.
1924
string sample_id = 999997;
2025
string sample_title = 999998;

domain/build.gradle.kts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ dependencies {
1111
implementation(libs.androidx.core.ktx)
1212
implementation(libs.androidx.appcompat)
1313
implementation(libs.material)
14+
implementation(libs.camerax.view)
15+
implementation(libs.camerax.lifecycle)
1416
testImplementation(libs.junit)
1517
androidTestImplementation(libs.androidx.junit)
1618
androidTestImplementation(libs.androidx.espresso.core)
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.foke.together.domain.interactor
2+
3+
import android.content.Context
4+
import com.foke.together.domain.output.ImageRepositoryInterface
5+
import com.foke.together.domain.output.InternalCameraRepositoryInterface
6+
import com.foke.together.util.AppLog
7+
import dagger.hilt.android.qualifiers.ApplicationContext
8+
import javax.inject.Inject
9+
10+
class CaptureWithInternalCameraUseCase @Inject constructor(
11+
private val internalCameraRepository: InternalCameraRepositoryInterface,
12+
private val imageRepository: ImageRepositoryInterface
13+
) {
14+
suspend operator fun invoke(
15+
context: Context,
16+
fileName: String
17+
): Result<Unit>{
18+
internalCameraRepository.capture(context)
19+
.onSuccess {
20+
AppLog.i(TAG, "invoke", "success: $it")
21+
imageRepository.cachingImage(it, fileName)
22+
return Result.success(Unit)
23+
}
24+
.onFailure {
25+
AppLog.e(TAG, "invoke", "failure: $it")
26+
return Result.failure(it)
27+
}
28+
return Result.failure(Exception("Unknown error"))
29+
}
30+
31+
companion object {
32+
private val TAG = CaptureWithInternalCameraUseCase::class.java.simpleName
33+
}
34+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.foke.together.domain.interactor
2+
3+
import com.foke.together.domain.output.AppPreferenceInterface
4+
import kotlinx.coroutines.flow.Flow
5+
import javax.inject.Inject
6+
7+
class GetInternalCameraAspectRatioUseCase @Inject constructor(
8+
private val appPreferenceRepository: AppPreferenceInterface
9+
) {
10+
operator fun invoke() : Flow<Int> = appPreferenceRepository.getInternalCameraAspectRatio()
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.foke.together.domain.interactor
2+
3+
import com.foke.together.domain.output.AppPreferenceInterface
4+
import kotlinx.coroutines.flow.Flow
5+
import javax.inject.Inject
6+
7+
class GetInternalCameraCaptureModeUseCase @Inject constructor(
8+
private val appPreferenceRepository: AppPreferenceInterface
9+
) {
10+
operator fun invoke() : Flow<Int> = appPreferenceRepository.getInternalCameraCaptureMode()
11+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package com.foke.together.domain.interactor
2+
3+
import com.foke.together.domain.output.AppPreferenceInterface
4+
import kotlinx.coroutines.flow.Flow
5+
import javax.inject.Inject
6+
7+
class GetInternalCameraFlashModeUseCase @Inject constructor(
8+
private val appPreferenceRepository: AppPreferenceInterface
9+
) {
10+
operator fun invoke() : Flow<Int> = appPreferenceRepository.getInterenalCameraFlashMode()
11+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.foke.together.domain.interactor
2+
3+
import androidx.camera.core.CameraSelector
4+
import com.foke.together.domain.output.AppPreferenceInterface
5+
import kotlinx.coroutines.flow.Flow
6+
import kotlinx.coroutines.flow.map
7+
import javax.inject.Inject
8+
9+
class GetInternalCameraLensFacingUseCase @Inject constructor(
10+
private val appPreferenceRepository: AppPreferenceInterface
11+
) {
12+
operator fun invoke() : Flow<CameraSelector> = appPreferenceRepository.getInternalCameraLensFacing().map { cameraSelectorIdx ->
13+
CameraSelector.Builder()
14+
.requireLensFacing(cameraSelectorIdx)
15+
.build()
16+
}
17+
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.foke.together.domain.interactor
2+
3+
import android.content.Context
4+
import androidx.annotation.IntRange
5+
import androidx.camera.core.CameraSelector
6+
import androidx.camera.core.ImageAnalysis
7+
import androidx.camera.view.PreviewView
8+
import androidx.lifecycle.LifecycleOwner
9+
import com.foke.together.domain.output.InternalCameraRepositoryInterface
10+
import javax.inject.Inject
11+
12+
class GetInternalCameraPreviewUseCase @Inject constructor(
13+
private val internalCameraRepository: InternalCameraRepositoryInterface,
14+
) {
15+
suspend operator fun invoke(
16+
context: Context,
17+
previewView: PreviewView,
18+
lifecycleOwner: LifecycleOwner,
19+
cameraSelector: CameraSelector,
20+
imageAnalysis: ImageAnalysis?,
21+
@IntRange(from = 0, to = 2) captureMode: Int,
22+
@IntRange(from = 0, to = 3) flashMode: Int,
23+
@IntRange(from = -1, to = 1) aspectRatio: Int
24+
) = internalCameraRepository.showCameraPreview(
25+
context = context,
26+
lifecycleOwner = lifecycleOwner,
27+
previewView = previewView,
28+
selector = cameraSelector,
29+
imageAnalysis = imageAnalysis,
30+
captureMode = captureMode,
31+
flashMode = flashMode,
32+
aspectRatio = aspectRatio
33+
)
34+
}

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.foke.together.domain.output
22

3+
import androidx.annotation.IntRange
4+
import androidx.camera.core.CameraSelector
35
import com.foke.together.domain.interactor.entity.CameraSourceType
46
import com.foke.together.domain.interactor.entity.ExternalCameraIP
57
import kotlinx.coroutines.flow.Flow
@@ -11,5 +13,25 @@ interface AppPreferenceInterface {
1113
fun getExternalCameraIP(): Flow<ExternalCameraIP>
1214
suspend fun setExternalCameraIP(ip: ExternalCameraIP)
1315

16+
fun getInternalCameraLensFacing(): Flow<Int>
17+
suspend fun setInternalCameraLensFacing(
18+
@IntRange(from = 0, to = 1) lensFacing: Int
19+
)
20+
21+
fun getInterenalCameraFlashMode(): Flow<Int>
22+
suspend fun setInterenalCameraFlashMode(
23+
@IntRange(from = 0, to = 3) flashMode: Int
24+
)
25+
26+
fun getInternalCameraCaptureMode(): Flow<Int>
27+
suspend fun setInterenalCameraCaptureMode(
28+
@IntRange(from = 0, to = 2) captureMode: Int
29+
)
30+
31+
fun getInternalCameraAspectRatio(): Flow<Int>
32+
suspend fun setInterenalCameraAspectRatio(
33+
@IntRange(from = -1, to = 1) aspectRatio: Int
34+
)
35+
1436
suspend fun clearAll()
1537
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.foke.together.domain.output
2+
3+
import android.content.Context
4+
import android.graphics.Bitmap
5+
import androidx.annotation.IntRange
6+
import androidx.camera.core.CameraSelector
7+
import androidx.camera.core.ImageAnalysis
8+
import androidx.camera.core.ImageCapture
9+
import androidx.camera.view.PreviewView
10+
import androidx.lifecycle.LifecycleOwner
11+
12+
interface InternalCameraRepositoryInterface {
13+
suspend fun capture(context: Context): Result<Bitmap>
14+
suspend fun showCameraPreview(
15+
context: Context,
16+
lifecycleOwner: LifecycleOwner,
17+
previewView: PreviewView,
18+
selector : CameraSelector,
19+
imageAnalysis: ImageAnalysis?,
20+
@IntRange(from = 0, to = 2) captureMode: Int,
21+
@IntRange(from = 0, to = 3) flashMode: Int,
22+
@IntRange(from = -1, to = 1) aspectRatio: Int
23+
)
24+
}

external/src/main/java/com/foke/together/external/camera/internal/AndroidCameraDataSource.kt

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

0 commit comments

Comments
 (0)