Skip to content
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 @@ -74,8 +74,9 @@ private fun PresentationExpectedQuestionResponse.toDomain(): ExpectedQuestion =

internal fun PresentationScriptDetailResponse.toDomain(): PresentationScriptDetail =
PresentationScriptDetail(
presentationId = presentationId,
originalScript = originalScript,
scriptCorrections = scriptDetails.map { item -> item.toDomain() },
scriptCorrections = scriptDetails?.map { item -> item.toDomain() }.orEmpty(),
)

internal fun PresentationScriptAnalysisResponse.toDomain(): ScriptCorrection =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@ internal class AuthRepositoryImpl @Inject constructor(
authSessionCache.clear()
}.mapDomainFailure()

override suspend fun loginAdmin(): Result<Unit> =
runCatching {
val response = authRemoteDataSource.loginAdmin()
authLocalDataSource.saveTokens(
accessToken = response.accessToken,
refreshToken = response.refreshToken,
)
authSessionCache.clear()
}.mapDomainFailure()

override suspend fun clearSession(): Result<Unit> = runCatching { clearLocalSession() }.mapDomainFailure()

override suspend fun withdraw(reason: WithdrawReason): Result<Unit> =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,21 @@ internal class PresentationRepositoryImpl @Inject constructor(
response.toDomain()
}.mapDomainFailure()

override suspend fun correctScript(
analysisResultId: Long,
finalScript: String,
correctedIndices: List<Int>,
): Result<PresentationScriptDetail> =
runCatching {
presentationRemoteDataSource.correctScript(
analysisResultId = analysisResultId,
finalScript = finalScript,
correctedIndices = correctedIndices,
)
}.mapCatching { response ->
response.toDomain()
}.mapDomainFailure()

override suspend fun fetchWordDetail(analysisResultId: Long): Result<PresentationWordDetail> =
runCatching {
presentationRemoteDataSource.getWordDetail(analysisResultId = analysisResultId)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,12 @@ fun PrezelDialog(
.padding(horizontal = PrezelTheme.spacing.V20)
.clip(shape = PrezelTheme.shapes.V12)
.background(color = PrezelTheme.colors.bgRegular)
.padding(horizontal = PrezelTheme.spacing.V24),
.padding(horizontal = PrezelTheme.spacing.V16),
) {
DialogContent(
title = title,
description = description,
modifier = Modifier.padding(horizontal = PrezelTheme.spacing.V8),
)

ActionSection { scope.content() }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import androidx.compose.ui.graphics.toComposeRect
import androidx.compose.ui.layout.boundsInWindow
import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.platform.LocalWindowInfo
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.dp
Expand All @@ -46,6 +47,7 @@ import com.team.prezel.core.designsystem.preview.BasicPreview
import com.team.prezel.core.designsystem.preview.PreviewScaffold
import com.team.prezel.core.designsystem.theme.PrezelColorScheme
import com.team.prezel.core.designsystem.theme.PrezelTheme
import kotlin.math.roundToInt

@Composable
fun PrezelTooltipBox(
Expand Down Expand Up @@ -87,8 +89,18 @@ fun PrezelTooltipBox(
}

@Composable
private fun rememberBalloonBuilder(showArrow: Boolean): Balloon.Builder =
rememberBalloonBuilder {
private fun rememberBalloonBuilder(showArrow: Boolean): Balloon.Builder {
val horizontalMarginDp = PrezelTheme.spacing.V20.value
.roundToInt()
val maxWidthDp = (LocalWindowInfo.current.containerSize.width - (horizontalMarginDp * 2)).coerceAtLeast(0)

return rememberBalloonBuilder(
key = Triple(
showArrow,
horizontalMarginDp,
maxWidthDp,
),
) {
setIsVisibleArrow(showArrow)
setArrowWidth(12)
setArrowHeight(6)
Expand All @@ -101,7 +113,10 @@ private fun rememberBalloonBuilder(showArrow: Boolean): Balloon.Builder =
setDismissWhenTouchOutside(false)
setBalloonAnimation(BalloonAnimation.NONE)
setBackgroundColor(PrezelColorScheme.Dark.bgMedium)
setMarginHorizontal(horizontalMarginDp)
if (maxWidthDp > 0) setMaxWidth(maxWidthDp)
}
}

private fun Rect.intersects(other: Rect): Boolean = left < other.right && right > other.left && top < other.bottom && bottom > other.top

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ interface AuthRepository {

suspend fun login(idToken: String): Result<Unit>

suspend fun loginAdmin(): Result<Unit>

suspend fun clearSession(): Result<Unit>

suspend fun withdraw(reason: WithdrawReason): Result<Unit>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ interface PresentationRepository {

suspend fun fetchScriptDetail(analysisResultId: Long): Result<PresentationScriptDetail>

suspend fun correctScript(
analysisResultId: Long,
finalScript: String,
correctedIndices: List<Int>,
): Result<PresentationScriptDetail>

suspend fun fetchWordDetail(analysisResultId: Long): Result<PresentationWordDetail>

suspend fun deleteAnalysis(analysisResultId: Long): Result<Unit>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,10 @@ class LoginUseCase @Inject constructor(
onSuccess = { userRepository.fetchUserInfo() },
onFailure = { exception -> Result.failure(exception) },
)

suspend fun loginAdmin(): Result<User> =
authRepository.loginAdmin().fold(
onSuccess = { userRepository.fetchUserInfo() },
onFailure = { exception -> Result.failure(exception) },
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package com.team.prezel.core.domain.usecase.presentation

import com.team.prezel.core.domain.repository.presentation.PresentationRepository
import com.team.prezel.core.model.presentation.PresentationScriptDetail
import javax.inject.Inject

class CorrectPresentationScriptUseCase @Inject constructor(
private val presentationRepository: PresentationRepository,
) {
suspend operator fun invoke(
analysisResultId: Long,
finalScript: String,
correctedIndices: List<Int>,
): Result<PresentationScriptDetail> =
presentationRepository.correctScript(
analysisResultId = analysisResultId,
finalScript = finalScript,
correctedIndices = correctedIndices,
)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.team.prezel.core.model.presentation

data class PresentationScriptDetail(
val presentationId: Long,
val originalScript: String,
val scriptCorrections: List<ScriptCorrection>,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ interface AuthRemoteDataSource {

suspend fun login(idToken: String): LoginResponse

suspend fun loginAdmin(): LoginResponse

suspend fun reissue(refreshToken: String): ReissueResponse

suspend fun withdraw(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ internal class AuthRemoteDataSourceImpl @Inject constructor(

override suspend fun login(idToken: String): LoginResponse = authService.login(request = LoginRequest(idToken = idToken)).requireData()

override suspend fun loginAdmin(): LoginResponse = authService.loginAdmin().requireData()

override suspend fun reissue(refreshToken: String): ReissueResponse =
authService.reissue(request = ReissueRequest(refreshToken = refreshToken)).requireData()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,12 @@ interface PresentationRemoteDataSource {

suspend fun getScriptDetail(analysisResultId: Long): PresentationScriptDetailResponse

suspend fun correctScript(
analysisResultId: Long,
finalScript: String,
correctedIndices: List<Int>,
): PresentationScriptDetailResponse

suspend fun getWordDetail(analysisResultId: Long): PresentationWordDetailResponse

suspend fun deleteAnalysis(analysisResultId: Long)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.team.prezel.core.network.datasource

import com.team.prezel.core.network.model.BaseResponse
import com.team.prezel.core.network.model.presentation.GetCurationResponse
import com.team.prezel.core.network.model.presentation.GetMainDataResponse
import com.team.prezel.core.network.model.presentation.GetPracticeRecordsResponse
Expand All @@ -8,14 +9,20 @@ import com.team.prezel.core.network.model.presentation.GetPresentationsResponse
import com.team.prezel.core.network.model.presentation.PresentationScriptDetailResponse
import com.team.prezel.core.network.model.presentation.PresentationSummaryResponse
import com.team.prezel.core.network.model.presentation.PresentationWordDetailResponse
import com.team.prezel.core.network.model.presentation.ScriptCorrectionRequest
import com.team.prezel.core.network.model.presentation.review.SelfFeedbackRequest
import com.team.prezel.core.network.model.requireData
import com.team.prezel.core.network.model.requireSuccess
import com.team.prezel.core.network.service.PresentationService
import io.ktor.client.HttpClient
import io.ktor.client.call.body
import io.ktor.client.plugins.timeout
import io.ktor.client.request.forms.ChannelProvider
import io.ktor.client.request.forms.FormBuilder
import io.ktor.client.request.forms.MultiPartFormDataContent
import io.ktor.client.request.forms.formData
import io.ktor.client.request.post
import io.ktor.client.request.setBody
import io.ktor.http.Headers
import io.ktor.http.HttpHeaders
import io.ktor.utils.io.jvm.javaio.toByteReadChannel
Expand All @@ -24,6 +31,7 @@ import javax.inject.Inject

internal class PresentationRemoteDataSourceImpl @Inject constructor(
private val presentationService: PresentationService,
private val httpClient: HttpClient,
) : PresentationRemoteDataSource {
override suspend fun analyzePresentation(
name: String,
Expand Down Expand Up @@ -54,8 +62,14 @@ internal class PresentationRemoteDataSourceImpl @Inject constructor(
},
)

return presentationService
.analyzePresentation(multipart = multipart)
return httpClient
.post("recording/analyze") {
timeout {
requestTimeoutMillis = ANALYSIS_TIMEOUT_MILLIS
socketTimeoutMillis = ANALYSIS_TIMEOUT_MILLIS
}
setBody(multipart)
}.body<BaseResponse<PresentationSummaryResponse>>()
.requireData()
}

Expand All @@ -77,16 +91,34 @@ internal class PresentationRemoteDataSourceImpl @Inject constructor(
},
)

return presentationService
.reAnalyzePresentation(
presentationId = presentationId,
multipart = multipart,
).requireData()
return httpClient
.post("recording/$presentationId/re-analyze") {
timeout {
requestTimeoutMillis = ANALYSIS_TIMEOUT_MILLIS
socketTimeoutMillis = ANALYSIS_TIMEOUT_MILLIS
}
setBody(multipart)
}.body<BaseResponse<PresentationSummaryResponse>>()
.requireData()
}

override suspend fun getScriptDetail(analysisResultId: Long): PresentationScriptDetailResponse =
presentationService.getScriptDetail(analysisResultId = analysisResultId).requireData()

override suspend fun correctScript(
analysisResultId: Long,
finalScript: String,
correctedIndices: List<Int>,
): PresentationScriptDetailResponse =
presentationService
.correctScript(
analysisResultId = analysisResultId,
request = ScriptCorrectionRequest(
finalScript = finalScript,
correctedIndices = correctedIndices,
),
).requireData()

override suspend fun getWordDetail(analysisResultId: Long): PresentationWordDetailResponse =
presentationService.getWordDetail(analysisResultId = analysisResultId).requireData()

Expand Down Expand Up @@ -160,3 +192,5 @@ private fun File.toChannelProvider(): ChannelProvider =
require(canRead()) { "파일을 읽을 수 없습니다: $path" }
inputStream().toByteReadChannel()
}

private const val ANALYSIS_TIMEOUT_MILLIS = 600_000L
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ data class PresentationScriptDetailResponse(
@SerialName("originalScript")
val originalScript: String,
@SerialName("scriptDetails")
val scriptDetails: List<PresentationScriptAnalysisResponse>,
val scriptDetails: List<PresentationScriptAnalysisResponse>?,
)

@Serializable
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.team.prezel.core.network.model.presentation

import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable

@Serializable
data class ScriptCorrectionRequest(
@SerialName("finalScript")
val finalScript: String,
@SerialName("correctedIndices")
val correctedIndices: List<Int>,
)
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import com.team.prezel.core.network.model.auth.reissue.ReissueRequest
import com.team.prezel.core.network.model.auth.reissue.ReissueResponse
import de.jensklingenberg.ktorfit.http.Body
import de.jensklingenberg.ktorfit.http.DELETE
import de.jensklingenberg.ktorfit.http.GET
import de.jensklingenberg.ktorfit.http.POST
import de.jensklingenberg.ktorfit.http.Tag

Expand All @@ -22,6 +23,11 @@ internal interface AuthService {
@Tag(AuthRequestAttributes.SKIP_AUTH) skipAuth: Boolean = true,
): BaseResponse<LoginResponse>

@GET("admin/login")
suspend fun loginAdmin(
@Tag(AuthRequestAttributes.SKIP_AUTH) skipAuth: Boolean = true,
): BaseResponse<LoginResponse>

@DELETE("auth/withdraw")
suspend fun withdraw(
@Body request: WithdrawRequest,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@ import com.team.prezel.core.network.model.presentation.GetPresentationsResponse
import com.team.prezel.core.network.model.presentation.PresentationScriptDetailResponse
import com.team.prezel.core.network.model.presentation.PresentationSummaryResponse
import com.team.prezel.core.network.model.presentation.PresentationWordDetailResponse
import com.team.prezel.core.network.model.presentation.ScriptCorrectionRequest
import com.team.prezel.core.network.model.presentation.review.SelfFeedbackRequest
import de.jensklingenberg.ktorfit.http.Body
import de.jensklingenberg.ktorfit.http.DELETE
import de.jensklingenberg.ktorfit.http.GET
import de.jensklingenberg.ktorfit.http.PATCH
import de.jensklingenberg.ktorfit.http.POST
import de.jensklingenberg.ktorfit.http.Path
import io.ktor.client.request.forms.MultiPartFormDataContent
Expand All @@ -34,6 +36,12 @@ interface PresentationService {
@Path("analysisResultId") analysisResultId: Long,
): BaseResponse<PresentationScriptDetailResponse>

@PATCH("recording/analyze/{analysisResultId}/scripts/correct")
suspend fun correctScript(
@Path("analysisResultId") analysisResultId: Long,
@Body request: ScriptCorrectionRequest,
): BaseResponse<PresentationScriptDetailResponse>

@GET("recording/analyze/{analysisResultId}/words")
suspend fun getWordDetail(
@Path("analysisResultId") analysisResultId: Long,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,10 @@ private fun PaginationRow(
painter = painterResource(PrezelIcons.ChevronLeft),
contentDescription = stringResource(R.string.core_ui_impl_practice_card_prev_page),
tint = chevronIconTintColor(enabled = hasPreviousPage),
modifier = Modifier.noRippleClickable(onClickLeft),
modifier = Modifier.noRippleClickable(
enabled = hasPreviousPage,
onClick = onClickLeft,
),
)
}

Expand All @@ -190,7 +193,10 @@ private fun PaginationRow(
painter = painterResource(PrezelIcons.ChevronRight),
contentDescription = stringResource(R.string.core_ui_impl_practice_card_next_page),
tint = chevronIconTintColor(enabled = hasNextPage),
modifier = Modifier.noRippleClickable(onClickRight),
modifier = Modifier.noRippleClickable(
enabled = hasNextPage,
onClick = onClickRight,
),
)
}
}
Expand Down
Loading