Skip to content
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

[FEAT] [#9] 사진 가이드 화면 구현 #52

Merged
merged 2 commits into from
Feb 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ package com.nexters.ilab.android.core.data.di

import com.nexters.ilab.android.core.data.datasource.FileDataSource
import com.nexters.ilab.android.core.data.datasource.FileDataSourceImpl
import com.nexters.ilab.android.core.datastore.PrivacyPolicyDataSource
import com.nexters.ilab.android.core.datastore.PrivacyPolicyDataSourceImpl
import com.nexters.ilab.android.core.datastore.TokenDataSource
import com.nexters.ilab.android.core.datastore.TokenDataSourceImpl
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
Expand All @@ -15,4 +19,12 @@ abstract class DataSourceModule {
@Singleton
@Binds
abstract fun bindFileDataSource(fileDataSourceImpl: FileDataSourceImpl): FileDataSource

@Singleton
@Binds
abstract fun bindTokenDataSource(tokenDataSourceImpl: TokenDataSourceImpl): TokenDataSource

@Singleton
@Binds
abstract fun bindPrivacyPolicyDataSource(privacyPolicyDataSourceImpl: PrivacyPolicyDataSourceImpl): PrivacyPolicyDataSource
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package com.nexters.ilab.android.core.data.di

import com.nexters.ilab.android.core.data.repository.FileRepositoryImpl
import com.nexters.ilab.android.core.data.repository.PrivacyPolicyRepositoryImpl
import com.nexters.ilab.android.core.domain.repository.FileRepository
import com.nexters.ilab.android.core.domain.repository.PrivacyPolicyRepository
import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
Expand All @@ -15,4 +17,8 @@ abstract class RepositoryModule {
@Binds
@Singleton
abstract fun bindFileRepository(fileRepositoryImpl: FileRepositoryImpl): FileRepository

@Binds
@Singleton
abstract fun bindPrivacyPolicyRepository(privacyPolicyRepositoryImpl: PrivacyPolicyRepositoryImpl): PrivacyPolicyRepository
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.nexters.ilab.android.core.data.repository

import com.nexters.ilab.android.core.datastore.PrivacyPolicyDataSource
import com.nexters.ilab.android.core.domain.repository.PrivacyPolicyRepository
import kotlinx.coroutines.flow.Flow
import javax.inject.Inject

class PrivacyPolicyRepositoryImpl @Inject constructor(
private val privacyPolicyDataSource: PrivacyPolicyDataSource,
) : PrivacyPolicyRepository {
override fun getPrivacyPolicyAgreement(): Flow<Boolean> =
privacyPolicyDataSource.isPrivacyPolicyAgreed

override suspend fun setPrivacyPolicyAgreement(flag: Boolean) {
privacyPolicyDataSource.setPrivacyPolicyAgreement(flag)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.nexters.ilab.android.core.datastore

import kotlinx.coroutines.flow.Flow

interface PrivacyPolicyDataSource {
val isPrivacyPolicyAgreed: Flow<Boolean>
suspend fun setPrivacyPolicyAgreement(flag: Boolean)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.nexters.ilab.android.core.datastore

import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.booleanPreferencesKey
import androidx.datastore.preferences.core.edit
import com.nexters.ilab.android.core.datastore.di.PrivacyPolicyDataStore
import kotlinx.coroutines.flow.map
import javax.inject.Inject

class PrivacyPolicyDataSourceImpl @Inject constructor(
@PrivacyPolicyDataStore private val dataStore: DataStore<Preferences>,
) : PrivacyPolicyDataSource {
private companion object {
private val KEY_PRIVACY_POLICY_AGREEMENT = booleanPreferencesKey("privacy_policy_agreement")
}

override val isPrivacyPolicyAgreed = dataStore.data.map { preferences ->
preferences[KEY_PRIVACY_POLICY_AGREEMENT] ?: false
}

override suspend fun setPrivacyPolicyAgreement(flag: Boolean) {
dataStore.edit { preferences -> preferences[KEY_PRIVACY_POLICY_AGREEMENT] = flag }
}
}
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
package com.nexters.ilab.android.core.datastore

interface TokenDataStore {
interface TokenDataSource {
suspend fun setAccessToken(accessToken: String)

suspend fun setRefreshToken(refreshToken: String)

suspend fun getAccessToken(): String

suspend fun getRefreshToken(): String

suspend fun clear()
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@ import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.core.edit
import androidx.datastore.preferences.core.emptyPreferences
import androidx.datastore.preferences.core.stringPreferencesKey
import com.nexters.ilab.android.core.datastore.di.TokenDataStore
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.first
import java.io.IOException
import javax.inject.Inject

class TokenDataStoreImpl @Inject constructor(
private val dataStore: DataStore<Preferences>,
) : TokenDataStore {
class TokenDataSourceImpl @Inject constructor(
@TokenDataStore val dataStore: DataStore<Preferences>,
) : TokenDataSource {
private companion object {
private val KEY_ACCESS_TOKEN = stringPreferencesKey("access_token")
private val KEY_REFRESH_TOKEN = stringPreferencesKey("refresh_token")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.Preferences
import androidx.datastore.preferences.preferencesDataStore
import com.nexters.ilab.android.core.datastore.TokenDataStoreImpl
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
Expand All @@ -15,15 +14,20 @@ import javax.inject.Singleton
private const val TOKEN_DATASTORE = "token_datastore"
private val Context.tokenDataStore: DataStore<Preferences> by preferencesDataStore(name = TOKEN_DATASTORE)

private const val PRIVACY_POLICY_DATASTORE = "privacy_policy_datastore"
private val Context.privacyPolicyDataStore: DataStore<Preferences> by preferencesDataStore(name = PRIVACY_POLICY_DATASTORE)

@Module
@InstallIn(SingletonComponent::class)
internal object DataStoreModule {

@TokenDataStore
@Singleton
@Provides
internal fun providePreferencesDataStore(@ApplicationContext context: Context) = context.tokenDataStore
internal fun provideTokenDataStore(@ApplicationContext context: Context) = context.tokenDataStore

@PrivacyPolicyDataStore
@Singleton
@Provides
internal fun provideTokenDataStore(dataStore: DataStore<Preferences>) = TokenDataStoreImpl(dataStore)
internal fun providePrivacyPolicyDataStore(@ApplicationContext context: Context) = context.privacyPolicyDataStore
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.nexters.ilab.android.core.datastore.di

import javax.inject.Qualifier

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class TokenDataStore

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class PrivacyPolicyDataStore
1 change: 1 addition & 0 deletions core/domain/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ plugins {
dependencies {
implementations(
libs.javax.inject,
libs.kotlinx.coroutines.core,
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.nexters.ilab.android.core.domain.repository

import kotlinx.coroutines.flow.Flow

interface PrivacyPolicyRepository {
fun getPrivacyPolicyAgreement(): Flow<Boolean>
suspend fun setPrivacyPolicyAgreement(flag: Boolean)
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,6 @@ import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
Expand Down Expand Up @@ -128,6 +125,7 @@ internal fun UploadPhotoRoute(
UploadPhotoScreen(
uiState = uiState,
onBackClick = onBackClick,
togglePrivacyPolicyAgreement = viewModel::togglePrivacyPolicyAgreement,
openPhotoPicker = viewModel::openPhotoPicker,
requestCameraPermission = viewModel::requestCameraPermission,
dismissPermissionDialog = viewModel::dismissPermissionDialog,
Expand All @@ -138,6 +136,7 @@ internal fun UploadPhotoRoute(
internal fun UploadPhotoScreen(
uiState: UploadPhotoState,
onBackClick: () -> Unit,
togglePrivacyPolicyAgreement: (Boolean) -> Unit,
openPhotoPicker: () -> Unit,
requestCameraPermission: () -> Unit,
dismissPermissionDialog: () -> Unit,
Expand Down Expand Up @@ -165,6 +164,8 @@ internal fun UploadPhotoScreen(

UploadPhotoTopAppBar(onBackClick = onBackClick)
UploadPhotoContent(
isPrivacyPolicyAgreed = uiState.isPrivacyPolicyAgreed,
togglePrivacyPolicyAgreement = togglePrivacyPolicyAgreement,
onPhotoPickerClick = openPhotoPicker,
onCameraClick = requestCameraPermission,
)
Expand All @@ -188,11 +189,11 @@ private fun UploadPhotoTopAppBar(

@Composable
private fun UploadPhotoContent(
isPrivacyPolicyAgreed: Boolean,
togglePrivacyPolicyAgreement: (Boolean) -> Unit,
onPhotoPickerClick: () -> Unit,
onCameraClick: () -> Unit,
) {
var checkedState by remember { mutableStateOf(false) }

Box {
Column(
modifier = Modifier
Expand Down Expand Up @@ -262,11 +263,11 @@ private fun UploadPhotoContent(
) {
Row(
modifier = Modifier
.clickable { checkedState = !checkedState }
.clickable { togglePrivacyPolicyAgreement(!isPrivacyPolicyAgreed) }
.padding(4.dp),
verticalAlignment = Alignment.CenterVertically,
) {
PrivacyPolicyCheckBox(checked = checkedState)
PrivacyPolicyCheckBox(checked = isPrivacyPolicyAgreed)
Spacer(modifier = Modifier.width(6.dp))
Text(
text = stringResource(id = R.string.personal_information_collection_and_usage_agreement),
Expand Down Expand Up @@ -300,6 +301,7 @@ private fun UploadPhotoContent(
.weight(1f)
.height(60.dp)
.padding(end = 4.dp),
enabled = isPrivacyPolicyAgreed,
containerColor = PurpleBlue200,
contentColor = PurpleBlue900,
text = {
Expand All @@ -315,6 +317,7 @@ private fun UploadPhotoContent(
.weight(1f)
.height(60.dp)
.padding(start = 4.dp),
enabled = isPrivacyPolicyAgreed,
text = {
Text(
text = stringResource(id = R.string.take_photo),
Expand Down Expand Up @@ -377,6 +380,7 @@ fun UploadPhotoScreenPreview() {
UploadPhotoScreen(
uiState = UploadPhotoState(),
onBackClick = {},
togglePrivacyPolicyAgreement = { _ -> },
openPhotoPicker = {},
requestCameraPermission = {},
dismissPermissionDialog = {},
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.nexters.ilab.android.feature.uploadphoto.viewmodel

data class UploadPhotoState(
val isPrivacyPolicyAgreed: Boolean = false,
val selectedPhotoUri: String = "",
val selectedStyle: String = "",
val isPermissionDialogVisible: Boolean = false,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package com.nexters.ilab.android.feature.uploadphoto.viewmodel

import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.nexters.ilab.android.core.domain.repository.PrivacyPolicyRepository
import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.launch
import org.orbitmvi.orbit.ContainerHost
import org.orbitmvi.orbit.syntax.simple.intent
import org.orbitmvi.orbit.syntax.simple.postSideEffect
Expand All @@ -10,10 +13,30 @@ import org.orbitmvi.orbit.viewmodel.container
import javax.inject.Inject

@HiltViewModel
class UploadPhotoViewModel @Inject constructor() : ViewModel(), ContainerHost<UploadPhotoState, UploadPhotoSideEffect> {
class UploadPhotoViewModel @Inject constructor(
private val privacyPolicyRepository: PrivacyPolicyRepository,
) : ViewModel(), ContainerHost<UploadPhotoState, UploadPhotoSideEffect> {

override val container = container<UploadPhotoState, UploadPhotoSideEffect>(UploadPhotoState())

init {
observePrivacyPolicyAgreement()
}

private fun observePrivacyPolicyAgreement() = intent {
viewModelScope.launch {
privacyPolicyRepository.getPrivacyPolicyAgreement().collect { isAgreed ->
reduce { state.copy(isPrivacyPolicyAgreed = isAgreed) }
}
}
}

fun togglePrivacyPolicyAgreement(flag: Boolean) {
viewModelScope.launch {
privacyPolicyRepository.setPrivacyPolicyAgreement(flag)
}
}

fun openPhotoPicker() = intent {
postSideEffect(UploadPhotoSideEffect.OpenPhotoPicker)
}
Expand Down
1 change: 1 addition & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ gradle-android = { module = "com.android.tools.build:gradle", version.ref = "and
gradle-kotlin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin-core" }

kotlin-ktlint = { group = "com.pinterest", name = "ktlint", version.ref = "kotlin-ktlint-source" }
kotlinx-coroutines-core = { group = "org.jetbrains.kotlinx", name = "kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
kotlinx-serialization-json = { group = "org.jetbrains.kotlinx", name = "kotlinx-serialization-json", version.ref = "kotlinx-serialization" }
kotlinx-datetime = { group = "org.jetbrains.kotlinx", name = "kotlinx-datetime", version.ref = "kotlinx-datetime" }
kotlinx-collections-immutable = { group = "org.jetbrains.kotlinx", name = "kotlinx-collections-immutable", version.ref = "kotlinx-collections-immutable" }
Expand Down
Loading