mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-05-06 02:09:08 +00:00
refactor: profile ID resolution ,improve addon handling logic
This commit is contained in:
parent
13da43d303
commit
ec53965105
3 changed files with 59 additions and 16 deletions
|
|
@ -53,9 +53,10 @@ object AddonRepository {
|
|||
private val activeRefreshJobs = mutableMapOf<String, Job>()
|
||||
|
||||
fun initialize() {
|
||||
val effectiveProfileId = resolveEffectiveProfileId(ProfileRepository.activeProfileId)
|
||||
if (initialized) return
|
||||
initialized = true
|
||||
currentProfileId = ProfileRepository.activeProfileId
|
||||
currentProfileId = effectiveProfileId
|
||||
log.d { "initialize() — loading local addons for profile $currentProfileId" }
|
||||
|
||||
val storedUrls = dedupeManifestUrls(AddonStorage.loadInstalledAddonUrls(currentProfileId))
|
||||
|
|
@ -78,9 +79,10 @@ object AddonRepository {
|
|||
}
|
||||
|
||||
fun onProfileChanged(profileId: Int) {
|
||||
if (profileId == currentProfileId && initialized) return
|
||||
val effectiveProfileId = resolveEffectiveProfileId(profileId)
|
||||
if (effectiveProfileId == currentProfileId && initialized) return
|
||||
cancelActiveRefreshes()
|
||||
currentProfileId = profileId
|
||||
currentProfileId = effectiveProfileId
|
||||
initialized = false
|
||||
pulledFromServer = false
|
||||
_uiState.value = AddonsUiState()
|
||||
|
|
@ -95,13 +97,13 @@ object AddonRepository {
|
|||
}
|
||||
|
||||
suspend fun pullFromServer(profileId: Int) {
|
||||
currentProfileId = profileId
|
||||
currentProfileId = resolveEffectiveProfileId(profileId)
|
||||
log.i { "pullFromServer() — profileId=$profileId, initialized=$initialized, pulledFromServer=$pulledFromServer" }
|
||||
runCatching {
|
||||
val rows = SupabaseProvider.client.postgrest
|
||||
.from("addons")
|
||||
.select {
|
||||
filter { eq("profile_id", profileId) }
|
||||
filter { eq("profile_id", currentProfileId) }
|
||||
order("sort_order", Order.ASCENDING)
|
||||
}
|
||||
.decodeList<AddonRow>()
|
||||
|
|
@ -111,10 +113,10 @@ object AddonRepository {
|
|||
urls.forEachIndexed { i, u -> log.d { " server[$i]: $u" } }
|
||||
|
||||
if (urls.isEmpty() && !pulledFromServer) {
|
||||
val localUrls = AddonStorage.loadInstalledAddonUrls(profileId)
|
||||
val localUrls = AddonStorage.loadInstalledAddonUrls(currentProfileId)
|
||||
log.i { "pullFromServer() — server empty, local has ${localUrls.size} addons" }
|
||||
if (localUrls.isNotEmpty()) {
|
||||
log.i { "pullFromServer() — migrating local addons to server for profile $profileId" }
|
||||
log.i { "pullFromServer() — migrating local addons to server for profile $currentProfileId" }
|
||||
initialize()
|
||||
pulledFromServer = true
|
||||
val addons = localUrls.mapIndexed { index, addonUrl ->
|
||||
|
|
@ -127,7 +129,7 @@ object AddonRepository {
|
|||
)
|
||||
}
|
||||
val params = buildJsonObject {
|
||||
put("p_profile_id", profileId)
|
||||
put("p_profile_id", currentProfileId)
|
||||
put("p_addons", json.encodeToJsonElement(addons))
|
||||
}
|
||||
SupabaseProvider.client.postgrest.rpc("sync_push_addons", params)
|
||||
|
|
@ -136,6 +138,29 @@ object AddonRepository {
|
|||
}
|
||||
}
|
||||
|
||||
if (urls.isEmpty()) {
|
||||
val localUrls = dedupeManifestUrls(AddonStorage.loadInstalledAddonUrls(currentProfileId))
|
||||
if (localUrls.isNotEmpty()) {
|
||||
log.w { "pullFromServer() — remote empty while local has ${localUrls.size} addons; preserving local addons" }
|
||||
val existingByUrl = _uiState.value.addons.associateBy(ManagedAddon::manifestUrl)
|
||||
_uiState.value = AddonsUiState(
|
||||
addons = localUrls.map { url ->
|
||||
existingByUrl[url].toPendingAddon(url)
|
||||
},
|
||||
)
|
||||
persist()
|
||||
localUrls.forEach { url ->
|
||||
val existing = existingByUrl[url]
|
||||
if (existing == null || (existing.manifest == null && !existing.isRefreshing)) {
|
||||
refreshAddon(url)
|
||||
}
|
||||
}
|
||||
pulledFromServer = true
|
||||
initialized = true
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val existingByUrl = _uiState.value.addons.associateBy(ManagedAddon::manifestUrl)
|
||||
_uiState.value = AddonsUiState(
|
||||
addons = urls.map { url ->
|
||||
|
|
@ -165,6 +190,9 @@ object AddonRepository {
|
|||
}
|
||||
|
||||
suspend fun addAddon(rawUrl: String): AddAddonResult {
|
||||
if (isUsingPrimaryAddonsFromSecondaryProfile()) {
|
||||
return AddAddonResult.Error("This profile uses primary addons.")
|
||||
}
|
||||
log.i { "addAddon() — rawUrl=$rawUrl" }
|
||||
val manifestUrl = try {
|
||||
normalizeManifestUrl(rawUrl)
|
||||
|
|
@ -204,6 +232,7 @@ object AddonRepository {
|
|||
}
|
||||
|
||||
fun removeAddon(manifestUrl: String) {
|
||||
if (isUsingPrimaryAddonsFromSecondaryProfile()) return
|
||||
log.i { "removeAddon() — $manifestUrl" }
|
||||
_uiState.update { current ->
|
||||
current.copy(
|
||||
|
|
@ -273,7 +302,10 @@ object AddonRepository {
|
|||
private fun pushToServer() {
|
||||
scope.launch {
|
||||
runCatching {
|
||||
val profileId = ProfileRepository.activeProfileId
|
||||
if (isUsingPrimaryAddonsFromSecondaryProfile()) {
|
||||
return@runCatching
|
||||
}
|
||||
val profileId = currentProfileId
|
||||
val addons = _uiState.value.addons
|
||||
.distinctBy { it.manifestUrl }
|
||||
.mapIndexed { index, addon ->
|
||||
|
|
@ -325,6 +357,16 @@ object AddonRepository {
|
|||
activeRefreshJobs.values.forEach(Job::cancel)
|
||||
activeRefreshJobs.clear()
|
||||
}
|
||||
|
||||
private fun resolveEffectiveProfileId(profileId: Int): Int {
|
||||
val active = ProfileRepository.state.value.activeProfile
|
||||
return if (active != null && active.profileIndex != 1 && active.usesPrimaryAddons) 1 else profileId
|
||||
}
|
||||
|
||||
private fun isUsingPrimaryAddonsFromSecondaryProfile(): Boolean {
|
||||
val active = ProfileRepository.state.value.activeProfile
|
||||
return active != null && active.profileIndex != 1 && active.usesPrimaryAddons
|
||||
}
|
||||
}
|
||||
|
||||
private fun ManagedAddon?.toPendingAddon(manifestUrl: String): ManagedAddon =
|
||||
|
|
|
|||
|
|
@ -85,10 +85,7 @@ internal fun AddonsSettingsPageContent(
|
|||
var formMessage by rememberSaveable { mutableStateOf<String?>(null) }
|
||||
var installModalState by remember { mutableStateOf<AddonInstallModalState?>(null) }
|
||||
|
||||
val sortedAddons = remember(uiState.addons) {
|
||||
uiState.addons.sortedBy { it.displayTitle.lowercase() }
|
||||
}
|
||||
val overview = remember(sortedAddons) { sortedAddons.toOverview() }
|
||||
val overview = remember(uiState.addons) { uiState.addons.toOverview() }
|
||||
|
||||
Column(
|
||||
modifier = modifier,
|
||||
|
|
@ -131,10 +128,10 @@ internal fun AddonsSettingsPageContent(
|
|||
)
|
||||
|
||||
SectionHeader("INSTALLED ADDONS")
|
||||
if (sortedAddons.isEmpty()) {
|
||||
if (uiState.addons.isEmpty()) {
|
||||
EmptyStateCard()
|
||||
} else {
|
||||
sortedAddons.forEach { addon ->
|
||||
uiState.addons.forEach { addon ->
|
||||
InstalledAddonCard(
|
||||
addon = addon,
|
||||
onRefreshClick = { AddonRepository.refreshAddon(addon.manifestUrl) },
|
||||
|
|
|
|||
|
|
@ -125,7 +125,11 @@ internal fun PlayerControlsShell(
|
|||
.align(Alignment.TopStart)
|
||||
.fillMaxWidth()
|
||||
.windowInsetsPadding(WindowInsets.safeContent.only(WindowInsetsSides.Top))
|
||||
.padding(horizontal = metrics.horizontalPadding, vertical = metrics.verticalPadding),
|
||||
.padding(
|
||||
start = metrics.horizontalPadding,
|
||||
end = metrics.horizontalPadding,
|
||||
top = metrics.verticalPadding / 4,
|
||||
),
|
||||
)
|
||||
|
||||
CenterControls(
|
||||
|
|
|
|||
Loading…
Reference in a new issue