Skip to content

Commit

Permalink
fix: clock list performance issues
Browse files Browse the repository at this point in the history
  • Loading branch information
SuhasDissa committed Dec 10, 2023
1 parent 4682053 commit c4d3d65
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 46 deletions.
37 changes: 17 additions & 20 deletions app/src/main/java/com/bnyro/clock/ui/model/ClockModel.kt
Original file line number Diff line number Diff line change
@@ -1,58 +1,55 @@
package com.bnyro.clock.ui.model

import android.os.Handler
import android.os.Looper
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.core.os.postDelayed
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.bnyro.clock.db.DatabaseHolder
import com.bnyro.clock.obj.SortOrder
import com.bnyro.clock.obj.TimeZone
import com.bnyro.clock.util.Preferences
import com.bnyro.clock.util.TimeHelper
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking

class ClockModel : ViewModel() {
private val handlerKey = "clockUpdateTimeHandler"
private val handler = Handler(Looper.getMainLooper())
var currentDate by mutableStateOf(TimeHelper.getTimeByZone())
private val sortOrderPref = Preferences.instance.getString(Preferences.clockSortOrder, "").orEmpty()
var sortOrder by mutableStateOf(
if (sortOrderPref.isNotEmpty()) SortOrder.valueOf(sortOrderPref) else SortOrder.ALPHABETIC
)
var sortOrder: SortOrder

var sortedZones by mutableStateOf(listOf<TimeZone>())
val timeZones = TimeHelper.getAvailableTimeZones()
var selectedTimeZones by mutableStateOf(
runBlocking {
DatabaseHolder.instance.timeZonesDao().getAll()
}
)

private fun updateTime() {
currentDate = TimeHelper.getTimeByZone()
handler.postDelayed(100, handlerKey, this::updateTime)
init {
val sortOrderPref =
Preferences.instance.getString(Preferences.clockSortOrder, "").orEmpty()
sortOrder =
if (sortOrderPref.isNotEmpty()) SortOrder.valueOf(sortOrderPref) else SortOrder.ALPHABETIC
updateSortOrder(sortOrder)
}

fun startLifecycle() {
updateTime()
fun updateSortOrder(sort: SortOrder) {
sortOrder = sort
val zones = selectedTimeZones.distinct()
sortedZones = when (sortOrder) {
SortOrder.ALPHABETIC -> zones.sortedBy { it.displayName }
SortOrder.OFFSET -> zones.sortedBy { it.offset }
}
}

fun setTimeZones(timeZones: List<com.bnyro.clock.obj.TimeZone>) = viewModelScope.launch(
fun setTimeZones(timeZones: List<TimeZone>) = viewModelScope.launch(
Dispatchers.IO
) {
selectedTimeZones = timeZones
DatabaseHolder.instance.timeZonesDao().clear()
DatabaseHolder.instance.timeZonesDao().insertAll(*timeZones.toTypedArray())
}

fun stopLifecycle() {
handler.removeCallbacksAndMessages(handlerKey)
}

fun getDateWithOffset(timeZone: String): Pair<String, String> {
val time = TimeHelper.getTimeByZone(timeZone)
return TimeHelper.formatDateTime(time, false)
Expand Down
56 changes: 30 additions & 26 deletions app/src/main/java/com/bnyro/clock/ui/screens/ClockScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
import androidx.compose.material3.surfaceColorAtElevation
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.toMutableStateList
Expand All @@ -52,6 +52,8 @@ import com.bnyro.clock.ui.model.ClockModel
import com.bnyro.clock.ui.nav.TopBarScaffold
import com.bnyro.clock.util.Preferences
import com.bnyro.clock.util.TimeHelper
import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive

@Composable
fun ClockScreen(
Expand All @@ -62,13 +64,6 @@ fun ClockScreen(
mutableStateOf(false)
}

DisposableEffect(Unit) {
clockModel.startLifecycle()
onDispose {
clockModel.stopLifecycle()
}
}

TopBarScaffold(title = stringResource(R.string.clock), onClickSettings, actions = {
Box {
var showDropdown by remember {
Expand All @@ -79,6 +74,8 @@ fun ClockScreen(
showDropdown = true
}

var sortOrder by remember { mutableStateOf(clockModel.sortOrder) }

DropdownMenu(
expanded = showDropdown,
onDismissRequest = { showDropdown = false }
Expand All @@ -89,7 +86,8 @@ fun ClockScreen(
Text(stringResource(it.value))
},
onClick = {
clockModel.sortOrder = it
sortOrder = it
clockModel.updateSortOrder(it)
Preferences.edit {
putString(Preferences.clockSortOrder, it.name)
}
Expand Down Expand Up @@ -121,30 +119,28 @@ fun ClockScreen(
.padding(horizontal = 28.dp, vertical = 28.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
val (date, time) = TimeHelper.formatDateTime(clockModel.currentDate)
val dateTime by produceState(
initialValue = TimeHelper.formatDateTime(TimeHelper.getTimeByZone()),
producer = {
while (isActive) {
value = TimeHelper.formatDateTime(TimeHelper.getTimeByZone())
delay(1000)
}
}
)
Text(
text = time,
text = dateTime.second,
style = MaterialTheme.typography.displayMedium
)
Text(
text = date,
text = dateTime.first,
style = MaterialTheme.typography.bodyLarge
)
}

Spacer(modifier = Modifier.height(6.dp))

val zones = clockModel.selectedTimeZones.distinct()
val sortedZones = when (clockModel.sortOrder) {
SortOrder.ALPHABETIC -> zones.sortedBy { it.displayName }
SortOrder.OFFSET -> zones.sortedBy { it.offset }
}
sortedZones.forEach { timeZone ->
// needed for auto updating the time displayed / re-composition
val (date, time) = clockModel.currentDate.let {
clockModel.getDateWithOffset(timeZone.name)
}

clockModel.sortedZones.forEach { timeZone ->
Box(
modifier = Modifier
.fillMaxWidth()
Expand All @@ -157,13 +153,21 @@ fun ClockScreen(
.fillMaxWidth()
.padding(horizontal = 16.dp, vertical = 16.dp)
) {
val dateTime by produceState(
initialValue = clockModel.getDateWithOffset(timeZone.name)
) {
while (isActive) {
value = clockModel.getDateWithOffset(timeZone.name)
delay(1000)
}
}
Row(
modifier = Modifier.fillMaxWidth(),
horizontalArrangement = Arrangement.SpaceBetween,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = timeZone.displayName.uppercase(),
text = timeZone.name.uppercase(),
color = MaterialTheme.colorScheme.primary,
style = MaterialTheme.typography.titleMedium,
maxLines = 1,
Expand All @@ -179,7 +183,7 @@ fun ClockScreen(
horizontal = 16.dp,
vertical = 8.dp
),
text = time,
text = dateTime.second,
color = MaterialTheme.colorScheme.onPrimaryContainer,
style = MaterialTheme.typography.headlineSmall
)
Expand All @@ -194,7 +198,7 @@ fun ClockScreen(
style = MaterialTheme.typography.bodyLarge
)
Text(
text = date,
text = dateTime.first,
style = MaterialTheme.typography.bodyMedium
)
}
Expand Down

0 comments on commit c4d3d65

Please sign in to comment.