diff --git a/app/schemas/com.github.damontecres.wholphin.data.AppDatabase/6.json b/app/schemas/com.github.damontecres.wholphin.data.AppDatabase/6.json new file mode 100644 index 00000000..40c938fb --- /dev/null +++ b/app/schemas/com.github.damontecres.wholphin.data.AppDatabase/6.json @@ -0,0 +1,303 @@ +{ + "formatVersion": 1, + "database": { + "version": 6, + "identityHash": "24390d64259f19e0e67ecfb827b974fb", + "entities": [ + { + "tableName": "servers", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` TEXT NOT NULL, `name` TEXT, `url` TEXT NOT NULL, PRIMARY KEY(`id`))", + "fields": [ + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT" + }, + { + "fieldPath": "url", + "columnName": "url", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "id" + ] + } + }, + { + "tableName": "users", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`rowId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `id` TEXT NOT NULL, `name` TEXT, `serverId` TEXT NOT NULL, `accessToken` TEXT, FOREIGN KEY(`serverId`) REFERENCES `servers`(`id`) ON UPDATE NO ACTION ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "rowId", + "columnName": "rowId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "id", + "columnName": "id", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "name", + "columnName": "name", + "affinity": "TEXT" + }, + { + "fieldPath": "serverId", + "columnName": "serverId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "accessToken", + "columnName": "accessToken", + "affinity": "TEXT" + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "rowId" + ] + }, + "indices": [ + { + "name": "index_users_id_serverId", + "unique": true, + "columnNames": [ + "id", + "serverId" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_users_id_serverId` ON `${TABLE_NAME}` (`id`, `serverId`)" + }, + { + "name": "index_users_id", + "unique": false, + "columnNames": [ + "id" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_users_id` ON `${TABLE_NAME}` (`id`)" + }, + { + "name": "index_users_serverId", + "unique": false, + "columnNames": [ + "serverId" + ], + "orders": [], + "createSql": "CREATE INDEX IF NOT EXISTS `index_users_serverId` ON `${TABLE_NAME}` (`serverId`)" + } + ], + "foreignKeys": [ + { + "table": "servers", + "onDelete": "CASCADE", + "onUpdate": "NO ACTION", + "columns": [ + "serverId" + ], + "referencedColumns": [ + "id" + ] + } + ] + }, + { + "tableName": "ItemPlayback", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`rowId` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `userId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `sourceId` TEXT, `audioIndex` INTEGER NOT NULL, `subtitleIndex` INTEGER NOT NULL, FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "rowId", + "columnName": "rowId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "itemId", + "columnName": "itemId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sourceId", + "columnName": "sourceId", + "affinity": "TEXT" + }, + { + "fieldPath": "audioIndex", + "columnName": "audioIndex", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "subtitleIndex", + "columnName": "subtitleIndex", + "affinity": "INTEGER", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": true, + "columnNames": [ + "rowId" + ] + }, + "indices": [ + { + "name": "index_ItemPlayback_userId_itemId", + "unique": true, + "columnNames": [ + "userId", + "itemId" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_ItemPlayback_userId_itemId` ON `${TABLE_NAME}` (`userId`, `itemId`)" + } + ], + "foreignKeys": [ + { + "table": "users", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "userId" + ], + "referencedColumns": [ + "rowId" + ] + } + ] + }, + { + "tableName": "NavDrawerPinnedItem", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `type` TEXT NOT NULL, PRIMARY KEY(`userId`, `itemId`), FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "itemId", + "columnName": "itemId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "type", + "columnName": "type", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "userId", + "itemId" + ] + }, + "foreignKeys": [ + { + "table": "users", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "userId" + ], + "referencedColumns": [ + "rowId" + ] + } + ] + }, + { + "tableName": "LibraryDisplayInfo", + "createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`userId` INTEGER NOT NULL, `itemId` TEXT NOT NULL, `sort` TEXT NOT NULL, `direction` TEXT NOT NULL, PRIMARY KEY(`userId`, `itemId`), FOREIGN KEY(`userId`) REFERENCES `users`(`rowId`) ON UPDATE CASCADE ON DELETE CASCADE )", + "fields": [ + { + "fieldPath": "userId", + "columnName": "userId", + "affinity": "INTEGER", + "notNull": true + }, + { + "fieldPath": "itemId", + "columnName": "itemId", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "sort", + "columnName": "sort", + "affinity": "TEXT", + "notNull": true + }, + { + "fieldPath": "direction", + "columnName": "direction", + "affinity": "TEXT", + "notNull": true + } + ], + "primaryKey": { + "autoGenerate": false, + "columnNames": [ + "userId", + "itemId" + ] + }, + "indices": [ + { + "name": "index_LibraryDisplayInfo_userId_itemId", + "unique": true, + "columnNames": [ + "userId", + "itemId" + ], + "orders": [], + "createSql": "CREATE UNIQUE INDEX IF NOT EXISTS `index_LibraryDisplayInfo_userId_itemId` ON `${TABLE_NAME}` (`userId`, `itemId`)" + } + ], + "foreignKeys": [ + { + "table": "users", + "onDelete": "CASCADE", + "onUpdate": "CASCADE", + "columns": [ + "userId" + ], + "referencedColumns": [ + "rowId" + ] + } + ] + } + ], + "setupQueries": [ + "CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)", + "INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '24390d64259f19e0e67ecfb827b974fb')" + ] + } +} diff --git a/app/src/main/java/com/github/damontecres/wholphin/data/AppDatabase.kt b/app/src/main/java/com/github/damontecres/wholphin/data/AppDatabase.kt index ad9fb3a7..305a3146 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/data/AppDatabase.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/data/AppDatabase.kt @@ -10,17 +10,21 @@ import androidx.sqlite.db.SupportSQLiteDatabase import com.github.damontecres.wholphin.data.model.ItemPlayback import com.github.damontecres.wholphin.data.model.JellyfinServer import com.github.damontecres.wholphin.data.model.JellyfinUser +import com.github.damontecres.wholphin.data.model.LibraryDisplayInfo import com.github.damontecres.wholphin.data.model.NavDrawerPinnedItem +import org.jellyfin.sdk.model.api.ItemSortBy +import org.jellyfin.sdk.model.api.SortOrder import org.jellyfin.sdk.model.serializer.toUUID import java.util.UUID @Database( - entities = [JellyfinServer::class, JellyfinUser::class, ItemPlayback::class, NavDrawerPinnedItem::class], - version = 5, + entities = [JellyfinServer::class, JellyfinUser::class, ItemPlayback::class, NavDrawerPinnedItem::class, LibraryDisplayInfo::class], + version = 6, exportSchema = true, autoMigrations = [ AutoMigration(3, 4), AutoMigration(4, 5), + AutoMigration(5, 6), ], ) @TypeConverters(Converters::class) @@ -30,6 +34,8 @@ abstract class AppDatabase : RoomDatabase() { abstract fun itemPlaybackDao(): ItemPlaybackDao abstract fun serverPreferencesDao(): ServerPreferencesDao + + abstract fun libraryDisplayInfoDao(): LibraryDisplayInfoDao } class Converters { @@ -38,6 +44,18 @@ class Converters { @TypeConverter fun convertToUUID(str: String): UUID = str.toUUID() + + @TypeConverter + fun convertItemSortBy(sort: ItemSortBy): String = sort.serialName + + @TypeConverter + fun convertItemSortBy(sort: String): ItemSortBy? = ItemSortBy.fromNameOrNull(sort) + + @TypeConverter + fun convertSortOrder(sort: SortOrder): String = sort.serialName + + @TypeConverter + fun convertSortOrder(sort: String): SortOrder? = SortOrder.fromNameOrNull(sort) } object Migrations { diff --git a/app/src/main/java/com/github/damontecres/wholphin/data/LibraryDisplayInfoDao.kt b/app/src/main/java/com/github/damontecres/wholphin/data/LibraryDisplayInfoDao.kt new file mode 100644 index 00000000..8e1b1ef2 --- /dev/null +++ b/app/src/main/java/com/github/damontecres/wholphin/data/LibraryDisplayInfoDao.kt @@ -0,0 +1,29 @@ +package com.github.damontecres.wholphin.data + +import androidx.room.Dao +import androidx.room.Insert +import androidx.room.OnConflictStrategy +import androidx.room.Query +import com.github.damontecres.wholphin.data.model.JellyfinUser +import com.github.damontecres.wholphin.data.model.LibraryDisplayInfo +import java.util.UUID + +@Dao +interface LibraryDisplayInfoDao { + fun getItem( + user: JellyfinUser, + itemId: UUID, + ): LibraryDisplayInfo? = getItem(user.rowId, itemId) + + @Query("SELECT * from LibraryDisplayInfo WHERE userId=:userId AND itemId=:itemId") + fun getItem( + userId: Int, + itemId: UUID, + ): LibraryDisplayInfo? + + @Insert(onConflict = OnConflictStrategy.REPLACE) + fun saveItem(item: LibraryDisplayInfo): Long + + @Query("SELECT * from LibraryDisplayInfo WHERE userId=:userId") + fun getItems(userId: Int): List +} diff --git a/app/src/main/java/com/github/damontecres/wholphin/data/model/LibraryDisplayInfo.kt b/app/src/main/java/com/github/damontecres/wholphin/data/model/LibraryDisplayInfo.kt new file mode 100644 index 00000000..d428f521 --- /dev/null +++ b/app/src/main/java/com/github/damontecres/wholphin/data/model/LibraryDisplayInfo.kt @@ -0,0 +1,40 @@ +@file:UseSerializers(UUIDSerializer::class) + +package com.github.damontecres.wholphin.data.model + +import androidx.room.Entity +import androidx.room.ForeignKey +import androidx.room.Ignore +import androidx.room.Index +import com.github.damontecres.wholphin.ui.data.SortAndDirection +import kotlinx.serialization.Serializable +import kotlinx.serialization.Transient +import kotlinx.serialization.UseSerializers +import org.jellyfin.sdk.model.api.ItemSortBy +import org.jellyfin.sdk.model.api.SortOrder +import org.jellyfin.sdk.model.serializer.UUIDSerializer +import java.util.UUID + +@Entity( + foreignKeys = [ + ForeignKey( + entity = JellyfinUser::class, + parentColumns = arrayOf("rowId"), + childColumns = arrayOf("userId"), + onDelete = ForeignKey.CASCADE, + onUpdate = ForeignKey.CASCADE, + ), + ], + primaryKeys = ["userId", "itemId"], + indices = [Index("userId", "itemId", unique = true)], +) +@Serializable +data class LibraryDisplayInfo( + val userId: Int, + val itemId: UUID, + val sort: ItemSortBy, + val direction: SortOrder, +) { + @Ignore @Transient + val sortAndDirection = SortAndDirection(sort, direction) +} diff --git a/app/src/main/java/com/github/damontecres/wholphin/hilt/DatabaseModule.kt b/app/src/main/java/com/github/damontecres/wholphin/hilt/DatabaseModule.kt index ab1fb0e5..441a9033 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/hilt/DatabaseModule.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/hilt/DatabaseModule.kt @@ -9,6 +9,7 @@ import androidx.room.Room import com.github.damontecres.wholphin.data.AppDatabase import com.github.damontecres.wholphin.data.ItemPlaybackDao import com.github.damontecres.wholphin.data.JellyfinServerDao +import com.github.damontecres.wholphin.data.LibraryDisplayInfoDao import com.github.damontecres.wholphin.data.Migrations import com.github.damontecres.wholphin.data.ServerPreferencesDao import com.github.damontecres.wholphin.preferences.AppPreferences @@ -51,6 +52,10 @@ object DatabaseModule { @Singleton fun serverPreferencesDao(db: AppDatabase): ServerPreferencesDao = db.serverPreferencesDao() + @Provides + @Singleton + fun libraryDisplayInfoDao(db: AppDatabase): LibraryDisplayInfoDao = db.libraryDisplayInfoDao() + @Provides @Singleton fun userPreferencesDataStore( diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt index 8d5139ca..38f34a07 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/components/CollectionFolderGrid.kt @@ -26,8 +26,11 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.viewModelScope import androidx.tv.material3.MaterialTheme import androidx.tv.material3.Text +import com.github.damontecres.wholphin.data.LibraryDisplayInfoDao +import com.github.damontecres.wholphin.data.ServerRepository import com.github.damontecres.wholphin.data.model.BaseItem import com.github.damontecres.wholphin.data.model.GetItemsFilter +import com.github.damontecres.wholphin.data.model.LibraryDisplayInfo import com.github.damontecres.wholphin.preferences.UserPreferences import com.github.damontecres.wholphin.ui.OneTimeLaunchedEffect import com.github.damontecres.wholphin.ui.SlimItemFields @@ -62,6 +65,8 @@ class CollectionFolderViewModel @Inject constructor( api: ApiClient, + private val serverRepository: ServerRepository, + private val libraryDisplayInfoDao: LibraryDisplayInfoDao, ) : ItemViewModel(api) { val loading = MutableLiveData(LoadingState.Loading) val pager = MutableLiveData>(listOf()) @@ -71,7 +76,7 @@ class CollectionFolderViewModel fun init( itemId: UUID?, potential: BaseItem?, - sortAndDirection: SortAndDirection, + initialSortAndDirection: SortAndDirection?, recursive: Boolean, filter: GetItemsFilter, ): Job = @@ -82,12 +87,41 @@ class CollectionFolderViewModel ) + Dispatchers.IO, ) { if (itemId != null) { - fetchItem(itemId, potential) + fetchItem(itemId) + + val sortAndDirection = + if (initialSortAndDirection == null) { + serverRepository.currentUser?.let { user -> + libraryDisplayInfoDao.getItem(user, itemId)?.sortAndDirection + } ?: SortAndDirection.DEFAULT + } else { + SortAndDirection.DEFAULT + } + loadResults(sortAndDirection, recursive, filter) } - loadResults(sortAndDirection, recursive, filter) } - fun loadResults( + fun onSortChange( + sortAndDirection: SortAndDirection, + recursive: Boolean, + filter: GetItemsFilter, + ) { + serverRepository.currentUser?.let { user -> + viewModelScope.launch(Dispatchers.IO) { + val libraryDisplayInfo = + LibraryDisplayInfo( + userId = user.rowId, + itemId = itemId, + sort = sortAndDirection.sort, + direction = sortAndDirection.direction, + ) + libraryDisplayInfoDao.saveItem(libraryDisplayInfo) + } + } + loadResults(sortAndDirection, recursive, filter) + } + + private fun loadResults( sortAndDirection: SortAndDirection, recursive: Boolean, filter: GetItemsFilter, @@ -126,17 +160,25 @@ class CollectionFolderViewModel recursive = recursive, excludeItemIds = item?.let { listOf(item.id) }, sortBy = - listOf( - sortAndDirection.sort, - ItemSortBy.SORT_NAME, - ItemSortBy.PRODUCTION_YEAR, - ), + buildList { + add(sortAndDirection.sort) + if (sortAndDirection.sort != ItemSortBy.SORT_NAME) { + add(ItemSortBy.SORT_NAME) + } + if (item?.data?.collectionType == CollectionType.MOVIES) { + add(ItemSortBy.PRODUCTION_YEAR) + } + }, sortOrder = - listOf( - sortAndDirection.direction, - SortOrder.ASCENDING, - SortOrder.ASCENDING, - ), + buildList { + add(sortAndDirection.direction) + if (sortAndDirection.sort != ItemSortBy.SORT_NAME) { + add(SortOrder.ASCENDING) + } + if (item?.data?.collectionType == CollectionType.MOVIES) { + add(SortOrder.ASCENDING) + } + }, fields = SlimItemFields, ), ) @@ -198,18 +240,14 @@ fun CollectionFolderGrid( onClickItem: (BaseItem) -> Unit, modifier: Modifier = Modifier, viewModel: CollectionFolderViewModel = hiltViewModel(), - initialSortAndDirection: SortAndDirection = - SortAndDirection( - ItemSortBy.SORT_NAME, - SortOrder.ASCENDING, - ), + initialSortAndDirection: SortAndDirection? = null, showTitle: Boolean = true, positionCallback: ((columns: Int, position: Int) -> Unit)? = null, ) { OneTimeLaunchedEffect { viewModel.init(itemId, item, initialSortAndDirection, recursive, initialFilter) } - val sortAndDirection by viewModel.sortAndDirection.observeAsState(initialSortAndDirection) + val sortAndDirection by viewModel.sortAndDirection.observeAsState() val filter by viewModel.filter.observeAsState(initialFilter) val loading by viewModel.loading.observeAsState(LoadingState.Loading) val item by viewModel.item.observeAsState() @@ -226,11 +264,11 @@ fun CollectionFolderGrid( preferences, item, pager, - sortAndDirection = sortAndDirection, + sortAndDirection = sortAndDirection!!, modifier = modifier, onClickItem = onClickItem, onSortChange = { - viewModel.loadResults(it, recursive, filter) + viewModel.onSortChange(it, recursive, filter) }, showTitle = showTitle, positionCallback = positionCallback, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/data/SortAndDirection.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/data/SortAndDirection.kt index 945ed053..ac0808a5 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/data/SortAndDirection.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/data/SortAndDirection.kt @@ -10,6 +10,14 @@ data class SortAndDirection( val direction: SortOrder, ) { fun flip() = copy(direction = direction.flip()) + + companion object { + val DEFAULT = + SortAndDirection( + ItemSortBy.SORT_NAME, + SortOrder.ASCENDING, + ) + } } fun SortOrder.flip() = if (this == SortOrder.ASCENDING) SortOrder.DESCENDING else SortOrder.ASCENDING @@ -20,6 +28,9 @@ val MovieSortOptions = ItemSortBy.PREMIERE_DATE, ItemSortBy.DATE_CREATED, ItemSortBy.DATE_PLAYED, + ItemSortBy.COMMUNITY_RATING, + ItemSortBy.CRITIC_RATING, + ItemSortBy.PLAY_COUNT, ItemSortBy.RANDOM, ) @@ -30,6 +41,7 @@ val SeriesSortOptions = ItemSortBy.DATE_CREATED, ItemSortBy.DATE_LAST_CONTENT_ADDED, ItemSortBy.DATE_PLAYED, + ItemSortBy.COMMUNITY_RATING, ItemSortBy.RANDOM, ) @@ -50,5 +62,8 @@ fun getStringRes(sort: ItemSortBy): Int = ItemSortBy.DATE_LAST_CONTENT_ADDED -> R.string.sort_by_date_episode_added ItemSortBy.DATE_PLAYED -> R.string.sort_by_date_played ItemSortBy.RANDOM -> R.string.sort_by_random + ItemSortBy.COMMUNITY_RATING -> R.string.community_rating + ItemSortBy.CRITIC_RATING -> R.string.critic_rating + ItemSortBy.PLAY_COUNT -> R.string.play_count else -> throw IllegalArgumentException("Unsupported sort option: $sort") } diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/ItemViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/ItemViewModel.kt index 8a15d2f9..fec6162a 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/ItemViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/ItemViewModel.kt @@ -25,21 +25,11 @@ abstract class ItemViewModel( val api: ApiClient, ) : ViewModel() { val item = MutableLiveData(null) + lateinit var itemId: UUID - suspend fun fetchItem( - itemId: UUID, - potential: BaseItem?, - ): BaseItem = + suspend fun fetchItem(itemId: UUID): BaseItem = withContext(Dispatchers.IO) { -// val fetchedItem = -// when { -// item.value == null && potential?.id == itemId -> potential -// item.value?.id == itemId -> item.value -// else -> { -// val it = api.userLibraryApi.getItem(itemId).content -// BaseItem.from(it, api) -// } -// } + this@ItemViewModel.itemId = itemId val it = api.userLibraryApi.getItem(itemId).content val fetchedItem = BaseItem.from(it, api) return@withContext fetchedItem.let { @@ -89,10 +79,8 @@ abstract class LoadingItemViewModel( open suspend fun fetchAndSetItem(itemId: UUID): BaseItem = withContext(Dispatchers.IO) { - val fetchedItem = api.userLibraryApi.getItem(itemId).content - val item = BaseItem.from(fetchedItem, api) + val item = fetchItem(itemId) withContext(Dispatchers.Main) { - this@LoadingItemViewModel.item.value = item loading.value = LoadingState.Success } return@withContext item diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/PlaylistDetails.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/PlaylistDetails.kt index 54551834..49538cca 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/PlaylistDetails.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/PlaylistDetails.kt @@ -102,7 +102,7 @@ class PlaylistViewModel Dispatchers.IO + LoadingExceptionHandler(loading, "Failed to fetch playlist $playlistId"), ) { - val playlist = fetchItem(playlistId, null) + val playlist = fetchItem(playlistId) val request = GetPlaylistItemsRequest( playlistId = playlist.id, diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/movie/MovieViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/movie/MovieViewModel.kt index 82671199..a27507ca 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/movie/MovieViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/movie/MovieViewModel.kt @@ -48,17 +48,14 @@ class MovieViewModel val itemPlaybackRepository: ItemPlaybackRepository, private val themeSongPlayer: ThemeSongPlayer, ) : LoadingItemViewModel(api) { - private lateinit var itemId: UUID - val trailers = MutableLiveData>(listOf()) val people = MutableLiveData>(listOf()) val chapters = MutableLiveData>(listOf()) val similar = MutableLiveData>() val chosenStreams = MutableLiveData(null) - fun init(itemId: UUID): Job? { - this.itemId = itemId - return viewModelScope.launch( + fun init(itemId: UUID): Job? = + viewModelScope.launch( Dispatchers.IO + LoadingExceptionHandler( loading, @@ -124,7 +121,6 @@ class MovieViewModel } } } - } fun setWatched(played: Boolean) = viewModelScope.launch(ExceptionHandler() + Dispatchers.IO) { diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesViewModel.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesViewModel.kt index 0937006d..8acb295e 100644 --- a/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesViewModel.kt +++ b/app/src/main/java/com/github/damontecres/wholphin/ui/detail/series/SeriesViewModel.kt @@ -84,7 +84,7 @@ class SeriesViewModel "Error loading series $seriesId", ) + Dispatchers.IO, ) { - val item = fetchItem(seriesId, potential) + val item = fetchItem(seriesId) val seasons = getSeasons(item) // If a particular season was requested, fetch those episodes, otherwise get the first season @@ -263,7 +263,7 @@ class SeriesViewModel if (listIndex != null) { refreshEpisode(itemId, listIndex) } else { - fetchItem(seriesId, null) + fetchItem(seriesId) } } @@ -272,7 +272,7 @@ class SeriesViewModel played: Boolean, ) = viewModelScope.launch(Dispatchers.IO + ExceptionHandler()) { setWatched(seasonId, played, null) - val series = fetchItem(seriesId, null) + val series = fetchItem(seriesId) val seasons = getSeasons(series) this@SeriesViewModel.seasons.setValueOnMain(seasons) } @@ -284,7 +284,7 @@ class SeriesViewModel } else { api.playStateApi.markUnplayedItem(seriesId) } - val series = fetchItem(seriesId, null) + val series = fetchItem(seriesId) val seasons = getSeasons(series) this@SeriesViewModel.seasons.setValueOnMain(seasons) } diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index f2ca9395..67fd8735 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -102,5 +102,8 @@ Click to switch pages Show next up Next Up + Community Rating + Critic Rating + Play Count