Round 2 candidate 2: merge origin/main

This commit is contained in:
root 2026-11-07 22:34:09 +01:00
commit ed103bcb96
74 changed files with 4267 additions and 201 deletions

View file

@ -16,6 +16,7 @@ import com.github.damontecres.wholphin.ui.preferences.PreferenceGroup
import com.github.damontecres.wholphin.ui.preferences.PreferenceScreenOption
import com.github.damontecres.wholphin.ui.preferences.PreferenceValidation
import com.github.damontecres.wholphin.util.DebugLogTree
import org.justinvisser.wolfskin.tv.update.UpdateChannel
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.minutes
@ -627,7 +628,7 @@ sealed interface AppPreference<Pref, T> {
val UpdateUrl =
AppStringPreference<AppPreferences>(
title = R.string.update_url,
defaultValue = "https://git.justinvisser.org/api/v1/repos/justinzeus/wolfskin/releases/latest",
defaultValue = UpdateChannel.defaultUrl(BuildConfig.APPLICATION_ID),
getter = { it.updateUrl },
setter = { prefs, value ->
prefs.update { updateUrl = value }

View file

@ -36,6 +36,9 @@ import kotlinx.serialization.json.jsonPrimitive
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.justinvisser.wolfskin.tv.update.AndroidUpdateService
import org.justinvisser.wolfskin.tv.update.UpdateChannel
import org.justinvisser.wolfskin.tv.update.UpdateTransport
import timber.log.Timber
import java.io.File
import java.io.InputStream
@ -43,6 +46,7 @@ import java.io.OutputStream
import java.util.Date
import javax.inject.Inject
import javax.inject.Singleton
import javax.inject.Provider
import kotlin.time.Duration.Companion.hours
import kotlin.time.Duration.Companion.milliseconds
@ -55,6 +59,7 @@ class UpdateChecker
constructor(
@param:ApplicationContext private val context: Context,
@param:StandardOkHttpClient private val okHttpClient: OkHttpClient,
private val household: Provider<AndroidUpdateService>,
) {
companion object {
const val ASSET_NAME = "Wolfskin"
@ -123,6 +128,10 @@ class UpdateChecker
updateUrl: String,
showNegativeToast: Boolean = false,
) {
if (context.packageName == UpdateChannel.PACKAGE) {
household.get().controller.check(manual = showNegativeToast)
return
}
val pref = PreferenceManager.getDefaultSharedPreferences(context)
val now = Date()
val lastUpdateCheckThreshold =
@ -181,6 +190,12 @@ class UpdateChecker
* so this searches the release list instead of fetching a tag.
*/
suspend fun getRelease(version: Version): Release? {
if (context.packageName == UpdateChannel.PACKAGE) {
return withContext(WholphinDispatchers.IO) {
val releases = UpdateTransport().releasesForLatest(household.get().channelUrl())
findReleaseByVersion(releases, version)?.let { parseRelease(it, false) }
}
}
val request =
Request
.Builder()
@ -233,6 +248,9 @@ class UpdateChecker
release: Release,
callback: DownloadCallback,
) {
check(context.packageName != UpdateChannel.PACKAGE) {
"Household updates require the verified update controller"
}
withContext(WholphinDispatchers.IO) {
cleanup()
val request =

View file

@ -47,6 +47,7 @@ import androidx.tv.material3.Text
import androidx.tv.material3.surfaceColorAtElevation
import coil3.SingletonImageLoader
import coil3.imageLoader
import com.github.damontecres.wholphin.BuildConfig
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.preferences.AppPreference
import com.github.damontecres.wholphin.preferences.AppPreferences
@ -89,6 +90,7 @@ import com.github.damontecres.wholphin.util.DataLoadingState
import com.github.damontecres.wholphin.util.ExceptionHandler
import com.github.damontecres.wholphin.util.LoadingState
import kotlinx.coroutines.launch
import org.justinvisser.wolfskin.tv.update.UpdateChannel
import timber.log.Timber
import java.util.Locale
@ -355,7 +357,9 @@ fun PreferencesContent(
AppPreference.Update -> {
ClickPreference(
title =
if (release != null && updateAvailable) {
if (BuildConfig.APPLICATION_ID == UpdateChannel.PACKAGE) {
stringResource(R.string.check_for_updates)
} else if (release != null && updateAvailable) {
stringResource(R.string.install_update)
} else if (!preferences.autoCheckForUpdates && release == null) {
stringResource(R.string.check_for_updates)
@ -364,7 +368,9 @@ fun PreferencesContent(
},
onClick = {
if (movementSounds) playOnClickSound(context)
if (release != null && updateAvailable) {
if (BuildConfig.APPLICATION_ID == UpdateChannel.PACKAGE) {
viewModel.navigationManager.navigateTo(Destination.UpdateApp)
} else if (release != null && updateAvailable) {
release?.let {
viewModel.navigationManager.navigateTo(
Destination.UpdateApp,

View file

@ -44,6 +44,7 @@ import androidx.tv.material3.MaterialTheme
import androidx.tv.material3.Text
import androidx.tv.material3.surfaceColorAtElevation
import com.github.damontecres.wholphin.R
import com.github.damontecres.wholphin.BuildConfig
import com.github.damontecres.wholphin.preferences.UserPreferences
import com.github.damontecres.wholphin.services.DownloadCallback
import com.github.damontecres.wholphin.services.NavigationManager
@ -73,6 +74,9 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import timber.log.Timber
import org.justinvisser.wolfskin.tv.update.ClassicUpdatePage
import org.justinvisser.wolfskin.tv.update.UpdateChannel
import org.justinvisser.wolfskin.tv.update.UpdateController
import javax.inject.Inject
@HiltViewModel
@ -82,6 +86,7 @@ class UpdateViewModel
private val userPreferencesService: UserPreferencesService,
val updater: UpdateChecker,
val navigationManager: NavigationManager,
val householdController: UpdateController,
) : ViewModel(),
DownloadCallback {
private val _state = MutableStateFlow(InstallUpdateState())
@ -93,6 +98,10 @@ class UpdateViewModel
val currentVersion = updater.getInstalledVersion()
fun init() {
if (BuildConfig.APPLICATION_ID == UpdateChannel.PACKAGE) {
householdController.check(true)
return
}
_state.update { it.copy(loading = LoadingState.Loading) }
viewModelScope.launchIO {
val updateUrl = userPreferencesService.getCurrent().appPreferences.updateUrl
@ -166,6 +175,10 @@ fun InstallUpdatePage(
modifier: Modifier = Modifier,
viewModel: UpdateViewModel = hiltViewModel(),
) {
if (BuildConfig.APPLICATION_ID == UpdateChannel.PACKAGE) {
ClassicUpdatePage(viewModel.householdController, modifier)
return
}
OneTimeLaunchedEffect { viewModel.init() }
val state by viewModel.state.collectAsState()

View file

@ -52,6 +52,9 @@ class SwitchSeerrViewModel
_state.update { it.copy(loading = LoadingState.Success) }
}
}
} else {
// Nothing to check so set success
_state.update { it.copy(loading = LoadingState.Success) }
}
}