Skip to content

Commit b59a334

Browse files
authored
Merge pull request #15 from nur-shuvo/goal-status-viewmodel
GoalProgressScreen Viewmodel and data load
2 parents a1fd6d8 + f45e1d8 commit b59a334

File tree

7 files changed

+125
-21
lines changed

7 files changed

+125
-21
lines changed

app/src/main/java/com/byteutility/dev/leetcode/plus/MainActivity.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ import androidx.core.splashscreen.SplashScreen.Companion.installSplashScreen
77
import androidx.lifecycle.lifecycleScope
88
import androidx.navigation.compose.rememberNavController
99
import com.byteutility.dev.leetcode.plus.data.datastore.UserDatastore
10-
import com.byteutility.dev.leetcode.plus.ui.LeetCodePlusNavGraph
11-
import com.byteutility.dev.leetcode.plus.ui.LeetCodePlusNavigationDestinations
10+
import com.byteutility.dev.leetcode.plus.ui.navigation.LeetCodePlusNavGraph
11+
import com.byteutility.dev.leetcode.plus.ui.navigation.LeetCodePlusNavigationDestinations
1212
import com.byteutility.dev.leetcode.plus.ui.theme.LeetcodePlusTheme
1313
import dagger.hilt.android.AndroidEntryPoint
1414
import kotlinx.coroutines.flow.first

app/src/main/java/com/byteutility/dev/leetcode/plus/data/database/entity/WeeklyGoalEntity.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,17 @@ data class WeeklyGoalEntity(
1616
@ColumnInfo(name = "problems")
1717
val problems: String,
1818
@ColumnInfo(name = "period")
19-
val period: String
19+
val period: String,
2020
) {
2121
fun toProblems(): List<LeetCodeProblem> {
2222
val type = object : TypeToken<List<LeetCodeProblem>>() {}.type
2323
return Gson().fromJson(problems, type)
2424
}
25+
2526
fun toWeeklyGoal(): WeeklyGoalPeriod {
2627
return Gson().fromJson(period, WeeklyGoalPeriod::class.java)
2728
}
29+
2830
companion object {
2931
fun createWeeklyGoalEntity(
3032
problems: List<LeetCodeProblem>,
Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,24 @@
11
package com.byteutility.dev.leetcode.plus.monitor
22

3+
import com.byteutility.dev.leetcode.plus.data.repository.userDetails.UserDetailsRepository
4+
import kotlinx.coroutines.CoroutineScope
5+
import kotlinx.coroutines.Dispatchers
6+
import kotlinx.coroutines.SupervisorJob
7+
import kotlinx.coroutines.launch
38
import javax.inject.Inject
9+
import javax.inject.Singleton
410

5-
class WeeklyGoalStatusMonitor @Inject constructor() {
6-
fun start() {
11+
@Singleton
12+
class WeeklyGoalStatusMonitor @Inject constructor(
13+
private val userDetailsRepository: UserDetailsRepository
14+
) {
15+
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO)
716

17+
fun start() {
18+
scope.launch {
19+
userDetailsRepository.getUserRecentSubmissions().collect {
20+
21+
}
22+
}
823
}
924
}

app/src/main/java/com/byteutility/dev/leetcode/plus/ui/LeetCodePlusNavGraph.kt renamed to app/src/main/java/com/byteutility/dev/leetcode/plus/ui/navigation/LeetCodePlusNavGraph.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.byteutility.dev.leetcode.plus.ui
1+
package com.byteutility.dev.leetcode.plus.ui.navigation
22

33
import androidx.compose.runtime.Composable
44
import androidx.navigation.NavHostController

app/src/main/java/com/byteutility/dev/leetcode/plus/ui/LeetCodePlusNavigation.kt renamed to app/src/main/java/com/byteutility/dev/leetcode/plus/ui/navigation/LeetCodePlusNavigation.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
package com.byteutility.dev.leetcode.plus.ui
1+
package com.byteutility.dev.leetcode.plus.ui.navigation
22

33
import androidx.navigation.NavController
44

app/src/main/java/com/byteutility/dev/leetcode/plus/ui/targetstatus/GoalProgressScreen.kt

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,33 +13,56 @@ import androidx.compose.foundation.layout.padding
1313
import androidx.compose.foundation.layout.size
1414
import androidx.compose.foundation.shape.CircleShape
1515
import androidx.compose.material3.Card
16+
import androidx.compose.material3.CardDefaults
17+
import androidx.compose.material3.ExperimentalMaterial3Api
1618
import androidx.compose.material3.MaterialTheme
19+
import androidx.compose.material3.Scaffold
1720
import androidx.compose.material3.Text
21+
import androidx.compose.material3.TopAppBar
1822
import androidx.compose.runtime.Composable
23+
import androidx.compose.runtime.getValue
1924
import androidx.compose.runtime.remember
2025
import androidx.compose.ui.Alignment
2126
import androidx.compose.ui.Modifier
2227
import androidx.compose.ui.draw.clip
28+
import androidx.compose.ui.graphics.Color
29+
import androidx.compose.ui.res.painterResource
2330
import androidx.compose.ui.text.style.TextOverflow
2431
import androidx.compose.ui.tooling.preview.Preview
2532
import androidx.compose.ui.unit.dp
26-
import androidx.compose.ui.graphics.Color
27-
import androidx.compose.ui.res.painterResource
33+
import androidx.hilt.navigation.compose.hiltViewModel
34+
import androidx.lifecycle.compose.collectAsStateWithLifecycle
2835
import com.byteutility.dev.leetcode.plus.R
2936
import com.byteutility.dev.leetcode.plus.data.model.ProblemStatus
37+
import com.byteutility.dev.leetcode.plus.ui.theme.LeetcodePlusTheme
3038

39+
@OptIn(ExperimentalMaterial3Api::class)
3140
@Composable
3241
fun GoalProgressScreen() {
33-
// Replace with viewmodel
34-
val problemsWithStatus = emptyList<ProblemStatus>()
42+
val viewmodel: GoalProgressViewModel = hiltViewModel()
43+
viewmodel.init()
44+
val uiState by viewmodel.uiState.collectAsStateWithLifecycle()
45+
Scaffold(
46+
topBar = {
47+
TopAppBar(
48+
title = { Text(text = "My Progress") },
49+
)
50+
},
51+
) { paddingValues ->
52+
ProgressScreenContent(uiState.problemsWithStatus, Modifier.padding(paddingValues))
53+
}
54+
}
55+
56+
@Composable
57+
fun ProgressScreenContent(
58+
problemsWithStatus: List<ProblemStatus>,
59+
modifier: Modifier = Modifier
60+
) {
3561
Column(
3662
modifier = Modifier
37-
.background(Color.White)
3863
.padding(16.dp)
64+
.then(modifier)
3965
) {
40-
Text("Goal Progress (Weekly)", style = MaterialTheme.typography.titleLarge)
41-
Spacer(modifier = Modifier.height(16.dp))
42-
4366
for (problem in problemsWithStatus) {
4467
ProblemCard(problem)
4568
Spacer(modifier = Modifier.height(8.dp))
@@ -49,7 +72,9 @@ fun GoalProgressScreen() {
4972

5073
@Composable
5174
fun ProblemCard(problemStatus: ProblemStatus) {
52-
Card(modifier = Modifier.fillMaxWidth()) {
75+
Card(
76+
modifier = Modifier.fillMaxWidth(),
77+
) {
5378
Row(
5479
modifier = Modifier.fillMaxWidth(),
5580
verticalAlignment = Alignment.CenterVertically,
@@ -64,7 +89,7 @@ fun ProblemCard(problemStatus: ProblemStatus) {
6489
text = problemStatus.title,
6590
maxLines = 1,
6691
overflow = TextOverflow.Ellipsis,
67-
style = MaterialTheme.typography.titleMedium
92+
style = MaterialTheme.typography.titleLarge
6893
)
6994
Text("Status: ${problemStatus.status}")
7095
Text("Attempts Count: ${problemStatus.attemptsCount}")
@@ -122,8 +147,5 @@ fun LeetCodeProgressScreenPreview() {
122147
ProblemStatus("Climbing Stairs", "Completed", "Easy", 2)
123148
)
124149
}
125-
126-
MaterialTheme {
127-
GoalProgressScreen()
128-
}
150+
ProgressScreenContent(problemStatuses)
129151
}
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package com.byteutility.dev.leetcode.plus.ui.targetstatus
2+
3+
import androidx.lifecycle.ViewModel
4+
import androidx.lifecycle.viewModelScope
5+
import com.byteutility.dev.leetcode.plus.data.model.ProblemStatus
6+
import com.byteutility.dev.leetcode.plus.data.repository.userDetails.UserDetailsRepository
7+
import com.byteutility.dev.leetcode.plus.data.repository.weeklyGoal.WeeklyGoalRepository
8+
import dagger.hilt.android.lifecycle.HiltViewModel
9+
import kotlinx.coroutines.Dispatchers
10+
import kotlinx.coroutines.flow.MutableStateFlow
11+
import kotlinx.coroutines.flow.asStateFlow
12+
import kotlinx.coroutines.flow.combine
13+
import kotlinx.coroutines.flow.merge
14+
import kotlinx.coroutines.launch
15+
import javax.inject.Inject
16+
17+
data class ProgressScreenState(
18+
val problemsWithStatus: List<ProblemStatus> = emptyList()
19+
)
20+
21+
@HiltViewModel
22+
class GoalProgressViewModel @Inject constructor(
23+
private val userDetailsRepository: UserDetailsRepository,
24+
private val goalRepository: WeeklyGoalRepository
25+
) : ViewModel() {
26+
27+
private val _uiState = MutableStateFlow(ProgressScreenState())
28+
val uiState = _uiState.asStateFlow()
29+
30+
fun init() {
31+
viewModelScope.launch(Dispatchers.IO) {
32+
combine(
33+
userDetailsRepository.getUserRecentSubmissions(),
34+
goalRepository.weeklyGoal
35+
) { recentSubmissions, goalProblems ->
36+
val completedTitles = recentSubmissions?.filter { sub ->
37+
goalProblems?.toProblems()?.any { it.title == sub.title } == true
38+
}?.map {
39+
it.title
40+
} ?: emptyList()
41+
42+
goalProblems?.toProblems()?.map {
43+
if (it.title in completedTitles) {
44+
ProblemStatus(
45+
title = it.title,
46+
status = "Completed",
47+
difficulty = it.difficulty,
48+
attemptsCount = 1,
49+
)
50+
} else {
51+
ProblemStatus(
52+
title = it.title,
53+
status = "Not Started",
54+
difficulty = it.difficulty,
55+
attemptsCount = 0,
56+
)
57+
}
58+
}
59+
}.collect {
60+
if (it != null)
61+
_uiState.value = ProgressScreenState(it)
62+
}
63+
}
64+
}
65+
}

0 commit comments

Comments
 (0)