diff --git a/README.md b/README.md
index 8fd53cfa..fd07c32d 100644
--- a/README.md
+++ b/README.md
@@ -18,23 +18,34 @@ This is not a fork of the [official client](https://github.com/jellyfin/jellyfin
-
+
## Features
+### User interface
+
- A navigation drawer for quick access to libraries, search, and settings from almost anywhere in the app
+- Option to combine Continue Watching & Next Up rows
- Show Movie/TV Show titles when browsing libraries
-- Play TV Show theme music, if available
-- Plex inspired playback controls, such as:
- - Using D-Pad left/right for seeking during playback
- - Quickly access video chapters during playback
- - Optionally skip back a few seconds when resuming playback
-- Other (subjective) enhancements:
- - Subtly show playback position along the bottom of the screen while seeking w/ D-Pad
- - Force Continue Watching & Next Up TV episodes to use their Series posters
+- Play theme music, if available
+- Customize layout grids for libraries
+- Access all your favorites quickly from the nav drawer
+- Multiple app color themes
+
+### Playback
+
- Different media playback engines, including:
- Default ExoPlayer/Media3
- Experimental MPV
+- Plex inspired playback controls, such as:
+ - Using D-Pad left/right for seeking during playback
+ - Quickly access video chapters & queue during playback
+ - Optionally skip back a few seconds when resuming playback
+- Live TV & DVR support
+- Auto play next episodes with pass out protection
+- Other (subjective) enhancements:
+ - Subtly show playback position along the bottom of the screen while seeking w/ D-Pad
+ - Force Continue Watching & Next Up TV episodes to use their Series posters
### Roadmap
@@ -88,8 +99,11 @@ You can [help translate Wholphin](https://translate.codeberg.org/engage/wholphin
### Movie library browsing
+### Movie page
+
+
### Series page
-
+
### Playlist
diff --git a/app/src/main/java/com/github/damontecres/wholphin/MainActivity.kt b/app/src/main/java/com/github/damontecres/wholphin/MainActivity.kt
index dd3312c8..ef90f38a 100644
--- a/app/src/main/java/com/github/damontecres/wholphin/MainActivity.kt
+++ b/app/src/main/java/com/github/damontecres/wholphin/MainActivity.kt
@@ -1,7 +1,6 @@
package com.github.damontecres.wholphin
import android.os.Bundle
-import android.view.WindowManager
import androidx.activity.compose.setContent
import androidx.appcompat.app.AppCompatActivity
import androidx.compose.foundation.background
@@ -10,7 +9,6 @@ import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.size
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.runtime.CompositionLocalProvider
-import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
@@ -45,7 +43,6 @@ import com.github.damontecres.wholphin.services.UpdateChecker
import com.github.damontecres.wholphin.services.hilt.AuthOkHttpClient
import com.github.damontecres.wholphin.ui.CoilConfig
import com.github.damontecres.wholphin.ui.LocalImageUrlService
-import com.github.damontecres.wholphin.ui.isNotNullOrBlank
import com.github.damontecres.wholphin.ui.launchIO
import com.github.damontecres.wholphin.ui.nav.ApplicationContent
import com.github.damontecres.wholphin.ui.nav.Destination
@@ -53,8 +50,6 @@ import com.github.damontecres.wholphin.ui.theme.WholphinTheme
import com.github.damontecres.wholphin.util.DebugLogTree
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.coroutines.Dispatchers
-import kotlinx.coroutines.flow.firstOrNull
-import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import okhttp3.OkHttpClient
import org.jellyfin.sdk.model.serializer.toUUIDOrNull
@@ -146,16 +141,17 @@ class MainActivity : AppCompatActivity() {
) {
var isRestoringSession by remember { mutableStateOf(true) }
LaunchedEffect(Unit) {
- if (appPreferences.signInAutomatically) {
- try {
- serverRepository.restoreSession(
- appPreferences.currentServerId?.toUUIDOrNull(),
- appPreferences.currentUserId?.toUUIDOrNull(),
- )
- } catch (ex: Exception) {
- Timber.e(ex, "Exception restoring session")
- }
+ // TODO PIN-related
+// if (appPreferences.signInAutomatically) {
+ try {
+ serverRepository.restoreSession(
+ appPreferences.currentServerId?.toUUIDOrNull(),
+ appPreferences.currentUserId?.toUUIDOrNull(),
+ )
+ } catch (ex: Exception) {
+ Timber.e(ex, "Exception restoring session")
}
+// }
isRestoringSession = false
}
val current by serverRepository.current.observeAsState()
@@ -177,32 +173,34 @@ class MainActivity : AppCompatActivity() {
)
}
} else {
- DisposableEffect(Unit) {
- onDispose {
- if (!appPreferences.signInAutomatically) {
- serverRepository.closeSession()
- }
- }
- }
+ // TODO PIN-related
+// DisposableEffect(Unit) {
+// onDispose {
+// if (!appPreferences.signInAutomatically || current?.user?.hasPin == true) {
+// serverRepository.closeSession()
+// }
+// }
+// }
key(current?.server?.id, current?.user?.id) {
- LaunchedEffect(current?.user?.pin) {
- if (current?.user?.pin?.isNotNullOrBlank() == true) {
- // If user has a pin, then obscure the window in previews
- window?.setFlags(
- WindowManager.LayoutParams.FLAG_SECURE,
- WindowManager.LayoutParams.FLAG_SECURE,
- )
- } else {
- window?.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
- }
- }
+ // TODO PIN-related
+// LaunchedEffect(current?.user?.pin) {
+// if (current?.user?.pin?.isNotNullOrBlank() == true) {
+// // If user has a pin, then obscure the window in previews
+// window?.setFlags(
+// WindowManager.LayoutParams.FLAG_SECURE,
+// WindowManager.LayoutParams.FLAG_SECURE,
+// )
+// } else {
+// window?.clearFlags(WindowManager.LayoutParams.FLAG_SECURE)
+// }
+// }
val initialDestination =
when {
current != null -> Destination.Home()
- !appPreferences.signInAutomatically -> Destination.ServerList
+ // TODO PIN-related
+ // !appPreferences.signInAutomatically -> Destination.ServerList
- // TODO user list?
else -> Destination.ServerList
}
val backStack = rememberNavBackStack(initialDestination)
@@ -249,11 +247,12 @@ class MainActivity : AppCompatActivity() {
override fun onRestart() {
super.onRestart()
- val signInAutomatically =
- runBlocking { userPreferencesDataStore.data.firstOrNull()?.signInAutomatically } ?: true
- Timber.i("onRestart: signInAutomatically=$signInAutomatically")
- if (!signInAutomatically) {
- serverRepository.closeSession()
- }
+ // TODO PIN-related
+// val signInAutomatically =
+// runBlocking { userPreferencesDataStore.data.firstOrNull()?.signInAutomatically } ?: true
+// Timber.i("onRestart: signInAutomatically=$signInAutomatically")
+// if (!signInAutomatically || serverRepository.currentUser.value?.hasPin == true) {
+// serverRepository.closeSession()
+// }
}
}
diff --git a/app/src/main/java/com/github/damontecres/wholphin/data/ServerRepository.kt b/app/src/main/java/com/github/damontecres/wholphin/data/ServerRepository.kt
index eed4422f..5fc98724 100644
--- a/app/src/main/java/com/github/damontecres/wholphin/data/ServerRepository.kt
+++ b/app/src/main/java/com/github/damontecres/wholphin/data/ServerRepository.kt
@@ -109,6 +109,8 @@ class ServerRepository
/**
* Restores a session for the given server & user such as when the app reopens
+ *
+ * If user has a PIN, this returns false
*/
suspend fun restoreSession(
serverId: UUID?,
@@ -124,7 +126,7 @@ class ServerRepository
}
if (serverAndUsers != null) {
val user = serverAndUsers.users.firstOrNull { it.id == userId }
- if (user != null) {
+ if (user != null && !user.hasPin) {
changeUser(serverAndUsers.server, user)
return true
}
diff --git a/app/src/main/java/com/github/damontecres/wholphin/data/model/JellyfinServer.kt b/app/src/main/java/com/github/damontecres/wholphin/data/model/JellyfinServer.kt
index 0b8a3302..d8e40779 100644
--- a/app/src/main/java/com/github/damontecres/wholphin/data/model/JellyfinServer.kt
+++ b/app/src/main/java/com/github/damontecres/wholphin/data/model/JellyfinServer.kt
@@ -52,6 +52,8 @@ data class JellyfinUser(
val accessToken: String?,
val pin: String? = null,
) {
+ val hasPin: Boolean get() = pin.isNotNullOrBlank()
+
override fun toString(): String =
"JellyfinUser(rowId=$rowId, id=$id, name=$name, serverId=$serverId, accessToken?=${accessToken.isNotNullOrBlank()}, pin?=${pin.isNotNullOrBlank()})"
}
diff --git a/app/src/main/java/com/github/damontecres/wholphin/preferences/AppPreference.kt b/app/src/main/java/com/github/damontecres/wholphin/preferences/AppPreference.kt
index 4e182e0c..9a196d6b 100644
--- a/app/src/main/java/com/github/damontecres/wholphin/preferences/AppPreference.kt
+++ b/app/src/main/java/com/github/damontecres/wholphin/preferences/AppPreference.kt
@@ -793,7 +793,8 @@ val basicPreferences =
title = R.string.ui_interface,
preferences =
listOf(
- AppPreference.SignInAuto,
+ // TODO PIN-related
+ // AppPreference.SignInAuto,
AppPreference.HomePageItems,
AppPreference.CombineContinueNext,
AppPreference.RewatchNextUp,
@@ -826,7 +827,8 @@ val basicPreferences =
title = R.string.profile_specific_settings,
preferences =
listOf(
- AppPreference.RequireProfilePin,
+ // TODO PIN-related
+ // AppPreference.RequireProfilePin,
AppPreference.UserPinnedNavDrawerItems,
),
),
diff --git a/app/src/main/java/com/github/damontecres/wholphin/ui/setup/SwitchUserContent.kt b/app/src/main/java/com/github/damontecres/wholphin/ui/setup/SwitchUserContent.kt
index e0aeb5a1..df0b79ee 100644
--- a/app/src/main/java/com/github/damontecres/wholphin/ui/setup/SwitchUserContent.kt
+++ b/app/src/main/java/com/github/damontecres/wholphin/ui/setup/SwitchUserContent.kt
@@ -119,11 +119,13 @@ fun SwitchUserContent(
users = users,
currentUser = currentUser,
onSwitchUser = { user ->
- if (user.pin.isNotNullOrBlank()) {
- switchUserWithPin = user
- } else {
- viewModel.switchUser(user)
- }
+ // TODO PIN-related
+// if (user.pin.isNotNullOrBlank()) {
+// switchUserWithPin = user
+// } else {
+// viewModel.switchUser(user)
+// }
+ viewModel.switchUser(user)
},
onAddUser = { showAddUser = true },
onRemoveUser = { user ->