Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move preference code to new preference module #1619

Merged
merged 1 commit into from
Apr 13, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ val versionTxt by tasks.registering {
dependencies {
// Jellyfin
implementation(projects.playback)
implementation(projects.preference)
implementation(libs.jellyfin.apiclient)
implementation(libs.jellyfin.sdk) {
// Change version if desired
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package org.jellyfin.androidtv.constant

import org.jellyfin.androidtv.R
import org.jellyfin.androidtv.preference.PreferenceEnum
import org.jellyfin.androidtv.ui.preference.dsl.EnumDisplayOptions
import org.jellyfin.preference.PreferenceEnum

/**
* All possible homesections, "synced" with jellyfin-web.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package org.jellyfin.androidtv.preference
import android.content.Context
import org.jellyfin.androidtv.auth.model.AuthenticationSortBy
import org.jellyfin.androidtv.preference.constant.UserSelectBehavior
import org.jellyfin.preference.Preference
import org.jellyfin.preference.store.SharedPreferenceStore

class AuthenticationPreferences(context: Context) : SharedPreferenceStore(
sharedPreferences = context.getSharedPreferences("authentication", Context.MODE_PRIVATE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package org.jellyfin.androidtv.preference
import org.jellyfin.androidtv.constant.GridDirection
import org.jellyfin.androidtv.constant.ImageType
import org.jellyfin.androidtv.constant.PosterSize
import org.jellyfin.androidtv.preference.store.DisplayPreferencesStore
import org.jellyfin.apiclient.model.entities.SortOrder
import org.jellyfin.apiclient.model.querying.ItemSortBy
import org.jellyfin.preference.Preference
import org.jellyfin.sdk.api.client.ApiClient

class LibraryPreferences(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.jellyfin.androidtv.preference

import org.jellyfin.androidtv.preference.store.DisplayPreferencesStore
import org.jellyfin.apiclient.model.querying.ItemSortBy
import org.jellyfin.preference.Preference
import org.jellyfin.sdk.api.client.ApiClient

class LiveTvPreferences(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package org.jellyfin.androidtv.preference

import android.content.Context
import org.jellyfin.androidtv.preference.constant.PreferredVideoPlayer
import org.jellyfin.preference.Preference
import org.jellyfin.preference.store.SharedPreferenceStore

/**
* System preferences are not possible to modify by the user.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ import org.jellyfin.androidtv.preference.constant.RatingType
import org.jellyfin.androidtv.preference.constant.WatchedIndicatorBehavior
import org.jellyfin.androidtv.preference.constant.defaultAudioBehavior
import org.jellyfin.androidtv.util.DeviceUtils
import org.jellyfin.preference.Preference
import org.jellyfin.preference.migration.putEnum
import org.jellyfin.preference.store.SharedPreferenceStore

/**
* User preferences are configurable by the user and change behavior of the application.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package org.jellyfin.androidtv.preference

import org.jellyfin.androidtv.constant.HomeSectionType
import org.jellyfin.androidtv.preference.store.DisplayPreferencesStore
import org.jellyfin.preference.Preference
import org.jellyfin.sdk.api.client.ApiClient

class UserSettingPreferences(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.jellyfin.androidtv.preference
package org.jellyfin.androidtv.preference.store

import org.jellyfin.preference.Preference
import org.jellyfin.preference.PreferenceEnum
import org.jellyfin.preference.store.AsyncPreferenceStore
import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.exception.ApiClientException
import org.jellyfin.sdk.api.client.extensions.displayPreferencesApi
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,12 @@ import org.jellyfin.androidtv.constant.GridDirection
import org.jellyfin.androidtv.constant.ImageType
import org.jellyfin.androidtv.constant.PosterSize
import org.jellyfin.androidtv.preference.LibraryPreferences
import org.jellyfin.androidtv.preference.PreferenceStore
import org.jellyfin.androidtv.preference.PreferencesRepository
import org.jellyfin.androidtv.ui.preference.dsl.OptionsFragment
import org.jellyfin.androidtv.ui.preference.dsl.checkbox
import org.jellyfin.androidtv.ui.preference.dsl.enum
import org.jellyfin.androidtv.ui.preference.dsl.optionsScreen
import org.jellyfin.preference.store.PreferenceStore
import org.koin.android.ext.android.inject

class DisplayPreferencesScreen : OptionsFragment() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import androidx.leanback.preference.LeanbackPreferenceFragmentCompat
import kotlinx.coroutines.async
import kotlinx.coroutines.awaitAll
import kotlinx.coroutines.runBlocking
import org.jellyfin.androidtv.preference.AsyncPreferenceStore
import org.jellyfin.androidtv.preference.PreferenceStore
import org.jellyfin.preference.store.AsyncPreferenceStore
import org.jellyfin.preference.store.PreferenceStore

abstract class OptionsFragment : LeanbackPreferenceFragmentCompat() {
abstract val screen: OptionsScreen
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ package org.jellyfin.androidtv.ui.preference.dsl
import android.content.Context
import androidx.annotation.StringRes
import androidx.preference.PreferenceCategory
import org.jellyfin.androidtv.preference.Preference
import org.jellyfin.androidtv.preference.PreferenceStore
import org.jellyfin.androidtv.ui.preference.custom.RichListPreference
import org.jellyfin.preference.Preference
import org.jellyfin.preference.store.PreferenceStore
import java.util.UUID

class OptionsItemEnum<T : Enum<T>>(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.jellyfin.androidtv.ui.preference.dsl

import org.jellyfin.androidtv.preference.Preference
import org.jellyfin.androidtv.preference.PreferenceStore
import org.jellyfin.preference.Preference
import org.jellyfin.preference.store.PreferenceStore

abstract class OptionsItemMutable<T : Any> : OptionsItem {
var title: String? = null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ package org.jellyfin.androidtv.ui.preference.screen
import androidx.core.os.bundleOf
import org.jellyfin.androidtv.R
import org.jellyfin.androidtv.auth.AuthenticationRepository
import org.jellyfin.androidtv.auth.model.AuthenticationSortBy
import org.jellyfin.androidtv.auth.SessionRepository
import org.jellyfin.androidtv.auth.model.AuthenticationSortBy
import org.jellyfin.androidtv.preference.AuthenticationPreferences
import org.jellyfin.androidtv.preference.Preference
import org.jellyfin.androidtv.preference.constant.UserSelectBehavior
import org.jellyfin.androidtv.ui.preference.category.aboutCategory
import org.jellyfin.androidtv.ui.preference.dsl.OptionsBinder
Expand All @@ -18,6 +17,7 @@ import org.jellyfin.androidtv.ui.preference.dsl.link
import org.jellyfin.androidtv.ui.preference.dsl.optionsScreen
import org.jellyfin.androidtv.ui.preference.dsl.userPicker
import org.jellyfin.androidtv.ui.startup.preference.EditServerScreen
import org.jellyfin.preference.Preference
import org.jellyfin.sdk.model.serializer.toUUIDOrNull
import org.koin.android.ext.android.inject

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@ package org.jellyfin.androidtv.ui.preference.screen

import org.jellyfin.androidtv.R
import org.jellyfin.androidtv.constant.HomeSectionType
import org.jellyfin.androidtv.preference.PreferenceStore
import org.jellyfin.androidtv.preference.UserSettingPreferences
import org.jellyfin.androidtv.ui.preference.dsl.OptionsFragment
import org.jellyfin.androidtv.ui.preference.dsl.enum
import org.jellyfin.androidtv.ui.preference.dsl.optionsScreen
import org.jellyfin.preference.store.PreferenceStore
import org.koin.android.ext.android.inject

class HomePreferencesScreen : OptionsFragment() {
Expand Down
2 changes: 1 addition & 1 deletion playback/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,5 @@ android {
}

dependencies {

}
42 changes: 42 additions & 0 deletions preference/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
plugins {
id("com.android.library")
kotlin("android")
}

android {
compileSdk = 31

defaultConfig {
minSdk = 21
targetSdk = 31
}

buildFeatures {
viewBinding = true
}

sourceSets["main"].java.srcDirs("src/main/kotlin")
sourceSets["test"].java.srcDirs("src/test/kotlin")

lint {
lintConfig = file("$rootDir/android-lint.xml")
abortOnError = false
}

testOptions.unitTests.all {
it.useJUnitPlatform()
}
}

dependencies {
// Kotlin
implementation(libs.kotlinx.coroutines)

// Logging
implementation(libs.timber)

// Testing
testImplementation(libs.kotest.runner.junit5)
testImplementation(libs.kotest.assertions)
testImplementation(libs.mockk)
}
7 changes: 7 additions & 0 deletions preference/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.jellyfin.preference">

<application>

</application>
</manifest>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.jellyfin.androidtv.preference
package org.jellyfin.preference

import kotlin.reflect.KClass

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.jellyfin.androidtv.preference
package org.jellyfin.preference

interface PreferenceEnum {
val serializedName: String
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.jellyfin.androidtv.preference.migrations
package org.jellyfin.preference.migration

import timber.log.Timber
import java.lang.Integer.max
import kotlin.math.max

class MigrationContext<E, V> {
private val migrations = mutableListOf<Migration<E, V>>()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.jellyfin.androidtv.preference
package org.jellyfin.preference.migration

import android.content.SharedPreferences

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.jellyfin.androidtv.preference
package org.jellyfin.preference.store

import kotlinx.coroutines.runBlocking

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
package org.jellyfin.androidtv.preference
package org.jellyfin.preference.store

import org.jellyfin.preference.Preference

/**
* Abstract class defining the required functions for a preference store.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package org.jellyfin.androidtv.preference
package org.jellyfin.preference.store

import android.content.SharedPreferences
import org.jellyfin.androidtv.preference.migrations.MigrationContext
import org.jellyfin.preference.Preference
import org.jellyfin.preference.PreferenceEnum
import org.jellyfin.preference.migration.MigrationContext
import org.jellyfin.preference.migration.MigrationEditor
import timber.log.Timber

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,37 @@
package org.jellyfin.androidtv.preference
package org.jellyfin.preference

import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import org.jellyfin.preference.store.PreferenceStore

/**
* Tests that the generic set/get methods dispatch to the correct
* internal getT/setT methods
*/
class PreferenceStoreTests : FunSpec({
fun <T : Any> verifySimpleType(expectedVal: T, preference: Preference<T>) {
val instance = TestStub()
instance[preference] = expectedVal
instance[preference] shouldBe expectedVal
instance.key shouldBe preference.key
}

test("Reading and writing primitives works correctly") {
verifySimpleType(1, Preference.int("key", 0))
verifySimpleType(1L, Preference.long("key", 0L))
verifySimpleType(true, Preference.boolean("key", false))
verifySimpleType("string", Preference.string("key", ""))
}

test("Reading and writing enums works correctly") {
val pref = Preference.enum("key", TestEnum.NOT_SET)
val expectedVal = TestEnum.SET
val instance = TestStub()
instance[pref] = expectedVal
instance[pref] shouldBe expectedVal
pref.key shouldBe instance.key
}
})

private class TestStub : PreferenceStore() {
var key: String? = null
Expand Down Expand Up @@ -52,36 +82,3 @@ private class TestStub : PreferenceStore() {
}

private enum class TestEnum { NOT_SET, SET }

/**
* Tests that the generic set/get methods dispatch to the correct
* internal getT/setT methods
*/
class PreferenceStoreTests : FunSpec({
fun <T : Any> verifySimpleType(expectedVal: T, preference: Preference<T>) {
val instance = TestStub()
instance[preference] = expectedVal
instance[preference] shouldBe expectedVal
instance.key shouldBe preference.key
}

test("get and setting native types") {
// Unfortunately KoTest will try to serialise to a base Serializable using rows
// So manually use generics for the same effect
verifySimpleType(1, Preference.int("key", 0))
verifySimpleType(1L, Preference.long("key", 0L))
verifySimpleType(true, Preference.boolean("key", false))
verifySimpleType("string", Preference.string("key", ""))
}

test("get and set with enum types") {
// Generics removes too much type info for us to use verifySimpleType
// we could be clever, but I prefer duplication and to KISS
val pref = Preference.enum("key", TestEnum.NOT_SET)
val expectedVal = TestEnum.SET
val instance = TestStub()
instance[pref] = expectedVal
instance[pref] shouldBe expectedVal
pref.key shouldBe instance.key
}
})
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ include(":app")

// Modules
include(":playback")
include(":preference")

pluginManagement {
repositories {
Expand Down