From 2b2b0997c5d918afa0ae0ad376d354549ef00a6e Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 22:34:01 +0000 Subject: [PATCH 01/10] Initial plan From 1e5520800b0da1f115a41427e3f47840d8efe8c9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 22:42:10 +0000 Subject: [PATCH 02/10] Replace CalendarScroller button navigation with HorizontalPager MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Use HorizontalPager with rememberPagerState for swipe-between-days - beyondBoundsPageCount=0 so only the current page's video is composed - LaunchedEffect on isScrollInProgress pauses videos during drag/fling and resumes them once the pager settles (uses existing temporaryPause/Resume) - Two-way sync: pager→ViewModel via LaunchedEffect(currentPage), ViewModel→pager (date picker) via LaunchedEffect(currentDayIndex) - Prev/next buttons animate the pager via animateScrollToPage Agent-Logs-Url: https://github.com/LukeNeedham/VideoDiary/sessions/e974c16a-349c-47f8-bfd4-bf30a508f4cd Co-authored-by: LukeNeedham <49884591+LukeNeedham@users.noreply.github.com> --- .../calendar/component/CalendarScroller.kt | 122 ++++++++++++------ 1 file changed, 83 insertions(+), 39 deletions(-) diff --git a/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt b/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt index 87422d8..33bcf64 100644 --- a/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt +++ b/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt @@ -2,10 +2,14 @@ package com.lukeneedham.videodiary.ui.feature.calendar.component import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxWithConstraints +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.pager.HorizontalPager +import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.runtime.Composable -import androidx.compose.runtime.key +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview @@ -20,6 +24,7 @@ import com.lukeneedham.videodiary.ui.feature.calendar.component.portrait.Calenda import com.lukeneedham.videodiary.ui.feature.calendar.component.portrait.CalendarScrollerPortrait import com.lukeneedham.videodiary.ui.feature.common.videoplayer.VideoPlayerController import com.lukeneedham.videodiary.ui.feature.common.videoplayer.rememberVideoPlayerController +import kotlinx.coroutines.launch @Composable fun CalendarScroller( @@ -34,36 +39,53 @@ fun CalendarScroller( share: (ShareRequest) -> Unit, videoPlayerController: VideoPlayerController, ) { - val currentDay = days[currentDayIndex] + val pagerState = rememberPagerState( + initialPage = currentDayIndex, + pageCount = { days.size }, + ) + val coroutineScope = rememberCoroutineScope() + + // Notify the ViewModel when the pager settles on a new page. + LaunchedEffect(pagerState.currentPage) { + setCurrentDayIndex(pagerState.currentPage) + } - fun goToPage(index: Int) { - if (index !in days.indices) return - setCurrentDayIndex(index) + // Respond to external navigation (e.g. date picker) by scrolling the pager. + LaunchedEffect(currentDayIndex) { + if (pagerState.currentPage != currentDayIndex) { + pagerState.scrollToPage(currentDayIndex) + } } + // Pause all videos while the pager is being dragged; resume once it settles. + LaunchedEffect(pagerState.isScrollInProgress) { + if (pagerState.isScrollInProgress) { + videoPlayerController.temporaryPause() + } else { + videoPlayerController.temporaryResume() + } + } + + val currentDay = days[pagerState.currentPage] val currentDateFormatted = currentDay.date.format(StandardDateTimeFormatter.date) val onPrevious = { - goToPage(currentDayIndex - 1) + coroutineScope.launch { + val target = pagerState.currentPage - 1 + if (target in days.indices) { + pagerState.animateScrollToPage(target) + } + } + Unit } val onNext = { - goToPage(currentDayIndex + 1) - } - - @Composable - fun DayContentFrame( - content: @Composable () -> Unit - ) { - key(currentDay) { - Box( - contentAlignment = Alignment.Center, - modifier = Modifier - .fillMaxWidth() - .padding(horizontal = 10.dp) - ) { - content() + coroutineScope.launch { + val target = pagerState.currentPage + 1 + if (target in days.indices) { + pagerState.animateScrollToPage(target) } } + Unit } BoxWithConstraints { @@ -79,15 +101,26 @@ fun CalendarScroller( openDayPicker = openDayPicker, currentDateFormatted = currentDateFormatted, ) { - DayContentFrame { - CalendarDayPortrait( - day = currentDay, - videoAspectRatio = videoAspectRatio, - onRecordTodayVideoClick = onRecordTodayVideoClick, - onDeleteTodayVideoClick = onDeleteTodayVideoClick, - videoPlayerController = videoPlayerController, - share = share, - ) + HorizontalPager( + state = pagerState, + beyondBoundsPageCount = 0, + modifier = Modifier.fillMaxSize(), + ) { pageIndex -> + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 10.dp), + ) { + CalendarDayPortrait( + day = days[pageIndex], + videoAspectRatio = videoAspectRatio, + onRecordTodayVideoClick = onRecordTodayVideoClick, + onDeleteTodayVideoClick = onDeleteTodayVideoClick, + videoPlayerController = videoPlayerController, + share = share, + ) + } } } } else { @@ -98,15 +131,26 @@ fun CalendarScroller( openDayPicker = openDayPicker, currentDateFormatted = currentDateFormatted, ) { - DayContentFrame { - CalendarDayLandscape( - day = currentDay, - videoAspectRatio = videoAspectRatio, - onRecordTodayVideoClick = onRecordTodayVideoClick, - onDeleteTodayVideoClick = onDeleteTodayVideoClick, - videoPlayerController = videoPlayerController, - share = share, - ) + HorizontalPager( + state = pagerState, + beyondBoundsPageCount = 0, + modifier = Modifier.fillMaxSize(), + ) { pageIndex -> + Box( + contentAlignment = Alignment.Center, + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 10.dp), + ) { + CalendarDayLandscape( + day = days[pageIndex], + videoAspectRatio = videoAspectRatio, + onRecordTodayVideoClick = onRecordTodayVideoClick, + onDeleteTodayVideoClick = onDeleteTodayVideoClick, + videoPlayerController = videoPlayerController, + share = share, + ) + } } } } From 1e73077e35bad56bd53dd6000e39fc47f009a82b Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 22:46:39 +0000 Subject: [PATCH 03/10] Address code review feedback on CalendarScroller - Add explanatory comments on both sync LaunchedEffects clarifying why the guard prevents any cyclic effect between them - Use days.getOrElse for bounds-safe current-day lookup - Extract navigateByOffset helper to deduplicate onPrevious/onNext Agent-Logs-Url: https://github.com/LukeNeedham/VideoDiary/sessions/e974c16a-349c-47f8-bfd4-bf30a508f4cd Co-authored-by: LukeNeedham <49884591+LukeNeedham@users.noreply.github.com> --- .../calendar/component/CalendarScroller.kt | 39 ++++++++++--------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt b/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt index 33bcf64..b93f52f 100644 --- a/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt +++ b/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt @@ -10,6 +10,7 @@ import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.rememberCoroutineScope +import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.tooling.preview.Preview @@ -24,6 +25,7 @@ import com.lukeneedham.videodiary.ui.feature.calendar.component.portrait.Calenda import com.lukeneedham.videodiary.ui.feature.calendar.component.portrait.CalendarScrollerPortrait import com.lukeneedham.videodiary.ui.feature.common.videoplayer.VideoPlayerController import com.lukeneedham.videodiary.ui.feature.common.videoplayer.rememberVideoPlayerController +import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch @Composable @@ -46,11 +48,18 @@ fun CalendarScroller( val coroutineScope = rememberCoroutineScope() // Notify the ViewModel when the pager settles on a new page. - LaunchedEffect(pagerState.currentPage) { - setCurrentDayIndex(pagerState.currentPage) + // Uses snapshotFlow + distinctUntilChanged so setCurrentDayIndex is only called + // when the page actually changes, preventing spurious state updates. + LaunchedEffect(pagerState) { + snapshotFlow { pagerState.currentPage } + .distinctUntilChanged() + .collect { page -> setCurrentDayIndex(page) } } // Respond to external navigation (e.g. date picker) by scrolling the pager. + // The guard ensures this is a no-op when the change originated from the pager + // itself (in which case currentPage already equals currentDayIndex), breaking + // any potential cycle between the two sync effects. LaunchedEffect(currentDayIndex) { if (pagerState.currentPage != currentDayIndex) { pagerState.scrollToPage(currentDayIndex) @@ -66,28 +75,20 @@ fun CalendarScroller( } } - val currentDay = days[pagerState.currentPage] + // Guard against stale pager state when the days list is updated externally. + val currentDay = days.getOrElse(pagerState.currentPage) { days.last() } val currentDateFormatted = currentDay.date.format(StandardDateTimeFormatter.date) - val onPrevious = { - coroutineScope.launch { - val target = pagerState.currentPage - 1 - if (target in days.indices) { - pagerState.animateScrollToPage(target) - } + fun navigateByOffset(offset: Int) { + val target = pagerState.currentPage + offset + if (target in days.indices) { + coroutineScope.launch { pagerState.animateScrollToPage(target) } } - Unit - } - val onNext = { - coroutineScope.launch { - val target = pagerState.currentPage + 1 - if (target in days.indices) { - pagerState.animateScrollToPage(target) - } - } - Unit } + val onPrevious: () -> Unit = { navigateByOffset(-1) } + val onNext: () -> Unit = { navigateByOffset(1) } + BoxWithConstraints { val width = constraints.maxWidth val height = constraints.maxHeight From d190eae09699f5a14f21f2f119446fef89e1cfa5 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 22:49:20 +0000 Subject: [PATCH 04/10] Use getOrNull for safe days access inside pager pages Also coerce initialPage into days.indices for safe pager initialization Agent-Logs-Url: https://github.com/LukeNeedham/VideoDiary/sessions/e974c16a-349c-47f8-bfd4-bf30a508f4cd Co-authored-by: LukeNeedham <49884591+LukeNeedham@users.noreply.github.com> --- .../ui/feature/calendar/component/CalendarScroller.kt | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt b/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt index b93f52f..004bd9f 100644 --- a/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt +++ b/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt @@ -42,7 +42,7 @@ fun CalendarScroller( videoPlayerController: VideoPlayerController, ) { val pagerState = rememberPagerState( - initialPage = currentDayIndex, + initialPage = currentDayIndex.coerceIn(days.indices), pageCount = { days.size }, ) val coroutineScope = rememberCoroutineScope() @@ -76,6 +76,8 @@ fun CalendarScroller( } // Guard against stale pager state when the days list is updated externally. + // CalendarPageContent guarantees days is non-empty before CalendarScroller is called, + // so the fallback to days.last() is only a safety net against edge cases. val currentDay = days.getOrElse(pagerState.currentPage) { days.last() } val currentDateFormatted = currentDay.date.format(StandardDateTimeFormatter.date) @@ -107,6 +109,7 @@ fun CalendarScroller( beyondBoundsPageCount = 0, modifier = Modifier.fillMaxSize(), ) { pageIndex -> + val day = days.getOrNull(pageIndex) ?: return@HorizontalPager Box( contentAlignment = Alignment.Center, modifier = Modifier @@ -114,7 +117,7 @@ fun CalendarScroller( .padding(horizontal = 10.dp), ) { CalendarDayPortrait( - day = days[pageIndex], + day = day, videoAspectRatio = videoAspectRatio, onRecordTodayVideoClick = onRecordTodayVideoClick, onDeleteTodayVideoClick = onDeleteTodayVideoClick, @@ -137,6 +140,7 @@ fun CalendarScroller( beyondBoundsPageCount = 0, modifier = Modifier.fillMaxSize(), ) { pageIndex -> + val day = days.getOrNull(pageIndex) ?: return@HorizontalPager Box( contentAlignment = Alignment.Center, modifier = Modifier @@ -144,7 +148,7 @@ fun CalendarScroller( .padding(horizontal = 10.dp), ) { CalendarDayLandscape( - day = days[pageIndex], + day = day, videoAspectRatio = videoAspectRatio, onRecordTodayVideoClick = onRecordTodayVideoClick, onDeleteTodayVideoClick = onDeleteTodayVideoClick, From f4cb1465892332c2ad106b20525cec072a0532c3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 22:52:04 +0000 Subject: [PATCH 05/10] Make onPrevious/onNext stable with remember; guard empty days in coerceIn - Use remember(pagerState, coroutineScope) for onPrevious/onNext lambdas so they are not recreated on every recomposition - Use pagerState.pageCount (dynamic property on stable pagerState) instead of days.indices, avoiding capturing mutable days in the remembered lambdas - Guard initialPage: use days.isNotEmpty() check before coerceIn(days.indices) Agent-Logs-Url: https://github.com/LukeNeedham/VideoDiary/sessions/e974c16a-349c-47f8-bfd4-bf30a508f4cd Co-authored-by: LukeNeedham <49884591+LukeNeedham@users.noreply.github.com> --- .../calendar/component/CalendarScroller.kt | 25 +++++++++++++------ 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt b/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt index 004bd9f..8665bd2 100644 --- a/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt +++ b/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt @@ -42,7 +42,7 @@ fun CalendarScroller( videoPlayerController: VideoPlayerController, ) { val pagerState = rememberPagerState( - initialPage = currentDayIndex.coerceIn(days.indices), + initialPage = if (days.isNotEmpty()) currentDayIndex.coerceIn(days.indices) else 0, pageCount = { days.size }, ) val coroutineScope = rememberCoroutineScope() @@ -81,15 +81,24 @@ fun CalendarScroller( val currentDay = days.getOrElse(pagerState.currentPage) { days.last() } val currentDateFormatted = currentDay.date.format(StandardDateTimeFormatter.date) - fun navigateByOffset(offset: Int) { - val target = pagerState.currentPage + offset - if (target in days.indices) { - coroutineScope.launch { pagerState.animateScrollToPage(target) } + // pagerState.pageCount mirrors days.size dynamically via the pageCount lambda, so + // these callbacks only need pagerState and coroutineScope as stable remember keys. + val onPrevious: () -> Unit = remember(pagerState, coroutineScope) { + { + val target = pagerState.currentPage - 1 + if (target >= 0) { + coroutineScope.launch { pagerState.animateScrollToPage(target) } + } + } + } + val onNext: () -> Unit = remember(pagerState, coroutineScope) { + { + val target = pagerState.currentPage + 1 + if (target < pagerState.pageCount) { + coroutineScope.launch { pagerState.animateScrollToPage(target) } + } } } - - val onPrevious: () -> Unit = { navigateByOffset(-1) } - val onNext: () -> Unit = { navigateByOffset(1) } BoxWithConstraints { val width = constraints.maxWidth From a6b4fe25240c5928fb0375c653a61a8c7ab3bec9 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 22:53:27 +0000 Subject: [PATCH 06/10] Extract navigateByOffset helper to deduplicate onPrevious/onNext Use a single remembered navigateByOffset: (Int) -> Unit lambda, with onPrevious/onNext as thin stable wrappers via remember(navigateByOffset) Agent-Logs-Url: https://github.com/LukeNeedham/VideoDiary/sessions/e974c16a-349c-47f8-bfd4-bf30a508f4cd Co-authored-by: LukeNeedham <49884591+LukeNeedham@users.noreply.github.com> --- .../calendar/component/CalendarScroller.kt | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt b/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt index 8665bd2..0770da9 100644 --- a/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt +++ b/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt @@ -83,22 +83,16 @@ fun CalendarScroller( // pagerState.pageCount mirrors days.size dynamically via the pageCount lambda, so // these callbacks only need pagerState and coroutineScope as stable remember keys. - val onPrevious: () -> Unit = remember(pagerState, coroutineScope) { - { - val target = pagerState.currentPage - 1 - if (target >= 0) { - coroutineScope.launch { pagerState.animateScrollToPage(target) } - } - } - } - val onNext: () -> Unit = remember(pagerState, coroutineScope) { - { - val target = pagerState.currentPage + 1 - if (target < pagerState.pageCount) { + val navigateByOffset: (Int) -> Unit = remember(pagerState, coroutineScope) { + { offset -> + val target = pagerState.currentPage + offset + if (target >= 0 && target < pagerState.pageCount) { coroutineScope.launch { pagerState.animateScrollToPage(target) } } } } + val onPrevious: () -> Unit = remember(navigateByOffset) { { navigateByOffset(-1) } } + val onNext: () -> Unit = remember(navigateByOffset) { { navigateByOffset(1) } } BoxWithConstraints { val width = constraints.maxWidth From 0dd5aa3e1e3d5e70026917cda4f81a939c5cb87c Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 3 Apr 2026 22:56:56 +0000 Subject: [PATCH 07/10] Add require guard for non-empty days; use snapshotFlow for scroll pause/resume - require(days.isNotEmpty()) documents the programming contract and makes the days.last() fallback provably safe - Replace LaunchedEffect(isScrollInProgress) with snapshotFlow so pause/resume only fires on actual scroll-state transitions, not at initial composition - Simplify initialPage back to currentDayIndex.coerceIn(days.indices) Agent-Logs-Url: https://github.com/LukeNeedham/VideoDiary/sessions/e974c16a-349c-47f8-bfd4-bf30a508f4cd Co-authored-by: LukeNeedham <49884591+LukeNeedham@users.noreply.github.com> --- .../calendar/component/CalendarScroller.kt | 25 +++++++++++-------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt b/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt index 0770da9..9f51f00 100644 --- a/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt +++ b/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt @@ -41,8 +41,11 @@ fun CalendarScroller( share: (ShareRequest) -> Unit, videoPlayerController: VideoPlayerController, ) { + // CalendarPageContent ensures days is always non-empty before reaching this composable. + require(days.isNotEmpty()) { "CalendarScroller requires a non-empty days list" } + val pagerState = rememberPagerState( - initialPage = if (days.isNotEmpty()) currentDayIndex.coerceIn(days.indices) else 0, + initialPage = currentDayIndex.coerceIn(days.indices), pageCount = { days.size }, ) val coroutineScope = rememberCoroutineScope() @@ -67,17 +70,19 @@ fun CalendarScroller( } // Pause all videos while the pager is being dragged; resume once it settles. - LaunchedEffect(pagerState.isScrollInProgress) { - if (pagerState.isScrollInProgress) { - videoPlayerController.temporaryPause() - } else { - videoPlayerController.temporaryResume() - } + // Uses snapshotFlow so this only fires on scroll-state transitions, not on + // every recomposition or at initial composition. + LaunchedEffect(pagerState, videoPlayerController) { + snapshotFlow { pagerState.isScrollInProgress } + .distinctUntilChanged() + .collect { isScrolling -> + if (isScrolling) videoPlayerController.temporaryPause() + else videoPlayerController.temporaryResume() + } } - // Guard against stale pager state when the days list is updated externally. - // CalendarPageContent guarantees days is non-empty before CalendarScroller is called, - // so the fallback to days.last() is only a safety net against edge cases. + // Safe fallback: pagerState may briefly lag behind after days grows, but days is + // guaranteed non-empty (enforced by the require above), so days.last() is safe. val currentDay = days.getOrElse(pagerState.currentPage) { days.last() } val currentDateFormatted = currentDay.date.format(StandardDateTimeFormatter.date) From f56ec04602f92fcd65b9676acec4d80aad90bc48 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 4 Apr 2026 08:57:44 +0000 Subject: [PATCH 08/10] Fix build: add missing import for remember in CalendarScroller Agent-Logs-Url: https://github.com/LukeNeedham/VideoDiary/sessions/88f1835c-fecc-47c7-864b-c5715eabc3f3 Co-authored-by: LukeNeedham <49884591+LukeNeedham@users.noreply.github.com> --- .../videodiary/ui/feature/calendar/component/CalendarScroller.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt b/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt index 9f51f00..04c1077 100644 --- a/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt +++ b/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt @@ -9,6 +9,7 @@ import androidx.compose.foundation.pager.HorizontalPager import androidx.compose.foundation.pager.rememberPagerState import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.remember import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment From d05e73941117fc1f32d5743c2ebc156d2c827026 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sat, 4 Apr 2026 22:44:35 +0000 Subject: [PATCH 09/10] Fix build: opt-in to ExperimentalFoundationApi for HorizontalPager usage Agent-Logs-Url: https://github.com/LukeNeedham/VideoDiary/sessions/6b501114-2906-493a-9312-3cd3443c972d Co-authored-by: LukeNeedham <49884591+LukeNeedham@users.noreply.github.com> --- .../ui/feature/calendar/component/CalendarScroller.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt b/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt index 04c1077..7311edb 100644 --- a/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt +++ b/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt @@ -1,5 +1,7 @@ package com.lukeneedham.videodiary.ui.feature.calendar.component +import androidx.annotation.OptIn +import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxWithConstraints import androidx.compose.foundation.layout.fillMaxSize @@ -29,6 +31,7 @@ import com.lukeneedham.videodiary.ui.feature.common.videoplayer.rememberVideoPla import kotlinx.coroutines.flow.distinctUntilChanged import kotlinx.coroutines.launch +@OptIn(ExperimentalFoundationApi::class) @Composable fun CalendarScroller( days: List, @@ -171,6 +174,7 @@ fun CalendarScroller( } } +@OptIn(ExperimentalFoundationApi::class) @Preview @Composable internal fun PreviewCalendarScroller() { From a2df9fc064f5660a593d29691d425ecdbf44a030 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 5 Apr 2026 11:47:04 +0000 Subject: [PATCH 10/10] Fix build: use kotlin.OptIn (not androidx.annotation.OptIn) for ExperimentalFoundationApi Agent-Logs-Url: https://github.com/LukeNeedham/VideoDiary/sessions/652c62cb-25bf-4871-b79e-20e781ed4f94 Co-authored-by: LukeNeedham <49884591+LukeNeedham@users.noreply.github.com> --- .../videodiary/ui/feature/calendar/component/CalendarScroller.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt b/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt index 7311edb..70b44e8 100644 --- a/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt +++ b/app/src/main/java/com/lukeneedham/videodiary/ui/feature/calendar/component/CalendarScroller.kt @@ -1,6 +1,5 @@ package com.lukeneedham.videodiary.ui.feature.calendar.component -import androidx.annotation.OptIn import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.BoxWithConstraints