Skip to content

Commit

Permalink
Merge pull request #216 from SWM-KAWAI-MANS/release/v1.1.0
Browse files Browse the repository at this point in the history
Release/v1.1.0
  • Loading branch information
nohjunh authored Oct 3, 2023
2 parents 5d98221 + 3ca3867 commit 9346563
Show file tree
Hide file tree
Showing 28 changed files with 502 additions and 189 deletions.
6 changes: 3 additions & 3 deletions buildSrc/src/main/java/Configurations.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ object Configurations {
const val MIN_SDK_VERSION = 26
const val TARGET_SDK_VERSION = 33
private const val MAJOR_VERSION = 1
private const val MINOR_VERSION = 0
private const val PATCH_VERSION = 1
private const val MINOR_VERSION = 1
private const val PATCH_VERSION = 0
const val VERSION_NAME = "$MAJOR_VERSION.$MINOR_VERSION.$PATCH_VERSION"
const val VERSION_CODE = 20
const val VERSION_CODE = 21
// kotlinCompilerExtensionVersion
const val COMPOSE = "1.4.5"
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ package online.partyrun.partyrunapplication.core.designsystem.component

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
Expand All @@ -26,6 +28,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import online.partyrun.partyrunapplication.core.designsystem.theme.DarkNavy30
Expand Down Expand Up @@ -152,7 +155,9 @@ fun PartyRunMatchButton(
) {
PartyRunTextButton(
onClick = onClick,
modifier = modifier.width(187.dp).height(60.dp),
modifier = modifier
.width(187.dp)
.height(60.dp),
enabled = enabled,
contentColor = Purple90,
containerColor = DarkNavy30,
Expand Down Expand Up @@ -184,6 +189,7 @@ fun PartyRunAnimatedButton(
}
}
}

@Composable
fun PartyRunGradientButton(
onClick: () -> Unit,
Expand Down Expand Up @@ -235,3 +241,18 @@ private fun PartyRunButtonContent(
text()
}
}

@Composable
fun PartyRunImageButton(
modifier: Modifier = Modifier,
image: Int,
onClick: () -> Unit
) {
Image(
painter = painterResource(id = image),
contentDescription = null,
modifier = modifier.clickable {
onClick()
}
)
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package online.partyrun.partyrunapplication.core.model.running

import online.partyrun.partyrunapplication.core.model.running_result.ui.RunnerRecordUiModel
import java.time.LocalDateTime

data class GpsDataWithDistance(
Expand All @@ -9,3 +10,13 @@ data class GpsDataWithDistance(
val time: LocalDateTime = LocalDateTime.now(),
val distance: Double
)

fun GpsDataWithDistance.toUiModel(): RunnerRecordUiModel {
return RunnerRecordUiModel(
altitude = this.altitude,
latitude = this.latitude,
longitude = this.longitude,
time = this.time,
distance = this.distance
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package online.partyrun.partyrunapplication.core.model.single

data class SingleTargetDetails(
val distance: Int = INITIAL_DISTANCE,
val time: Int = INITIAL_TIME
) {
companion object {
const val INITIAL_DISTANCE = 5000 // 'm' 단위
const val INITIAL_TIME = 900 // '초' 단위, 900초 = 15분
const val DISTANCE_INCREMENT = 250
const val TIME_INCREMENT = 300
const val SECONDS_IN_HOUR = 3600
const val SECONDS_IN_MINUTE = 60
}
}

fun SingleTargetDetails.incrementDistance(): SingleTargetDetails {
return copy(distance = this.distance + SingleTargetDetails.DISTANCE_INCREMENT)
}

fun SingleTargetDetails.decrementDistance(): SingleTargetDetails {
if (this.distance > SingleTargetDetails.DISTANCE_INCREMENT) {
return copy(distance = this.distance - SingleTargetDetails.DISTANCE_INCREMENT)
}
return this
}

fun SingleTargetDetails.incrementTime(): SingleTargetDetails {
return copy(time = this.time + SingleTargetDetails.TIME_INCREMENT)
}

fun SingleTargetDetails.decrementTime(): SingleTargetDetails {
if (this.time > SingleTargetDetails.TIME_INCREMENT) {
return copy(time = this.time - SingleTargetDetails.TIME_INCREMENT)
}
return this
}

fun SingleTargetDetails.getFormattedTime(): String {
val hours = this.time / SingleTargetDetails.SECONDS_IN_HOUR
val remainingTime = this.time % SingleTargetDetails.SECONDS_IN_HOUR
val minutes = remainingTime / SingleTargetDetails.SECONDS_IN_MINUTE
return String.format("%02d:%02d", hours, minutes)
}

fun SingleTargetDetails.getFormattedDistance(): String {
return String.format("%04.2f", (this.distance.toFloat() / 1000f) * 100f / 100)
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,17 +24,16 @@ fun SingleResultResponse.toDomainModel(): SingleResult {
)
}

val rawTargetDistance = records.lastOrNull()?.distance
val adjustedTargetDistance = (rawTargetDistance?.div(10)?.toInt() ?: 1) * 10
val targetDistance = records.lastOrNull()?.distance?.toInt() ?: 0

return SingleResult(
singleRunnerStatus = SingleRunnerStatus(
records = this.records.map { it.toDomainModel() } // 각 record를 도메인 모델로 변환
),
runningTime = runningTime.toDomainModel(),
targetDistance = adjustedTargetDistance,
targetDistanceFormatted = formatDistanceWithComma(adjustedTargetDistance),
targetDistanceInKm = formatDistanceInKm(adjustedTargetDistance),
targetDistance = targetDistance,
targetDistanceFormatted = formatDistanceWithComma(targetDistance),
targetDistanceInKm = formatDistanceInKm(targetDistance),
singleDate = parsedStartTime?.let { formatDate(it) } ?: "" // "x월 x일" format
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.max
import androidx.compose.ui.unit.sp
import androidx.compose.ui.window.Dialog
import androidx.compose.ui.zIndex
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
Expand Down Expand Up @@ -107,6 +108,7 @@ fun Content(
onShowSnackbar: (String) -> Unit,
profileSnackbarMessage: String
) {
val updateProgressState by profileViewModel.updateProgressState.collectAsStateWithLifecycle()
val keyboardController = LocalSoftwareKeyboardController.current
val focusManager = LocalFocusManager.current

Expand All @@ -121,6 +123,10 @@ fun Content(
navigateToMyPage()
}

if (updateProgressState) {
ProgressIndicator()
}

Scaffold(
modifier = modifier,
topBar = {
Expand Down Expand Up @@ -183,12 +189,6 @@ private fun ProfileBody(
keyboardController: SoftwareKeyboardController,
focusManager: FocusManager
) {
val updateProgressState by profileViewModel.updateProgressState.collectAsStateWithLifecycle()

if (updateProgressState) {
ProgressIndicator()
}

LaunchedEffect(Unit) {
profileViewModel.initProfileContent(
name = userData.nickName,
Expand Down Expand Up @@ -249,12 +249,7 @@ private fun ProfileBody(

@Composable
private fun ProgressIndicator() {
Box(
modifier = Modifier
.fillMaxSize()
.zIndex(1f),
contentAlignment = Alignment.Center
) {
Dialog(onDismissRequest = { }) {
LottieImage(modifier = Modifier.size(60.dp), rawAnimation = R.raw.mypage_progress)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
package online.partyrun.partyrunapplication.feature.my_page.profile

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.ImageDecoder
import android.net.Uri
import android.os.Build
import android.provider.MediaStore
import androidx.annotation.RequiresApi
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
Expand All @@ -22,6 +27,7 @@ import online.partyrun.partyrunapplication.core.domain.member.SaveUserDataUseCas
import online.partyrun.partyrunapplication.core.domain.member.UpdateProfileImageUseCase
import online.partyrun.partyrunapplication.core.domain.member.UpdateUserDataUseCase
import timber.log.Timber
import java.io.ByteArrayOutputStream
import javax.inject.Inject

@HiltViewModel
Expand All @@ -31,6 +37,9 @@ class ProfileViewModel @Inject constructor(
private val getUserDataUseCase: GetUserDataUseCase,
private val saveUserDataUseCase: SaveUserDataUseCase
) : ViewModel() {
companion object {
const val COMPRESS_BITMAP_QUALITY = 80
}

private val _profileUiState = MutableStateFlow(ProfileUiState())
val profileUiState = _profileUiState.asStateFlow()
Expand Down Expand Up @@ -78,7 +87,6 @@ class ProfileViewModel @Inject constructor(
)
}

// 조건을 만족하면 true, 아니면 false 반환
private fun getResultOfNickNameCondition(condition: Boolean, errorState: String): Boolean {
_profileUiState.update {
it.copy(
Expand All @@ -95,15 +103,53 @@ class ProfileViewModel @Inject constructor(

fun handlePickedImage(context: Context, uri: Uri) {
_updateProgressState.value = true
val requestBody = context.contentResolver.openInputStream(uri)?.use { inputStream ->
inputStream.readBytes().toRequestBody("image/*".toMediaTypeOrNull())
}

val requestBody =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
val bitmap = getBitmapFromUriUsingImageDecoder(context, uri, 500, 500)
val compressedBitmap = compressBitmap(bitmap)
val byteArray = bitmapToByteArray(compressedBitmap)
byteArray.toRequestBody("image/*".toMediaTypeOrNull())
} else {
context.contentResolver.openInputStream(uri)?.use { inputStream ->
inputStream.readBytes().toRequestBody("image/*".toMediaTypeOrNull())
}
}

val fileName = getFileName(context, uri)
requestBody?.let {
updateProfileImage(requestBody, fileName)
}
}

@RequiresApi(Build.VERSION_CODES.P)
fun getBitmapFromUriUsingImageDecoder(
context: Context,
uri: Uri,
width: Int,
height: Int
): Bitmap {
val source = ImageDecoder.createSource(context.contentResolver, uri)
return ImageDecoder.decodeBitmap(source) { decoder, _, _ ->
decoder.setTargetSize(width, height)
}
}


private fun compressBitmap(bitmap: Bitmap): Bitmap {
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, COMPRESS_BITMAP_QUALITY, stream)
val byteArray = stream.toByteArray()
return BitmapFactory.decodeByteArray(byteArray, 0, byteArray.size)
}

private fun bitmapToByteArray(bitmap: Bitmap): ByteArray {
val stream = ByteArrayOutputStream()
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream)
return stream.toByteArray()
}


private fun getFileName(context: Context, uri: Uri): String? {
return context.contentResolver.query(uri, null, null, null, null)?.use { cursor ->
val nameIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package online.partyrun.partyrunapplication.feature.party.room

import android.widget.Toast
import androidx.compose.foundation.BorderStroke
import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Arrangement
Expand Down Expand Up @@ -207,6 +206,9 @@ fun RoomSuccessBody(
openPartyExitDialog = openPartyExitDialog,
startPartyBattle = {
partyRoomViewModel.startPartyBattle(partyCode = partyCode)
},
copyToClipboardMessage = {
partyRoomViewModel.copyToClipboardMessage()
}
)
}
Expand All @@ -219,7 +221,8 @@ private fun PartyRoomBody(
hasManagerPrivileges: Boolean,
partyRoomState: PartyRoomState,
openPartyExitDialog: MutableState<Boolean>,
startPartyBattle: () -> Unit
startPartyBattle: () -> Unit,
copyToClipboardMessage: () -> Unit
) {
Column(
modifier = modifier
Expand All @@ -229,7 +232,8 @@ private fun PartyRoomBody(
horizontalAlignment = Alignment.CenterHorizontally
) {
PartyRoomInfoBox(
partyCode = partyRoomState.entryCode
partyCode = partyRoomState.entryCode,
copyToClipboardMessage = copyToClipboardMessage
)
Column(
modifier = Modifier
Expand Down Expand Up @@ -309,14 +313,15 @@ private fun PartyRoomBody(

@Composable
private fun PartyRoomInfoBox(
partyCode: String
partyCode: String,
copyToClipboardMessage: () -> Unit
) {
val context = LocalContext.current

PartyRunGradientButton(
onClick = {
copyToClipboard(context, partyCode)
Toast.makeText(context, R.string.party_code_copy_desc, Toast.LENGTH_SHORT).show()
copyToClipboardMessage()
}
) {
Column(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,10 @@ class PartyRoomViewModel @Inject constructor(
_snackbarMessage.value = "메뉴 기능 준비 중이에요."
}

fun copyToClipboardMessage() {
_snackbarMessage.value = "번호가 복사되었어요.\n친구에게 붙여넣기 해주세요."
}

override fun onCleared() {
super.onCleared()
clearPartyProcess()
Expand Down
1 change: 1 addition & 0 deletions feature/running/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,5 @@ dependencies {
implementation(libs.google.accompanist.permission)

implementation(project(":core:network"))
implementation(project(":feature:running_result"))
}
Loading

0 comments on commit 9346563

Please sign in to comment.