Skip to content

Commit af75b2e

Browse files
committed
Merge branch 'main' into develop/server-plugin
2 parents 3f8dfac + c68ab33 commit af75b2e

71 files changed

Lines changed: 5056 additions & 2393 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/schemas/com.github.damontecres.wholphin.data.AppDatabase/32.json

Lines changed: 659 additions & 0 deletions
Large diffs are not rendered by default.

app/src/main/java/com/github/damontecres/wholphin/MainActivity.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -434,15 +434,18 @@ class MainActivityViewModel
434434
appUpgradeHandler.copySubfont(false)
435435
val prefs =
436436
preferences.data.firstOrNull() ?: AppPreferences.getDefaultInstance()
437-
val userHasPin = serverRepository.currentUser.value?.hasPin == true
438-
if (prefs.signInAutomatically && !userHasPin) {
437+
val profileProtected =
438+
serverRepository.currentUser.value?.let {
439+
it.hasPin || it.requireLogin
440+
} == true
441+
if (prefs.signInAutomatically && !profileProtected) {
439442
val current =
440443
serverRepository.restoreSession(
441444
prefs.currentServerId?.toUUIDOrNull(),
442445
prefs.currentUserId?.toUUIDOrNull(),
443446
)
444447
if (current != null) {
445-
if (current.user.hasPin) {
448+
if (current.user.hasPin || current.user.requireLogin) {
446449
navigationManager.navigateTo(SetupDestination.UserList(current.server))
447450
} else {
448451
// Restored

app/src/main/java/com/github/damontecres/wholphin/MainContent.kt

Lines changed: 74 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import androidx.compose.foundation.layout.fillMaxSize
77
import androidx.compose.foundation.layout.size
88
import androidx.compose.material3.CircularProgressIndicator
99
import androidx.compose.runtime.Composable
10+
import androidx.compose.runtime.CompositionLocalProvider
1011
import androidx.compose.runtime.LaunchedEffect
1112
import androidx.compose.runtime.collectAsState
1213
import androidx.compose.runtime.getValue
@@ -36,6 +37,8 @@ import com.github.damontecres.wholphin.ui.components.AppScreensaver
3637
import com.github.damontecres.wholphin.ui.nav.ApplicationContent
3738
import com.github.damontecres.wholphin.ui.setup.SwitchServerContent
3839
import com.github.damontecres.wholphin.ui.setup.SwitchUserContent
40+
import com.github.damontecres.wholphin.ui.util.InterfaceCustomization
41+
import com.github.damontecres.wholphin.ui.util.LocalInterfaceCustomization
3942

4043
@Composable
4144
fun MainContent(
@@ -55,64 +58,22 @@ fun MainContent(
5558
) {
5659
// val backStack = rememberNavBackStack(SetupDestination.Loading)
5760
// setupNavigationManager.backStack = backStack
58-
NavDisplay(
59-
backStack = backStack,
60-
onBack = { backStack.removeLastOrNull() },
61-
entryDecorators =
62-
listOf(
63-
rememberSaveableStateHolderNavEntryDecorator(),
64-
rememberViewModelStoreNavEntryDecorator(),
65-
),
66-
entryProvider = { key ->
67-
key as SetupDestination
68-
NavEntry(key) {
69-
when (key) {
70-
SetupDestination.Loading -> {
71-
Box(
72-
modifier = Modifier.size(200.dp),
73-
contentAlignment = Alignment.Center,
74-
) {
75-
CircularProgressIndicator(
76-
color = MaterialTheme.colorScheme.border,
77-
modifier = Modifier.align(Alignment.Center),
78-
)
79-
}
80-
}
81-
82-
SetupDestination.ServerList -> {
83-
SwitchServerContent(Modifier.fillMaxSize())
84-
}
85-
86-
is SetupDestination.UserList -> {
87-
SwitchUserContent(
88-
server = key.server,
89-
Modifier.fillMaxSize(),
90-
)
91-
}
92-
93-
is SetupDestination.AppContent -> {
94-
LaunchedEffect(Unit) {
95-
backdropService.clearBackdrop()
96-
}
97-
val current = key.current
98-
var showContent by remember {
99-
mutableStateOf(true)
100-
}
101-
LifecycleEventEffect(Lifecycle.Event.ON_STOP) {
102-
if (!appPreferences.signInAutomatically) {
103-
showContent = false
104-
}
105-
}
106-
107-
if (showContent) {
108-
ApplicationContent(
109-
user = current.user,
110-
server = current.server,
111-
navigationManager = navigationManager,
112-
preferences = preferences,
113-
modifier = Modifier.fillMaxSize(),
114-
)
115-
} else {
61+
val interfaceCustomization =
62+
remember(appPreferences) { InterfaceCustomization(appPreferences) }
63+
CompositionLocalProvider(LocalInterfaceCustomization provides interfaceCustomization) {
64+
NavDisplay(
65+
backStack = backStack,
66+
onBack = { backStack.removeLastOrNull() },
67+
entryDecorators =
68+
listOf(
69+
rememberSaveableStateHolderNavEntryDecorator(),
70+
rememberViewModelStoreNavEntryDecorator(),
71+
),
72+
entryProvider = { key ->
73+
key as SetupDestination
74+
NavEntry(key) {
75+
when (key) {
76+
SetupDestination.Loading -> {
11677
Box(
11778
modifier = Modifier.size(200.dp),
11879
contentAlignment = Alignment.Center,
@@ -123,18 +84,64 @@ fun MainContent(
12384
)
12485
}
12586
}
87+
88+
SetupDestination.ServerList -> {
89+
SwitchServerContent(Modifier.fillMaxSize())
90+
}
91+
92+
is SetupDestination.UserList -> {
93+
SwitchUserContent(
94+
server = key.server,
95+
Modifier.fillMaxSize(),
96+
)
97+
}
98+
99+
is SetupDestination.AppContent -> {
100+
LaunchedEffect(Unit) {
101+
backdropService.clearBackdrop()
102+
}
103+
val current = key.current
104+
var showContent by remember {
105+
mutableStateOf(true)
106+
}
107+
LifecycleEventEffect(Lifecycle.Event.ON_STOP) {
108+
if (!appPreferences.signInAutomatically) {
109+
showContent = false
110+
}
111+
}
112+
113+
if (showContent) {
114+
ApplicationContent(
115+
user = current.user,
116+
server = current.server,
117+
navigationManager = navigationManager,
118+
preferences = preferences,
119+
modifier = Modifier.fillMaxSize(),
120+
)
121+
} else {
122+
Box(
123+
modifier = Modifier.size(200.dp),
124+
contentAlignment = Alignment.Center,
125+
) {
126+
CircularProgressIndicator(
127+
color = MaterialTheme.colorScheme.border,
128+
modifier = Modifier.align(Alignment.Center),
129+
)
130+
}
131+
}
132+
}
126133
}
127134
}
135+
},
136+
)
137+
val screenSaverState by screensaverService.state.collectAsState()
138+
if (screenSaverState.enabled || screenSaverState.enabledTemp) {
139+
AnimatedVisibility(
140+
screenSaverState.show,
141+
Modifier.fillMaxSize(),
142+
) {
143+
AppScreensaver(appPreferences, Modifier.fillMaxSize())
128144
}
129-
},
130-
)
131-
val screenSaverState by screensaverService.state.collectAsState()
132-
if (screenSaverState.enabled || screenSaverState.enabledTemp) {
133-
AnimatedVisibility(
134-
screenSaverState.show,
135-
Modifier.fillMaxSize(),
136-
) {
137-
AppScreensaver(appPreferences, Modifier.fillMaxSize())
138145
}
139146
}
140147
}

app/src/main/java/com/github/damontecres/wholphin/data/AppDatabase.kt

Lines changed: 40 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,19 @@ import com.github.damontecres.wholphin.data.model.PlaybackLanguageChoice
1919
import com.github.damontecres.wholphin.data.model.SeerrServer
2020
import com.github.damontecres.wholphin.data.model.SeerrUser
2121
import com.github.damontecres.wholphin.ui.components.ViewOptions
22+
import kotlinx.serialization.KSerializer
23+
import kotlinx.serialization.descriptors.PrimitiveKind
24+
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
25+
import kotlinx.serialization.descriptors.SerialDescriptor
26+
import kotlinx.serialization.encoding.Decoder
27+
import kotlinx.serialization.encoding.Encoder
2228
import kotlinx.serialization.json.Json
2329
import org.jellyfin.sdk.model.api.ItemSortBy
2430
import org.jellyfin.sdk.model.api.SortOrder
2531
import org.jellyfin.sdk.model.serializer.toUUID
2632
import timber.log.Timber
33+
import java.time.ZonedDateTime
34+
import java.time.format.DateTimeFormatter
2735
import java.util.UUID
2836

2937
@Database(
@@ -40,7 +48,7 @@ import java.util.UUID
4048
SeerrUser::class,
4149

4250
],
43-
version = 31,
51+
version = 32,
4452
exportSchema = true,
4553
autoMigrations = [
4654
AutoMigration(3, 4),
@@ -55,6 +63,7 @@ import java.util.UUID
5563
AutoMigration(12, 20),
5664
AutoMigration(20, 30),
5765
AutoMigration(30, 31),
66+
AutoMigration(31, 32),
5867
],
5968
)
6069
@TypeConverters(Converters::class)
@@ -75,6 +84,11 @@ abstract class AppDatabase : RoomDatabase() {
7584
}
7685

7786
class Converters {
87+
private val json =
88+
Json {
89+
ignoreUnknownKeys = true
90+
}
91+
7892
@TypeConverter
7993
fun convertToString(id: UUID): String = id.toString().replace("-", "")
8094

@@ -94,28 +108,49 @@ class Converters {
94108
fun convertSortOrder(sort: String): SortOrder? = SortOrder.fromNameOrNull(sort)
95109

96110
@TypeConverter
97-
fun convertGetItemsFilter(filter: GetItemsFilter): String = Json.encodeToString(filter)
111+
fun convertGetItemsFilter(filter: GetItemsFilter): String = json.encodeToString(filter)
98112

99113
@TypeConverter
100114
fun convertGetItemsFilter(filter: String): GetItemsFilter =
101115
try {
102-
Json.decodeFromString(filter)
116+
json.decodeFromString(filter)
103117
} catch (ex: Exception) {
104118
Timber.e(ex, "Error parsing filter")
105119
GetItemsFilter()
106120
}
107121

108122
@TypeConverter
109-
fun convertViewOptions(viewOptions: ViewOptions?): String? = viewOptions?.let { Json.encodeToString(viewOptions) }
123+
fun convertViewOptions(viewOptions: ViewOptions?): String? = viewOptions?.let { json.encodeToString(viewOptions) }
110124

111125
@TypeConverter
112126
fun convertViewOptions(viewOptions: String?): ViewOptions? =
113127
try {
114-
viewOptions?.let { Json.decodeFromString(viewOptions) }
128+
viewOptions?.let { json.decodeFromString(viewOptions) }
115129
} catch (ex: Exception) {
116130
Timber.e(ex, "Error parsing view options")
117131
null
118132
}
133+
134+
@TypeConverter
135+
fun convertToString(dateTime: ZonedDateTime): String = DateTimeFormatter.ISO_ZONED_DATE_TIME.format(dateTime)
136+
137+
@TypeConverter
138+
fun convertToLocalDateTime(dateTime: String): ZonedDateTime = ZonedDateTime.parse(dateTime, DateTimeFormatter.ISO_ZONED_DATE_TIME)
139+
}
140+
141+
class ZonedDateTimeSerializer : KSerializer<ZonedDateTime> {
142+
override val descriptor: SerialDescriptor =
143+
PrimitiveSerialDescriptor(ZonedDateTime::class.qualifiedName!!, PrimitiveKind.STRING)
144+
145+
override fun deserialize(decoder: Decoder): ZonedDateTime =
146+
ZonedDateTime.parse(decoder.decodeString(), DateTimeFormatter.ISO_ZONED_DATE_TIME)
147+
148+
override fun serialize(
149+
encoder: Encoder,
150+
value: ZonedDateTime,
151+
) {
152+
encoder.encodeString(DateTimeFormatter.ISO_ZONED_DATE_TIME.format(value))
153+
}
119154
}
120155

121156
object Migrations {

app/src/main/java/com/github/damontecres/wholphin/data/ExtrasItem.kt

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@ import androidx.annotation.PluralsRes
44
import androidx.annotation.StringRes
55
import com.github.damontecres.wholphin.R
66
import com.github.damontecres.wholphin.data.model.BaseItem
7+
import com.github.damontecres.wholphin.ui.AspectRatio
8+
import com.github.damontecres.wholphin.ui.components.ViewOptions
79
import com.github.damontecres.wholphin.ui.nav.Destination
10+
import com.github.damontecres.wholphin.util.GetItemsRequestHandler
811
import org.jellyfin.sdk.model.UUID
912
import org.jellyfin.sdk.model.api.ExtraType
13+
import org.jellyfin.sdk.model.api.ItemSortBy
14+
import org.jellyfin.sdk.model.api.SortOrder
15+
import org.jellyfin.sdk.model.api.request.GetItemsRequest
1016

1117
/**
1218
* Represents "extras" for media such as behind-the-scenes or deleted scenes
@@ -34,7 +40,24 @@ sealed interface ExtrasItem {
3440
override val isPlayed: Boolean,
3541
) : ExtrasItem {
3642
override val destination: Destination =
37-
Destination.ItemGrid(null, type.stringRes, items.map { it.id })
43+
Destination.ItemGrid(
44+
title = null,
45+
titleRes = type.stringRes,
46+
request =
47+
GetItemsRequest(
48+
ids = items.map { it.id },
49+
sortBy = listOf(ItemSortBy.SORT_NAME),
50+
sortOrder = listOf(SortOrder.ASCENDING),
51+
),
52+
requestHandler = GetItemsRequestHandler,
53+
initialPosition = 0,
54+
viewOptions =
55+
ViewOptions(
56+
columns = 3,
57+
spacing = 24,
58+
aspectRatio = AspectRatio.WIDE,
59+
),
60+
)
3861

3962
override val playedPercentage
4063
get() = -1.0

0 commit comments

Comments
 (0)