Skip to content
Draft
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
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ class ServerRepository
val currentUser: JellyfinUser? get() = _current.value?.user
val currentUserFlow: Flow<JellyfinUser?> get() = _current.map { it?.user }

val serverPluginInstalled = MutableStateFlow<Boolean>(false)

/**
* Adds a server to the app database and updated the [ApiClient] to the server's URL
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ class HomeSettingsService
constructor(
@param:ApplicationContext private val context: Context,
private val api: ApiClient,
private val serverPluginApi: ServerPluginApi,
private val serverRepository: ServerRepository,
private val userPreferencesService: UserPreferencesService,
private val navDrawerService: NavDrawerService,
Expand Down Expand Up @@ -204,6 +205,14 @@ class HomeSettingsService
return HomePageSettings(rows, version)
}

private suspend fun tryLoad(block: suspend () -> HomePageSettings?): HomePageSettings? =
try {
block.invoke()
} catch (ex: Exception) {
Timber.w(ex, "Error loading settings")
null
}

/**
* Loads [HomePageSettings] into [currentSettings]
*
Expand All @@ -214,22 +223,14 @@ class HomeSettingsService
suspend fun loadCurrentSettings(userId: UUID) {
Timber.v("Getting setting for %s", userId)
// User local then server/remote otherwise create a default
// TODO figure out priority order
val settings =
try {
val local = loadFromLocal(userId)
Timber.v("Found local? %s", local != null)
local
} catch (ex: Exception) {
Timber.w(ex, "Error loading local settings")
// TODO show toast?
null
} ?: try {
val remote = loadFromServer(userId)
Timber.v("Found remote? %s", remote != null)
remote
} catch (ex: Exception) {
Timber.w(ex, "Error loading remote settings")
null
tryLoad {
serverPluginApi.fetchHomePageSettings()
} ?: tryLoad {
loadFromLocal(userId)
} ?: tryLoad {
loadFromServer(userId)
}
val resolvedSettings =
if (settings != null) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package com.github.damontecres.wholphin.services

import com.github.damontecres.wholphin.data.model.HomePageSettings
import com.github.damontecres.wholphin.services.hilt.AuthOkHttpClient
import kotlinx.serialization.ExperimentalSerializationApi
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.decodeFromStream
import okhttp3.OkHttpClient
import okhttp3.Request
import org.jellyfin.sdk.api.client.ApiClient
import org.jellyfin.sdk.api.client.exception.ApiClientException
import timber.log.Timber
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class ServerPluginApi
@Inject
constructor(
@param:AuthOkHttpClient private val okHttpClient: OkHttpClient,
private val api: ApiClient,
) {
private fun createUrl(path: String): String? =
api.baseUrl?.let { if (it.endsWith("/")) "${it}wholphin/$path" else "$it/wholphin/$path" }

private val json =
Json {
ignoreUnknownKeys = false
}

companion object {
private const val HOME_CONFIG_PATH = "homesettings"
}

suspend fun public(): Boolean {
val url = createUrl("public") ?: return false
val request =
Request
.Builder()
.url(url)
.get()
.build()
return okHttpClient.newCall(request).execute().isSuccessful
}

@OptIn(ExperimentalSerializationApi::class)
suspend fun fetchHomePageSettings(): HomePageSettings? {
val url = createUrl(HOME_CONFIG_PATH) ?: return null
val request =
Request
.Builder()
.url(url)
.get()
.build()
return okHttpClient.newCall(request).execute().use { res ->
if (res.isSuccessful) {
json.decodeFromStream<HomePageSettings>(res.body.byteStream())
} else if (res.code == 404) {
Timber.w("fetchHomePageSettings returned 404")
null
} else {
throw ApiClientException(res.code.toString() + " " + res.body.string())
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class UserSwitchListener
private val seerrServerDao: SeerrServerDao,
private val seerrApi: SeerrApi,
private val homeSettingsService: HomeSettingsService,
private val serverPluginApi: ServerPluginApi,
) {
init {
context as AppCompatActivity
Expand All @@ -60,8 +61,19 @@ class UserSwitchListener
AppCompatDelegate.setApplicationLocales(localeList)
}

// Check for home settings
// Check if plugin is installed, then for home settings
launchIO {
val serverPluginInstalled =
try {
serverPluginApi.public()
} catch (ex: Exception) {
Timber.e(ex, "Error checking for server plugin")
false
}
Timber.i("Server plugin installed: %s", serverPluginInstalled)
serverRepository.serverPluginInstalled.value = serverPluginInstalled

// Check for home settings
homeSettingsService.loadCurrentSettings(user.id)
}
if (BuildConfig.DISCOVER_ENABLED) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ fun HomeSettingsGlobal(
onClickSave: () -> Unit,
onClickLoad: () -> Unit,
onClickLoadWeb: () -> Unit,
serverPluginActive: Boolean,
onClickLoadPlugin: () -> Unit,
onClickReset: () -> Unit,
onClickViewNextUp: () -> Unit,
modifier: Modifier = Modifier,
Expand Down Expand Up @@ -178,6 +180,22 @@ fun HomeSettingsGlobal(
modifier = Modifier,
)
}
if (serverPluginActive) {
item {
HomeSettingsListItem(
selected = false,
headlineText = stringResource(R.string.load_from_server_plugin),
leadingContent = {
Text(
text = stringResource(R.string.fa_download),
fontFamily = FontAwesome,
)
},
onClick = onClickLoadPlugin,
modifier = Modifier,
)
}
}
item {
HomeSettingsListItem(
selected = false,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ fun HomeSettingsPage(
var showRemovedNextUpDialog by remember { mutableStateOf(false) }

val state by viewModel.state.collectAsState()
val serverPluginActive by viewModel.serverPluginActive.collectAsState()
var position by rememberPosition(0, 0)
// TODO discover rows
val discoverEnabled = false // by viewModel.discoverEnabled.collectAsState(false)
Expand Down Expand Up @@ -290,6 +291,13 @@ fun HomeSettingsPage(
viewModel.loadFromRemote()
}
},
serverPluginActive = serverPluginActive,
onClickLoadPlugin = {
showConfirmDialog =
ShowConfirm(R.string.overwrite_local_settings) {
viewModel.loadFromRemotePlugin()
}
},
onClickLoadWeb = {
showConfirmDialog =
ShowConfirm(R.string.overwrite_local_settings) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import com.github.damontecres.wholphin.services.HomeRowConfigDisplay
import com.github.damontecres.wholphin.services.HomeSettingsService
import com.github.damontecres.wholphin.services.NavDrawerService
import com.github.damontecres.wholphin.services.SeerrServerRepository
import com.github.damontecres.wholphin.services.ServerPluginApi
import com.github.damontecres.wholphin.services.UnsupportedHomeSettingsVersionException
import com.github.damontecres.wholphin.services.UserPreferencesService
import com.github.damontecres.wholphin.services.hilt.IoCoroutineScope
Expand Down Expand Up @@ -79,12 +80,15 @@ class HomeSettingsViewModel
private val navDrawerService: NavDrawerService,
private val backdropService: BackdropService,
private val seerrServerRepository: SeerrServerRepository,
private val serverPluginApi: ServerPluginApi,
val preferencesDataStore: DataStore<AppPreferences>,
@param:IoCoroutineScope private val ioScope: CoroutineScope,
) : ViewModel() {
private val _state = MutableStateFlow(HomePageSettingsState.EMPTY)
val state: StateFlow<HomePageSettingsState> = _state

val serverPluginActive get() = serverRepository.serverPluginInstalled

private var idCounter by Delegates.notNull<Int>()

val discoverEnabled = seerrServerRepository.active
Expand Down Expand Up @@ -784,6 +788,40 @@ class HomeSettingsViewModel
}
}

fun loadFromRemotePlugin() {
viewModelScope.launchIO {
Timber.d("Loading home settings from server plugin")
try {
// TODO should this remove local settings?
// TODO how to set up priorities
_state.update { it.copy(loading = LoadingState.Loading) }
val result = serverPluginApi.fetchHomePageSettings()
if (result != null) {
Timber.v("Got remote settings")
val newRows =
result.rows.mapIndexed { index, config ->
homeSettingsService.resolve(index, config)
}
idCounter = newRows.maxOfOrNull { it.id }?.plus(1) ?: 0
_state.update {
it.copy(rows = newRows)
}
} else {
Timber.v("No server plugin settings")
showToast(context, "No server plugin settings found")
}
fetchRowData()
} catch (ex: UnsupportedHomeSettingsVersionException) {
// TODO
Timber.w(ex)
showToast(context, "Error: ${ex.localizedMessage}")
} catch (ex: Exception) {
Timber.e(ex)
showToast(context, "Error: ${ex.localizedMessage}")
}
}
}

fun onConfigAction(
row: HomeRowConfigDisplay,
action: HomeRowConfigAction,
Expand Down
1 change: 1 addition & 0 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -822,4 +822,5 @@
<string name="tomatoes">Tomatoes</string>
<string name="sort">Sort</string>
<string name="split_into_separate_rows">Split into separate rows</string>
<string name="load_from_server_plugin">Load default from server</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ class TestHomeRowSamples {
imageUrlService = mockk(),
suggestionService = mockk(),
displayPreferencesService = mockk(),
serverPluginApi = mockk(),
)

val str = """{
Expand Down
Loading