Skip to content

Initial Highlights Networking#103

Open
amjiao wants to merge 11 commits intomainfrom
amy-highlights-networking
Open

Initial Highlights Networking#103
amjiao wants to merge 11 commits intomainfrom
amy-highlights-networking

Conversation

@amjiao
Copy link
Contributor

@amjiao amjiao commented Feb 18, 2026

Overview

highlights UI bug fixes/improvements, initial highlights networking

Changes Made

  • Completed networking for main highlights screen (displays highlights cards in "today" and "past 3 days" sections)
  • Some refactoring since some of the UI I made previously didn't meet the model specs

Test Coverage

visually matches figma, double checked that all highlights in specified date range are shown

Next Steps

  • network highlights subscreens
  • implement search and filtering functionality

Screenshots (delete if not applicable)

(note, we realized showing only "today" and "past 3 day" categories could be a flaw in cases like this where there's very few recent highlights. our designer is working on improving this!)

image

Summary by CodeRabbit

Release Notes

  • New Features

    • Highlights feed now displays curated articles and videos filtered by sport type.
    • Video highlights include duration information.
    • Added pull-to-refresh functionality for highlights.
  • Improvements

    • Enhanced date and time display formatting across highlight cards.
    • Refined search bar and filter component spacing.
    • Updated sport selection interface for improved usability.

@AndrewCheung360
Copy link
Member

@coderabbitai

@coderabbitai
Copy link

coderabbitai bot commented Mar 17, 2026

The PR description image shows the Highlights screen of the Score Android app, displaying:

  • A "Highlights" title with a search bar ("Search keywords")
  • Filter chips for Baseball, Basketball, and Field Hockey
  • A "Past 3 days" section showing 1 Result — a lacrosse article card ("No. 4 Men's Lacrosse Gets by Albany in Season Opener", sourced from Cornell Daily Sun, dated 2/16/2026)
  • A bottom navigation bar with Schedule, Highlights (active), and Scores tabs

@AndrewCheung360 It looks like you've tagged me — I'll go ahead and review this PR for you! 🐰

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai
Copy link

coderabbitai bot commented Mar 17, 2026

📝 Walkthrough

Walkthrough

This PR introduces a comprehensive highlights feature, including new GraphQL queries and schema extensions, data models with date handling, a repository layer for fetching highlights, MVVM-based view models for state management, updated UI components with sport filtering, and navigation updates to support the highlights search functionality.

Changes

Cohort / File(s) Summary
GraphQL Schema & Queries
app/src/main/graphql/Highlights.graphql, app/src/main/graphql/schema.graphqls
Added new Highlights query with optional sportsType filter; extended schema with gamesByDate query, DateTime scalar, and new duration and sportsType fields on YoutubeVideoType.
Data Models & Utilities
app/src/main/java/com/cornellappdev/score/model/Highlights.kt, app/src/main/java/com/cornellappdev/score/util/DateUtil.kt, app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt
Refactored highlight data classes to use nullable LocalDate instead of String dates, added dateString formatting, made Sport and GenderDivision nullable, added toHighlightData() extension functions for GraphQL mapping, added parseIsoDateToLocalDateOrNull() date parser, and updated test constants.
Repository & ViewModel
app/src/main/java/com/cornellappdev/score/model/HighlightsRepository.kt, app/src/main/java/com/cornellappdev/score/viewmodel/HighlightsViewModel.kt
Introduced HighlightsRepository for GraphQL data fetching with state flow emission; added HighlightsViewModel with MVVM state management, sport filtering, and refresh capabilities.
Highlights UI Components
app/src/main/java/com/cornellappdev/score/components/highlights/ArticleHighlightsCard.kt, app/src/main/java/com/cornellappdev/score/components/highlights/VideoHighlightsCard.kt, app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsFilter.kt, app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsSearchBar.kt, app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsScreenSearchFilterBar.kt
Updated card components to use dateString and handle nullable fields; refactored filter components to use SportSelection type instead of Sport; adjusted spacing and layout in search bar.
Screens
app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt, app/src/main/java/com/cornellappdev/score/screen/HighlightsSearchScreen.kt, app/src/main/java/com/cornellappdev/score/screen/HighlightsSubScreen.kt
Converted HighlightsScreen to MVVM-driven state-based rendering; refactored all screens to use SportSelection instead of Sport; added pull-to-refresh and loading/error state handling.
Navigation
app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt, app/src/main/java/com/cornellappdev/score/nav/root/RootNavigation.kt
Updated navigation to use sportSelectionList data source and added header parameter to HighlightsSearchScreen; corrected routing to map to HighlightsSearchScreen instead of HighlightsScreen.
Other
app/src/main/java/com/cornellappdev/score/screen/HomeScreen.kt
Minor formatting adjustment to error state lambda spacing.

Sequence Diagram

sequenceDiagram
    participant User as User/UI
    participant ViewModel as HighlightsViewModel
    participant Repo as HighlightsRepository
    participant Apollo as Apollo Client
    participant API as GraphQL API
    participant Data as State Flow

    User->>ViewModel: Init / onRefresh()
    ViewModel->>ViewModel: Set state to Loading
    ViewModel->>Repo: fetchHighlights()
    Repo->>Repo: Set highlightsFlow to Loading
    Repo->>Apollo: Execute Highlights query
    Apollo->>API: GraphQL request
    API-->>Apollo: articles + youtubeVideos
    Apollo-->>Repo: Query result
    Repo->>Repo: Map to HighlightData (toHighlightData)
    Repo->>Repo: Emit ApiResponse.Success
    Repo-->>Data: highlightsFlow updated
    Data-->>ViewModel: Collect response
    ViewModel->>ViewModel: Sort by date, compute derived lists
    ViewModel-->>User: Render Success state with highlights
    
    User->>ViewModel: onSportSelected(SportSelection)
    ViewModel->>ViewModel: Filter highlights by sport
    ViewModel->>ViewModel: Recompute derived lists
    ViewModel-->>User: Update UI with filtered highlights
Loading

Estimated Code Review Effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A rabbit hops through highlights bright,
With dates parsed clean and sport filters tight,
GraphQL queries fetch the scores with glee,
State flows pure as morning dew you see! 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'Initial Highlights Networking' clearly summarizes the main objective of the changeset - implementing the networking layer for the highlights feature.
Description check ✅ Passed The PR description includes all essential template sections with appropriate content: Overview, Changes Made, Test Coverage, Next Steps, and Screenshots demonstrating the feature.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch amy-highlights-networking
📝 Coding Plan
  • Generate coding plan for human review comments

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
app/src/main/java/com/cornellappdev/score/screen/HighlightsSubScreen.kt (1)

99-99: ⚠️ Potential issue | 🟠 Major

The navigateBack parameter is not being used.

HighlightsSubScreenHeader is called with an empty lambda {} instead of the actual navigateBack callback passed to HighlightsSubScreen. This breaks the back navigation functionality.

🐛 Proposed fix
-        HighlightsSubScreenHeader(header, {})
+        HighlightsSubScreenHeader(header, navigateBack = onCloseClick)

Note: Using onCloseClick as it appears to be the intended close/back action. Alternatively, add a dedicated navigateBack parameter if distinct behavior is needed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/screen/HighlightsSubScreen.kt` at
line 99, HighlightsSubScreen is passing an empty lambda to
HighlightsSubScreenHeader which ignores the provided navigateBack callback;
replace the empty lambda with the actual navigateBack callback so the header's
onCloseClick (or the intended close/back action) invokes navigateBack. Locate
the call to HighlightsSubScreenHeader in HighlightsSubScreen and pass
navigateBack (or wire navigateBack into onCloseClick) instead of {} to restore
back navigation.
🧹 Nitpick comments (4)
app/src/main/java/com/cornellappdev/score/viewmodel/HighlightsViewModel.kt (1)

41-41: Inconsistent sort order: filtered sorted ascending while loadedState data is descending.

Line 72 sorts response.data descending by date before calling buildDerivedLists, but line 41 re-sorts filtered ascending. This inconsistency may cause confusion. Clarify the intended order or align them.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/viewmodel/HighlightsViewModel.kt`
at line 41, filtered is currently sorted ascending (val filtered =
validHighlights.sortedBy { it.date }) while elsewhere (response.data before
buildDerivedLists and loadedState) uses descending order; make the ordering
consistent by changing filtered to use descending sorting (e.g., use
sortedByDescending { it.date }) or, if ascending is intended, adjust the earlier
descending sort in the loadedState/response.data preparation and
buildDerivedLists call to ascending—update the filtered declaration and any
related assumptions in buildDerivedLists/loadedState to match the chosen order.
app/src/main/java/com/cornellappdev/score/model/Highlights.kt (1)

67-71: Gender inference logic may be incomplete.

The code assumes FEMALE if the title doesn't contain "Men's". This doesn't account for:

  • Co-ed sports
  • Titles without gender indication (e.g., "Cornell Tennis Wins Championship")
  • "Women's" explicit match

Consider making gender nullable or adding explicit "Women's" check:

♻️ Proposed alternative
             gender = if (title.contains("Men's")) {
                 GenderDivision.MALE
-            } else {
+            } else if (title.contains("Women's")) {
                 GenderDivision.FEMALE
-            },
+            } else {
+                null // Unknown gender
+            },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/model/Highlights.kt` around lines
67 - 71, The gender inference in the Highlights.kt assignment currently sets
GenderDivision.FEMALE whenever title does not contain "Men's"; update the logic
in the gender assignment (the expression using title.contains("Men's")) to
explicitly detect "Men's" -> GenderDivision.MALE, "Women's" (or "Women’s") ->
GenderDivision.FEMALE, and common co‑ed indicators (e.g., "Co‑ed", "Coed",
"Mixed") -> GenderDivision.COED if you have that enum, otherwise set gender to
null; make the gender field nullable in the containing data class/constructor if
not already and use case‑insensitive matching on the title string to avoid false
negatives.
app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt (1)

231-283: Test data with null dates will be filtered out by ViewModel.

All highlights in highlightsList have date = null (e.g., line 237). In HighlightsViewModel.buildDerivedLists(), line 32 filters out highlights with null dates: .filter { it.date != null }. This means these test highlights won't appear in todayHighlights or pastThreeDaysHighlights during preview/testing.

Consider using actual LocalDate values for more realistic test coverage:

♻️ Proposed fix example
 HighlightData.Video
 (VideoHighlightData(
     "vs Columbia",
     "maxresdefault.jpg",
     "https://cornellsun.com/article/london-mcdavid-is-making-a-name-for-herself-at-cornell",
-    null,
+    LocalDate.now(),
     "11/09",
     Sport.BASEBALL,
     GenderDivision.MALE,
     "0:44"
 )),
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt` around
lines 231 - 283, The test highlights in highlightsList use null dates so they
get filtered out by HighlightsViewModel.buildDerivedLists() (.filter { it.date
!= null }); update the HighlightData instances (VideoHighlightData and
ArticleHighlightData inside highlightsList) to supply concrete LocalDate values
(e.g., LocalDate.now() and LocalDate.now().minusDays(1/2/3) as appropriate)
instead of null so the preview/test data appears in todayHighlights and
pastThreeDaysHighlights; ensure the date field types match the model (LocalDate)
and adjust any imports or constructors if needed.
app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt (1)

49-52: TODO: Create highlights-specific loading screen.

The comment acknowledges that LoadingScreen with "Loading Schedules..." text is inappropriate for the highlights feature. Track this for follow-up.

Do you want me to open an issue to track creating a highlights-specific loading screen?

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt` around
lines 49 - 52, The HighlightsScreen currently shows a generic LoadingScreen with
"Loading Schedules..." in the ApiResponse.Loading branch; replace this with a
highlights-specific loading UI by creating a new component (e.g.,
HighlightsLoadingScreen) or updating LoadingScreen to accept contextual text,
then use that from HighlightsScreen (replace the LoadingScreen call in the
ApiResponse.Loading branch). Ensure the new component or prop displays "Loading
Highlights..." (and any highlights-specific placeholders) and update any
references to LoadingScreen in HighlightsScreen to call the new name or pass the
appropriate prop so the loading text is correct.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@app/src/main/java/com/cornellappdev/score/model/HighlightsRepository.kt`:
- Around line 26-29: The KDoc at the top of HighlightsRepository incorrectly
mentions "games" and `upcomingGamesFlow`; update the comment to describe
fetching highlights and emitting the repository's highlights flow (e.g.,
`highlightsFlow` or the actual flow property in HighlightsRepository). Edit the
comment block above the asynchronous fetch method or class to reference
highlights, the correct flow name used in this file, and briefly state its
behavior (asynchronous fetch and emission) so the documentation matches
functions like HighlightsRepository.fetch... and the highlights flow identifier.

In `@app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt`:
- Around line 59-61: The pull-to-refresh indicator never shows because
ScorePullToRefreshBox's isRefreshing uses uiState.loadedState ==
ApiResponse.Loading inside the ApiResponse.Success branch; add a dedicated
boolean refresh state and wire it through the ViewModel instead of reusing
loadedState. Update HighlightsUiState to include isRefreshing (or add a separate
loading state), set and clear it from highlightsViewModel.onRefresh()/refresh
handling, and pass uiState.isRefreshing to ScorePullToRefreshBox.isRefreshing so
the indicator can show while content is displayed (referencing
ScorePullToRefreshBox, uiState.loadedState, HighlightsUiState, and
highlightsViewModel.onRefresh).

In `@app/src/main/java/com/cornellappdev/score/util/DateUtil.kt`:
- Around line 72-76: Update the KDoc for the ISO-8601 parsing function in
DateUtil.kt so the `@return` matches the actual return type (nullable LocalDate)
instead of stating LocalDateTime; explicitly document that the function returns
a LocalDate? (nullable) and that it returns null for invalid/unsupported
formats, and keep the format example ("yyyy-MM-dd'T'HH:mm:ss'Z'") and parameter
description unchanged so readers can find the parsing function (DateUtil's
ISO-8601 parsing method) and understand the nullable return contract.
- Around line 82-83: The catch block in DateUtil.kt that currently swallows
exceptions and returns null should instead log a warning before returning null:
update the catch (e: Exception) block inside the date-parsing function to call
your logging facility (e.g., Log.w or Timber.w) with a concise message that
includes the exception and the offending input string/variable (so we can
identify which timestamp failed) and then continue returning null to preserve
behavior.

In `@app/src/main/java/com/cornellappdev/score/viewmodel/HighlightsViewModel.kt`:
- Around line 43-48: pastThreeDaysHighlights currently uses filter { it.date!!
>= threeDaysAgo } which includes today and duplicates items in todayHighlights;
update the filter in HighlightsViewModel.kt to exclude today by requiring the
date be >= threeDaysAgo AND < today (e.g., filter { val d = it.date!!; d >=
threeDaysAgo && d < today }) so pastThreeDaysHighlights covers only the prior 3
days and not today's items.

---

Outside diff comments:
In `@app/src/main/java/com/cornellappdev/score/screen/HighlightsSubScreen.kt`:
- Line 99: HighlightsSubScreen is passing an empty lambda to
HighlightsSubScreenHeader which ignores the provided navigateBack callback;
replace the empty lambda with the actual navigateBack callback so the header's
onCloseClick (or the intended close/back action) invokes navigateBack. Locate
the call to HighlightsSubScreenHeader in HighlightsSubScreen and pass
navigateBack (or wire navigateBack into onCloseClick) instead of {} to restore
back navigation.

---

Nitpick comments:
In `@app/src/main/java/com/cornellappdev/score/model/Highlights.kt`:
- Around line 67-71: The gender inference in the Highlights.kt assignment
currently sets GenderDivision.FEMALE whenever title does not contain "Men's";
update the logic in the gender assignment (the expression using
title.contains("Men's")) to explicitly detect "Men's" -> GenderDivision.MALE,
"Women's" (or "Women’s") -> GenderDivision.FEMALE, and common co‑ed indicators
(e.g., "Co‑ed", "Coed", "Mixed") -> GenderDivision.COED if you have that enum,
otherwise set gender to null; make the gender field nullable in the containing
data class/constructor if not already and use case‑insensitive matching on the
title string to avoid false negatives.

In `@app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt`:
- Around line 49-52: The HighlightsScreen currently shows a generic
LoadingScreen with "Loading Schedules..." in the ApiResponse.Loading branch;
replace this with a highlights-specific loading UI by creating a new component
(e.g., HighlightsLoadingScreen) or updating LoadingScreen to accept contextual
text, then use that from HighlightsScreen (replace the LoadingScreen call in the
ApiResponse.Loading branch). Ensure the new component or prop displays "Loading
Highlights..." (and any highlights-specific placeholders) and update any
references to LoadingScreen in HighlightsScreen to call the new name or pass the
appropriate prop so the loading text is correct.

In `@app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt`:
- Around line 231-283: The test highlights in highlightsList use null dates so
they get filtered out by HighlightsViewModel.buildDerivedLists() (.filter {
it.date != null }); update the HighlightData instances (VideoHighlightData and
ArticleHighlightData inside highlightsList) to supply concrete LocalDate values
(e.g., LocalDate.now() and LocalDate.now().minusDays(1/2/3) as appropriate)
instead of null so the preview/test data appears in todayHighlights and
pastThreeDaysHighlights; ensure the date field types match the model (LocalDate)
and adjust any imports or constructors if needed.

In `@app/src/main/java/com/cornellappdev/score/viewmodel/HighlightsViewModel.kt`:
- Line 41: filtered is currently sorted ascending (val filtered =
validHighlights.sortedBy { it.date }) while elsewhere (response.data before
buildDerivedLists and loadedState) uses descending order; make the ordering
consistent by changing filtered to use descending sorting (e.g., use
sortedByDescending { it.date }) or, if ascending is intended, adjust the earlier
descending sort in the loadedState/response.data preparation and
buildDerivedLists call to ascending—update the filtered declaration and any
related assumptions in buildDerivedLists/loadedState to match the chosen order.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d99ea79c-3618-43a1-80ed-9ea11e23e457

📥 Commits

Reviewing files that changed from the base of the PR and between 88f53a7 and a6c076a.

📒 Files selected for processing (18)
  • app/src/main/graphql/Highlights.graphql
  • app/src/main/graphql/schema.graphqls
  • app/src/main/java/com/cornellappdev/score/components/highlights/ArticleHighlightsCard.kt
  • app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsFilter.kt
  • app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsScreenSearchFilterBar.kt
  • app/src/main/java/com/cornellappdev/score/components/highlights/HighlightsSearchBar.kt
  • app/src/main/java/com/cornellappdev/score/components/highlights/VideoHighlightsCard.kt
  • app/src/main/java/com/cornellappdev/score/model/Highlights.kt
  • app/src/main/java/com/cornellappdev/score/model/HighlightsRepository.kt
  • app/src/main/java/com/cornellappdev/score/nav/ScoreNavHost.kt
  • app/src/main/java/com/cornellappdev/score/nav/root/RootNavigation.kt
  • app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt
  • app/src/main/java/com/cornellappdev/score/screen/HighlightsSearchScreen.kt
  • app/src/main/java/com/cornellappdev/score/screen/HighlightsSubScreen.kt
  • app/src/main/java/com/cornellappdev/score/screen/HomeScreen.kt
  • app/src/main/java/com/cornellappdev/score/util/DateUtil.kt
  • app/src/main/java/com/cornellappdev/score/util/TestingConstants.kt
  • app/src/main/java/com/cornellappdev/score/viewmodel/HighlightsViewModel.kt

Comment on lines +26 to +29
/**
* Asynchronously fetches the list of games from the API. Once finished, will send down
* `upcomingGamesFlow` to be observed.
*/
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Incorrect comment: references "games" instead of "highlights".

The doc comment mentions "upcomingGamesFlow" which appears to be copy-pasted from another repository. Update to reflect this class.

📝 Proposed fix
     /**
-     * Asynchronously fetches the list of games from the API. Once finished, will send down
-     * `upcomingGamesFlow` to be observed.
+     * Asynchronously fetches the list of highlights from the API. Once finished, will send down
+     * `highlightsFlow` to be observed.
      */
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
/**
* Asynchronously fetches the list of games from the API. Once finished, will send down
* `upcomingGamesFlow` to be observed.
*/
/**
* Asynchronously fetches the list of highlights from the API. Once finished, will send down
* `highlightsFlow` to be observed.
*/
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/model/HighlightsRepository.kt`
around lines 26 - 29, The KDoc at the top of HighlightsRepository incorrectly
mentions "games" and `upcomingGamesFlow`; update the comment to describe
fetching highlights and emitting the repository's highlights flow (e.g.,
`highlightsFlow` or the actual flow property in HighlightsRepository). Edit the
comment block above the asynchronous fetch method or class to reference
highlights, the correct flow name used in this file, and briefly state its
behavior (asynchronous fetch and emission) so the documentation matches
functions like HighlightsRepository.fetch... and the highlights flow identifier.

Comment on lines +59 to +61
ScorePullToRefreshBox(
isRefreshing = uiState.loadedState == ApiResponse.Loading,
{ highlightsViewModel.onRefresh() }
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

isRefreshing will always be false inside the Success branch.

The condition uiState.loadedState == ApiResponse.Loading is checked inside the ApiResponse.Success branch of the when statement. By definition, if we're in the Success branch, loadedState cannot be Loading, so the pull-to-refresh indicator will never show.

🐛 Proposed fix

Option 1: Add a dedicated isRefreshing state to HighlightsUiState:

// In HighlightsUiState:
data class HighlightsUiState(
    val isRefreshing: Boolean = false,
    // ... other fields
)

Option 2: Track loading state separately from content state, allowing "refreshing while showing stale data" pattern.

The current architecture clears content during refresh, so the Success branch exits immediately when refreshing starts.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/screen/HighlightsScreen.kt` around
lines 59 - 61, The pull-to-refresh indicator never shows because
ScorePullToRefreshBox's isRefreshing uses uiState.loadedState ==
ApiResponse.Loading inside the ApiResponse.Success branch; add a dedicated
boolean refresh state and wire it through the ViewModel instead of reusing
loadedState. Update HighlightsUiState to include isRefreshing (or add a separate
loading state), set and clear it from highlightsViewModel.onRefresh()/refresh
handling, and pass uiState.isRefreshing to ScorePullToRefreshBox.isRefreshing so
the indicator can show while content is displayed (referencing
ScorePullToRefreshBox, uiState.loadedState, HighlightsUiState, and
highlightsViewModel.onRefresh).

Comment on lines +72 to +76
* Parses an ISO-8601 timestamp: yyyy-MM-dd'T'HH:mm:ss'Z' into a LocalDateTime object.
*
* @param strDate the date string to parse, in the format "yyyy-MM-dd'T'HH:mm:ss'Z'"
* @return a LocalDateTime object if parsing succeeds, or null if the format is invalid
*/
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix return-type mismatch in KDoc.

The doc says this returns LocalDateTime, but the function returns LocalDate?. Please align the comment to prevent misuse.

Proposed doc fix
- * Parses an ISO-8601 timestamp: yyyy-MM-dd'T'HH:mm:ss'Z' into a LocalDateTime object.
+ * Parses an ISO-8601 timestamp: yyyy-MM-dd'T'HH:mm:ss'Z' into a LocalDate object.
@@
- * `@return` a LocalDateTime object if parsing succeeds, or null if the format is invalid
+ * `@return` a LocalDate object if parsing succeeds, or null if the format is invalid
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
* Parses an ISO-8601 timestamp: yyyy-MM-dd'T'HH:mm:ss'Z' into a LocalDateTime object.
*
* @param strDate the date string to parse, in the format "yyyy-MM-dd'T'HH:mm:ss'Z'"
* @return a LocalDateTime object if parsing succeeds, or null if the format is invalid
*/
* Parses an ISO-8601 timestamp: yyyy-MM-dd'T'HH:mm:ss'Z' into a LocalDate object.
*
* `@param` strDate the date string to parse, in the format "yyyy-MM-dd'T'HH:mm:ss'Z'"
* `@return` a LocalDate object if parsing succeeds, or null if the format is invalid
*/
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/util/DateUtil.kt` around lines 72 -
76, Update the KDoc for the ISO-8601 parsing function in DateUtil.kt so the
`@return` matches the actual return type (nullable LocalDate) instead of stating
LocalDateTime; explicitly document that the function returns a LocalDate?
(nullable) and that it returns null for invalid/unsupported formats, and keep
the format example ("yyyy-MM-dd'T'HH:mm:ss'Z'") and parameter description
unchanged so readers can find the parsing function (DateUtil's ISO-8601 parsing
method) and understand the nullable return contract.

Comment on lines +82 to +83
} catch (e: Exception) {
null
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Avoid silently swallowing parse failures.

Right now malformed timestamps disappear without signal. Adding a warning log keeps behavior (null) while improving diagnosability.

Proposed fix
-    } catch (e: Exception) {
-        null
-    }
+    } catch (e: Exception) {
+        Log.w("parseIsoDateToLocalDateOrNull", "Invalid ISO timestamp: $strDate", e)
+        null
+    }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
} catch (e: Exception) {
null
} catch (e: Exception) {
Log.w("parseIsoDateToLocalDateOrNull", "Invalid ISO timestamp: $strDate", e)
null
}
🧰 Tools
🪛 detekt (1.23.8)

[warning] 82-82: The caught exception is swallowed. The original exception could be lost.

(detekt.exceptions.SwallowedException)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/util/DateUtil.kt` around lines 82 -
83, The catch block in DateUtil.kt that currently swallows exceptions and
returns null should instead log a warning before returning null: update the
catch (e: Exception) block inside the date-parsing function to call your logging
facility (e.g., Log.w or Timber.w) with a concise message that includes the
exception and the offending input string/variable (so we can identify which
timestamp failed) and then continue returning null to preserve behavior.

Comment on lines +43 to +48
val todayHighlights = validHighlights.filter { it.date == today }

val pastThreeDaysHighlights = validHighlights
.filter { it.date!! >= threeDaysAgo } // null dates filtered out in line 32
.sortedBy { it.date }

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

pastThreeDaysHighlights includes today's items, causing overlap with todayHighlights.

The filter it.date!! >= threeDaysAgo includes all dates from 3 days ago up to and including today. This means items in todayHighlights will also appear in pastThreeDaysHighlights, potentially causing duplicate display in the UI.

If the intent is to show "past 3 days excluding today":

🐛 Proposed fix
     val pastThreeDaysHighlights = validHighlights
-        .filter { it.date!! >= threeDaysAgo } // null dates filtered out in line 32
+        .filter { it.date!! in threeDaysAgo..<today } // exclude today
         .sortedBy { it.date }

Alternatively, if including today is intentional, the UI should handle deduplication.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
val todayHighlights = validHighlights.filter { it.date == today }
val pastThreeDaysHighlights = validHighlights
.filter { it.date!! >= threeDaysAgo } // null dates filtered out in line 32
.sortedBy { it.date }
val todayHighlights = validHighlights.filter { it.date == today }
val pastThreeDaysHighlights = validHighlights
.filter { it.date!! in threeDaysAgo..<today } // exclude today
.sortedBy { it.date }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/java/com/cornellappdev/score/viewmodel/HighlightsViewModel.kt`
around lines 43 - 48, pastThreeDaysHighlights currently uses filter { it.date!!
>= threeDaysAgo } which includes today and duplicates items in todayHighlights;
update the filter in HighlightsViewModel.kt to exclude today by requiring the
date be >= threeDaysAgo AND < today (e.g., filter { val d = it.date!!; d >=
threeDaysAgo && d < today }) so pastThreeDaysHighlights covers only the prior 3
days and not today's items.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants