Skip to content

Commit

Permalink
fix(card): unhandled circumstance
Browse files Browse the repository at this point in the history
  • Loading branch information
I-Info committed Oct 30, 2023
1 parent 11df6b0 commit c511df9
Show file tree
Hide file tree
Showing 8 changed files with 104 additions and 59 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
run: chmod +x gradlew

- name: Build with Gradle
run: ./gradlew build
run: ./gradlew assembleRelease

- name: Publish Release
uses: softprops/action-gh-release@v1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,18 +21,19 @@ import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.zjutjh.ijh.R
import com.zjutjh.ijh.ui.theme.IJhTheme
import com.zjutjh.ijh.util.LoadResult
import com.zjutjh.ijh.util.toLocalizedString
import java.time.Duration

@Composable
fun CampusCardInfoCard(
modifier: Modifier = Modifier,
balance: String?,
lastSyncDuration: Duration?
balance: LoadResult<String?>,
lastSync: LoadResult<Duration?>,
) {
val context = LocalContext.current
val subtitle = remember(lastSyncDuration) {
prompt(context, lastSyncDuration)
val subtitle = remember(lastSync) {
prompt(context, lastSync)
}

GlanceCard(
Expand All @@ -50,7 +51,7 @@ fun CampusCardInfoCard(
label = "Loading",
) {
when (it) {
null -> Column(
is LoadResult.Loading -> Column(
horizontalAlignment = Alignment.CenterHorizontally
) {
CircularProgressIndicator()
Expand All @@ -60,11 +61,17 @@ fun CampusCardInfoCard(
)
}

else -> {
is LoadResult.Ready -> {
val text = if (it.data == null) {
"N/A"
} else {
"¥${it.data}"
}

Text(
modifier = Modifier.padding(vertical = 8.dp),
color = MaterialTheme.colorScheme.primary,
text = "¥$it",
text = text,
style = MaterialTheme.typography.displaySmall,
textAlign = TextAlign.Center,
maxLines = 1,
Expand All @@ -75,15 +82,21 @@ fun CampusCardInfoCard(
}
}

private fun prompt(context: Context, lastSyncDuration: Duration?) =
private fun prompt(context: Context, lastSyncDuration: LoadResult<Duration?>) =
buildString {
val separator = ""
append(context.getString(R.string.balance))
append(separator)
if (lastSyncDuration != null) {
append(lastSyncDuration.toLocalizedString(context))
} else {
append(context.getString(R.string.never))
when (lastSyncDuration) {
is LoadResult.Loading -> append(context.getString(R.string.unknown))
is LoadResult.Ready -> {
val duration = lastSyncDuration.data
if (duration != null) {
append(duration.toLocalizedString(context))
} else {
append(context.getString(R.string.never))
}
}
}
}

Expand All @@ -92,14 +105,17 @@ private fun prompt(context: Context, lastSyncDuration: Duration?) =
@Composable
private fun CampusCardInfoCardPreview() {
IJhTheme {
CampusCardInfoCard(balance = "123", lastSyncDuration = Duration.ofDays(1))
CampusCardInfoCard(
balance = LoadResult.Ready("123"),
lastSync = LoadResult.Ready(Duration.ofSeconds(10))
)
}
}

@Preview
@Composable
private fun CampusCardInfoCardPreviewEmpty() {
IJhTheme {
CampusCardInfoCard(balance = null, lastSyncDuration = null)
CampusCardInfoCard(balance = LoadResult.Loading, lastSync = LoadResult.Loading)
}
}
12 changes: 6 additions & 6 deletions app/src/main/kotlin/com/zjutjh/ijh/ui/component/ScheduleCard.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ fun ScheduleCard(
modifier: Modifier = Modifier,
courses: List<Course>?,
termDay: TermDayState?,
lastSyncDuration: Duration?,
lastSync: Duration?,
onButtonClick: () -> Unit,
) {
val context = LocalContext.current

val subtitle = remember(termDay, lastSyncDuration) {
prompt(context, termDay, lastSyncDuration)
val subtitle = remember(termDay, lastSync) {
prompt(context, termDay, lastSync)
}

GlanceCard(
Expand Down Expand Up @@ -226,7 +226,7 @@ private fun ScheduleSurfacePreview() {
courses = CourseRepositoryMock.getCourses(),
onButtonClick = {},
termDay = termDay,
lastSyncDuration = Duration.ofDays(2),
lastSync = Duration.ofDays(2),
)
}
}
Expand All @@ -242,7 +242,7 @@ private fun ScheduleSurfaceEmptyPreview() {
courses = emptyList(),
onButtonClick = {},
termDay = null,
lastSyncDuration = Duration.ofDays(1),
lastSync = Duration.ofDays(1),
)
}
}
Expand All @@ -258,7 +258,7 @@ private fun ScheduleSurfaceLoadingPreview() {
courses = null,
onButtonClick = {},
termDay = null,
lastSyncDuration = Duration.ofDays(1),
lastSync = Duration.ofDays(1),
)
}
}
Expand Down
20 changes: 12 additions & 8 deletions app/src/main/kotlin/com/zjutjh/ijh/ui/screen/HomeScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@ fun HomeRoute(
val termDayState by viewModel.termDayState.collectAsStateWithLifecycle()
val coursesLastSyncState by viewModel.courseLastSyncState.collectAsStateWithLifecycle()
val cardBalanceState by viewModel.cardBalanceState.collectAsStateWithLifecycle()
val cardBalanceLastSyncState by viewModel.cardBalanceLastSyncState.collectAsStateWithLifecycle()

val isLoggedIn = when (loginState) {
null -> false
Expand All @@ -99,8 +100,9 @@ fun HomeRoute(
isLoggedIn = isLoggedIn,
courses = courses,
termDay = termDay,
coursesLastSyncDuration = coursesLastSyncState,
coursesLastSync = coursesLastSyncState,
cardBalance = cardBalanceState,
cardBalanceLastSync = cardBalanceLastSyncState,
onRefresh = viewModel::refreshAll,
onNavigateToLogin = onNavigateToLogin,
onNavigateToProfile = onNavigateToProfile,
Expand All @@ -115,8 +117,9 @@ private fun HomeScreen(
isLoggedIn: Boolean?,
courses: List<Course>?,
termDay: TermDayState?,
coursesLastSyncDuration: Duration?,
cardBalance: Pair<String, Duration>?,
coursesLastSync: Duration?,
cardBalance: LoadResult<String?>,
cardBalanceLastSync: LoadResult<Duration?>,
onRefresh: () -> Unit,
onNavigateToLogin: () -> Unit,
onNavigateToProfile: () -> Unit,
Expand Down Expand Up @@ -151,12 +154,12 @@ private fun HomeScreen(
courses = courses,
termDay = termDay,
onButtonClick = onNavigateToCalendar,
lastSyncDuration = coursesLastSyncDuration,
lastSync = coursesLastSync,
)
CampusCardInfoCard(
modifier = modifier,
balance = cardBalance?.first,
lastSyncDuration = cardBalance?.second
balance = cardBalance,
lastSync = cardBalanceLastSync,
)
}

Expand Down Expand Up @@ -350,8 +353,9 @@ private fun HomeScreenPreview() {
isLoggedIn = true,
courses = courses,
termDay = termDay,
coursesLastSyncDuration = Duration.ofDays(1),
cardBalance = "123" to Duration.ofDays(2),
coursesLastSync = Duration.ofDays(1),
cardBalance = LoadResult.Ready("123"),
cardBalanceLastSync = LoadResult.Ready(Duration.ofDays(2)),
onRefresh = ::emptyFun,
onNavigateToAbout = ::emptyFun,
onNavigateToCalendar = ::emptyFun,
Expand Down
54 changes: 30 additions & 24 deletions app/src/main/kotlin/com/zjutjh/ijh/ui/viewmodel/HomeViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,7 @@ class HomeViewModel @Inject constructor(
.distinctUntilChanged()
.combine(timerFlow) { t1, _ -> t1 }
.map {
if (it == null) null else {
Duration.between(it, ZonedDateTime.now())
}
it?.let { Duration.between(it, ZonedDateTime.now()) }
}
.flowOn(Dispatchers.Default)
.stateIn(
Expand Down Expand Up @@ -73,7 +71,6 @@ class HomeViewModel @Inject constructor(
.mapLatest {
it?.toTermDayState()
}
.flowOn(Dispatchers.Default)
.asLoadResultStateFlow(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(),
Expand All @@ -91,27 +88,30 @@ class HomeViewModel @Inject constructor(
} else flowOf(emptyList())
} else flowOf(emptyList())
}
.flowOn(Dispatchers.Default)
.asLoadResultStateFlow(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000)
)

val cardBalanceState: StateFlow<Pair<String, Duration>?> = cardInfoRepository.balanceStream
val cardBalanceState: StateFlow<LoadResult<String?>> = cardInfoRepository.balanceStream
.distinctUntilChanged()
.combine(timerFlow) { t, _ -> t }
.map {
if (it == null) null else {
Pair(it.first, Duration.between(it.second, ZonedDateTime.now()))
}
}
.flowOn(Dispatchers.Default)
.stateIn(
.asLoadResultStateFlow(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000),
initialValue = null
)

val cardBalanceLastSyncState: StateFlow<LoadResult<Duration?>> =
cardInfoRepository.lastSyncTimeStream
.distinctUntilChanged()
.combine(timerFlow) { t1, _ -> t1 }
.map {
it?.let { Duration.between(it, ZonedDateTime.now()) }
}
.asLoadResultStateFlow(
scope = viewModelScope,
started = SharingStarted.WhileSubscribed(5_000)
)

init {
viewModelScope.launch(Dispatchers.Default) {
// Check session state, renew if needed. TODO: move to application scope
Expand All @@ -131,7 +131,7 @@ class HomeViewModel @Inject constructor(
}
}
}
// Subscribe latest login state, and trigger refresh.
//Subscribe latest login state, and trigger refresh.
loginState.collectLatest {
refreshAll(this)
}
Expand All @@ -155,19 +155,25 @@ class HomeViewModel @Inject constructor(
_refreshState.update { true }
val timer = scope.async { delay(300L) }

val term = refreshTerm()

val isLoggedIn = loginState.value
if (isLoggedIn != null) {
if (term != null) {
refreshCourse(term.first, term.second)
val tasks = if (isLoggedIn != null) {
val task1 = scope.async {
val term = refreshTerm()
if (term != null) {
refreshCourse(term.first, term.second)
}
}
refreshCard()
val task2 = scope.async {
refreshCard()
}
mutableListOf(task1, task2)
} else {
mutableListOf()
}

tasks.add(timer)
awaitAll(deferreds = tasks.toTypedArray())
Log.i("Home", "Synchronization complete.")

timer.await()
_refreshState.update { false }
}

Expand Down
15 changes: 15 additions & 0 deletions app/src/main/kotlin/com/zjutjh/ijh/util/LoadResult.kt
Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
package com.zjutjh.ijh.util

import androidx.compose.runtime.Stable
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onStart
import kotlinx.coroutines.flow.shareIn
import kotlinx.coroutines.flow.stateIn
import kotlin.coroutines.CoroutineContext

@Stable
sealed interface LoadResult<out T> {
data object Loading : LoadResult<Nothing>
class Ready<T>(val data: T) : LoadResult<T>
Expand All @@ -23,6 +28,12 @@ sealed interface LoadResult<out T> {
if (this is Ready && v is Ready) {
areEquivalent(this.data, v.data)
} else this is Loading && v is Loading

fun <R> map(transform: (T) -> R): LoadResult<R> =
when (this) {
is Loading -> Loading
is Ready -> Ready(transform(data))
}
}

fun <T> LoadResult<T>.isLoading(): Boolean = this is LoadResult.Loading
Expand All @@ -36,13 +47,15 @@ fun <T> Flow<T>.asLoadResultFlow(): Flow<LoadResult<T>> = this
.onStart { emit(LoadResult.Loading) }

fun <T> Flow<T>.asLoadResultSharedFlow(
context: CoroutineContext = Dispatchers.Default,
scope: CoroutineScope,
started: SharingStarted
): SharedFlow<LoadResult<T>> = this
.map<T, LoadResult<T>> {
LoadResult.Ready(it)
}
.onStart { emit(LoadResult.Loading) }
.flowOn(context)
.shareIn(
scope = scope,
started = started,
Expand All @@ -51,12 +64,14 @@ fun <T> Flow<T>.asLoadResultSharedFlow(


fun <T> Flow<T>.asLoadResultStateFlow(
context: CoroutineContext = Dispatchers.Default,
scope: CoroutineScope,
started: SharingStarted
): StateFlow<LoadResult<T>> = this
.map<T, LoadResult<T>> {
LoadResult.Ready(it)
}
.flowOn(context)
.stateIn(
scope = scope,
started = started,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ import java.util.Date
interface CardInfoRepository {

/**
* [Pair]: balance (Unit: CNY) in string, last sync time
* balance (Unit: CNY) in string
*/
val balanceStream: Flow<Pair<String, ZonedDateTime>?>
val balanceStream: Flow<String?>

val lastSyncTimeStream: Flow<ZonedDateTime?>

suspend fun sync()

Expand Down
Loading

0 comments on commit c511df9

Please sign in to comment.