Store remembered tabs in app database instead of preferences (#1541)
## Description Moves storing the remembered tabs from app preferences to the app database. This means deleting the user will remove the remembered tabs and the app preferences file is smaller and faster to load. The remembered tabs are migrated automatically when the app is updated. There are no significant user facing changes in this PR. ### Related issues N/A ### Testing Emulator ## Screenshots N/A ## AI or LLM usage None
This commit is contained in:
parent
a4ee1e5175
commit
b49926f80b
24 changed files with 1379 additions and 599 deletions
|
|
@ -6,7 +6,11 @@ import android.os.Build
|
|||
import androidx.core.content.edit
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.preference.PreferenceManager
|
||||
import com.github.damontecres.wholphin.data.JellyfinServerDao
|
||||
import com.github.damontecres.wholphin.data.RememberedTabDao
|
||||
import com.github.damontecres.wholphin.data.SeerrServerDao
|
||||
import com.github.damontecres.wholphin.data.model.JellyfinUser
|
||||
import com.github.damontecres.wholphin.data.model.RememberedTab
|
||||
import com.github.damontecres.wholphin.preferences.AppPreference
|
||||
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||
import com.github.damontecres.wholphin.preferences.ScreensaverPreference
|
||||
|
|
@ -28,9 +32,12 @@ import com.github.damontecres.wholphin.ui.preferences.subtitle.SubtitleSettings
|
|||
import com.github.damontecres.wholphin.ui.setup.seerr.migrateSeerrUrl
|
||||
import com.github.damontecres.wholphin.util.Version
|
||||
import dagger.hilt.android.qualifiers.ApplicationContext
|
||||
import kotlinx.coroutines.flow.first
|
||||
import org.jellyfin.sdk.model.api.BaseItemKind
|
||||
import org.jellyfin.sdk.model.serializer.toUUIDOrNull
|
||||
import timber.log.Timber
|
||||
import java.io.File
|
||||
import java.util.UUID
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
|
@ -44,6 +51,8 @@ class AppUpgradeHandler
|
|||
@param:ApplicationContext private val context: Context,
|
||||
private val appPreferences: DataStore<AppPreferences>,
|
||||
private val seerrServerDao: SeerrServerDao,
|
||||
private val serverDao: JellyfinServerDao,
|
||||
private val rememberedTabDao: RememberedTabDao,
|
||||
) {
|
||||
val pkgInfo: PackageInfo get() = context.packageManager.getPackageInfo(context.packageName, 0)
|
||||
val currentVersion: Version get() = Version.fromString(pkgInfo.versionName!!)
|
||||
|
|
@ -350,5 +359,55 @@ class AppUpgradeHandler
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (previous.isEqualOrBefore(Version.fromString("1.0.1-2-g0"))) {
|
||||
Timber.i("Starting tab migration")
|
||||
val users = mutableMapOf<UUID, JellyfinUser?>()
|
||||
val tabs =
|
||||
appPreferences.data.first().interfacePreferences.rememberedTabsMap.mapNotNull { (key, tabIndex) ->
|
||||
// "serverId_userId_itemId", itemId can have underscores
|
||||
try {
|
||||
val firstUnderScore = key.indexOf("_").takeIf { it >= 1 }
|
||||
if (firstUnderScore != null) {
|
||||
val secondUnderscore =
|
||||
key
|
||||
.indexOf("_", startIndex = firstUnderScore + 1)
|
||||
.takeIf { it >= 1 }
|
||||
if (secondUnderscore != null) {
|
||||
val serverId = key.substring(0, firstUnderScore).toUUIDOrNull()
|
||||
val userId =
|
||||
key
|
||||
.substring(firstUnderScore + 1, secondUnderscore)
|
||||
.toUUIDOrNull()
|
||||
val itemId = key.substring(secondUnderscore + 1, key.length)
|
||||
if (userId != null && serverId != null) {
|
||||
return@mapNotNull users
|
||||
.getOrPut(userId) {
|
||||
serverDao.getUser(serverId, userId)
|
||||
}?.let {
|
||||
RememberedTab(it.rowId, itemId, tabIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
Timber.w(ex, "Error parsing '%s'", key)
|
||||
}
|
||||
null
|
||||
}
|
||||
Timber.v("Migrating %s tabs", tabs.size)
|
||||
try {
|
||||
if (tabs.isNotEmpty()) {
|
||||
rememberedTabDao.saveAll(tabs)
|
||||
}
|
||||
appPreferences.updateData {
|
||||
it.updateInterfacePreferences {
|
||||
clearRememberedTabs()
|
||||
}
|
||||
}
|
||||
} catch (ex: Exception) {
|
||||
Timber.e(ex, "Error saving migrated tabs")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,34 @@
|
|||
package com.github.damontecres.wholphin.services
|
||||
|
||||
import com.github.damontecres.wholphin.data.RememberedTabDao
|
||||
import com.github.damontecres.wholphin.data.ServerRepository
|
||||
import com.github.damontecres.wholphin.data.model.RememberedTab
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class RememberedTabService
|
||||
@Inject
|
||||
constructor(
|
||||
private val serverRepository: ServerRepository,
|
||||
private val rememberedTabDao: RememberedTabDao,
|
||||
) {
|
||||
suspend fun getRememberedTab(itemId: String): Int? =
|
||||
withContext(Dispatchers.IO) {
|
||||
serverRepository.currentUser?.rowId?.let { userId ->
|
||||
rememberedTabDao.getRememberedTab(userId, itemId)?.index
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun saveRememberedTab(
|
||||
itemId: String,
|
||||
tabIndex: Int,
|
||||
): Unit =
|
||||
withContext(Dispatchers.IO) {
|
||||
serverRepository.currentUser?.rowId?.let { userId ->
|
||||
rememberedTabDao.save(RememberedTab(userId, itemId, tabIndex))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,18 +1,12 @@
|
|||
package com.github.damontecres.wholphin.services.hilt
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.work.WorkManager
|
||||
import com.github.damontecres.wholphin.BuildConfig
|
||||
import com.github.damontecres.wholphin.R
|
||||
import com.github.damontecres.wholphin.data.ServerRepository
|
||||
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||
import com.github.damontecres.wholphin.preferences.UserPreferences
|
||||
import com.github.damontecres.wholphin.preferences.updateInterfacePreferences
|
||||
import com.github.damontecres.wholphin.services.SeerrApi
|
||||
import com.github.damontecres.wholphin.util.CoroutineContextApiClientFactory
|
||||
import com.github.damontecres.wholphin.util.ExceptionHandler
|
||||
import com.github.damontecres.wholphin.util.RememberTabManager
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import dagger.hilt.InstallIn
|
||||
|
|
@ -22,7 +16,6 @@ import kotlinx.coroutines.CoroutineDispatcher
|
|||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import okhttp3.OkHttpClient
|
||||
import org.jellyfin.sdk.Jellyfin
|
||||
import org.jellyfin.sdk.android.androidDevice
|
||||
|
|
@ -160,51 +153,6 @@ object AppModule {
|
|||
@Singleton
|
||||
fun apiClient(jellyfin: Jellyfin) = jellyfin.createApi()
|
||||
|
||||
/**
|
||||
* Implementation of [RememberTabManager] which remembers by server, user, & item
|
||||
*/
|
||||
@Provides
|
||||
@Singleton
|
||||
fun rememberTabManager(
|
||||
serverRepository: ServerRepository,
|
||||
appPreference: DataStore<AppPreferences>,
|
||||
@IoCoroutineScope scope: CoroutineScope,
|
||||
) = object : RememberTabManager {
|
||||
fun key(itemId: String): String =
|
||||
serverRepository.current.value.let {
|
||||
"${it?.server?.id}_${it?.user?.id}_$itemId"
|
||||
}
|
||||
|
||||
override fun getRememberedTab(
|
||||
preferences: UserPreferences,
|
||||
itemId: String,
|
||||
defaultTab: Int,
|
||||
): Int {
|
||||
if (preferences.appPreferences.interfacePreferences.rememberSelectedTab) {
|
||||
return preferences.appPreferences.interfacePreferences
|
||||
.getRememberedTabsOrDefault(key(itemId), defaultTab)
|
||||
} else {
|
||||
return defaultTab
|
||||
}
|
||||
}
|
||||
|
||||
override fun saveRememberedTab(
|
||||
preferences: UserPreferences,
|
||||
itemId: String,
|
||||
tabIndex: Int,
|
||||
) {
|
||||
if (preferences.appPreferences.interfacePreferences.rememberSelectedTab) {
|
||||
scope.launch(ExceptionHandler()) {
|
||||
appPreference.updateData {
|
||||
it.updateInterfacePreferences {
|
||||
putRememberedTabs(key(itemId), tabIndex)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
@IoDispatcher
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import com.github.damontecres.wholphin.data.LibraryDisplayInfoDao
|
|||
import com.github.damontecres.wholphin.data.Migrations
|
||||
import com.github.damontecres.wholphin.data.PlaybackEffectDao
|
||||
import com.github.damontecres.wholphin.data.PlaybackLanguageChoiceDao
|
||||
import com.github.damontecres.wholphin.data.RememberedTabDao
|
||||
import com.github.damontecres.wholphin.data.SeerrServerDao
|
||||
import com.github.damontecres.wholphin.data.ServerPreferencesDao
|
||||
import com.github.damontecres.wholphin.preferences.AppPreferences
|
||||
|
|
@ -74,6 +75,10 @@ object DatabaseModule {
|
|||
@Singleton
|
||||
fun playbackEffectDao(db: AppDatabase): PlaybackEffectDao = db.playbackEffectDao()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun rememberedTabDao(db: AppDatabase): RememberedTabDao = db.rememberedTabDao()
|
||||
|
||||
@Provides
|
||||
@Singleton
|
||||
fun userPreferencesDataStore(
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue