Skip to content

Commit

Permalink
Merge pull request #39 from Nexters/feature/image-upload
Browse files Browse the repository at this point in the history
프로필 사진 required 제거
  • Loading branch information
yxnsx authored Aug 18, 2023
2 parents f54e1f2 + 281960f commit 9e8870e
Show file tree
Hide file tree
Showing 8 changed files with 118 additions and 39 deletions.
11 changes: 11 additions & 0 deletions app/src/main/java/com/keyme/app/ui/KeymeApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -53,15 +53,26 @@ fun KeymeApp() {
appState.onBackClick()
appState.navigate(DailyKeymeTestDestination)
},
nestedGraphs = {
takeKeymeTestGraph(
onBackClick = appState::onBackClick,
onTestSolved = {
appState.onBackClick()
appState.navigate(DailyKeymeTestDestination)
},
)
},
)
dailyKeymeTestGraph(
navigateToTakeKeymeTest = { appState.navigate(TakeKeymeTestDestination, it) },
nestedGraphs = {
takeKeymeTestGraph(
onBackClick = appState::onBackClick,
onTestSolved = appState::onBackClick,
)
},
)
// takeKeymeTestGraph -> 문제 풀이, 결과 확인

myProfileGraph(
navigateToQuestionResult = { question ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import androidx.room.PrimaryKey

@Entity(tableName = "userAuth")
data class UserAuthEntity(
@PrimaryKey(autoGenerate = false) val id: Int,
val id: Int = 0,
val nickname: String?,
val profileImage: String?,
val profileThumbnail: String?,
val friendCode: String?,
val onboardingTestResultId: Int?,
val accessToken: String,
@PrimaryKey val accessToken: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ object OnboardingDestination : KeymeNavigationDestination {
fun NavGraphBuilder.onboardingGraph(
navigateToOnboardingKeymeTest: (testId: Int) -> Unit,
navigateToMyDaily: () -> Unit,
nestedGraphs: NavGraphBuilder.() -> Unit,
) {
navigation(
route = OnboardingDestination.route,
Expand All @@ -24,5 +25,6 @@ fun NavGraphBuilder.onboardingGraph(
navigateToMyDaily = navigateToMyDaily,
)
}
nestedGraphs()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import androidx.compose.foundation.pager.rememberPagerState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
Expand All @@ -35,6 +34,7 @@ import com.keyme.presentation.onboarding.guide.Guide03Screen
import com.keyme.presentation.onboarding.guide.Guide04Screen
import com.keyme.presentation.onboarding.nickname.NicknameScreen
import com.keyme.presentation.onboarding.signin.SignInScreen
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.launch

@Composable
Expand All @@ -57,7 +57,6 @@ fun OnboardingScreen(
) {
val coroutineScope = rememberCoroutineScope()
val composition by rememberLottieComposition(LottieCompositionSpec.RawRes(R.raw.animation_signin_background))
val localOnboardingState by viewModel.userAuthState.collectAsState()

val pagerState = rememberPagerState(initialPage = 0)
val onboardingSteps = listOf(
Expand All @@ -69,15 +68,16 @@ fun OnboardingScreen(
OnboardingStepsEnum.GUIDE_04,
)

LaunchedEffect(localOnboardingState) {
localOnboardingState.let {
when {
it?.accessToken == null -> pagerState.scrollToPage(OnboardingStepsEnum.KAKAO_SIGN_IN.ordinal)
it.nickname == null -> pagerState.scrollToPage(OnboardingStepsEnum.NICKNAME.ordinal)
it.onboardingTestResultId == null -> pagerState.scrollToPage(OnboardingStepsEnum.GUIDE_01.ordinal)
else -> navigateToMyDaily.invoke()
LaunchedEffect(key1 = Unit) {
viewModel.userAuthState
.collectLatest {
when {
it?.accessToken == null -> pagerState.scrollToPage(OnboardingStepsEnum.KAKAO_SIGN_IN.ordinal)
it.nickname.isNullOrBlank() -> pagerState.scrollToPage(OnboardingStepsEnum.NICKNAME.ordinal)
it.onboardingTestResultId == null -> pagerState.scrollToPage(OnboardingStepsEnum.GUIDE_01.ordinal)
else -> navigateToMyDaily.invoke()
}
}
}
}

when (pagerState.currentPage) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,8 @@ class OnboardingViewModel @Inject constructor(
originalUrl: String,
thumbnailUrl: String,
) {
if (uploadProfileImageState.value == null) return
// todo 프로필 사진 선택
// if (uploadProfileImageState.value == null) return
apiCall(apiRequest = {
updateMemberUseCase.invoke(
nickname = nickname,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package com.keyme.presentation.onboarding.nickname

import android.annotation.SuppressLint
import android.net.Uri
import android.util.Base64
import android.widget.Toast
import androidx.activity.compose.rememberLauncherForActivityResult
import androidx.activity.result.contract.ActivityResultContracts
Expand All @@ -28,7 +27,6 @@ import androidx.compose.foundation.text.BasicTextField
import androidx.compose.foundation.text.KeyboardActions
import androidx.compose.material3.Icon
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
Expand Down Expand Up @@ -86,16 +84,6 @@ fun NicknameScreen(
ActivityResultContracts.GetContent(),
) { uri -> uri?.let { selectedImage = uri } }

LaunchedEffect(key1 = uploadProfileImageState) {
uploadProfileImageState?.let {
viewModel.updateMember(
nickname = nickname,
originalUrl = it.originalUrl,
thumbnailUrl = it.thumbnailUrl,
)
}
}

Column(
modifier = Modifier
.fillMaxSize()
Expand Down Expand Up @@ -140,7 +128,13 @@ fun NicknameScreen(
nickname = nickname,
isNicknameValidated = verifyNicknameState?.valid ?: false,
selectedImage = selectedImage,
uploadProfileImage = viewModel::uploadProfileImage,
uploadProfileImage = {
viewModel.updateMember(
nickname = nickname,
originalUrl = "",
thumbnailUrl = "",
)
},
)

Spacer(modifier = Modifier.size(54.dp))
Expand Down Expand Up @@ -374,24 +368,24 @@ fun NextButton(
uploadProfileImage: (String) -> Unit,
) {
val context = LocalContext.current
val contentResolver = context.contentResolver

KeymeTextButton(
text = "다음",
onClick = {
if (nickname.isBlank() || !isNicknameValidated) {
Toast.makeText(context, "닉네임을 확인해주세요", Toast.LENGTH_SHORT).show()
} else if (selectedImage == null) {
Toast.makeText(context, "프로필 사진을 선택해주세요", Toast.LENGTH_SHORT).show()
} else {
run {
val inputStream = contentResolver.openInputStream(selectedImage)
val imageBytes = inputStream?.readBytes()
val imageString = Base64.encodeToString(imageBytes, Base64.DEFAULT)
inputStream?.close()

uploadProfileImage.invoke(imageString)
}
}
// todo 프로필 사진 선택
// else if (selectedImage == null) {
// Toast.makeText(context, "프로필 사진을 선택해주세요", Toast.LENGTH_SHORT).show()
// }
else {
// todo 프로필 사진 선택
// val imageString = ImageUploadUtil.getProfileImageString(context, selectedImage)
// imageString?.let {
// uploadProfileImage.invoke(imageString)
// }
uploadProfileImage("")
}
},
modifier = Modifier
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ object TakeKeymeTestDestination : KeymeNavigationDestination {

fun NavGraphBuilder.takeKeymeTestGraph(
onBackClick: () -> Unit,
onTestSolved: () -> Unit,
) {
composable(
route = "${TakeKeymeTestDestination.route}/{${TakeKeymeTestDestination.testIdArg}}",
Expand All @@ -31,6 +32,7 @@ fun NavGraphBuilder.takeKeymeTestGraph(
TakeKeymeTestRoute(
onBackClick = onBackClick,
onCloseClick = { onBackClick() },
onTestSolved = { onTestSolved() },
)
}
}
Expand All @@ -39,6 +41,7 @@ fun NavGraphBuilder.takeKeymeTestGraph(
fun TakeKeymeTestRoute(
takeKeymeTestViewModel: TakeKeymeTestViewModel = hiltViewModel(),
onBackClick: () -> Unit,
onTestSolved: () -> Unit,
onCloseClick: () -> Unit,
) {
val loadTestUrl = takeKeymeTestViewModel.keymeTestUrl
Expand All @@ -59,7 +62,9 @@ fun TakeKeymeTestRoute(
KeymeTestResultScreen(
myCharacter = myCharacter,
testResult = keymeTestResult,
onCloseClick = onCloseClick,
onCloseClick = {
onTestSolved()
},
)
}
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.keyme.presentation.utils

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import android.util.Base64
import timber.log.Timber
import java.io.ByteArrayOutputStream

object ImageUploadUtil {

fun getProfileImageString(context: Context, uri: Uri): String? {
val resized = resize(context, uri, 360)
val result = resized?.let {
val compressed = compress(it)
Timber.d("><> compressed: ${compressed.byteCount}")
getStringImage(compressed)
}

return result
}

private fun resize(context: Context, uri: Uri, resizePx: Int): Bitmap? {
val options = BitmapFactory.Options()

BitmapFactory.decodeStream(context.contentResolver.openInputStream(uri), null, options)
var width = options.outWidth
var height = options.outHeight
var samplesize = 1
while (width > resizePx || height > resizePx) {
width /= 2
height /= 2
samplesize *= 2
}
options.inSampleSize = samplesize

val resized = BitmapFactory.decodeStream(
context.contentResolver.openInputStream(uri),
null,
options,
)

return resized?.let {
Bitmap.createScaledBitmap(resized, width, height, true)
}
}

private fun compress(bitmap: Bitmap): Bitmap {
val baos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 80, baos)

return BitmapFactory.decodeByteArray(
baos.toByteArray(),
0,
baos.toByteArray().size,
)
}

private fun getStringImage(bitmap: Bitmap): String {
val baos = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, baos)
val imageBytes = baos.toByteArray()
return Base64.encodeToString(imageBytes, Base64.DEFAULT)
}
}

0 comments on commit 9e8870e

Please sign in to comment.