mirror of
https://github.com/Myzel394/NumberHub.git
synced 2025-06-19 00:35:26 +02:00
Use wrapper for table entities
This commit is contained in:
parent
f7fe300706
commit
2d78ab05bd
@ -0,0 +1,4 @@
|
||||
-keepclassmembers class ** {
|
||||
@com.squareup.moshi.FromJson *;
|
||||
@com.squareup.moshi.ToJson *;
|
||||
}
|
@ -52,6 +52,7 @@ import com.sadellie.unitto.data.userprefs.getUnitConverterFormatTime
|
||||
import com.sadellie.unitto.data.userprefs.getUnitConverterSorting
|
||||
import com.squareup.moshi.JsonAdapter
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.adapter
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.flow.first
|
||||
@ -61,6 +62,7 @@ import java.io.File
|
||||
import java.io.InputStreamReader
|
||||
import javax.inject.Inject
|
||||
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
class BackupManager @Inject constructor(
|
||||
@ApplicationContext private val mContext: Context,
|
||||
private val dataStore: DataStore<Preferences>,
|
||||
@ -69,8 +71,10 @@ class BackupManager @Inject constructor(
|
||||
// Not planned at the moment
|
||||
// private val calculatorHistoryDao: CalculatorHistoryDao,
|
||||
) {
|
||||
private val moshi: Moshi = Moshi.Builder().build()
|
||||
private val jsonAdapter: JsonAdapter<UserData> = moshi.adapter(UserData::class.java)
|
||||
private val moshi: Moshi = Moshi.Builder()
|
||||
.add(UserDataTableAdapter())
|
||||
.build()
|
||||
private val jsonAdapter: JsonAdapter<UserData> = moshi.adapter<UserData>()
|
||||
private val auth = "com.sadellie.unitto.BackupManager"
|
||||
|
||||
suspend fun backup(): Uri = withContext(Dispatchers.IO) {
|
||||
|
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.data.backup
|
||||
|
||||
import com.sadellie.unitto.data.database.TimeZoneEntity
|
||||
import com.sadellie.unitto.data.database.UnitsEntity
|
||||
import com.squareup.moshi.FromJson
|
||||
import com.squareup.moshi.ToJson
|
||||
|
||||
// Have to use this wrapper since entity classes are in database module
|
||||
@Suppress("UNUSED")
|
||||
internal class UserDataTableAdapter {
|
||||
@ToJson
|
||||
fun toJson(unitsEntity: UnitsEntity): UserDataUnit =
|
||||
UserDataUnit(
|
||||
unitId = unitsEntity.unitId,
|
||||
isFavorite = unitsEntity.isFavorite,
|
||||
pairedUnitId = unitsEntity.pairedUnitId,
|
||||
frequency = unitsEntity.frequency
|
||||
)
|
||||
|
||||
@FromJson
|
||||
fun fromJson(userDataUnit: UserDataUnit): UnitsEntity =
|
||||
UnitsEntity(
|
||||
unitId = userDataUnit.unitId,
|
||||
isFavorite = userDataUnit.isFavorite,
|
||||
pairedUnitId = userDataUnit.pairedUnitId,
|
||||
frequency = userDataUnit.frequency
|
||||
)
|
||||
|
||||
@ToJson
|
||||
fun toJson(timeZoneEntity: TimeZoneEntity): UserDataTimezone =
|
||||
UserDataTimezone(
|
||||
id = timeZoneEntity.id,
|
||||
position = timeZoneEntity.position,
|
||||
label = timeZoneEntity.label
|
||||
)
|
||||
|
||||
@FromJson
|
||||
fun fromJson(userDataTimezone: UserDataTimezone): TimeZoneEntity =
|
||||
TimeZoneEntity(
|
||||
id = userDataTimezone.id,
|
||||
position = userDataTimezone.position,
|
||||
label = userDataTimezone.label
|
||||
)
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.data.backup
|
||||
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class UserDataTimezone(
|
||||
val id: String,
|
||||
val position: Int,
|
||||
val label: String,
|
||||
)
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Unitto is a unit converter for Android
|
||||
* Copyright (c) 2023 Elshan Agaev
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.sadellie.unitto.data.backup
|
||||
|
||||
import com.squareup.moshi.JsonClass
|
||||
|
||||
@JsonClass(generateAdapter = true)
|
||||
internal data class UserDataUnit(
|
||||
val unitId: String,
|
||||
val isFavorite: Boolean,
|
||||
val pairedUnitId: String?,
|
||||
val frequency: Int,
|
||||
)
|
@ -26,7 +26,6 @@ import androidx.activity.compose.BackHandler
|
||||
import androidx.activity.compose.rememberLauncherForActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.Crossfade
|
||||
import androidx.compose.animation.expandVertically
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
@ -110,41 +109,21 @@ internal fun SettingsRoute(
|
||||
if (showErrorToast) Toast.makeText(mContext, errorLabel, Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
|
||||
Crossfade(targetState = uiState) { state ->
|
||||
when (state) {
|
||||
SettingsUIState.Loading -> UnittoEmptyScreen()
|
||||
when (uiState) {
|
||||
SettingsUIState.Loading -> UnittoEmptyScreen()
|
||||
|
||||
SettingsUIState.BackupInProgress -> BackingUpScreen()
|
||||
|
||||
is SettingsUIState.Ready -> SettingsScreen(
|
||||
uiState = state,
|
||||
navigateUp = navigateUp,
|
||||
navControllerAction = navControllerAction,
|
||||
updateVibrations = viewModel::updateVibrations,
|
||||
clearCache = viewModel::clearCache,
|
||||
backup = viewModel::backup,
|
||||
restore = viewModel::restore
|
||||
)
|
||||
}
|
||||
is SettingsUIState.Ready -> SettingsScreen(
|
||||
uiState = uiState,
|
||||
navigateUp = navigateUp,
|
||||
navControllerAction = navControllerAction,
|
||||
updateVibrations = viewModel::updateVibrations,
|
||||
clearCache = viewModel::clearCache,
|
||||
backup = viewModel::backup,
|
||||
restore = viewModel::restore
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun BackingUpScreen() {
|
||||
Scaffold { padding ->
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(padding)
|
||||
.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
CircularProgressIndicator()
|
||||
}
|
||||
}
|
||||
|
||||
BackHandler {}
|
||||
}
|
||||
|
||||
@Composable
|
||||
private fun SettingsScreen(
|
||||
uiState: SettingsUIState.Ready,
|
||||
@ -163,6 +142,8 @@ private fun SettingsScreen(
|
||||
if (pickedUri != null) restore(pickedUri)
|
||||
}
|
||||
|
||||
BackHandler(uiState.backupInProgress) {}
|
||||
|
||||
UnittoScreenWithLargeTopBar(
|
||||
title = stringResource(R.string.settings_title),
|
||||
navigationIcon = { NavigateUpButton(navigateUp) },
|
||||
@ -176,11 +157,11 @@ private fun SettingsScreen(
|
||||
onDismissRequest = { showMenu = false }
|
||||
) {
|
||||
DropdownMenuItem(
|
||||
onClick = backup,
|
||||
onClick = { showMenu = false; backup() },
|
||||
text = { Text("Backup") }
|
||||
)
|
||||
DropdownMenuItem(
|
||||
onClick = { launcher.launch(arrayOf(backupMimeType)) },
|
||||
onClick = { showMenu = false; launcher.launch(arrayOf(backupMimeType)) },
|
||||
text = { Text("Restore") }
|
||||
)
|
||||
}
|
||||
@ -266,13 +247,26 @@ private fun SettingsScreen(
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
AnimatedVisibility(visible = uiState.backupInProgress) {
|
||||
Scaffold { padding ->
|
||||
Box(
|
||||
modifier = Modifier
|
||||
.padding(padding)
|
||||
.fillMaxSize(),
|
||||
contentAlignment = Alignment.Center,
|
||||
) {
|
||||
CircularProgressIndicator()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Context.share(uri: Uri) {
|
||||
val shareIntent = Intent().apply {
|
||||
action = Intent.ACTION_SEND
|
||||
putExtra(Intent.EXTRA_STREAM, uri)
|
||||
type = backupMimeType // This is a fucking war crime, it should be text/json
|
||||
type = backupMimeType
|
||||
}
|
||||
|
||||
startActivity(shareIntent)
|
||||
@ -289,6 +283,7 @@ private fun PreviewSettingsScreen() {
|
||||
uiState = SettingsUIState.Ready(
|
||||
enableVibrations = false,
|
||||
cacheSize = 2,
|
||||
backupInProgress = false
|
||||
),
|
||||
navigateUp = {},
|
||||
navControllerAction = {},
|
||||
@ -301,5 +296,16 @@ private fun PreviewSettingsScreen() {
|
||||
@Preview
|
||||
@Composable
|
||||
private fun PreviewBackingUpScreen() {
|
||||
BackingUpScreen()
|
||||
SettingsScreen(
|
||||
uiState = SettingsUIState.Ready(
|
||||
enableVibrations = false,
|
||||
cacheSize = 2,
|
||||
backupInProgress = true
|
||||
),
|
||||
navigateUp = {},
|
||||
navControllerAction = {},
|
||||
updateVibrations = {},
|
||||
clearCache = {},
|
||||
backup = {}
|
||||
)
|
||||
}
|
||||
|
@ -21,10 +21,9 @@ package com.sadellie.unitto.feature.settings
|
||||
internal sealed class SettingsUIState {
|
||||
data object Loading : SettingsUIState()
|
||||
|
||||
data object BackupInProgress : SettingsUIState()
|
||||
|
||||
data class Ready(
|
||||
val enableVibrations: Boolean,
|
||||
val cacheSize: Int,
|
||||
val backupInProgress: Boolean,
|
||||
) : SettingsUIState()
|
||||
}
|
||||
|
@ -49,19 +49,19 @@ internal class SettingsViewModel @Inject constructor(
|
||||
private val _showErrorToast = MutableSharedFlow<Boolean>()
|
||||
val showErrorToast = _showErrorToast.asSharedFlow()
|
||||
|
||||
private val _operation = MutableStateFlow(false)
|
||||
private val _backupInProgress = MutableStateFlow(false)
|
||||
private var backupJob: Job? = null
|
||||
|
||||
val uiState = combine(
|
||||
userPrefsRepository.generalPrefs,
|
||||
currencyRatesDao.size(),
|
||||
_operation,
|
||||
) { prefs, cacheSize, operation ->
|
||||
if (operation) return@combine SettingsUIState.BackupInProgress
|
||||
_backupInProgress,
|
||||
) { prefs, cacheSize, backupInProgress ->
|
||||
|
||||
SettingsUIState.Ready(
|
||||
enableVibrations = prefs.enableVibrations,
|
||||
cacheSize = cacheSize,
|
||||
backupInProgress = backupInProgress
|
||||
)
|
||||
}
|
||||
.stateIn(viewModelScope, SettingsUIState.Loading)
|
||||
@ -69,7 +69,7 @@ internal class SettingsViewModel @Inject constructor(
|
||||
fun backup() {
|
||||
backupJob?.cancel()
|
||||
backupJob = viewModelScope.launch(Dispatchers.IO) {
|
||||
_operation.update { true }
|
||||
_backupInProgress.update { true }
|
||||
try {
|
||||
val backupFileUri = backupManager.backup()
|
||||
_backupFileUri.emit(backupFileUri) // Emit to trigger file share intent
|
||||
@ -78,14 +78,14 @@ internal class SettingsViewModel @Inject constructor(
|
||||
_showErrorToast.emit(true)
|
||||
Log.e(TAG, "$e")
|
||||
}
|
||||
_operation.update { false }
|
||||
_backupInProgress.update { false }
|
||||
}
|
||||
}
|
||||
|
||||
fun restore(uri: Uri) {
|
||||
backupJob?.cancel()
|
||||
backupJob = viewModelScope.launch(Dispatchers.IO) {
|
||||
_operation.update { true }
|
||||
_backupInProgress.update { true }
|
||||
try {
|
||||
backupManager.restore(uri)
|
||||
_showErrorToast.emit(false)
|
||||
@ -93,7 +93,7 @@ internal class SettingsViewModel @Inject constructor(
|
||||
_showErrorToast.emit(true)
|
||||
Log.e(TAG, "$e")
|
||||
}
|
||||
_operation.update { false }
|
||||
_backupInProgress.update { false }
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user