Skip to content

Commit

Permalink
Merge pull request #242 from SuhasDissa/clock-performance
Browse files Browse the repository at this point in the history
fix: clock list performance issues
  • Loading branch information
SuhasDissa authored Dec 12, 2023
2 parents c6afdc0 + 8e6305f commit c643b7f
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 50 deletions.
45 changes: 21 additions & 24 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(
private val sortOrderPref =
Preferences.instance.getString(Preferences.clockSortOrder, "").orEmpty()
var sortOrder: SortOrder =
if (sortOrderPref.isNotEmpty()) SortOrder.valueOf(sortOrderPref) else SortOrder.ALPHABETIC
)

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

private fun updateTime() {
currentDate = TimeHelper.getTimeByZone()
handler.postDelayed(100, handlerKey, this::updateTime)
init {
updateSortOrder()
}

fun startLifecycle() {
updateTime()
fun updateSortOrder(sort: SortOrder? = null) {
sort?.let {
sortOrder = it
}
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
updateSortOrder()
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 c643b7f

Please sign in to comment.