Add network settings (#192)
* Add new network settings with socket timeout option * Add socketTimeout to AppPreferences * Format with ktlint * Add request timeout and connect timeout as options
This commit is contained in:
parent
2c4fb8d7fe
commit
5895b2c8d8
11 changed files with 146 additions and 8 deletions
|
@ -2,7 +2,9 @@ package dev.jdtech.jellyfin.api
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import dev.jdtech.jellyfin.BuildConfig
|
import dev.jdtech.jellyfin.BuildConfig
|
||||||
|
import dev.jdtech.jellyfin.utils.Constants
|
||||||
import java.util.UUID
|
import java.util.UUID
|
||||||
|
import org.jellyfin.sdk.api.client.HttpClientOptions
|
||||||
import org.jellyfin.sdk.api.client.extensions.devicesApi
|
import org.jellyfin.sdk.api.client.extensions.devicesApi
|
||||||
import org.jellyfin.sdk.api.client.extensions.itemsApi
|
import org.jellyfin.sdk.api.client.extensions.itemsApi
|
||||||
import org.jellyfin.sdk.api.client.extensions.mediaInfoApi
|
import org.jellyfin.sdk.api.client.extensions.mediaInfoApi
|
||||||
|
@ -21,15 +23,27 @@ import org.jellyfin.sdk.model.ClientInfo
|
||||||
* Jellyfin API class using org.jellyfin.sdk:jellyfin-platform-android
|
* Jellyfin API class using org.jellyfin.sdk:jellyfin-platform-android
|
||||||
*
|
*
|
||||||
* @param androidContext The context
|
* @param androidContext The context
|
||||||
|
* @param socketTimeout The socket timeout
|
||||||
* @constructor Creates a new [JellyfinApi] instance
|
* @constructor Creates a new [JellyfinApi] instance
|
||||||
*/
|
*/
|
||||||
class JellyfinApi(androidContext: Context) {
|
class JellyfinApi(
|
||||||
|
androidContext: Context,
|
||||||
|
requestTimeout: Long = Constants.NETWORK_DEFAULT_REQUEST_TIMEOUT,
|
||||||
|
connectTimeout: Long = Constants.NETWORK_DEFAULT_CONNECT_TIMEOUT,
|
||||||
|
socketTimeout: Long = Constants.NETWORK_DEFAULT_SOCKET_TIMEOUT
|
||||||
|
) {
|
||||||
val jellyfin = createJellyfin {
|
val jellyfin = createJellyfin {
|
||||||
clientInfo =
|
clientInfo =
|
||||||
ClientInfo(name = androidContext.applicationInfo.loadLabel(androidContext.packageManager).toString(), version = BuildConfig.VERSION_NAME)
|
ClientInfo(name = androidContext.applicationInfo.loadLabel(androidContext.packageManager).toString(), version = BuildConfig.VERSION_NAME)
|
||||||
context = androidContext
|
context = androidContext
|
||||||
}
|
}
|
||||||
val api = jellyfin.createApi()
|
val api = jellyfin.createApi(
|
||||||
|
httpClientOptions = HttpClientOptions(
|
||||||
|
requestTimeout = requestTimeout,
|
||||||
|
connectTimeout = connectTimeout,
|
||||||
|
socketTimeout = socketTimeout
|
||||||
|
)
|
||||||
|
)
|
||||||
var userId: UUID? = null
|
var userId: UUID? = null
|
||||||
|
|
||||||
val devicesApi = api.devicesApi
|
val devicesApi = api.devicesApi
|
||||||
|
@ -48,11 +62,21 @@ class JellyfinApi(androidContext: Context) {
|
||||||
@Volatile
|
@Volatile
|
||||||
private var INSTANCE: JellyfinApi? = null
|
private var INSTANCE: JellyfinApi? = null
|
||||||
|
|
||||||
fun getInstance(context: Context): JellyfinApi {
|
fun getInstance(
|
||||||
|
context: Context,
|
||||||
|
requestTimeout: Long = Constants.NETWORK_DEFAULT_REQUEST_TIMEOUT,
|
||||||
|
connectTimeout: Long = Constants.NETWORK_DEFAULT_CONNECT_TIMEOUT,
|
||||||
|
socketTimeout: Long = Constants.NETWORK_DEFAULT_SOCKET_TIMEOUT
|
||||||
|
): JellyfinApi {
|
||||||
synchronized(this) {
|
synchronized(this) {
|
||||||
var instance = INSTANCE
|
var instance = INSTANCE
|
||||||
if (instance == null) {
|
if (instance == null) {
|
||||||
instance = JellyfinApi(context.applicationContext)
|
instance = JellyfinApi(
|
||||||
|
androidContext = context.applicationContext,
|
||||||
|
requestTimeout = requestTimeout,
|
||||||
|
connectTimeout = connectTimeout,
|
||||||
|
socketTimeout = socketTimeout
|
||||||
|
)
|
||||||
INSTANCE = instance
|
INSTANCE = instance
|
||||||
}
|
}
|
||||||
return instance
|
return instance
|
||||||
|
|
|
@ -9,6 +9,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext
|
||||||
import dagger.hilt.components.SingletonComponent
|
import dagger.hilt.components.SingletonComponent
|
||||||
import dev.jdtech.jellyfin.api.JellyfinApi
|
import dev.jdtech.jellyfin.api.JellyfinApi
|
||||||
import dev.jdtech.jellyfin.database.ServerDatabaseDao
|
import dev.jdtech.jellyfin.database.ServerDatabaseDao
|
||||||
|
import dev.jdtech.jellyfin.utils.AppPreferences
|
||||||
import javax.inject.Singleton
|
import javax.inject.Singleton
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
|
@ -19,9 +20,15 @@ object ApiModule {
|
||||||
fun provideJellyfinApi(
|
fun provideJellyfinApi(
|
||||||
@ApplicationContext application: Context,
|
@ApplicationContext application: Context,
|
||||||
sharedPreferences: SharedPreferences,
|
sharedPreferences: SharedPreferences,
|
||||||
|
appPreferences: AppPreferences,
|
||||||
serverDatabase: ServerDatabaseDao
|
serverDatabase: ServerDatabaseDao
|
||||||
): JellyfinApi {
|
): JellyfinApi {
|
||||||
val jellyfinApi = JellyfinApi.getInstance(application)
|
val jellyfinApi = JellyfinApi.getInstance(
|
||||||
|
context = application,
|
||||||
|
requestTimeout = appPreferences.requestTimeout,
|
||||||
|
connectTimeout = appPreferences.connectTimeout,
|
||||||
|
socketTimeout = appPreferences.socketTimeout
|
||||||
|
)
|
||||||
|
|
||||||
val serverId = sharedPreferences.getString("selectedServer", null)
|
val serverId = sharedPreferences.getString("selectedServer", null)
|
||||||
if (serverId != null) {
|
if (serverId != null) {
|
||||||
|
|
|
@ -10,7 +10,7 @@ import dev.jdtech.jellyfin.utils.serializable
|
||||||
import java.io.Serializable
|
import java.io.Serializable
|
||||||
import java.lang.IllegalStateException
|
import java.lang.IllegalStateException
|
||||||
|
|
||||||
class ErrorDialogFragment: DialogFragment() {
|
class ErrorDialogFragment : DialogFragment() {
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
val error = requireArguments().serializable<Exception>("error")!!
|
val error = requireArguments().serializable<Exception>("error")!!
|
||||||
return activity?.let {
|
return activity?.let {
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
package dev.jdtech.jellyfin.fragments
|
||||||
|
|
||||||
|
import android.os.Bundle
|
||||||
|
import android.text.InputType
|
||||||
|
import androidx.preference.EditTextPreference
|
||||||
|
import androidx.preference.PreferenceFragmentCompat
|
||||||
|
import dev.jdtech.jellyfin.R
|
||||||
|
import dev.jdtech.jellyfin.utils.Constants
|
||||||
|
|
||||||
|
@Suppress("unused")
|
||||||
|
class SettingsNetworkFragment : PreferenceFragmentCompat() {
|
||||||
|
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
|
||||||
|
setPreferencesFromResource(R.xml.fragment_settings_network, rootKey)
|
||||||
|
|
||||||
|
findPreference<EditTextPreference>(Constants.PREF_NETWORK_SOCKET_TIMEOUT)?.setOnBindEditTextListener { editText ->
|
||||||
|
editText.inputType = InputType.TYPE_CLASS_NUMBER
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -43,4 +43,20 @@ constructor(
|
||||||
DEFAULT_SEEK_FORWARD_INCREMENT_MS.toString()
|
DEFAULT_SEEK_FORWARD_INCREMENT_MS.toString()
|
||||||
)!!.toLongOrNull() ?: DEFAULT_SEEK_FORWARD_INCREMENT_MS
|
)!!.toLongOrNull() ?: DEFAULT_SEEK_FORWARD_INCREMENT_MS
|
||||||
val mpvDisableHwDec = sharedPreferences.getBoolean("mpv_disable_hwdec", false)
|
val mpvDisableHwDec = sharedPreferences.getBoolean("mpv_disable_hwdec", false)
|
||||||
|
|
||||||
|
// Network
|
||||||
|
val requestTimeout = sharedPreferences.getString(
|
||||||
|
Constants.PREF_NETWORK_REQUEST_TIMEOUT,
|
||||||
|
Constants.NETWORK_DEFAULT_REQUEST_TIMEOUT.toString()
|
||||||
|
)!!.toLongOrNull() ?: Constants.NETWORK_DEFAULT_REQUEST_TIMEOUT
|
||||||
|
|
||||||
|
val connectTimeout = sharedPreferences.getString(
|
||||||
|
Constants.PREF_NETWORK_CONNECT_TIMEOUT,
|
||||||
|
Constants.NETWORK_DEFAULT_CONNECT_TIMEOUT.toString()
|
||||||
|
)!!.toLongOrNull() ?: Constants.NETWORK_DEFAULT_CONNECT_TIMEOUT
|
||||||
|
|
||||||
|
val socketTimeout = sharedPreferences.getString(
|
||||||
|
Constants.PREF_NETWORK_SOCKET_TIMEOUT,
|
||||||
|
Constants.NETWORK_DEFAULT_SOCKET_TIMEOUT.toString()
|
||||||
|
)!!.toLongOrNull() ?: Constants.NETWORK_DEFAULT_SOCKET_TIMEOUT
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,9 @@ object Constants {
|
||||||
const val PREF_IMAGE_CACHE_SIZE = "pref_image_cache_size"
|
const val PREF_IMAGE_CACHE_SIZE = "pref_image_cache_size"
|
||||||
const val PREF_THEME = "theme"
|
const val PREF_THEME = "theme"
|
||||||
const val PREF_DYNAMIC_COLORS = "dynamic_colors"
|
const val PREF_DYNAMIC_COLORS = "dynamic_colors"
|
||||||
|
const val PREF_NETWORK_REQUEST_TIMEOUT = "pref_network_request_timeout"
|
||||||
|
const val PREF_NETWORK_CONNECT_TIMEOUT = "pref_network_connect_timeout"
|
||||||
|
const val PREF_NETWORK_SOCKET_TIMEOUT = "pref_network_socket_timeout"
|
||||||
|
|
||||||
// caching
|
// caching
|
||||||
const val DEFAULT_CACHE_SIZE = 20
|
const val DEFAULT_CACHE_SIZE = 20
|
||||||
|
@ -27,4 +30,9 @@ object Constants {
|
||||||
const val FAVORITE_TYPE_MOVIES = 0
|
const val FAVORITE_TYPE_MOVIES = 0
|
||||||
const val FAVORITE_TYPE_SHOWS = 1
|
const val FAVORITE_TYPE_SHOWS = 1
|
||||||
const val FAVORITE_TYPE_EPISODES = 2
|
const val FAVORITE_TYPE_EPISODES = 2
|
||||||
|
|
||||||
|
// network
|
||||||
|
const val NETWORK_DEFAULT_REQUEST_TIMEOUT = 30_000L
|
||||||
|
const val NETWORK_DEFAULT_CONNECT_TIMEOUT = 6_000L
|
||||||
|
const val NETWORK_DEFAULT_SOCKET_TIMEOUT = 10_000L
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,9 @@ import androidx.fragment.app.Fragment
|
||||||
import androidx.navigation.fragment.findNavController
|
import androidx.navigation.fragment.findNavController
|
||||||
import dev.jdtech.jellyfin.AppNavigationDirections
|
import dev.jdtech.jellyfin.AppNavigationDirections
|
||||||
import dev.jdtech.jellyfin.models.View
|
import dev.jdtech.jellyfin.models.View
|
||||||
|
import java.io.Serializable
|
||||||
import org.jellyfin.sdk.model.api.BaseItemDto
|
import org.jellyfin.sdk.model.api.BaseItemDto
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import java.io.Serializable
|
|
||||||
|
|
||||||
fun BaseItemDto.toView(): View {
|
fun BaseItemDto.toView(): View {
|
||||||
return View(
|
return View(
|
||||||
|
@ -58,4 +58,4 @@ fun ImageButton.setTintColorAttribute(@AttrRes attributeId: Int, theme: Resource
|
||||||
inline fun <reified T : Serializable> Bundle.serializable(key: String): T? = when {
|
inline fun <reified T : Serializable> Bundle.serializable(key: String): T? = when {
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getSerializable(key, T::class.java)
|
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU -> getSerializable(key, T::class.java)
|
||||||
else -> @Suppress("DEPRECATION") getSerializable(key) as? T
|
else -> @Suppress("DEPRECATION") getSerializable(key) as? T
|
||||||
}
|
}
|
||||||
|
|
37
app/src/main/res/drawable/ic_network.xml
Normal file
37
app/src/main/res/drawable/ic_network.xml
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:pathData="M9,2h6v6h-6z"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeColor="@android:color/white"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M16,16h6v6h-6z"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeColor="@android:color/white"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M2,16h6v6h-6z"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeColor="@android:color/white"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M5,16v-4h14v4"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeColor="@android:color/white"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
<path
|
||||||
|
android:pathData="M12,12V8"
|
||||||
|
android:strokeLineJoin="round"
|
||||||
|
android:strokeWidth="2"
|
||||||
|
android:strokeColor="@android:color/white"
|
||||||
|
android:strokeLineCap="round"/>
|
||||||
|
</vector>
|
|
@ -138,4 +138,8 @@
|
||||||
<string name="theme_system">Follow system</string>
|
<string name="theme_system">Follow system</string>
|
||||||
<string name="theme_light">Light</string>
|
<string name="theme_light">Light</string>
|
||||||
<string name="theme_dark">Dark</string>
|
<string name="theme_dark">Dark</string>
|
||||||
|
<string name="settings_category_network">Network</string>
|
||||||
|
<string name="settings_request_timeout">Request timeout (ms)</string>
|
||||||
|
<string name="settings_connect_timeout">Connect timeout (ms)</string>
|
||||||
|
<string name="settings_socket_timeout">Socket timeout (ms)</string>
|
||||||
</resources>
|
</resources>
|
|
@ -31,6 +31,11 @@
|
||||||
app:title="@string/settings_category_device"
|
app:title="@string/settings_category_device"
|
||||||
app:icon="@drawable/ic_smartphone" />
|
app:icon="@drawable/ic_smartphone" />
|
||||||
|
|
||||||
|
<Preference
|
||||||
|
app:fragment="dev.jdtech.jellyfin.fragments.SettingsNetworkFragment"
|
||||||
|
app:title="@string/settings_category_network"
|
||||||
|
app:icon="@drawable/ic_network"/>
|
||||||
|
|
||||||
<Preference
|
<Preference
|
||||||
app:fragment="dev.jdtech.jellyfin.fragments.SettingsCacheFragment"
|
app:fragment="dev.jdtech.jellyfin.fragments.SettingsCacheFragment"
|
||||||
app:title="@string/settings_category_cache" />
|
app:title="@string/settings_category_cache" />
|
||||||
|
|
18
app/src/main/res/xml/fragment_settings_network.xml
Normal file
18
app/src/main/res/xml/fragment_settings_network.xml
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||||
|
<EditTextPreference
|
||||||
|
app:defaultValue="30000"
|
||||||
|
app:key="pref_network_request_timeout"
|
||||||
|
app:title="@string/settings_request_timeout"
|
||||||
|
app:useSimpleSummaryProvider="true" />
|
||||||
|
<EditTextPreference
|
||||||
|
app:defaultValue="6000"
|
||||||
|
app:key="pref_network_connect_timeout"
|
||||||
|
app:title="@string/settings_connect_timeout"
|
||||||
|
app:useSimpleSummaryProvider="true" />
|
||||||
|
<EditTextPreference
|
||||||
|
app:defaultValue="10000"
|
||||||
|
app:key="pref_network_socket_timeout"
|
||||||
|
app:title="@string/settings_socket_timeout"
|
||||||
|
app:useSimpleSummaryProvider="true" />
|
||||||
|
</PreferenceScreen>
|
Loading…
Reference in a new issue