Improved UX for cache clearing

This commit is contained in:
Sad Ellie 2023-09-30 15:33:26 +03:00
parent d519af6ec8
commit 8be61f03f2
7 changed files with 163 additions and 88 deletions

View File

@ -23,7 +23,6 @@ import android.app.PendingIntent.FLAG_IMMUTABLE
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.widget.Toast
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.core.content.pm.ShortcutInfoCompat import androidx.core.content.pm.ShortcutInfoCompat
@ -82,7 +81,7 @@ fun Context.addShortcut(
PendingIntent.getBroadcast(context, 0, shortCutIntent, FLAG_IMMUTABLE).intentSender PendingIntent.getBroadcast(context, 0, shortCutIntent, FLAG_IMMUTABLE).intentSender
) )
} catch (e: Exception) { } catch (e: Exception) {
Toast.makeText(context, e.message, Toast.LENGTH_SHORT).show() showToast(context, e.message ?: "Error")
} }
} }

View File

@ -35,9 +35,17 @@ fun openLink(mContext: Context, url: String) {
try { try {
mContext.startActivity(Intent(Intent.ACTION_VIEW).setData(Uri.parse(url))) mContext.startActivity(Intent(Intent.ACTION_VIEW).setData(Uri.parse(url)))
} catch (e: ActivityNotFoundException) { } catch (e: ActivityNotFoundException) {
Toast.makeText(mContext, R.string.error_label, Toast.LENGTH_SHORT).show() showToast(mContext, mContext.getString(R.string.error_label))
} }
} }
fun showToast(
mContext: Context,
text: String,
duration: Int = Toast.LENGTH_SHORT
) {
Toast.makeText(mContext, text, duration).show()
}
@Composable @Composable
fun isPortrait() = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT fun isPortrait() = LocalConfiguration.current.orientation == Configuration.ORIENTATION_PORTRAIT

View File

@ -22,6 +22,7 @@ import androidx.room.Dao
import androidx.room.Insert import androidx.room.Insert
import androidx.room.OnConflictStrategy import androidx.room.OnConflictStrategy
import androidx.room.Query import androidx.room.Query
import kotlinx.coroutines.flow.Flow
@Dao @Dao
interface CurrencyRatesDao { interface CurrencyRatesDao {
@ -32,6 +33,9 @@ interface CurrencyRatesDao {
@Query("SELECT DISTINCT * FROM currency_rates WHERE timestamp = (SELECT MAX(timestamp) FROM currency_rates) AND base_unit_id = :baseId") @Query("SELECT DISTINCT * FROM currency_rates WHERE timestamp = (SELECT MAX(timestamp) FROM currency_rates) AND base_unit_id = :baseId")
suspend fun getLatestRates(baseId: String): List<CurrencyRatesEntity> suspend fun getLatestRates(baseId: String): List<CurrencyRatesEntity>
@Query("SELECT COUNT(*) from currency_rates")
fun size(): Flow<Int>
@Query("DELETE FROM currency_rates") @Query("DELETE FROM currency_rates")
suspend fun clear() suspend fun clear()
} }

View File

@ -23,7 +23,6 @@ import android.content.ActivityNotFoundException
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.provider.CalendarContract import android.provider.CalendarContract
import android.widget.Toast
import androidx.activity.compose.BackHandler import androidx.activity.compose.BackHandler
import androidx.compose.animation.AnimatedVisibility import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.fadeIn import androidx.compose.animation.fadeIn
@ -73,6 +72,7 @@ import com.sadellie.unitto.core.base.R
import com.sadellie.unitto.core.ui.common.textfield.addTokens import com.sadellie.unitto.core.ui.common.textfield.addTokens
import com.sadellie.unitto.core.ui.common.textfield.deleteTokens import com.sadellie.unitto.core.ui.common.textfield.deleteTokens
import com.sadellie.unitto.core.ui.isPortrait import com.sadellie.unitto.core.ui.isPortrait
import com.sadellie.unitto.core.ui.showToast
import com.sadellie.unitto.feature.datecalculator.components.AddSubtractKeyboard import com.sadellie.unitto.feature.datecalculator.components.AddSubtractKeyboard
import com.sadellie.unitto.feature.datecalculator.components.DateTimeDialogs import com.sadellie.unitto.feature.datecalculator.components.DateTimeDialogs
import com.sadellie.unitto.feature.datecalculator.components.DateTimeSelectorBlock import com.sadellie.unitto.feature.datecalculator.components.DateTimeSelectorBlock
@ -340,7 +340,7 @@ private fun Context.addEvent(start: ZonedDateTime, end: ZonedDateTime) {
try { try {
startActivity(intent) startActivity(intent)
} catch (e: ActivityNotFoundException) { } catch (e: ActivityNotFoundException) {
Toast.makeText(this, R.string.error_label, Toast.LENGTH_SHORT).show() showToast(this, this.getString(R.string.error_label))
} }
} }

View File

@ -18,8 +18,23 @@
package com.sadellie.unitto.feature.settings package com.sadellie.unitto.feature.settings
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.expandVertically
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
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.shape.CircleShape
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Cached import androidx.compose.material.icons.filled.Cached
import androidx.compose.material.icons.filled.Calculate import androidx.compose.material.icons.filled.Calculate
@ -29,12 +44,24 @@ import androidx.compose.material.icons.filled.Palette
import androidx.compose.material.icons.filled.RateReview import androidx.compose.material.icons.filled.RateReview
import androidx.compose.material.icons.filled.SwapHoriz import androidx.compose.material.icons.filled.SwapHoriz
import androidx.compose.material.icons.filled.Vibration import androidx.compose.material.icons.filled.Vibration
import androidx.compose.material.icons.filled.Warning
import androidx.compose.material.icons.filled._123 import androidx.compose.material.icons.filled._123
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.compositeOver
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import androidx.hilt.navigation.compose.hiltViewModel import androidx.hilt.navigation.compose.hiltViewModel
import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.sadellie.unitto.core.base.BuildConfig import com.sadellie.unitto.core.base.BuildConfig
@ -44,6 +71,7 @@ import com.sadellie.unitto.core.ui.common.NavigateUpButton
import com.sadellie.unitto.core.ui.common.UnittoListItem import com.sadellie.unitto.core.ui.common.UnittoListItem
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
import com.sadellie.unitto.core.ui.openLink import com.sadellie.unitto.core.ui.openLink
import com.sadellie.unitto.core.ui.showToast
import com.sadellie.unitto.data.userprefs.GeneralPreferences import com.sadellie.unitto.data.userprefs.GeneralPreferences
import com.sadellie.unitto.feature.settings.navigation.aboutRoute import com.sadellie.unitto.feature.settings.navigation.aboutRoute
import com.sadellie.unitto.feature.settings.navigation.calculatorSettingsRoute import com.sadellie.unitto.feature.settings.navigation.calculatorSettingsRoute
@ -59,13 +87,15 @@ internal fun SettingsRoute(
navControllerAction: (String) -> Unit, navControllerAction: (String) -> Unit,
) { ) {
val userPrefs = viewModel.userPrefs.collectAsStateWithLifecycle() val userPrefs = viewModel.userPrefs.collectAsStateWithLifecycle()
val cachePercentage = viewModel.cachePercentage.collectAsStateWithLifecycle()
SettingsScreen( SettingsScreen(
userPrefs = userPrefs.value, userPrefs = userPrefs.value,
navigateUp = navigateUp, navigateUp = navigateUp,
navControllerAction = navControllerAction, navControllerAction = navControllerAction,
updateVibrations = viewModel::updateVibrations, updateVibrations = viewModel::updateVibrations,
clearCache = viewModel::clearCache cachePercentage = cachePercentage.value,
clearCache = viewModel::clearCache,
) )
} }
@ -75,6 +105,7 @@ private fun SettingsScreen(
navigateUp: () -> Unit, navigateUp: () -> Unit,
navControllerAction: (String) -> Unit, navControllerAction: (String) -> Unit,
updateVibrations: (Boolean) -> Unit, updateVibrations: (Boolean) -> Unit,
cachePercentage: Float,
clearCache: () -> Unit, clearCache: () -> Unit,
) { ) {
val mContext = LocalContext.current val mContext = LocalContext.current
@ -83,9 +114,12 @@ private fun SettingsScreen(
title = stringResource(R.string.settings_screen), title = stringResource(R.string.settings_screen),
navigationIcon = { NavigateUpButton(navigateUp) } navigationIcon = { NavigateUpButton(navigateUp) }
) { padding -> ) { padding ->
LazyColumn(contentPadding = padding) { Column(
modifier = Modifier
item("theme") { .fillMaxSize()
.verticalScroll(rememberScrollState())
.padding(padding)
) {
UnittoListItem( UnittoListItem(
icon = Icons.Default.Palette, icon = Icons.Default.Palette,
iconDescription = stringResource(R.string.display_settings), iconDescription = stringResource(R.string.display_settings),
@ -93,9 +127,7 @@ private fun SettingsScreen(
supportingText = stringResource(R.string.theme_setting_support), supportingText = stringResource(R.string.theme_setting_support),
modifier = Modifier.clickable { navControllerAction(displayRoute) } modifier = Modifier.clickable { navControllerAction(displayRoute) }
) )
}
item("starting screen") {
UnittoListItem( UnittoListItem(
icon = Icons.Default.Home, icon = Icons.Default.Home,
iconDescription = stringResource(R.string.starting_screen_setting), iconDescription = stringResource(R.string.starting_screen_setting),
@ -103,9 +135,7 @@ private fun SettingsScreen(
supportingText = stringResource(R.string.starting_screen_setting_support), supportingText = stringResource(R.string.starting_screen_setting_support),
modifier = Modifier.clickable { navControllerAction(startingScreenRoute) } modifier = Modifier.clickable { navControllerAction(startingScreenRoute) }
) )
}
item("formatting") {
UnittoListItem( UnittoListItem(
icon = Icons.Default._123, icon = Icons.Default._123,
iconDescription = stringResource(R.string.formatting_setting), iconDescription = stringResource(R.string.formatting_setting),
@ -113,9 +143,7 @@ private fun SettingsScreen(
supportingText = stringResource(R.string.formatting_setting_support), supportingText = stringResource(R.string.formatting_setting_support),
modifier = Modifier.clickable { navControllerAction(formattingRoute) } modifier = Modifier.clickable { navControllerAction(formattingRoute) }
) )
}
item("calculator") {
UnittoListItem( UnittoListItem(
icon = Icons.Default.Calculate, icon = Icons.Default.Calculate,
iconDescription = stringResource(R.string.calculator), iconDescription = stringResource(R.string.calculator),
@ -123,9 +151,7 @@ private fun SettingsScreen(
supportingText = stringResource(R.string.calculator_settings_support), supportingText = stringResource(R.string.calculator_settings_support),
modifier = Modifier.clickable { navControllerAction(calculatorSettingsRoute) } modifier = Modifier.clickable { navControllerAction(calculatorSettingsRoute) }
) )
}
item("unit converter") {
UnittoListItem( UnittoListItem(
icon = Icons.Default.SwapHoriz, icon = Icons.Default.SwapHoriz,
iconDescription = stringResource(R.string.unit_converter), iconDescription = stringResource(R.string.unit_converter),
@ -133,11 +159,9 @@ private fun SettingsScreen(
supportingText = stringResource(R.string.converter_settings_support), supportingText = stringResource(R.string.converter_settings_support),
modifier = Modifier.clickable { navControllerAction(converterSettingsRoute) } modifier = Modifier.clickable { navControllerAction(converterSettingsRoute) }
) )
}
item("additional") { Header(stringResource(R.string.additional_settings_group)) } Header(stringResource(R.string.additional_settings_group))
item("vibrations") {
UnittoListItem( UnittoListItem(
icon = Icons.Default.Vibration, icon = Icons.Default.Vibration,
iconDescription = stringResource(R.string.enable_vibrations), iconDescription = stringResource(R.string.enable_vibrations),
@ -147,19 +171,50 @@ private fun SettingsScreen(
switchState = userPrefs.enableVibrations, switchState = userPrefs.enableVibrations,
onSwitchChange = updateVibrations onSwitchChange = updateVibrations
) )
}
item("clear cache") { AnimatedVisibility(
visible = cachePercentage > 0,
enter = expandVertically() + fadeIn(),
exit = shrinkVertically() + fadeOut(),
) {
UnittoListItem( UnittoListItem(
headlineText = stringResource(R.string.clear_cache), headlineText = stringResource(R.string.clear_cache),
icon = Icons.Default.Cached, icon = Icons.Default.Cached,
iconDescription = stringResource(R.string.clear_cache), iconDescription = stringResource(R.string.clear_cache),
modifier = Modifier.clickable { clearCache() }, modifier = Modifier.clickable { clearCache(); showToast(mContext, "👌") },
trailing = {
Box(
Modifier
.clip(CircleShape)
.background(MaterialTheme.colorScheme.errorContainer)
.size(52.dp, 24.dp),
contentAlignment = Alignment.CenterStart
) {
Box(
Modifier
.background(
MaterialTheme.colorScheme.error.copy(alpha = cachePercentage)
.compositeOver(Color.Green)
)
.height(24.dp)
.fillMaxWidth(cachePercentage),
contentAlignment = Alignment.Center
) {
if (cachePercentage == 1f) {
Icon(
imageVector = Icons.Default.Warning,
contentDescription = null,
tint = MaterialTheme.colorScheme.onError,
modifier = Modifier.size(18.dp)
)
}
}
}
}
) )
} }
if (BuildConfig.STORE_LINK.isNotEmpty()) { if (BuildConfig.STORE_LINK.isNotEmpty()) {
item("rate this app") {
UnittoListItem( UnittoListItem(
icon = Icons.Default.RateReview, icon = Icons.Default.RateReview,
iconDescription = stringResource(R.string.rate_this_app), iconDescription = stringResource(R.string.rate_this_app),
@ -167,9 +222,7 @@ private fun SettingsScreen(
modifier = Modifier.clickable { openLink(mContext, BuildConfig.STORE_LINK) } modifier = Modifier.clickable { openLink(mContext, BuildConfig.STORE_LINK) }
) )
} }
}
item("about") {
UnittoListItem( UnittoListItem(
icon = Icons.Default.Info, icon = Icons.Default.Info,
iconDescription = stringResource(R.string.about_unitto), iconDescription = stringResource(R.string.about_unitto),
@ -179,17 +232,19 @@ private fun SettingsScreen(
) )
} }
} }
}
} }
@Preview @Preview
@Composable @Composable
private fun PreviewSettingsScreen() { private fun PreviewSettingsScreen() {
var cacheSize by remember { mutableFloatStateOf(0.9f) }
SettingsScreen( SettingsScreen(
userPrefs = GeneralPreferences(), userPrefs = GeneralPreferences(),
navigateUp = {}, navigateUp = {},
navControllerAction = {}, navControllerAction = {},
updateVibrations = {}, updateVibrations = {},
clearCache = {} cachePercentage = cacheSize,
clearCache = { cacheSize = 0f }
) )
} }

View File

@ -25,6 +25,8 @@ import com.sadellie.unitto.data.database.CurrencyRatesDao
import com.sadellie.unitto.data.userprefs.GeneralPreferences import com.sadellie.unitto.data.userprefs.GeneralPreferences
import com.sadellie.unitto.data.userprefs.UserPreferencesRepository import com.sadellie.unitto.data.userprefs.UserPreferencesRepository
import dagger.hilt.android.lifecycle.HiltViewModel import dagger.hilt.android.lifecycle.HiltViewModel
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import javax.inject.Inject import javax.inject.Inject
@ -36,6 +38,12 @@ internal class SettingsViewModel @Inject constructor(
val userPrefs = userPrefsRepository.generalPrefs val userPrefs = userPrefsRepository.generalPrefs
.stateIn(viewModelScope, GeneralPreferences()) .stateIn(viewModelScope, GeneralPreferences())
val cachePercentage = currencyRatesDao.size()
.map {
(it / 100_000f).coerceIn(0f, 1f)
}
.stateIn(viewModelScope, 0f)
/** /**
* @see UserPreferencesRepository.updateVibrations * @see UserPreferencesRepository.updateVibrations
*/ */
@ -43,7 +51,7 @@ internal class SettingsViewModel @Inject constructor(
userPrefsRepository.updateVibrations(enabled) userPrefsRepository.updateVibrations(enabled)
} }
fun clearCache() = viewModelScope.launch { fun clearCache() = viewModelScope.launch(Dispatchers.IO) {
currencyRatesDao.clear() currencyRatesDao.clear()
} }
} }

View File

@ -50,6 +50,7 @@ import com.sadellie.unitto.core.ui.common.NavigateUpButton
import com.sadellie.unitto.core.ui.common.UnittoListItem import com.sadellie.unitto.core.ui.common.UnittoListItem
import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar import com.sadellie.unitto.core.ui.common.UnittoScreenWithLargeTopBar
import com.sadellie.unitto.core.ui.openLink import com.sadellie.unitto.core.ui.openLink
import com.sadellie.unitto.core.ui.showToast
import com.sadellie.unitto.data.userprefs.AboutPreferences import com.sadellie.unitto.data.userprefs.AboutPreferences
@Composable @Composable
@ -158,7 +159,7 @@ private fun AboutScreen(
supportingText = "${BuildConfig.APP_NAME} (${BuildConfig.APP_CODE})", supportingText = "${BuildConfig.APP_NAME} (${BuildConfig.APP_CODE})",
modifier = Modifier.combinedClickable { modifier = Modifier.combinedClickable {
if (prefs.enableToolsExperiment) { if (prefs.enableToolsExperiment) {
Toast.makeText(mContext, "Experiments features are already enabled!", Toast.LENGTH_LONG).show() showToast(mContext, "Experiments features are already enabled!", Toast.LENGTH_LONG)
return@combinedClickable return@combinedClickable
} }
@ -166,7 +167,7 @@ private fun AboutScreen(
if (aboutItemClick < 7) return@combinedClickable if (aboutItemClick < 7) return@combinedClickable
enableToolsExperiment() enableToolsExperiment()
Toast.makeText(mContext, "Experimental features enabled!", Toast.LENGTH_LONG).show() showToast(mContext, "Experimental features enabled!", Toast.LENGTH_LONG)
} }
) )
} }