From 0f946d8b4ecf4bcda4d3869f86a9d3261ddc47da Mon Sep 17 00:00:00 2001 From: Kayos Date: Tue, 26 May 2026 07:17:29 -0700 Subject: [PATCH] vc=49: Auto-start playback setting (cold-open autoplay) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Settings → Autoplay section now has a third toggle: Auto-start playback (default on). When on, opening a fresh video starts playing immediately on the detail page. When off, the page renders with the thumbnail + Play overlay and you tap to start. Independent of the end-of-queue autoplay mode and the back-from- fullscreen behavior (that already auto-resumes because the controller is mid-stream — preserved). Implementation: a single OR into the initial inlinePlaying state in VideoDetailScreen. --- buildSrc/src/main/kotlin/ProjectConfig.kt | 4 +-- .../com/sulkta/straw/data/SettingsStore.kt | 21 +++++++++++++++ .../straw/feature/detail/VideoDetailScreen.kt | 21 ++++++++------- .../straw/feature/settings/SettingsScreen.kt | 26 +++++++++++++++++++ 4 files changed, 61 insertions(+), 11 deletions(-) diff --git a/buildSrc/src/main/kotlin/ProjectConfig.kt b/buildSrc/src/main/kotlin/ProjectConfig.kt index a155f1f75..937c3b1c7 100644 --- a/buildSrc/src/main/kotlin/ProjectConfig.kt +++ b/buildSrc/src/main/kotlin/ProjectConfig.kt @@ -55,6 +55,6 @@ const val NEWPIPE_APPLICATION_ID_NEW = "net.newpipe.app" // vc=19 / 0.1.0-AE — rust pipeline cutover. Extraction via // strawcore-core (Sulkta-Coop/strawcore) via the UniFFI wrapper; no // NewPipeExtractor in the runtime path. -const val STRAW_VERSION_CODE = 48 -const val STRAW_VERSION_NAME = "0.1.0-BH" +const val STRAW_VERSION_CODE = 49 +const val STRAW_VERSION_NAME = "0.1.0-BI" const val STRAW_APPLICATION_ID = "com.sulkta.straw" diff --git a/strawApp/src/main/kotlin/com/sulkta/straw/data/SettingsStore.kt b/strawApp/src/main/kotlin/com/sulkta/straw/data/SettingsStore.kt index 2580f8128..4a1c79780 100644 --- a/strawApp/src/main/kotlin/com/sulkta/straw/data/SettingsStore.kt +++ b/strawApp/src/main/kotlin/com/sulkta/straw/data/SettingsStore.kt @@ -65,6 +65,7 @@ private const val KEY_THEME = "theme_mode_v1" private const val KEY_CACHE_ENABLED = "cache_enabled_v1" private const val KEY_AUTOPLAY_MODE = "autoplay_mode_v1" private const val KEY_AUTOPLAY_SKIP_WATCHED = "autoplay_skip_watched_v1" +private const val KEY_AUTOSTART_PLAYBACK = "autostart_playback_v1" class SettingsStore(context: Context) { private val sp: SharedPreferences = context.getSharedPreferences(PREFS, Context.MODE_PRIVATE) @@ -89,6 +90,19 @@ class SettingsStore(context: Context) { ) val autoplaySkipWatched: StateFlow = _autoplaySkipWatched.asStateFlow() + /** + * "Open a video → it starts playing immediately." Default on — + * matches YT/NewPipe. When off, opening a fresh video lands you + * on the detail page with the thumbnail + Play overlay; you tap + * to start. Doesn't affect back-from-fullscreen (that's a + * separate path in VideoDetailScreen that defaults to true when + * the shared controller is already streaming the URL). + */ + private val _autoStartPlayback = MutableStateFlow( + sp.getBoolean(KEY_AUTOSTART_PLAYBACK, true), + ) + val autoStartPlayback: StateFlow = _autoStartPlayback.asStateFlow() + fun toggle(cat: SbCategory) { // Atomic toggle via updateAndGet — see AUD-HIGH note in HistoryStore. val next = _sbCategories.updateAndGet { cur -> @@ -137,6 +151,13 @@ class SettingsStore(context: Context) { sp.edit().putBoolean(KEY_AUTOPLAY_SKIP_WATCHED, skip).apply() } + fun setAutoStartPlayback(autoStart: Boolean) { + val before = _autoStartPlayback.value + if (before == autoStart) return + _autoStartPlayback.value = autoStart + sp.edit().putBoolean(KEY_AUTOSTART_PLAYBACK, autoStart).apply() + } + private fun loadCategories(): Set { val raw = sp.getStringSet(KEY_SB_CATS, null) return if (raw == null) { diff --git a/strawApp/src/main/kotlin/com/sulkta/straw/feature/detail/VideoDetailScreen.kt b/strawApp/src/main/kotlin/com/sulkta/straw/feature/detail/VideoDetailScreen.kt index fb2f9aaef..cdcd0bbfe 100644 --- a/strawApp/src/main/kotlin/com/sulkta/straw/feature/detail/VideoDetailScreen.kt +++ b/strawApp/src/main/kotlin/com/sulkta/straw/feature/detail/VideoDetailScreen.kt @@ -133,16 +133,19 @@ fun VideoDetailScreen( ) } // Inline-play state resets when navigating to a different video. - // BUT: if the shared MediaController is already playing this exact - // stream — most commonly because the user popped back from - // fullscreen Player — default to true so the inline surface picks - // up the running playback instead of dropping back to the - // thumbnail+Play placeholder. Without this, system back from - // fullscreen looked like "the video went to background" — audio - // continued via the persistent controller but the video page - // re-rendered as a freshly-loaded detail. + // Defaults to TRUE when: + // * the shared MediaController is already streaming this URL + // (back-from-fullscreen — without this the page renders as + // "freshly loaded" while audio keeps playing in the + // background), or + // * the user has Settings → Auto-start playback enabled (cold + // open from search / subs / wherever immediately plays). + // Off + fresh URL → thumbnail + Play overlay, user taps to start. + val autoStart by Settings.get().autoStartPlayback.collectAsState() var inlinePlaying by remember(streamUrl) { - mutableStateOf(NowPlaying.current.value?.streamUrl == streamUrl) + mutableStateOf( + NowPlaying.current.value?.streamUrl == streamUrl || autoStart, + ) } LaunchedEffect(streamUrl) { vm.load(streamUrl) } diff --git a/strawApp/src/main/kotlin/com/sulkta/straw/feature/settings/SettingsScreen.kt b/strawApp/src/main/kotlin/com/sulkta/straw/feature/settings/SettingsScreen.kt index 8d6a75551..a97af48b4 100644 --- a/strawApp/src/main/kotlin/com/sulkta/straw/feature/settings/SettingsScreen.kt +++ b/strawApp/src/main/kotlin/com/sulkta/straw/feature/settings/SettingsScreen.kt @@ -242,6 +242,32 @@ fun SettingsScreen() { onCheckedChange = { store.setAutoplaySkipWatched(it) }, ) } + val autoStartPlayback by store.autoStartPlayback.collectAsState() + Row( + modifier = Modifier + .fillMaxWidth() + .padding(vertical = 6.dp), + verticalAlignment = Alignment.CenterVertically, + horizontalArrangement = Arrangement.SpaceBetween, + ) { + Column(modifier = Modifier.weight(1f)) { + Text( + "Auto-start playback", + style = MaterialTheme.typography.bodyLarge, + fontWeight = FontWeight.SemiBold, + ) + Text( + "Open a video → it starts immediately. Off: tap " + + "the thumbnail to start.", + style = MaterialTheme.typography.bodySmall, + color = MaterialTheme.colorScheme.onSurfaceVariant, + ) + } + Switch( + checked = autoStartPlayback, + onCheckedChange = { store.setAutoStartPlayback(it) }, + ) + } Spacer(modifier = Modifier.height(32.dp)) Text(