From e3ae1019b6cf8ca441ef08e6ba8cb4d146e41a2d Mon Sep 17 00:00:00 2001 From: RFait Date: Sun, 5 Oct 2025 22:07:45 -0700 Subject: [PATCH] Android Compat Layer --- src/routes/app/schedule/+page.svelte | 185 ++++++++++++++----- src/routes/app/schedule/DayDetailPane.svelte | 66 +++++-- src/routes/app/schedule/ThreeDayView.svelte | 86 +++++++-- 3 files changed, 253 insertions(+), 84 deletions(-) diff --git a/src/routes/app/schedule/+page.svelte b/src/routes/app/schedule/+page.svelte index 0992c47..8c4704d 100644 --- a/src/routes/app/schedule/+page.svelte +++ b/src/routes/app/schedule/+page.svelte @@ -3,6 +3,7 @@ import { addMonths, endOfMonth, endOfWeek, format, isSameMonth, isToday, startOfMonth, startOfWeek, subMonths } from 'date-fns' import { persisted } from 'svelte-persisted-store' import Cross2 from 'svelte-radix/Cross2.svelte' + import { onMount } from 'svelte' import type { Schedule, ScheduleMedia } from '$lib/modules/anilist/queries' import type { ResultOf } from 'gql.tada' @@ -18,6 +19,7 @@ import { authAggregator, list } from '$lib/modules/auth' import { dragScroll } from '$lib/modules/navigate' import { cn, breakpoints } from '$lib/utils' + import { SUPPORTS } from '$lib/modules/settings' import ThreeDayView from './ThreeDayView.svelte' import DayDetailPane from './DayDetailPane.svelte' @@ -149,9 +151,28 @@ highlightUntil = Date.now() + 3000 highlightTimer = setTimeout(() => { highlightUntil = 0 }, 3000) } + + // Android portrait detection + let androidPortrait = false + let androidLandscape = false + onMount(() => { + const mq = window.matchMedia('(orientation: portrait)') + const update = () => { + androidPortrait = SUPPORTS.isAndroid && mq.matches + androidLandscape = SUPPORTS.isAndroid && !mq.matches + } + update() + mq.addEventListener('change', update) + return () => { + mq.removeEventListener('change', update) + } + }) + + // Today state for button styling + $: isOnToday = +midnight(selectedDate) === +midnight(new Date()) -
+
@@ -161,47 +182,90 @@
- -
- -
- - -
- - -
- - - - - -
- {format(selectedDate, 'MMMM, EEEE do')}{selectedDate.getFullYear() !== new Date().getFullYear() ? ` ${format(selectedDate, 'yyyy')}` : ''} + + {#if androidPortrait} + +
+ +
+
+ + +
+
+ {format(selectedDate, 'MMMM, EEEE do')}{selectedDate.getFullYear() !== new Date().getFullYear() ? ` ${format(selectedDate, 'yyyy')}` : ''} +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ +
- - - - - -
+ {:else} + +
+ +
+ + +
- -
- + +
+
+ + +
+
+ {format(selectedDate, 'MMMM, EEEE do')}{selectedDate.getFullYear() !== new Date().getFullYear() ? ` ${format(selectedDate, 'yyyy')}` : ''} +
+
+ + +
+ + +
+ + +
+ +
-
+ {/if}
{#if $query.fetching} @@ -222,19 +286,38 @@
{:else} {#if $viewMode === 'three-day'} -
- selectedDate = d} - onSelectEpisode={highlightEpisode} - /> - selectedEpisode = ep} /> -
+ {#if androidPortrait} + +
+ selectedEpisode = ep} androidPortrait={true} /> + selectedDate = d} + onSelectEpisode={highlightEpisode} + androidPortrait={true} + /> +
+ {:else} +
+ selectedDate = d} + onSelectEpisode={highlightEpisode} + androidLandscape={androidLandscape} + /> + selectedEpisode = ep} androidLandscape={androidLandscape} /> +
+ {/if} {:else if $viewMode === 'month'}
Mon
diff --git a/src/routes/app/schedule/DayDetailPane.svelte b/src/routes/app/schedule/DayDetailPane.svelte index f23c293..b2745c6 100644 --- a/src/routes/app/schedule/DayDetailPane.svelte +++ b/src/routes/app/schedule/DayDetailPane.svelte @@ -1,7 +1,7 @@
-
{#if episodes.length === 0} @@ -79,36 +91,58 @@ )} on:click={() => onSelectEpisode(ep)}> {#if ep.bannerImage} - {ep.title?.userPreferred} + {ep.title?.userPreferred} {:else if ep.coverImage?.extraLarge} - {ep.title?.userPreferred} + {ep.title?.userPreferred} {:else if ep.coverImage?.large} - {ep.title?.userPreferred} + {ep.title?.userPreferred} {:else if ep.coverImage?.medium} - {ep.title?.userPreferred} + {ep.title?.userPreferred} {:else}
{/if}
+
{#if status}
-
-
- {#if ep.format}{ep.format}{/if} - {#if ep.duration}• Length: {ep.duration}m{/if} - {#if ep.episodes}• Episodes: {ep.episodes}{/if} + + {#if wide1600} + +
+
+ {#if ep.format}{ep.format}{/if} + {#if ep.duration}• Length: {ep.duration}m{/if} + {#if ep.episodes}• Episodes: {ep.episodes}{/if} +
+
+
Ep {ep.episode}
+
+ {format(ep.airTime, 'h:mm')} {format(ep.airTime, 'a')} +
+
-
-
Ep {ep.episode}
-
+ {:else} + +
+ {#if ep.format}{ep.format}{/if} + {#if ep.episodes} + • {ep.episodes}eps + {/if} + {#if ep.duration} + • {ep.duration}m + {/if} +
+
+
Ep {ep.episode}
+
{format(ep.airTime, 'h:mm')} {format(ep.airTime, 'a')}
-
+ {/if}
{/each} diff --git a/src/routes/app/schedule/ThreeDayView.svelte b/src/routes/app/schedule/ThreeDayView.svelte index 9a206a4..e9410fc 100644 --- a/src/routes/app/schedule/ThreeDayView.svelte +++ b/src/routes/app/schedule/ThreeDayView.svelte @@ -3,6 +3,7 @@ import { Button as ButtonPrimitive } from 'bits-ui' import { goto } from '$app/navigation' import { cn } from '$lib/utils' + import { onMount } from 'svelte' export let prevDate: Date export let currentDate: Date @@ -14,6 +15,8 @@ export let onSelectDate: (date: Date) => void export let onSelectEpisode: (ep: any) => void + export let androidPortrait: boolean = false + export let androidLandscape: boolean = false let lastClickId: string | null = null let lastClickAt = 0 @@ -40,11 +43,43 @@ function keydownSelectPrev(e: KeyboardEvent) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); e.stopPropagation(); onSelectDate(prevDate) } } function keydownSelectCurrent(e: KeyboardEvent) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); e.stopPropagation(); onSelectDate(currentDate) } } function keydownSelectNext(e: KeyboardEvent) { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); e.stopPropagation(); onSelectDate(nextDate) } } + + // Android portrait: collapse current-day list to 6 items with More+ button + let showAllCurrent = false + $: visibleCurrentEpisodes = androidPortrait && !showAllCurrent ? currentEpisodes.slice(0, 6) : currentEpisodes + + // Apply same behavior to previous and next day in Android portrait + let showAllPrev = false + let showAllNext = false + $: visiblePrevEpisodes = androidPortrait && !showAllPrev ? prevEpisodes.slice(0, 6) : prevEpisodes + $: visibleNextEpisodes = androidPortrait && !showAllNext ? nextEpisodes.slice(0, 6) : nextEpisodes + + // Below 1400px: change 3-day list to 2-day (current + next). Hide Previous. + let wide1400 = false + onMount(() => { + const mq = window.matchMedia('(min-width: 1400px)') + const update = () => { wide1400 = mq.matches } + update() + mq.addEventListener('change', update) + return () => mq.removeEventListener('change', update) + }) + + // Reset expanded state when dates change + let _prevKey = 0, _currentKey = 0, _nextKey = 0 + $: { const k = +prevDate; if (k !== _prevKey) { _prevKey = k; showAllPrev = false } } + $: { const k = +currentDate; if (k !== _currentKey) { _currentKey = k; showAllCurrent = false } } + $: { const k = +nextDate; if (k !== _nextKey) { _nextKey = k; showAllNext = false } } -
+
-
+ {#if wide1400} +
@@ -60,22 +95,28 @@ {#if prevEpisodes.length === 0}
No episodes
{:else} - {#each prevEpisodes as ep (ep.id + ':' + ep.episode)} + {#each visiblePrevEpisodes as ep (ep.id + ':' + ep.episode)} handleEpisodeClick(e, ep)}> -
{format(ep.airTime, 'HH:mm')}
-
+
{format(ep.airTime, 'HH:mm')}
+
{ep.title?.userPreferred}
-
Ep {ep.episode}
+
Ep {ep.episode}
{/each} + {#if androidPortrait && prevEpisodes.length > 6 && !showAllPrev} +
+ +
+ {/if} {/if}
- + {/if} -
+
@@ -83,22 +124,27 @@ {#if currentEpisodes.length === 0}
No episodes
{:else} - {#each currentEpisodes as ep (ep.id + ':' + ep.episode)} + {#each visibleCurrentEpisodes as ep (ep.id + ':' + ep.episode)} handleEpisodeClick(e, ep)}> -
{format(ep.airTime, 'HH:mm')}
-
+
{format(ep.airTime, 'HH:mm')}
+
{ep.title?.userPreferred}
-
Ep {ep.episode}
+
Ep {ep.episode}
{/each} + {#if androidPortrait && currentEpisodes.length > 6 && !showAllCurrent} +
+ +
+ {/if} {/if}
-
+
@@ -113,16 +159,22 @@ {#if nextEpisodes.length === 0}
No episodes
{:else} - {#each nextEpisodes as ep (ep.id + ':' + ep.episode)} + {#each visibleNextEpisodes as ep (ep.id + ':' + ep.episode)} handleEpisodeClick(e, ep)}> -
{format(ep.airTime, 'HH:mm')}
-
+
{format(ep.airTime, 'HH:mm')}
+
{ep.title?.userPreferred}
-
Ep {ep.episode}
+
Ep {ep.episode}
{/each} + {#if androidPortrait && nextEpisodes.length > 6 && !showAllNext} +
+ +
+ {/if} {/if}