Refactoring to expose current configuration

This commit is contained in:
Damontecres 2026-01-24 18:27:58 -05:00
parent ee8a4ac0ac
commit a174d981a8
No known key found for this signature in database
5 changed files with 312 additions and 269 deletions

View file

@ -18,7 +18,6 @@ import kotlinx.coroutines.withContext
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.jellyfin.sdk.Jellyfin import org.jellyfin.sdk.Jellyfin
import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.extensions.displayPreferencesApi
import org.jellyfin.sdk.api.client.extensions.systemApi import org.jellyfin.sdk.api.client.extensions.systemApi
import org.jellyfin.sdk.api.client.extensions.userApi import org.jellyfin.sdk.api.client.extensions.userApi
import org.jellyfin.sdk.model.api.AuthenticationResult import org.jellyfin.sdk.model.api.AuthenticationResult
@ -103,27 +102,6 @@ class ServerRepository
currentUserId = updatedUser.id.toServerString() currentUserId = updatedUser.id.toServerString()
}.build() }.build()
} }
val settings =
apiClient.displayPreferencesApi
.getDisplayPreferences(
displayPreferencesId = "settings",
userId = user.id,
client = "wholphin",
).content
val newSettings =
settings.copy(
customPrefs =
settings.customPrefs.toMutableMap().apply {
put("test_key", "test_value")
},
)
apiClient.displayPreferencesApi.updateDisplayPreferences(
displayPreferencesId = "settings",
userId = user.id,
client = "wholphin",
data = newSettings,
)
Timber.v("settings=$settings")
withContext(Dispatchers.Main) { withContext(Dispatchers.Main) {
_current.value = CurrentUser(updatedServer, updatedUser) _current.value = CurrentUser(updatedServer, updatedUser)
_currentUserDto.value = userDto _currentUserDto.value = userDto

View file

@ -144,9 +144,21 @@ data class HomeRowConfigDisplay(
@Serializable @Serializable
@SerialName("HomePageSettings") @SerialName("HomePageSettings")
data class HomePageSettings( data class HomePageSettings(
val version: Int = 1,
val rows: List<HomeRowConfig>, val rows: List<HomeRowConfig>,
) val version: Int = 1,
) {
companion object {
val EMPTY = HomePageSettings(listOf())
}
}
data class HomePageResolvedSettings(
val rows: List<HomeRowConfigDisplay>,
) {
companion object {
val EMPTY = HomePageResolvedSettings(listOf())
}
}
@Serializable @Serializable
data class HomeRowViewOptions( data class HomeRowViewOptions(

View file

@ -2,17 +2,28 @@ package com.github.damontecres.wholphin.services
import android.content.Context import android.content.Context
import com.github.damontecres.wholphin.R import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.ServerRepository import com.github.damontecres.wholphin.data.NavDrawerItemRepository
import com.github.damontecres.wholphin.data.model.HomePageResolvedSettings
import com.github.damontecres.wholphin.data.model.HomePageSettings import com.github.damontecres.wholphin.data.model.HomePageSettings
import com.github.damontecres.wholphin.data.model.HomeRowConfig
import com.github.damontecres.wholphin.data.model.HomeRowConfigDisplay
import com.github.damontecres.wholphin.data.model.HomeRowViewOptions
import com.github.damontecres.wholphin.ui.main.settings.Library
import com.github.damontecres.wholphin.ui.nav.ServerNavDrawerItem
import com.github.damontecres.wholphin.ui.toServerString import com.github.damontecres.wholphin.ui.toServerString
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.serialization.ExperimentalSerializationApi import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream import kotlinx.serialization.json.decodeFromStream
import kotlinx.serialization.json.encodeToStream import kotlinx.serialization.json.encodeToStream
import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.extensions.displayPreferencesApi import org.jellyfin.sdk.api.client.extensions.displayPreferencesApi
import org.jellyfin.sdk.api.client.extensions.userLibraryApi
import org.jellyfin.sdk.model.UUID import org.jellyfin.sdk.model.UUID
import org.jellyfin.sdk.model.serializer.toUUID
import timber.log.Timber
import java.io.File import java.io.File
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -23,7 +34,8 @@ class HomeSettingsService
constructor( constructor(
@param:ApplicationContext private val context: Context, @param:ApplicationContext private val context: Context,
private val api: ApiClient, private val api: ApiClient,
private val serverRepository: ServerRepository, private val userPreferencesService: UserPreferencesService,
private val navDrawerItemRepository: NavDrawerItemRepository,
) { ) {
val jsonParser = val jsonParser =
Json { Json {
@ -31,32 +43,35 @@ class HomeSettingsService
ignoreUnknownKeys = true ignoreUnknownKeys = true
} }
val currentSettings = MutableStateFlow(HomePageResolvedSettings.EMPTY)
suspend fun saveToServer( suspend fun saveToServer(
userId: UUID,
settings: HomePageSettings, settings: HomePageSettings,
displayPreferencesId: String = DISPLAY_PREF_ID, displayPreferencesId: String = DISPLAY_PREF_ID,
) { ) {
serverRepository.currentUser.value?.let { user -> val current = getDisplayPreferences(userId, DISPLAY_PREF_ID)
val current = getDisplayPreferences(user.id, DISPLAY_PREF_ID) val customPrefs =
val customPrefs = current.customPrefs.toMutableMap().apply {
current.customPrefs.toMutableMap().apply { put(CUSTOM_PREF_ID, jsonParser.encodeToString(settings))
put(CUSTOM_PREF_ID, jsonParser.encodeToString(settings)) }
} api.displayPreferencesApi.updateDisplayPreferences(
api.displayPreferencesApi.updateDisplayPreferences( displayPreferencesId = displayPreferencesId,
displayPreferencesId = displayPreferencesId, userId = userId,
userId = user.id, client = context.getString(R.string.app_name),
client = context.getString(R.string.app_name), data = current.copy(customPrefs = customPrefs),
data = current.copy(customPrefs = customPrefs), )
)
}
} }
suspend fun loadFromServer(displayPreferencesId: String = DISPLAY_PREF_ID): HomePageSettings? = suspend fun loadFromServer(
serverRepository.currentUser.value?.let { user -> userId: UUID,
val current = getDisplayPreferences(user.id, displayPreferencesId) displayPreferencesId: String = DISPLAY_PREF_ID,
current.customPrefs[DISPLAY_PREF_ID]?.let { ): HomePageSettings? {
Json.decodeFromString<HomePageSettings>(it) val current = getDisplayPreferences(userId, displayPreferencesId)
} return current.customPrefs[DISPLAY_PREF_ID]?.let {
Json.decodeFromString<HomePageSettings>(it)
} }
}
private suspend fun getDisplayPreferences( private suspend fun getDisplayPreferences(
userId: UUID, userId: UUID,
@ -71,27 +86,202 @@ class HomeSettingsService
private fun filename(userId: UUID) = "${CUSTOM_PREF_ID}_${userId.toServerString()}.json" private fun filename(userId: UUID) = "${CUSTOM_PREF_ID}_${userId.toServerString()}.json"
@OptIn(ExperimentalSerializationApi::class) @OptIn(ExperimentalSerializationApi::class)
suspend fun saveToLocal(settings: HomePageSettings) { suspend fun saveToLocal(
serverRepository.currentUser.value?.let { user -> userId: UUID,
val dir = File(context.filesDir, CUSTOM_PREF_ID) settings: HomePageSettings,
dir.mkdirs() ) {
File(dir, filename(user.id)).outputStream().use { val dir = File(context.filesDir, CUSTOM_PREF_ID)
jsonParser.encodeToStream(settings, it) dir.mkdirs()
} File(dir, filename(userId)).outputStream().use {
jsonParser.encodeToStream(settings, it)
} }
} }
@OptIn(ExperimentalSerializationApi::class) @OptIn(ExperimentalSerializationApi::class)
suspend fun loadFromLocal(): HomePageSettings? = suspend fun loadFromLocal(userId: UUID): HomePageSettings? {
serverRepository.currentUser.value?.let { user -> val dir = File(context.filesDir, CUSTOM_PREF_ID)
val dir = File(context.filesDir, CUSTOM_PREF_ID) val file = File(dir, filename(userId))
val file = File(dir, filename(user.id)) return if (file.exists()) {
if (file.exists()) { file.inputStream().use {
file.inputStream().use { jsonParser.decodeFromStream<HomePageSettings>(it)
jsonParser.decodeFromStream<HomePageSettings>(it) }
} } else {
null
}
}
suspend fun updateCurrent(userId: UUID) {
Timber.v("Getting setting for %s", userId)
// User local then server/remote otherwise create a default
val settings = loadFromLocal(userId) ?: loadFromServer(userId)
val resolvedSettings =
if (settings != null) {
Timber.v("Found settings")
// Resolve
val resolvedRows = settings.rows.map { convert(it) }
HomePageResolvedSettings(resolvedRows)
} else { } else {
null createDefault(userId)
}
currentSettings.update { resolvedSettings }
}
suspend fun createDefault(userId: UUID): HomePageResolvedSettings {
Timber.v("Creating default settings")
val navDrawerItems = navDrawerItemRepository.getNavDrawerItems()
val libraries =
navDrawerItems
.filter { it is ServerNavDrawerItem }
.map {
it as ServerNavDrawerItem
Library(it.itemId, it.name, it.type)
}
val prefs =
userPreferencesService.getCurrent().appPreferences.homePagePreferences
val includedIds =
navDrawerItemRepository
.getFilteredNavDrawerItems(navDrawerItems)
.filter { it is ServerNavDrawerItem }
.mapIndexed { index, it ->
val id = (it as ServerNavDrawerItem).itemId
val name = libraries.firstOrNull { it.itemId == id }?.name
val title =
name?.let { context.getString(R.string.recently_added_in, it) }
?: context.getString(R.string.recently_added)
HomeRowConfigDisplay(
title,
HomeRowConfig.RecentlyAdded(
index,
id,
HomeRowViewOptions(),
),
)
}
val continueWatchingRows =
if (prefs.combineContinueNext) {
listOf(
HomeRowConfigDisplay(
context.getString(R.string.combine_continue_next),
HomeRowConfig.ContinueWatchingCombined(
includedIds.size + 1,
HomeRowViewOptions(),
),
),
)
} else {
listOf(
HomeRowConfigDisplay(
context.getString(R.string.continue_watching),
HomeRowConfig.ContinueWatching(
includedIds.size + 1,
HomeRowViewOptions(),
),
),
HomeRowConfigDisplay(
context.getString(R.string.next_up),
HomeRowConfig.NextUp(
includedIds.size + 2,
HomeRowViewOptions(),
),
),
)
}
val rowConfig =
continueWatchingRows + includedIds +
// TODO remove after testing
listOf(
HomeRowConfigDisplay(
"Collection",
HomeRowConfig.ByParent(
id = 100,
parentId = "34ab6fd1f51c41bb014981f2e334f465".toUUID(),
recursive = true,
viewOptions = HomeRowViewOptions(),
),
),
HomeRowConfigDisplay(
"Playlist",
HomeRowConfig.ByParent(
id = 101,
parentId = "f94be36e9836127a0bccfc7843b19e5b".toUUID(),
recursive = true,
viewOptions = HomeRowViewOptions(),
),
),
)
return HomePageResolvedSettings(rowConfig)
}
suspend fun convert(config: HomeRowConfig): HomeRowConfigDisplay =
when (config) {
is HomeRowConfig.ByParent -> {
val name =
api.userLibraryApi
.getItem(itemId = config.parentId)
.content.name ?: ""
HomeRowConfigDisplay(
name,
config,
)
}
is HomeRowConfig.ContinueWatching -> {
HomeRowConfigDisplay(
context.getString(R.string.continue_watching),
config,
)
}
is HomeRowConfig.ContinueWatchingCombined -> {
HomeRowConfigDisplay(
context.getString(R.string.combine_continue_next),
config,
)
}
is HomeRowConfig.Genres -> {
val name =
api.userLibraryApi
.getItem(itemId = config.parentId)
.content.name ?: ""
HomeRowConfigDisplay(
context.getString(R.string.genres_in, name),
config,
)
}
is HomeRowConfig.GetItems -> {
HomeRowConfigDisplay(config.name, config)
}
is HomeRowConfig.NextUp -> {
HomeRowConfigDisplay(
context.getString(R.string.next_up),
config,
)
}
is HomeRowConfig.RecentlyAdded -> {
val name =
api.userLibraryApi
.getItem(itemId = config.parentId)
.content.name ?: ""
HomeRowConfigDisplay(
context.getString(R.string.recently_added_in, name),
config,
)
}
is HomeRowConfig.RecentlyReleased -> {
val name =
api.userLibraryApi
.getItem(itemId = config.parentId)
.content.name ?: ""
HomeRowConfigDisplay(
context.getString(R.string.recently_released_in, name),
config,
)
} }
} }

View file

@ -11,6 +11,7 @@ import com.github.damontecres.wholphin.api.seerr.model.PublicSettings
import com.github.damontecres.wholphin.api.seerr.model.User import com.github.damontecres.wholphin.api.seerr.model.User
import com.github.damontecres.wholphin.data.SeerrServerDao import com.github.damontecres.wholphin.data.SeerrServerDao
import com.github.damontecres.wholphin.data.ServerRepository import com.github.damontecres.wholphin.data.ServerRepository
import com.github.damontecres.wholphin.data.model.HomePageResolvedSettings
import com.github.damontecres.wholphin.data.model.SeerrAuthMethod import com.github.damontecres.wholphin.data.model.SeerrAuthMethod
import com.github.damontecres.wholphin.data.model.SeerrPermission import com.github.damontecres.wholphin.data.model.SeerrPermission
import com.github.damontecres.wholphin.data.model.SeerrServer import com.github.damontecres.wholphin.data.model.SeerrServer
@ -213,6 +214,7 @@ class UserSwitchListener
private val seerrServerRepository: SeerrServerRepository, private val seerrServerRepository: SeerrServerRepository,
private val seerrServerDao: SeerrServerDao, private val seerrServerDao: SeerrServerDao,
private val seerrApi: SeerrApi, private val seerrApi: SeerrApi,
private val homeSettingsService: HomeSettingsService,
) { ) {
init { init {
context as AppCompatActivity context as AppCompatActivity
@ -220,41 +222,58 @@ class UserSwitchListener
serverRepository.currentUser.asFlow().collect { user -> serverRepository.currentUser.asFlow().collect { user ->
Timber.d("New user") Timber.d("New user")
seerrServerRepository.clear() seerrServerRepository.clear()
homeSettingsService.currentSettings.update { HomePageResolvedSettings.EMPTY }
if (user != null) { if (user != null) {
seerrServerDao // Check for home settings
.getUsersByJellyfinUser(user.rowId) launchIO {
.firstOrNull() homeSettingsService.updateCurrent(user.id)
?.let { seerrUser -> }
val server = seerrServerDao.getServer(seerrUser.serverId)?.server // Check for seerr server
if (server != null) { launchIO {
Timber.i("Found a seerr user & server") seerrServerDao
seerrApi.update(server.url, seerrUser.credential) .getUsersByJellyfinUser(user.rowId)
val userConfig = .firstOrNull()
if (seerrUser.authMethod != SeerrAuthMethod.API_KEY) { ?.let { seerrUser ->
try { val server =
login( seerrServerDao.getServer(seerrUser.serverId)?.server
seerrApi.api, if (server != null) {
seerrUser.authMethod, Timber.i("Found a seerr user & server")
seerrUser.username, seerrApi.update(server.url, seerrUser.credential)
seerrUser.password, val userConfig =
) if (seerrUser.authMethod != SeerrAuthMethod.API_KEY) {
} catch (ex: Exception) { try {
Timber.w(ex, "Error logging into %s", server.url) login(
seerrServerRepository.clear() seerrApi.api,
return@let seerrUser.authMethod,
seerrUser.username,
seerrUser.password,
)
} catch (ex: Exception) {
Timber.w(
ex,
"Error logging into %s",
server.url,
)
seerrServerRepository.clear()
return@let
}
} else {
try {
seerrApi.api.usersApi.authMeGet()
} catch (ex: Exception) {
Timber.w(
ex,
"Error logging into %s",
server.url,
)
seerrServerRepository.clear()
return@let
}
} }
} else { seerrServerRepository.set(server, seerrUser, userConfig)
try { }
seerrApi.api.usersApi.authMeGet()
} catch (ex: Exception) {
Timber.w(ex, "Error logging into %s", server.url)
seerrServerRepository.clear()
return@let
}
}
seerrServerRepository.set(server, seerrUser, userConfig)
} }
} }
} }
} }
} }

View file

@ -9,6 +9,7 @@ import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.data.NavDrawerItemRepository import com.github.damontecres.wholphin.data.NavDrawerItemRepository
import com.github.damontecres.wholphin.data.ServerRepository import com.github.damontecres.wholphin.data.ServerRepository
import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.data.model.BaseItem
import com.github.damontecres.wholphin.data.model.HomePageResolvedSettings
import com.github.damontecres.wholphin.data.model.HomePageSettings import com.github.damontecres.wholphin.data.model.HomePageSettings
import com.github.damontecres.wholphin.data.model.HomeRowConfig import com.github.damontecres.wholphin.data.model.HomeRowConfig
import com.github.damontecres.wholphin.data.model.HomeRowConfigDisplay import com.github.damontecres.wholphin.data.model.HomeRowConfigDisplay
@ -33,6 +34,7 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.qualifiers.ApplicationContext import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.update import kotlinx.coroutines.flow.update
import org.jellyfin.sdk.api.client.ApiClient import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.extensions.userLibraryApi import org.jellyfin.sdk.api.client.extensions.userLibraryApi
@ -43,7 +45,6 @@ import org.jellyfin.sdk.model.api.UserDto
import org.jellyfin.sdk.model.api.request.GetGenresRequest import org.jellyfin.sdk.model.api.request.GetGenresRequest
import org.jellyfin.sdk.model.api.request.GetItemsRequest import org.jellyfin.sdk.model.api.request.GetItemsRequest
import org.jellyfin.sdk.model.api.request.GetLatestMediaRequest import org.jellyfin.sdk.model.api.request.GetLatestMediaRequest
import org.jellyfin.sdk.model.serializer.toUUID
import timber.log.Timber import timber.log.Timber
import java.util.UUID import java.util.UUID
import javax.inject.Inject import javax.inject.Inject
@ -77,178 +78,19 @@ class HomeSettingsViewModel
it as ServerNavDrawerItem it as ServerNavDrawerItem
Library(it.itemId, it.name, it.type) Library(it.itemId, it.name, it.type)
} }
_state.update { it.copy(libraries = libraries) } val currentSettings =
homeSettingsService.currentSettings.first { it != HomePageResolvedSettings.EMPTY }
val localSettings = Timber.v("currentSettings=%s", currentSettings)
try { _state.update {
homeSettingsService.loadFromLocal() it.copy(
} catch (ex: Exception) { libraries = libraries,
Timber.e(ex) rows = currentSettings.rows,
showToast(context, "Error loading settings: ${ex.localizedMessage}") )
null
}
if (localSettings != null) {
val displays = localSettings.rows.map { convert(it) }
_state.update {
it.copy(rows = displays)
}
} else {
// Or create default
val prefs =
userPreferencesService.getCurrent().appPreferences.homePagePreferences
val includedIds =
navDrawerItemRepository
.getFilteredNavDrawerItems(navDrawerItems)
.filter { it is ServerNavDrawerItem }
.mapIndexed { index, it ->
val id = (it as ServerNavDrawerItem).itemId
val name = libraries.firstOrNull { it.itemId == id }?.name
val title =
name?.let { context.getString(R.string.recently_added_in, it) }
?: context.getString(R.string.recently_added)
HomeRowConfigDisplay(
title,
HomeRowConfig.RecentlyAdded(
index,
id,
HomeRowViewOptions(),
),
)
}
val continueWatchingRows =
if (prefs.combineContinueNext) {
listOf(
HomeRowConfigDisplay(
context.getString(R.string.combine_continue_next),
HomeRowConfig.ContinueWatchingCombined(
includedIds.size + 1,
HomeRowViewOptions(),
),
),
)
} else {
listOf(
HomeRowConfigDisplay(
context.getString(R.string.continue_watching),
HomeRowConfig.ContinueWatching(
includedIds.size + 1,
HomeRowViewOptions(),
),
),
HomeRowConfigDisplay(
context.getString(R.string.next_up),
HomeRowConfig.NextUp(
includedIds.size + 2,
HomeRowViewOptions(),
),
),
)
}
val rowConfig =
continueWatchingRows + includedIds +
// TODO remove after testing
listOf(
HomeRowConfigDisplay(
"Collection",
HomeRowConfig.ByParent(
id = 100,
parentId = "34ab6fd1f51c41bb014981f2e334f465".toUUID(),
recursive = true,
viewOptions = HomeRowViewOptions(),
),
),
HomeRowConfigDisplay(
"Playlist",
HomeRowConfig.ByParent(
id = 101,
parentId = "f94be36e9836127a0bccfc7843b19e5b".toUUID(),
recursive = true,
viewOptions = HomeRowViewOptions(),
),
),
)
_state.update {
it.copy(rows = rowConfig)
}
} }
fetchRowData() fetchRowData()
} }
} }
private suspend fun convert(config: HomeRowConfig): HomeRowConfigDisplay =
when (config) {
is HomeRowConfig.ByParent -> {
val name =
api.userLibraryApi
.getItem(itemId = config.parentId)
.content.name ?: ""
HomeRowConfigDisplay(
name,
config,
)
}
is HomeRowConfig.ContinueWatching -> {
HomeRowConfigDisplay(
context.getString(R.string.continue_watching),
config,
)
}
is HomeRowConfig.ContinueWatchingCombined -> {
HomeRowConfigDisplay(
context.getString(R.string.combine_continue_next),
config,
)
}
is HomeRowConfig.Genres -> {
val name =
api.userLibraryApi
.getItem(itemId = config.parentId)
.content.name ?: ""
HomeRowConfigDisplay(
context.getString(R.string.genres_in, name),
config,
)
}
is HomeRowConfig.GetItems -> {
HomeRowConfigDisplay(config.name, config)
}
is HomeRowConfig.NextUp -> {
HomeRowConfigDisplay(
context.getString(R.string.next_up),
config,
)
}
is HomeRowConfig.RecentlyAdded -> {
val name =
api.userLibraryApi
.getItem(itemId = config.parentId)
.content.name ?: ""
HomeRowConfigDisplay(
context.getString(R.string.recently_added_in, name),
config,
)
}
is HomeRowConfig.RecentlyReleased -> {
val name =
api.userLibraryApi
.getItem(itemId = config.parentId)
.content.name ?: ""
HomeRowConfigDisplay(
context.getString(R.string.recently_released_in, name),
config,
)
}
}
fun updateBackdrop(item: BaseItem) { fun updateBackdrop(item: BaseItem) {
viewModelScope.launchIO { viewModelScope.launchIO {
backdropService.submit(item) backdropService.submit(item)
@ -709,14 +551,16 @@ class HomeSettingsViewModel
fun saveToLocal() { fun saveToLocal() {
viewModelScope.launchIO { viewModelScope.launchIO {
val rows = state.value.rows.map { it.config } serverRepository.currentUser.value?.let { user ->
val settings = HomePageSettings(rows = rows) val rows = state.value.rows.map { it.config }
try { val settings = HomePageSettings(rows = rows)
homeSettingsService.saveToLocal(settings) try {
showToast(context, context.getString(R.string.save), Toast.LENGTH_SHORT) homeSettingsService.saveToLocal(user.id, settings)
} catch (ex: Exception) { showToast(context, context.getString(R.string.save), Toast.LENGTH_SHORT)
Timber.e(ex) } catch (ex: Exception) {
showToast(context, "Error saving: ${ex.localizedMessage}") Timber.e(ex)
showToast(context, "Error saving: ${ex.localizedMessage}")
}
} }
} }
} }