CICD: сборка APK на release → F-Droid; versionCode из тега; фикс скролла каталога и масштаба
build / Android APK to F-Droid (release) Failing after 36s

This commit is contained in:
2026-08-21 19:27:02 +03:00
parent ee86b9dc50
commit ee9700c558
11 changed files with 267 additions and 7 deletions
+2 -2
View File
@@ -37,8 +37,8 @@ android {
applicationId = "pw.binom.viewmate.phone"
minSdk = 26
targetSdk = 34
versionCode = 1
versionName = "0.1.0"
versionCode = (project.findProperty("versionCode") as? String)?.toIntOrNull() ?: 1
versionName = (project.findProperty("versionName") as? String) ?: "0.1.0"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
// LLM-ключ из local.properties (llm.apiKey) — вне git; пустой = ещё не задан
@@ -14,6 +14,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.GridCells
import androidx.compose.foundation.lazy.grid.LazyVerticalGrid
import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.lazy.grid.rememberLazyGridState
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Text
@@ -26,6 +27,7 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.runtime.snapshotFlow
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
@@ -77,6 +79,13 @@ class CatalogState(
private set
var path by mutableStateOf<Path>(Path.Root)
private set
var scrollIndex by mutableStateOf(0)
private set
var scrollOffset by mutableStateOf(0)
private set
/** Сохранённые позиции скролла по пути (ключ — путь, из которого ушли). */
private val savedScroll = mutableMapOf<CatalogState.Path, Pair<Int, Int>>()
private var searchJob: Job? = null
private var loadJob: Job? = null
@@ -102,16 +111,19 @@ class CatalogState(
}
fun openSeries(item: JellyfinItem) {
savedScroll[path] = scrollIndex to scrollOffset
path = Path.Series(item)
refresh()
}
fun openSeason(season: JellyfinItem, series: JellyfinItem) {
savedScroll[path] = scrollIndex to scrollOffset
path = Path.Season(season, series)
refresh()
}
fun openFolder(item: JellyfinItem) {
savedScroll[path] = scrollIndex to scrollOffset
path = Path.Folder(item)
refresh()
}
@@ -123,9 +135,27 @@ class CatalogState(
is Path.Season -> Path.Series(p.series)
is Path.Folder -> Path.Root
}
val (idx, off) = savedScroll[path] ?: Pair(0, 0)
scrollIndex = idx
scrollOffset = off
refresh()
}
/** Сохранить позицию для текущего пути (перед уходом на детали и т.п.). */
fun saveScrollNow() {
savedScroll[path] = scrollIndex to scrollOffset
}
/** Сохранить текущую позицию (вызывается при скролле из UI). */
fun setScroll(index: Int, offset: Int) {
scrollIndex = index
scrollOffset = offset
}
/** Позиция скролла для текущего пути (восстановление после навигации). */
fun savedScrollForCurrentPath(): Pair<Int, Int> =
savedScroll[path] ?: Pair(0, 0)
/** Заголовок под шапкой: текущая вкладка или хлебная крошка внутри сериала/папки. */
fun subtitle(): String = when (val p = path) {
Path.Root -> when (tab) {
@@ -200,6 +230,21 @@ fun CatalogScreen(
) {
val app = PhoneApp.instance
val userId by app.userId.collectAsState()
// Позиция скролла каталога: сохраняется/восстанавливается между навигациями.
val gridState = rememberLazyGridState()
// Восстановить позицию при смене пути/загрузке.
LaunchedEffect(state.path, state.items) {
val (idx, off) = state.savedScrollForCurrentPath()
gridState.scrollToItem(idx, off)
}
// Сохранять позицию при скролле.
LaunchedEffect(gridState) {
snapshotFlow {
gridState.firstVisibleItemIndex to gridState.firstVisibleItemScrollOffset
}.collect { (idx, off) -> state.setScroll(idx, off) }
}
val downloaded by app.state.downloadedFlow.collectAsState()
val localDownloaded by app.downloadManager.downloadedIds.collectAsState()
@@ -218,6 +263,7 @@ fun CatalogScreen(
ScreenPlaceholder(if (state.query.isNotBlank()) "ничего не нашлось" else "пусто")
} else {
LazyVerticalGrid(
state = gridState,
columns = GridCells.Fixed(2),
contentPadding = PaddingValues(14.dp),
horizontalArrangement = Arrangement.spacedBy(12.dp),
@@ -246,7 +292,11 @@ fun CatalogScreen(
state.openSeason(item, series)
}
item.Type in CatalogState.CONTAINER_TYPES -> state.openFolder(item)
else -> onItemClick(item)
else -> {
// уходим на детали — сохранить позицию, чтобы назад вернул скролл
state.saveScrollNow()
onItemClick(item)
}
}
},
)
@@ -213,6 +213,15 @@ fun GlassesScreen(
Spacer(modifier = Modifier.height(12.dp))
RemoteButton(
text = "⏻ Выключить очки",
big = true,
onClick = {
scope.launch { app.actions?.shutdownGlasses() }
},
modifier = Modifier.fillMaxWidth().padding(horizontal = 14.dp),
)
RemoteButton(
text = "Скачанное на очках →",
big = true,