Skip to content

Commit

Permalink
Merge pull request #371 from 6QuizOnTheBlock/and/feat#366-organizatio…
Browse files Browse the repository at this point in the history
…n_statistics

And/feat#366 organization statistics
  • Loading branch information
ghddbwns9808 authored May 19, 2024
2 parents e82b753 + 5933b40 commit 070c348
Show file tree
Hide file tree
Showing 14 changed files with 277 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ fun StudentSimpleCardItem(
name: String = "",
photo: String = "",
score: Int? = null,
onClick: (Long) -> Unit = {}
onClick: (Long) -> Unit = {},
isCount: Boolean = false
) {
Card(
modifier = modifier,
Expand Down Expand Up @@ -67,7 +68,7 @@ fun StudentSimpleCardItem(
)
if (score != null) {
Text(
text = "${score}",
text = if (isCount)"${score}" else "${score}",
style = UlbanTypography.bodySmall
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.sixkids.model

data class ClassSummary(
val challengeCounts: List<MemberSimpleClassSummary>,
val relayCounts: List<MemberSimpleClassSummary>,
val postsCounts: List<MemberSimpleClassSummary>,
val challengeCounts: List<MemberSimpleClassSummary> = emptyList(),
val relayCounts: List<MemberSimpleClassSummary> = emptyList(),
val postsCounts: List<MemberSimpleClassSummary> = emptyList(),
)
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
package com.sixkids.data.model.response

import com.sixkids.model.ClassSummary
import com.sixkids.model.MemberSimpleClassSummary

data class ClassSummaryResponse(
val challengeCounts: List<ClassSummaryMemberResponse>,
val relayCounts: List<ClassSummaryMemberResponse>,
val postsCounts: List<ClassSummaryMemberResponse>,
val postCounts: List<ClassSummaryMemberResponse>,
)

data class ClassSummaryMemberResponse(
Expand All @@ -18,4 +19,12 @@ fun ClassSummaryMemberResponse.toModel(): MemberSimpleClassSummary {
member.toModel(),
count
)
}

internal fun ClassSummaryResponse.toModel(): ClassSummary {
return ClassSummary(
challengeCounts.map { it.toModel() },
relayCounts.map { it.toModel() },
postCounts.map { it.toModel() }
)
}
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
package com.sixkids.data.repository.organization

import com.sixkids.data.model.response.toModel
import com.sixkids.data.repository.organization.local.OrganizationLocalDataSource
import com.sixkids.data.repository.organization.remote.OrganizationRemoteDataSource
import com.sixkids.domain.repository.OrganizationRepository
import com.sixkids.model.MemberDetail
import com.sixkids.model.ClassSummary
import com.sixkids.model.MemberDetail
import com.sixkids.model.MemberRankItem
import com.sixkids.model.MemberSimple
import com.sixkids.model.MemberSimpleWithScore
Expand Down Expand Up @@ -38,13 +37,7 @@ class OrganizationRepositoryImpl @Inject constructor(
}

override suspend fun getOrganizationSummary(organizationId: Int): ClassSummary {
organizationRemoteDataSource.getOrganizationSummary(organizationId).let {
return ClassSummary(
it.challengeCounts.map { challengeCount -> challengeCount.toModel() },
it.relayCounts.map { challengeCount -> challengeCount.toModel() },
it.postsCounts.map { challengeCount -> challengeCount.toModel() },
)
}
return organizationRemoteDataSource.getOrganizationSummary(organizationId)
}

override suspend fun updateOrganization(organizationId: Int, name: String): String {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.sixkids.data.repository.organization.remote

import com.sixkids.model.ClassSummary
import com.sixkids.data.model.response.ClassSummaryResponse
import com.sixkids.data.model.response.RankResponse
import com.sixkids.model.MemberDetail
Expand All @@ -15,7 +16,7 @@ interface OrganizationRemoteDataSource {

suspend fun joinOrganization(orgId: Int, code: String): Long

suspend fun getOrganizationSummary(organizationId: Int): ClassSummaryResponse
suspend fun getOrganizationSummary(organizationId: Int): ClassSummary

suspend fun updateOrganization(organizationId: Int, name: String): String

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import com.sixkids.data.model.request.NewOrganizationRequest
import com.sixkids.data.model.response.ClassSummaryResponse
import com.sixkids.data.model.response.RankResponse
import com.sixkids.data.model.response.toModel
import com.sixkids.model.ClassSummary
import com.sixkids.model.MemberDetail
import com.sixkids.model.MemberSimple
import com.sixkids.model.MemberSimpleWithScore
Expand All @@ -32,8 +33,8 @@ class OrganizationRemoteDataSourceImpl @Inject constructor(
.getOrThrow().data
}

override suspend fun getOrganizationSummary(organizationId: Int): ClassSummaryResponse {
return organizationService.getOrganizationSummary(organizationId).getOrThrow().data
override suspend fun getOrganizationSummary(organizationId: Int): ClassSummary {
return organizationService.getOrganizationSummary(organizationId).getOrThrow().data.toModel()
}

override suspend fun updateOrganization(organizationId: Int, name: String): String {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.sixkids.domain.usecase.organization

import com.sixkids.domain.repository.OrganizationRepository
import javax.inject.Inject

class GetOrganizationSummaryUseCase @Inject constructor(
private val organizationRepository: OrganizationRepository
){
suspend operator fun invoke(organizationId: Int) = runCatching {
organizationRepository.getOrganizationSummary(organizationId)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ import com.sixkids.teacher.manageclass.navigation.navigateChattingFilter
import com.sixkids.teacher.manageclass.navigation.navigateClassSetting
import com.sixkids.teacher.manageclass.navigation.navigateInvite
import com.sixkids.teacher.manageclass.navigation.navigateManageClass
import com.sixkids.teacher.manageclass.navigation.navigateStatistics
import com.sixkids.teacher.managestudent.navigation.ManageStudentRoute
import com.sixkids.teacher.managestudent.navigation.navigateManageStudent
import com.sixkids.teacher.managestudent.navigation.navigateStudentDetail
Expand Down Expand Up @@ -211,6 +212,10 @@ class MainNavigator(
navController.navigateClassSetting()
}

fun navigateClassStatistics() {
navController.navigateStatistics()
}

/**
* Manage Student Navigation
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ fun MainScreen(
manageClassNavGraph(
padding = innerPadding,
onShowSnackBar = viewModel::onShowSnackbar,
navigateToClassSummary = { },
navigateToClassSummary = navigator::navigateClassStatistics,
navigateToClassSetting = navigator::navigateClassSetting,
navigateToChattingFilter = navigator::navigateChattingFilter,
navigateToInvite = navigator::navigateClassInvite,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import androidx.navigation.NavController
import androidx.navigation.NavGraphBuilder
import androidx.navigation.NavOptions
import androidx.navigation.compose.composable
import com.sixkids.teacher.manageclass.chattingfilter.ChattingFilterEffect
import com.sixkids.teacher.manageclass.chattingfilter.ChattingFilterRoute
import com.sixkids.teacher.manageclass.invite.ClassInviteRoute
import com.sixkids.teacher.manageclass.main.ManageClassMainRoute
import com.sixkids.teacher.manageclass.setting.ClassSettingRoute
import com.sixkids.teacher.manageclass.statistics.StatisticsRoute
import com.sixkids.ui.SnackbarToken

fun NavController.navigateManageClass(navOptions: NavOptions) {
Expand All @@ -28,6 +28,10 @@ fun NavController.navigateClassSetting() {
navigate(ManageClassRoute.settingRoute)
}

fun NavController.navigateStatistics(){
navigate(ManageClassRoute.summaryRoute)
}

fun NavGraphBuilder.manageClassNavGraph(
padding: PaddingValues,
onShowSnackBar: (SnackbarToken) -> Unit,
Expand Down Expand Up @@ -67,6 +71,10 @@ fun NavGraphBuilder.manageClassNavGraph(
navigateBack = navigateBack
)
}

composable(ManageClassRoute.summaryRoute){
StatisticsRoute()
}
}

object ManageClassRoute {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.sixkids.teacher.manageclass.statistics

import com.sixkids.model.ClassSummary
import com.sixkids.ui.base.SideEffect
import com.sixkids.ui.base.UiState

data class StatisticsState(
val isLoading: Boolean = false,
val organizationName: String = "",
val statistics: ClassSummary = ClassSummary()
) : UiState

sealed interface StatisticsEffect : SideEffect{
data class HandleException(val throwable: Throwable, val retry: () -> Unit) : StatisticsEffect
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
package com.sixkids.teacher.manageclass.statistics

import androidx.annotation.DrawableRes
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import coil.compose.AsyncImage
import com.sixkids.designsystem.component.appbar.UlbanDetailAppBar
import com.sixkids.designsystem.component.item.StudentSimpleCardItem
import com.sixkids.designsystem.theme.Blue
import com.sixkids.designsystem.theme.UlbanTypography
import com.sixkids.model.MemberSimpleClassSummary
import com.sixkids.teacher.manageclass.R
import kotlin.math.max
import kotlin.math.min
import com.sixkids.designsystem.R as DesignSystemR

@Composable
fun StatisticsRoute(
viewModel: StatisticsViewModel = hiltViewModel()
) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()

LaunchedEffect(key1 = Unit) {
viewModel.initData()
}

StatisticsScreen(
uiState = uiState
)
}

@Composable
fun StatisticsScreen(
modifier: Modifier = Modifier,
uiState: StatisticsState = StatisticsState(),
) {
val scrollState = rememberScrollState()
val isScrolled by remember {
derivedStateOf {
scrollState.value > 100
}
}

Column(
modifier = modifier.fillMaxSize(),
) {
UlbanDetailAppBar(
leftIcon = DesignSystemR.drawable.statistics,
title = stringResource(id = R.string.manage_class_statistics),
content = stringResource(id = R.string.manage_class_statistics),
topDescription = "",
bottomDescription = uiState.organizationName,
color = Blue,
expanded = !isScrolled,
)
Column(
modifier = Modifier
.fillMaxSize()
.padding(20.dp).verticalScroll(scrollState)
) {
BestWorstStudent(
studentList = uiState.statistics.challengeCounts,
title = stringResource(id = R.string.statistics_challenge),
icon = DesignSystemR.drawable.hifive
)

BestWorstStudent(
studentList = uiState.statistics.relayCounts,
title = stringResource(id = R.string.statistics_relay),
icon = DesignSystemR.drawable.relay
)

BestWorstStudent(
studentList = uiState.statistics.postsCounts,
title = stringResource(id = R.string.statistics_post),
icon = DesignSystemR.drawable.board
)
}
}
}

@Composable
fun BestWorstStudent(
studentList: List<MemberSimpleClassSummary> = emptyList(),
title: String = "",
@DrawableRes icon: Int,

){
Spacer(modifier = Modifier.height(20.dp))
Row(verticalAlignment = Alignment.CenterVertically) {
AsyncImage(
model = icon,
contentDescription = "relay",
modifier = Modifier
.padding(end = 10.dp)
.size(50.dp)
)
Text(text = title, style = UlbanTypography.titleSmall)
}


if (studentList.isNotEmpty()) {
Text(
text = "가장 많이 참여한 학생",
style = UlbanTypography.bodyMedium,
modifier = Modifier.padding(vertical = 10.dp)
)

Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
for (i in 0 until min(3,studentList.size )) {
StudentSimpleCardItem(
modifier = Modifier.weight(1f),
id = studentList[i].member.id,
name = studentList[i].member.name,
photo = studentList[i].member.photo,
score = studentList[i].count,
isCount = true
)
}
}

Text(
text = "가장 적게 참여한 학생",
style = UlbanTypography.bodyMedium,
modifier = Modifier.padding(vertical = 10.dp)
)

val startIdx = max(studentList.size - 1, 0)
val endIdx = max(studentList.size - 3, 0)

Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
for (i in startIdx downTo endIdx) {
StudentSimpleCardItem(
modifier = Modifier.weight(1f),
id = studentList[i].member.id,
name = studentList[i].member.name,
photo = studentList[i].member.photo,
score = studentList[i].count,
isCount = true
)
}
}
}
}

@Composable
@Preview(showBackground = true)
fun StatisticsScreenPreview() {
StatisticsScreen()
}
Loading

0 comments on commit 070c348

Please sign in to comment.