Skip to content

[User Availability] Implement user availability UI and networking stubs.#92

Open
conniecliu wants to merge 1 commit intomainfrom
Connie/UserAvailibities
Open

[User Availability] Implement user availability UI and networking stubs.#92
conniecliu wants to merge 1 commit intomainfrom
Connie/UserAvailibities

Conversation

@conniecliu
Copy link
Copy Markdown
Contributor

@conniecliu conniecliu commented Apr 27, 2026

Overview

Implemented the User Availability feature based on these designs.

This PR adds a fully completed UI, a view model for the Availability Screen, Resell-specific composables, and networking stubs.

Changes Made

  • Added AvailabilityScreen.kt with active panel control on the UI
  • Added composables for panels MonthCalendar.kt and AvailabilityFilters.kt
  • Added a view model for the Availability Screen and corresponding repository and API Service.
  • Began networking for the screen and left stubs for better handoff (needs more work).
  • Created a Resell-specific checkbox composable and factored out a Resell-specific switch composable.

Test Coverage

  • Ran with previews because there is currently no navigation to and from the Availability Screen and its features.
  • Checked with interactive mode.

Next Steps

  • Properly network end-to-end (OAuth, sharing calendars with Resell, etc.)
  • Create view models for the custom composables created for panels (MonthCalendar, AvailabilityFilters)
  • Test with full navigation from the Profile Screen.

Related PRs or Issues

Note: the above PR implements the changes to the User Availability feature introduced on the Profile Screen. It's the upstream screen that leads to the implementation in this PR.

Screenshots and recordings

Availability Screen UI + Other Composables Screenshot 2026-04-26 at 11 59 33 PM Screenshot 2026-04-26 at 11 59 52 PM Screenshot 2026-04-27 at 12 01 12 AM
Screen.Recording.2026-04-27.at.12.05.19.AM.mov

Summary by CodeRabbit

  • New Features

    • Added availability management screen where users can view and manage their schedule using an interactive calendar interface
    • Introduced availability filters for organizing and controlling sub-calendar preferences
    • Added new reusable UI controls (checkbox and switch components) for consistent design across the app
    • Added hamburger menu icon to navigation
  • Refactor

    • Improved notification settings interface with refactored components for better maintainability

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 27, 2026

📝 Walkthrough

Walkthrough

A new availability management feature is introduced, consisting of a Retrofit API service layer with data models, a repository for time-slot transformation, a ViewModel for state management, and Compose UI screens including calendar and filter panels. Related UI components for switches and checkboxes are extracted as reusable utilities, and the notification settings screen is refactored to use the new switch component.

Changes

Cohort / File(s) Summary
API Layer & Data Models
app/src/main/java/com/cornellappdev/resell/android/model/api/AvailabilityApiService.kt, RetrofitInstance.kt
Introduces AvailabilityApiService interface with suspend functions for fetching and updating user availability; defines UserAvailability, AvailabilityResponse, AvailabilitySlot, and UpdateAvailabilityRequest data classes. Registers the service in RetrofitInstance with a lazy-initialized Retrofit client.
Data Transformation & Repository
app/src/main/java/com/cornellappdev/resell/android/model/profile/AvailabilityRepository.kt
New singleton repository that orchestrates availability operations: transforms List<LocalDateTime> into a schedule map grouped by date strings and converts responses back to LocalDateTime objects.
Reusable UI Components
app/src/main/java/com/cornellappdev/resell/android/ui/components/global/ResellCheckbox.kt, ResellSwitchRow.kt, availability/helper/AvailabilityFilters.kt, availability/helper/MonthCalendar.kt
Adds shared Compose components: ResellCheckboxRow and ResellSwitchRow for consistent styling; AvailabilityFilters with hard-coded sub-calendar checkboxes and TODOs; MonthCalendar with day-range selection rendering logic.
Feature Screen & State Management
app/src/main/java/com/cornellappdev/resell/android/ui/screens/main/AvailabilityScreen.kt, viewmodel/main/AvailabilityViewModel.kt
New AvailabilityScreen composable integrates calendar and filter panels with animated overlay toggling; AvailabilityViewModel manages slot selection, month navigation, feature flags, and coordinates repository calls with loading/error state.
Integration & Refactoring
app/src/main/java/com/cornellappdev/resell/android/ui/screens/settings/NotificationSettings.kt
Replaces local SwitchRow implementation with the new shared ResellSwitchRow component; applies consistent padding and formatting.
Assets
app/src/main/res/drawable/ic_hamburger.xml
New hamburger menu vector drawable icon.

Sequence Diagram

sequenceDiagram
    actor User
    participant Screen as AvailabilityScreen
    participant ViewModel as AvailabilityViewModel
    participant Repo as AvailabilityRepository
    participant API as AvailabilityApiService
    participant Server as Remote API

    User->>Screen: Opens availability feature
    Screen->>ViewModel: Loads on init
    ViewModel->>Repo: getMyAvailability()
    Repo->>API: getMyAvailability()
    API->>Server: GET /availability/
    Server-->>API: UserAvailability + schedule
    API-->>Repo: AvailabilityResponse
    Repo->>Repo: Convert schedule to List<LocalDateTime>
    Repo-->>ViewModel: List<LocalDateTime>
    ViewModel->>ViewModel: Update selectedAvailabilities & UI state
    ViewModel-->>Screen: Display loaded slots

    User->>Screen: Selects date range in MonthCalendar
    Screen->>ViewModel: setSelectedAvailabilities(slots)
    ViewModel->>ViewModel: Update state

    User->>Screen: Clicks "Save" button
    Screen->>ViewModel: saveAvailability()
    ViewModel->>Repo: updateAvailability(selectedSlots)
    Repo->>Repo: Transform List<LocalDateTime> to schedule map
    Repo->>API: updateAvailability(UpdateAvailabilityRequest)
    API->>Server: POST /availability/update/
    Server-->>API: Updated UserAvailability
    API-->>Repo: AvailabilityResponse
    Repo-->>ViewModel: UserAvailability
    ViewModel->>ViewModel: Update saveSuccess & UI state
    ViewModel-->>Screen: Display success/error
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Poem

🐰 A calendar of slots, so neat and bright,
With switches, checks, and dates aligned just right,
From timestamps transformed to schedules fine,
Through viewmodels and repos, the data does align,
Availability flows like spring's first light! 🌷

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.04% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically summarizes the main change: implementing user availability UI and networking for the Resell app.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description check ✅ Passed The pull request description comprehensively covers all required sections including overview, changes made, test coverage, next steps, and related PRs with supporting screenshots.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch Connie/UserAvailibities

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Copy link
Copy Markdown

@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: 10

🧹 Nitpick comments (5)
app/src/main/res/drawable/ic_hamburger.xml (1)

8-8: Avoid hardcoded icon color in drawable.

Using #1E1E1E directly makes this asset less theme-aware (dark mode / dynamic theming). Prefer tinting at usage sites or using a theme-backed color resource.

Also applies to: 11-11, 14-14

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

In `@app/src/main/res/drawable/ic_hamburger.xml` at line 8, The drawable
ic_hamburger.xml currently hardcodes android:fillColor="#1E1E1E" (also at the
other occurrences noted), which prevents theme-aware coloring; remove the
hardcoded fillColor entries and make the vector drawable colorless (or use
android:fillColor="?android:attr/colorControlNormal" / a theme attribute), then
apply tinting at usage sites (ImageView/AppCompatImageButton via android:tint or
app:tint or via MaterialComponents theme attributes) so the icon respects
light/dark and dynamic theming.
app/src/main/java/com/cornellappdev/resell/android/ui/components/global/ResellSwitchRow.kt (1)

42-54: Avoid coupling visual checked state to enabled.

checked = checked && enabled makes the thumb render in the unchecked position whenever enabled = false, even when the underlying value is true. Material3's Switch already renders a distinct disabled appearance via the enabled parameter (and SwitchDefaults exposes disabledCheckedTrackColor / disabledUncheckedTrackColor etc.). Masking checked here hides the real state from the user and from accessibility services (the Role.Switch semantics will report Off when the model is On).

Consider passing checked straight through and adding the disabled color slots if you want a different look for the disabled state.

♻️ Proposed change
         Switch(
-            checked = checked && enabled,
+            checked = checked,
             onCheckedChange = onCheckedChange,
             colors = SwitchDefaults.colors(
                 checkedThumbColor = Color.White,
                 uncheckedThumbColor = IconInactive,
                 checkedTrackColor = ResellPurple,
                 uncheckedTrackColor = Color.White,
                 checkedBorderColor = ResellPurple,
                 uncheckedBorderColor = IconInactive
             ),
             enabled = enabled,
         )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/cornellappdev/resell/android/ui/components/global/ResellSwitchRow.kt`
around lines 42 - 54, The Switch in ResellSwitchRow.kt currently passes checked
= checked && enabled which masks the true model state when the control is
disabled; change it to checked = checked (do not combine with enabled) and
instead customize the disabled appearance by supplying the appropriate disabled
color slots via SwitchDefaults.colors (e.g., disabledCheckedTrackColor,
disabledUncheckedTrackColor,
disabledCheckedThumbColor/disabledUncheckedThumbColor or the equivalent
properties you need) while leaving enabled = enabled; keep onCheckedChange and
other props the same so accessibility and semantics reflect the real checked
value.
app/src/main/java/com/cornellappdev/resell/android/viewmodel/main/AvailabilityViewModel.kt (2)

87-97: Optional: guard against concurrent saves and consume the server response.

Two thoughts for follow-up, not blocking:

  1. Tapping Save twice in quick succession (or while a load is in flight) launches overlapping coroutines and produces racing POSTs. A simple guard via stateValue().isLoading early-return — or by holding the in-flight Job — would prevent that.
  2. updateAvailability returns the canonical UserAvailability from the server, but it's discarded. If the backend normalizes/merges/rejects-partial slots, the client state silently drifts from the server. Consider applying result.toLocalDateTimes() to selectedAvailabilities on success.
♻️ Sketch
 fun saveAvailability() {
+    if (stateValue().isLoading) return
     viewModelScope.launch {
         applyMutation { copy(isLoading = true, saveSuccess = false) }
         try {
-            availabilityRepository.updateAvailability(stateValue().selectedAvailabilities)
-            applyMutation { copy(isLoading = false, saveSuccess = true) }
+            val updated = availabilityRepository.updateAvailability(stateValue().selectedAvailabilities)
+            applyMutation {
+                copy(
+                    selectedAvailabilities = updated.toLocalDateTimes(),
+                    isLoading = false,
+                    saveSuccess = true,
+                    errorMessage = null,
+                )
+            }
         } catch (e: Exception) {
             applyMutation { copy(isLoading = false, errorMessage = e.message) }
         }
     }
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/cornellappdev/resell/android/viewmodel/main/AvailabilityViewModel.kt`
around lines 87 - 97, The saveAvailability function can launch overlapping
requests and currently discards the server's canonical result; fix by
early-return if stateValue().isLoading is true (or store the launched Job and
check its isActive) at the start of saveAvailability to prevent concurrent
saves, and on successful call to availabilityRepository.updateAvailability(...)
capture the returned UserAvailability and map it (e.g., call
result.toLocalDateTimes()) to update selectedAvailabilities via applyMutation
while still toggling isLoading and saveSuccess appropriately; ensure the error
path still clears isLoading and sets errorMessage.

21-37: Sub-calendar state initialization.

subCalendars defaults to emptyList() while enabledSubCalendars defaults to emptySet(). Until the Google Calendar API wiring lands (per the TODO), the filters panel will render an empty list. The PR's own preview screenshot, though, shows four named sub-calendars — so for the preview/interactive testing path you may want a temporary default list or a preview-only state to avoid an empty section while the screen is being demoed. Just flagging — feel free to defer.

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

In
`@app/src/main/java/com/cornellappdev/resell/android/viewmodel/main/AvailabilityViewModel.kt`
around lines 21 - 37, AvailabilityUiState currently initializes subCalendars to
emptyList() and enabledSubCalendars to emptySet(), which leaves the filters
panel empty in previews; to fix, provide temporary preview defaults (e.g., a
list of sample calendar names and a matching enabled set) or add a preview-only
constructor/flag to populate subCalendars and enabledSubCalendars for
interactive/testing flows so the UI shows the four demo calendars; update
AvailabilityUiState (the data class) to accept or set those preview defaults and
ensure enabledSubCalendars contains the IDs/names that should be toggled on for
the preview.
app/src/main/java/com/cornellappdev/resell/android/model/api/AvailabilityApiService.kt (1)

18-36: Optional: extract DTOs to a separate file.

Co-locating four data class DTOs in the Retrofit service file works, but moving them into a sibling AvailabilityModels.kt (or model/availability/ package) keeps the service interface focused and matches typical separation-of-concerns conventions. Defer to existing repo style.

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

In
`@app/src/main/java/com/cornellappdev/resell/android/model/api/AvailabilityApiService.kt`
around lines 18 - 36, Extract the four DTO data classes (AvailabilityResponse,
UserAvailability, AvailabilitySlot, UpdateAvailabilityRequest) out of the
Retrofit service file into a new Kotlin file (e.g., AvailabilityModels.kt or
under a model/availability package) so the AvailabilityApiService stays focused;
keep the classes’ names and fields unchanged, place them in the same package as
the service (or adjust package/imports accordingly), and update the
AvailabilityApiService imports/usages to reference the moved classes. Ensure no
behavior changes and that serialization annotations or visibility modifiers (if
any) are preserved during the move.
🤖 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/resell/android/model/api/AvailabilityApiService.kt`:
- Around line 18-36: The model classes (AvailabilityResponse, UserAvailability,
AvailabilitySlot, UpdateAvailabilityRequest) need Gson `@SerializedName`
annotations for fields that the backend uses in snake_case: add
`@SerializedName`("user_id") to userId, `@SerializedName`("updated_at") to
updatedAt, `@SerializedName`("start_date") and `@SerializedName`("end_date") to
startDate/endDate in AvailabilitySlot, and add `@SerializedName` annotations as
needed for id and schedule (e.g., "id" and "schedule") so
GsonConverterFactory.create() can correctly map JSON keys to the Kotlin
properties; update the data classes to include these annotations on the
corresponding properties.

In
`@app/src/main/java/com/cornellappdev/resell/android/model/profile/AvailabilityRepository.kt`:
- Around line 22-32: Update AvailabilityRepository so the datetime formatter
matches the parser used by AvailabilityViewModel.toLocalDateTimes(): replace
DateTimeFormatter.ISO_LOCAL_DATE_TIME with a formatter that includes
offset/timezone (e.g., DateTimeFormatter.ISO_OFFSET_DATE_TIME or the same
formatter used by toLocalDateTimes()) when formatting startDate and endDate for
AvailabilitySlot; also replace daySlots.sortedBy { it } with daySlots.sorted()
since LocalDateTime is Comparable. Extract the hardcoded 30L into a shared
constant (e.g., SLOT_DURATION_MINUTES) and use that constant in
AvailabilityRepository (endDate calculation), AvailabilityUtil,
SelectableAvailabilityGrid, ViewOnlyAvailabilityGrid, and test helpers so all
code references the same slot duration.

In
`@app/src/main/java/com/cornellappdev/resell/android/ui/components/availability/helper/AvailabilityFilters.kt`:
- Around line 78-80: The checkedStates mutable map is currently local to
AvailabilityFilters and reset when the composable is removed; move its state
into AvailabilityViewModel (add a MutableState<Map<String,Boolean>> or similar)
and expose it via state + update callback parameters to AvailabilityFilters
(mirror the pattern used by NotificationSettings). In practice: remove remember
{ mutableStateMapOf... } from AvailabilityFilters, add properties and updater
functions in AvailabilityViewModel (e.g., checkedStates, setCheckedState(key,
value)), also hoist the two switch values into the ViewModel with corresponding
setters, and update AvailabilityFilters to accept the current states and
callbacks so the TODO switch handlers call the supplied setters rather than
mutating local state.

In
`@app/src/main/java/com/cornellappdev/resell/android/ui/components/availability/helper/MonthCalendar.kt`:
- Around line 24-30: MonthCalendar declares onMonthChange but never calls it, so
wire month navigation controls to invoke it: add previous/next buttons or
chevrons in the MonthCalendar header (matching Figma) and call
onMonthChange(currentMonth.minusMonths(1)) for the previous control and
onMonthChange(currentMonth.plusMonths(1)) for the next control; ensure the
clickable composables update accessibility/tap targets and preserve the existing
parameters (currentMonth, selectedDates) when rendering, or if you prefer not to
implement navigation now, remove the onMonthChange parameter from MonthCalendar
and its callers (e.g., AvailabilityScreen ->
availabilityViewModel.setCurrentMonth) to avoid a dead callback.

In
`@app/src/main/java/com/cornellappdev/resell/android/ui/components/global/ResellCheckbox.kt`:
- Around line 41-74: Move the toggleable modifier off the inner Box and onto the
Row (or add Modifier.semantics) so the entire Row toggles and accessibility
announcements include the label; add semantics/stateDescription or
contentDescription that uses the title and the checked state (e.g., "$title,
${if (checked) "checked" else "unchecked"}") so TalkBack reads the name and
state. Also make the visual styling respect enabled by changing how fillColor
and borderColor are computed in ResellCheckbox (use disabled variants or apply
alpha when enabled == false) and ensure the Icon tint/opacity follows enabled as
well; remove duplicate toggleable on the Box if moved. Ensure Role.Checkbox
remains on the toggleable call for accessibility.

In
`@app/src/main/java/com/cornellappdev/resell/android/ui/screens/main/AvailabilityScreen.kt`:
- Around line 216-220: The preview crashes because AvailabilityScreen() calls
hiltViewModel(), which isn't available in the IDE preview; update the preview to
not resolve a Hilt VM — either replace AvailabilityScreenPreview to render the
hoisted UI (call AvailabilityScreenContent(...) with a mocked
AvailabilityViewState and no-op callbacks) or change AvailabilityScreen
signature to accept viewModel: AvailabilityViewModel? = null and short-circuit
when viewModel is null so the preview can pass a fake/null viewModel; reference
AvailabilityScreenPreview, AvailabilityScreen, hiltViewModel,
AvailabilityScreenContent, and AvailabilityViewModel when making the change.
- Around line 70-71: The code in AvailabilityScreen.kt incorrectly sets
firstOfWeek = availabilityUiState.currentMonth.atDay(1) which yields the 1st–3rd
of the month; change the logic so the 3-day window is derived from the user's
selected anchor date or selectedDates range (e.g., use
availabilityUiState.selectedDates.firstOrNull() or an anchorDate from the view
state, falling back to currentMonth.atDay(1) only as a last resort), rename
firstOfWeek to a clearer name like windowStartDate, and build dates = (0..2).map
{ windowStartDate.plusDays(it.toLong()) } so the visible 3-day grid follows the
user selection/Mont hCalendar rather than always the start of the month.

In
`@app/src/main/java/com/cornellappdev/resell/android/viewmodel/main/AvailabilityViewModel.kt`:
- Around line 70-97: In loadAvailability and saveAvailability clear stale UI
flags on success: when you call applyMutation in the successful branches of
loadAvailability and saveAvailability, explicitly reset errorMessage to null (or
empty) and ensure saveSuccess is set appropriately (e.g., true after save, and
cleared to false when loading new data). Specifically update the applyMutation
calls in loadAvailability to set errorMessage = null and saveSuccess = false
when loading finishes successfully, and update the applyMutation in
saveAvailability to set errorMessage = null alongside saveSuccess = true; keep
existing isLoading handling. This ensures state produced by applyMutation (and
observed via stateValue()/selectedAvailabilities) doesn't retain old error or
success flags after subsequent successful operations.
- Around line 105-108: Change the DateTimeFormatter used in
UserAvailability.toLocalDateTimes to match the repository serialization: replace
DateTimeFormatter.ISO_DATE_TIME with DateTimeFormatter.ISO_LOCAL_DATE_TIME when
parsing slot.startDate in the toLocalDateTimes() function so parsing
consistently uses the local-date-time format used by
AvailabilityRepository.updateAvailability.

In `@app/src/main/res/drawable/ic_hamburger.xml`:
- Around line 2-5: The icon's intrinsic size is set too large; update the
android:width and android:height attributes in ic_hamburger.xml from 204dp x
186dp to the standard icon size (e.g., 24dp x 24dp) while leaving the
android:viewportWidth, android:viewportHeight and the existing path data
unchanged so the visual scales correctly to your design-system icon size.

---

Nitpick comments:
In
`@app/src/main/java/com/cornellappdev/resell/android/model/api/AvailabilityApiService.kt`:
- Around line 18-36: Extract the four DTO data classes (AvailabilityResponse,
UserAvailability, AvailabilitySlot, UpdateAvailabilityRequest) out of the
Retrofit service file into a new Kotlin file (e.g., AvailabilityModels.kt or
under a model/availability package) so the AvailabilityApiService stays focused;
keep the classes’ names and fields unchanged, place them in the same package as
the service (or adjust package/imports accordingly), and update the
AvailabilityApiService imports/usages to reference the moved classes. Ensure no
behavior changes and that serialization annotations or visibility modifiers (if
any) are preserved during the move.

In
`@app/src/main/java/com/cornellappdev/resell/android/ui/components/global/ResellSwitchRow.kt`:
- Around line 42-54: The Switch in ResellSwitchRow.kt currently passes checked =
checked && enabled which masks the true model state when the control is
disabled; change it to checked = checked (do not combine with enabled) and
instead customize the disabled appearance by supplying the appropriate disabled
color slots via SwitchDefaults.colors (e.g., disabledCheckedTrackColor,
disabledUncheckedTrackColor,
disabledCheckedThumbColor/disabledUncheckedThumbColor or the equivalent
properties you need) while leaving enabled = enabled; keep onCheckedChange and
other props the same so accessibility and semantics reflect the real checked
value.

In
`@app/src/main/java/com/cornellappdev/resell/android/viewmodel/main/AvailabilityViewModel.kt`:
- Around line 87-97: The saveAvailability function can launch overlapping
requests and currently discards the server's canonical result; fix by
early-return if stateValue().isLoading is true (or store the launched Job and
check its isActive) at the start of saveAvailability to prevent concurrent
saves, and on successful call to availabilityRepository.updateAvailability(...)
capture the returned UserAvailability and map it (e.g., call
result.toLocalDateTimes()) to update selectedAvailabilities via applyMutation
while still toggling isLoading and saveSuccess appropriately; ensure the error
path still clears isLoading and sets errorMessage.
- Around line 21-37: AvailabilityUiState currently initializes subCalendars to
emptyList() and enabledSubCalendars to emptySet(), which leaves the filters
panel empty in previews; to fix, provide temporary preview defaults (e.g., a
list of sample calendar names and a matching enabled set) or add a preview-only
constructor/flag to populate subCalendars and enabledSubCalendars for
interactive/testing flows so the UI shows the four demo calendars; update
AvailabilityUiState (the data class) to accept or set those preview defaults and
ensure enabledSubCalendars contains the IDs/names that should be toggled on for
the preview.

In `@app/src/main/res/drawable/ic_hamburger.xml`:
- Line 8: The drawable ic_hamburger.xml currently hardcodes
android:fillColor="#1E1E1E" (also at the other occurrences noted), which
prevents theme-aware coloring; remove the hardcoded fillColor entries and make
the vector drawable colorless (or use
android:fillColor="?android:attr/colorControlNormal" / a theme attribute), then
apply tinting at usage sites (ImageView/AppCompatImageButton via android:tint or
app:tint or via MaterialComponents theme attributes) so the icon respects
light/dark and dynamic theming.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 51cceb0c-2327-4a46-8e0b-6d3f15f94c35

📥 Commits

Reviewing files that changed from the base of the PR and between 09f546e and f74572e.

📒 Files selected for processing (11)
  • app/src/main/java/com/cornellappdev/resell/android/model/api/AvailabilityApiService.kt
  • app/src/main/java/com/cornellappdev/resell/android/model/api/RetrofitInstance.kt
  • app/src/main/java/com/cornellappdev/resell/android/model/profile/AvailabilityRepository.kt
  • app/src/main/java/com/cornellappdev/resell/android/ui/components/availability/helper/AvailabilityFilters.kt
  • app/src/main/java/com/cornellappdev/resell/android/ui/components/availability/helper/MonthCalendar.kt
  • app/src/main/java/com/cornellappdev/resell/android/ui/components/global/ResellCheckbox.kt
  • app/src/main/java/com/cornellappdev/resell/android/ui/components/global/ResellSwitchRow.kt
  • app/src/main/java/com/cornellappdev/resell/android/ui/screens/main/AvailabilityScreen.kt
  • app/src/main/java/com/cornellappdev/resell/android/ui/screens/settings/NotificationSettings.kt
  • app/src/main/java/com/cornellappdev/resell/android/viewmodel/main/AvailabilityViewModel.kt
  • app/src/main/res/drawable/ic_hamburger.xml

Comment on lines +18 to +36
data class AvailabilityResponse(
val availability: UserAvailability
)

data class UserAvailability(
val id: String,
val userId: String,
val schedule: Map<String, List<AvailabilitySlot>>,
val updatedAt: String
)

data class AvailabilitySlot(
val startDate: String,
val endDate: String
)

data class UpdateAvailabilityRequest(
val schedule: Map<String, List<AvailabilitySlot>>
) No newline at end of file
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Check which JSON converter is used and whether a naming policy is configured.
rg -nP '\b(GsonConverterFactory|MoshiConverterFactory|setFieldNamingPolicy|FieldNamingPolicy|GsonBuilder|Moshi\.Builder)\b' --type=kotlin -C2

# Check whether other API models in this repo use `@SerializedName` / `@Json` annotations.
rg -nP '@(SerializedName|Json)\b' --type=kotlin -C1 -g 'app/src/main/java/com/cornellappdev/resell/android/model/api/**'

# Spot-check the actual backend contract (if documented) for these endpoints.
rg -nP 'availability/(update)?' --type=kotlin -C2

Repository: cuappdev/resell-android

Length of output: 12237


Add @SerializedName annotations to match backend JSON keys.

The codebase uses GsonConverterFactory.create() without a custom naming policy, and other API models extensively use @SerializedName annotations (e.g., SettingsApiService, LoginApiService, PostsApiService). Fields like userId, updatedAt, startDate, and endDate in UserAvailability and AvailabilitySlot will fail to deserialize if the backend uses snake_case naming, which follows the established pattern in this project.

Add missing annotations
+import com.google.gson.annotations.SerializedName
+
 data class UserAvailability(
     val id: String,
-    val userId: String,
+    `@SerializedName`("user_id") val userId: String,
     val schedule: Map<String, List<AvailabilitySlot>>,
-    val updatedAt: String
+    `@SerializedName`("updated_at") val updatedAt: String
 )

 data class AvailabilitySlot(
-    val startDate: String,
-    val endDate: String
+    `@SerializedName`("start_date") val startDate: String,
+    `@SerializedName`("end_date") val endDate: String
 )
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/cornellappdev/resell/android/model/api/AvailabilityApiService.kt`
around lines 18 - 36, The model classes (AvailabilityResponse, UserAvailability,
AvailabilitySlot, UpdateAvailabilityRequest) need Gson `@SerializedName`
annotations for fields that the backend uses in snake_case: add
`@SerializedName`("user_id") to userId, `@SerializedName`("updated_at") to
updatedAt, `@SerializedName`("start_date") and `@SerializedName`("end_date") to
startDate/endDate in AvailabilitySlot, and add `@SerializedName` annotations as
needed for id and schedule (e.g., "id" and "schedule") so
GsonConverterFactory.create() can correctly map JSON keys to the Kotlin
properties; update the data classes to include these annotations on the
corresponding properties.

Comment on lines +22 to +32
val schedule = slots
.groupBy { it.toLocalDate().toString() }
.mapValues { (_, daySlots) ->
daySlots.sortedBy { it }.map { start ->
AvailabilitySlot(
startDate = start.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME),
endDate = start.plusMinutes(30L)
.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
)
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Look for any backend contract docs / sample payloads / tests that pin the expected datetime format.
rg -nP --type=kotlin -C2 'AvailabilitySlot|UpdateAvailabilityRequest|getMyAvailability|updateAvailability'
# And see how the grid defines slot duration so we can share the constant.
rg -nP --type=kotlin -C3 'plusMinutes|slotMinutes|SLOT_|stepMinutes'

Repository: cuappdev/resell-android

Length of output: 12724


🏁 Script executed:

#!/bin/bash
# Search for any SLOT-related constants or Duration definitions
rg -n 'SLOT|MINUTE|DURATION|SLOT_LENGTH|SLOT_HEIGHT' --type=kotlin | head -50

Repository: cuappdev/resell-android

Length of output: 438


🏁 Script executed:

#!/bin/bash
# Search for test files related to AvailabilityRepository or API
fd -e 'Test.kt' -o -e 'Test.java' | xargs rg -l 'Availability' 2>/dev/null

Repository: cuappdev/resell-android

Length of output: 2611


🏁 Script executed:

#!/bin/bash
# Check if there's any configuration or constants file defining slot length
fd -type f \( -name '*Constants*' -o -name '*Config*' \) --type kotlin | head -20

Repository: cuappdev/resell-android

Length of output: 238


🏁 Script executed:

#!/bin/bash
# Look for ISO_LOCAL_DATE_TIME usage elsewhere to see if this is a pattern
rg 'ISO_LOCAL_DATE_TIME|ISO_OFFSET_DATE_TIME|ZonedDateTime|OffsetDateTime' --type=kotlin -n

Repository: cuappdev/resell-android

Length of output: 875


🏁 Script executed:

#!/bin/bash
# Check Functions.kt to see the ZonedDateTime pattern
sed -n '100,110p' app/src/main/java/com/cornellappdev/resell/android/util/Functions.kt

Repository: cuappdev/resell-android

Length of output: 448


🏁 Script executed:

#!/bin/bash
# Look for Retrofit/Gson/Moshi configuration that might handle datetime serialization
rg -n 'GsonBuilder|JsonDeserializer|JsonSerializer|Moshi|kotlinx.serialization' --type=kotlin -C 3

Repository: cuappdev/resell-android

Length of output: 23001


🏁 Script executed:

#!/bin/bash
# Check if AvailabilitySlot has any serialization annotations
rg -B5 -A5 'data class AvailabilitySlot' app/src/main/java/com/cornellappdev/resell/android/model/api/AvailabilityApiService.kt

Repository: cuappdev/resell-android

Length of output: 296


🏁 Script executed:

#!/antml:bash
# Search for where UserAvailability and AvailabilitySlot are deserialized from backend
rg -n 'UserAvailability|AvailabilityResponse' --type=kotlin -B2 -A2 | head -80

Repository: cuappdev/resell-android

Length of output: 5497


🏁 Script executed:

#!/bin/bash
# Check the full context of AvailabilityViewModel parsing
sed -n '100,115p' app/src/main/java/com/cornellappdev/resell/android/viewmodel/main/AvailabilityViewModel.kt

Repository: cuappdev/resell-android

Length of output: 496


🏁 Script executed:

#!/bin/bash
# Look for Retrofit/Interceptor configuration that might set up custom datetime handling
rg -n 'HttpClient|OkHttpClient|Interceptor|GsonBuilder|Converter' --type=kotlin -B2 -A5

Repository: cuappdev/resell-android

Length of output: 17562


🏁 Script executed:

#!/antml:bash
# Check if there are any test files or examples showing the actual API format
fd -name '*.kt' | xargs rg -l 'AvailabilitySlot.*startDate' | head -5

Repository: cuappdev/resell-android

Length of output: 298


🏁 Script executed:

#!/bin/bash
# Look for any backend API documentation or mock responses
fd -name '*.json' -o -name '*.md' | xargs rg -l 'availability\|Availability' 2>/dev/null | head -10

Repository: cuappdev/resell-android

Length of output: 298


Fix datetime format mismatch and extract hardcoded slot duration.

Two issues must be resolved before production use:

  1. Incompatible datetime formats between send/receive. AvailabilityRepository uses ISO_LOCAL_DATE_TIME (produces "2026-04-27T14:30:00" with no offset), but AvailabilityViewModel.toLocalDateTimes() parses with ISO_DATE_TIME (expects "2026-04-27T14:30:00+05:00" with offset). This will cause a DateTimeParseException once the backend returns real data. Align both to the same format — likely ISO_OFFSET_DATE_TIME / ISO_DATE_TIME with timezone info if comparing across clients/zones, or verify the backend contract and use a consistent formatter throughout.

  2. Hardcoded 30-minute slot length. The magic 30L is duplicated across AvailabilityRepository.kt (lines 28), AvailabilityUtil.kt, SelectableAvailabilityGrid.kt, ViewOnlyAvailabilityGrid.kt, and test helpers. Extract to a shared constant (e.g., SLOT_DURATION_MINUTES) so grid and repository use the same value.

Also replace daySlots.sortedBy { it } (line 25) with daySlots.sorted() since LocalDateTime is Comparable.

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

In
`@app/src/main/java/com/cornellappdev/resell/android/model/profile/AvailabilityRepository.kt`
around lines 22 - 32, Update AvailabilityRepository so the datetime formatter
matches the parser used by AvailabilityViewModel.toLocalDateTimes(): replace
DateTimeFormatter.ISO_LOCAL_DATE_TIME with a formatter that includes
offset/timezone (e.g., DateTimeFormatter.ISO_OFFSET_DATE_TIME or the same
formatter used by toLocalDateTimes()) when formatting startDate and endDate for
AvailabilitySlot; also replace daySlots.sortedBy { it } with daySlots.sorted()
since LocalDateTime is Comparable. Extract the hardcoded 30L into a shared
constant (e.g., SLOT_DURATION_MINUTES) and use that constant in
AvailabilityRepository (endDate calculation), AvailabilityUtil,
SelectableAvailabilityGrid, ViewOnlyAvailabilityGrid, and test helpers so all
code references the same slot duration.

Comment on lines +78 to +80
val checkedStates = remember { mutableStateMapOf<String, Boolean>().apply {
subCalendars.forEach { put(it, it != "Personal" && it != "Capra") }
}}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Hoist checkedStates to the ViewModel so it survives panel collapse and configuration changes.

AvailabilityFilters is rendered inside an AnimatedVisibility in AvailabilityScreen.kt whose content is removed from composition when the panel closes. Because checkedStates is a plain remember { mutableStateMapOf(...) }, every collapse/expand of the filter panel will reset the user's selections back to the hardcoded defaults. Same applies to rotation (no rememberSaveable).

When you wire this up to the backend, hoist the map (and the two switch values) into AvailabilityViewModel and pass them in as parameters with callbacks, matching the pattern used by NotificationSettings. This will also make the existing // TODO switch handlers natural to fill in.

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

In
`@app/src/main/java/com/cornellappdev/resell/android/ui/components/availability/helper/AvailabilityFilters.kt`
around lines 78 - 80, The checkedStates mutable map is currently local to
AvailabilityFilters and reset when the composable is removed; move its state
into AvailabilityViewModel (add a MutableState<Map<String,Boolean>> or similar)
and expose it via state + update callback parameters to AvailabilityFilters
(mirror the pattern used by NotificationSettings). In practice: remove remember
{ mutableStateMapOf... } from AvailabilityFilters, add properties and updater
functions in AvailabilityViewModel (e.g., checkedStates, setCheckedState(key,
value)), also hoist the two switch values into the ViewModel with corresponding
setters, and update AvailabilityFilters to accept the current states and
callbacks so the TODO switch handlers call the supplied setters rather than
mutating local state.

Comment on lines +24 to +30
@Composable
fun MonthCalendar(
currentMonth: YearMonth,
selectedDates: List<LocalDate>,
onMonthChange: (YearMonth) -> Unit,
modifier: Modifier = Modifier,
) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

onMonthChange is wired in but never invoked — month navigation is unreachable.

AvailabilityScreen.kt passes onMonthChange = { availabilityViewModel.setCurrentMonth(it) }, but MonthCalendar itself never calls the callback. There is no header arrow/chevron, no swipe gesture, and no clickable surface that produces a YearMonth. As written, the user cannot navigate to previous/next months from this calendar at all.

Either add the previous/next month controls (matching the Figma) and invoke onMonthChange(currentMonth.minusMonths(1) / .plusMonths(1)), or drop the parameter from the public API until navigation is implemented to avoid a dead callback.

Also applies to: 60-101

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

In
`@app/src/main/java/com/cornellappdev/resell/android/ui/components/availability/helper/MonthCalendar.kt`
around lines 24 - 30, MonthCalendar declares onMonthChange but never calls it,
so wire month navigation controls to invoke it: add previous/next buttons or
chevrons in the MonthCalendar header (matching Figma) and call
onMonthChange(currentMonth.minusMonths(1)) for the previous control and
onMonthChange(currentMonth.plusMonths(1)) for the next control; ensure the
clickable composables update accessibility/tap targets and preserve the existing
parameters (currentMonth, selectedDates) when rendering, or if you prefer not to
implement navigation now, remove the onMonthChange parameter from MonthCalendar
and its callers (e.g., AvailabilityScreen ->
availabilityViewModel.setCurrentMonth) to avoid a dead callback.

Comment on lines +41 to +74
Row(
modifier = modifier.fillMaxWidth(),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.SpaceBetween
) {
Text(
text = title,
style = Style.body2,
)
// Custom checkbox for Resell. Checkbox in Material3 doesn't offer enough customization.
Box(
modifier = Modifier
.size(22.dp)
.clip(shape)
.background(fillColor, shape)
.border(1.5.dp, borderColor, shape)
.toggleable(
value = checked,
enabled = enabled,
role = Role.Checkbox,
onValueChange = onCheckedChange
),
contentAlignment = Alignment.Center
) {
if (checked) {
Icon(
imageVector = Icons.Default.Check,
contentDescription = null,
tint = Color.White,
modifier = Modifier.fillMaxSize(0.6f)
)
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Tie the title to the checkbox for accessibility, and reflect enabled visually.

Two small issues in this otherwise nice custom control:

  1. The Row itself is not toggleable, so users have to tap the small 22dp box. More importantly, the toggleable modifier with Role.Checkbox is on the inner Box and there is no contentDescription/stateDescription, so TalkBack will only announce "checked/unchecked" without the calendar name. Moving toggleable to the Row (or adding Modifier.semantics { contentDescription = title }) makes the whole row tappable and properly labeled.
  2. fillColor/borderColor only depend on checked. When enabled = false the control still looks fully active even though interaction is blocked.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/cornellappdev/resell/android/ui/components/global/ResellCheckbox.kt`
around lines 41 - 74, Move the toggleable modifier off the inner Box and onto
the Row (or add Modifier.semantics) so the entire Row toggles and accessibility
announcements include the label; add semantics/stateDescription or
contentDescription that uses the title and the checked state (e.g., "$title,
${if (checked) "checked" else "unchecked"}") so TalkBack reads the name and
state. Also make the visual styling respect enabled by changing how fillColor
and borderColor are computed in ResellCheckbox (use disabled variants or apply
alpha when enabled == false) and ensure the Icon tint/opacity follows enabled as
well; remove duplicate toggleable on the Box if moved. Ensure Role.Checkbox
remains on the toggleable call for accessibility.

Comment on lines +70 to +71
val firstOfWeek = availabilityUiState.currentMonth.atDay(1)
val dates: List<LocalDate> = (0..2).map { firstOfWeek.plusDays(it.toLong()) }
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Misleading name and likely wrong window: this always shows days 1–3 of the displayed month.

firstOfWeek = currentMonth.atDay(1) is the first of the month, not the first of any week, and the resulting dates is always the 1st, 2nd, 3rd of that month. If the user changes month via MonthCalendar or selects a date range, the visible 3-day grid will always snap back to "the 1st through 3rd". I'd expect the visible 3 days to derive from the selectedDates range (or the user's currently-selected anchor date) rather than atDay(1).

Suggested rename + likely intent:

♻️ Suggested change
-    val firstOfWeek = availabilityUiState.currentMonth.atDay(1)
-    val dates: List<LocalDate> = (0..2).map { firstOfWeek.plusDays(it.toLong()) }
+    val anchorDate = availabilityUiState.selectedDates.minOrNull()
+        ?: availabilityUiState.currentMonth.atDay(1)
+    val dates: List<LocalDate> = (0..2).map { anchorDate.plusDays(it.toLong()) }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/cornellappdev/resell/android/ui/screens/main/AvailabilityScreen.kt`
around lines 70 - 71, The code in AvailabilityScreen.kt incorrectly sets
firstOfWeek = availabilityUiState.currentMonth.atDay(1) which yields the 1st–3rd
of the month; change the logic so the 3-day window is derived from the user's
selected anchor date or selectedDates range (e.g., use
availabilityUiState.selectedDates.firstOrNull() or an anchorDate from the view
state, falling back to currentMonth.atDay(1) only as a last resort), rename
firstOfWeek to a clearer name like windowStartDate, and build dates = (0..2).map
{ windowStartDate.plusDays(it.toLong()) } so the visible 3-day grid follows the
user selection/Mont hCalendar rather than always the start of the month.

Comment on lines +216 to +220
@Preview
@Composable
fun AvailabilityScreenPreview() {
AvailabilityScreen()
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

AvailabilityScreenPreview will crash under Hilt.

AvailabilityScreen() resolves its VM via hiltViewModel(), which requires a Hilt-instrumented Activity at runtime and is not available in the IDE preview pane. Any attempt to render this preview will throw. Either preview a hoisted AvailabilityScreenContent(...) that takes plain state/callbacks (recommended — also unblocks design iteration), or accept a viewModel: AvailabilityViewModel? = null and short-circuit in preview.

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

In
`@app/src/main/java/com/cornellappdev/resell/android/ui/screens/main/AvailabilityScreen.kt`
around lines 216 - 220, The preview crashes because AvailabilityScreen() calls
hiltViewModel(), which isn't available in the IDE preview; update the preview to
not resolve a Hilt VM — either replace AvailabilityScreenPreview to render the
hoisted UI (call AvailabilityScreenContent(...) with a mocked
AvailabilityViewState and no-op callbacks) or change AvailabilityScreen
signature to accept viewModel: AvailabilityViewModel? = null and short-circuit
when viewModel is null so the preview can pass a fake/null viewModel; reference
AvailabilityScreenPreview, AvailabilityScreen, hiltViewModel,
AvailabilityScreenContent, and AvailabilityViewModel when making the change.

Comment on lines +70 to +97
private fun loadAvailability() {
viewModelScope.launch {
applyMutation { copy(isLoading = true) }
try {
val availability = availabilityRepository.getMyAvailability()
applyMutation {
copy(
selectedAvailabilities = availability.toLocalDateTimes(),
isLoading = false
)
}
} catch (e: Exception) {
applyMutation { copy(isLoading = false, errorMessage = e.message) }
}
}
}

fun saveAvailability() {
viewModelScope.launch {
applyMutation { copy(isLoading = true, saveSuccess = false) }
try {
availabilityRepository.updateAvailability(stateValue().selectedAvailabilities)
applyMutation { copy(isLoading = false, saveSuccess = true) }
} catch (e: Exception) {
applyMutation { copy(isLoading = false, errorMessage = e.message) }
}
}
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Clear errorMessage on success paths.

Both loadAvailability and saveAvailability set errorMessage only on failure but never reset it on success. After a transient failure (e.g., flaky network), a subsequent successful retry will leave the stale error sitting in UI state and the user will keep seeing the old toast/banner. Same pattern applies to saveSuccess — a fresh loadAvailability after a save should arguably clear it so the screen doesn't keep flagging "saved".

🛠️ Suggested fix
             try {
                 val availability = availabilityRepository.getMyAvailability()
                 applyMutation {
                     copy(
                         selectedAvailabilities = availability.toLocalDateTimes(),
-                        isLoading = false
+                        isLoading = false,
+                        errorMessage = null,
                     )
                 }
             } catch (e: Exception) {
                 applyMutation { copy(isLoading = false, errorMessage = e.message) }
             }
             try {
                 availabilityRepository.updateAvailability(stateValue().selectedAvailabilities)
-                applyMutation { copy(isLoading = false, saveSuccess = true) }
+                applyMutation { copy(isLoading = false, saveSuccess = true, errorMessage = null) }
             } catch (e: Exception) {
-                applyMutation { copy(isLoading = false, errorMessage = e.message) }
+                applyMutation { copy(isLoading = false, saveSuccess = false, errorMessage = e.message) }
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In
`@app/src/main/java/com/cornellappdev/resell/android/viewmodel/main/AvailabilityViewModel.kt`
around lines 70 - 97, In loadAvailability and saveAvailability clear stale UI
flags on success: when you call applyMutation in the successful branches of
loadAvailability and saveAvailability, explicitly reset errorMessage to null (or
empty) and ensure saveSuccess is set appropriately (e.g., true after save, and
cleared to false when loading new data). Specifically update the applyMutation
calls in loadAvailability to set errorMessage = null and saveSuccess = false
when loading finishes successfully, and update the applyMutation in
saveAvailability to set errorMessage = null alongside saveSuccess = true; keep
existing isLoading handling. This ensures state produced by applyMutation (and
observed via stateValue()/selectedAvailabilities) doesn't retain old error or
success flags after subsequent successful operations.

Comment on lines +105 to +108
private fun UserAvailability.toLocalDateTimes(): List<LocalDateTime> {
return schedule.values.flatten().map { slot ->
LocalDateTime.parse(slot.startDate, DateTimeFormatter.ISO_DATE_TIME)
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🌐 Web query:

Does Java's DateTimeFormatter.ISO_DATE_TIME successfully parse a local date-time string like "2024-01-15T14:30:00" into a LocalDateTime?

💡 Result:

Yes, Java's DateTimeFormatter.ISO_DATE_TIME successfully parses a local date-time string like "2024-01-15T14:30:00" into a LocalDateTime.

Citations:


🏁 Script executed:

cat -n app/src/main/java/com/cornellappdev/resell/android/viewmodel/main/AvailabilityViewModel.kt | sed -n '100,120p'

Repository: cuappdev/resell-android

Length of output: 566


🏁 Script executed:

# Search for AvailabilityRepository to confirm formatter usage
fd -t f AvailabilityRepository.kt | head -5

Repository: cuappdev/resell-android

Length of output: 158


🏁 Script executed:

# Search for the Slot or schedule model definition
fd -t f -i "slot\|availability" app/src/main/java | grep -i "model\|data\|dto" | head -10

Repository: cuappdev/resell-android

Length of output: 49


🏁 Script executed:

cat -n app/src/main/java/com/cornellappdev/resell/android/model/profile/AvailabilityRepository.kt | head -150

Repository: cuappdev/resell-android

Length of output: 1875


🏁 Script executed:

# Search for the UserAvailability and Slot model definitions
fd -t f UserAvailability.kt

Repository: cuappdev/resell-android

Length of output: 49


🏁 Script executed:

# Also search for AvailabilitySlot or similar
rg -l "AvailabilitySlot\|class Slot" --type kt

Repository: cuappdev/resell-android

Length of output: 94


🏁 Script executed:

rg -l "class AvailabilitySlot|data class AvailabilitySlot" --type kotlin

Repository: cuappdev/resell-android

Length of output: 154


🏁 Script executed:

rg -l "class UserAvailability|data class UserAvailability" --type kotlin

Repository: cuappdev/resell-android

Length of output: 154


🏁 Script executed:

cat -n app/src/main/java/com/cornellappdev/resell/android/model/api/AvailabilityApiService.kt

Repository: cuappdev/resell-android

Length of output: 1131


🏁 Script executed:

# Check the AvailabilityViewModel more broadly to see how toLocalDateTimes is used
rg -A 5 -B 5 "toLocalDateTimes" app/src/main/java/com/cornellappdev/resell/android/viewmodel/main/AvailabilityViewModel.kt

Repository: cuappdev/resell-android

Length of output: 992


🏁 Script executed:

# Look at how selectedAvailabilities is used in UI or elsewhere
rg "selectedAvailabilities" app/src/main/java/com/cornellappdev/resell/android/viewmodel/main/AvailabilityViewModel.kt | head -20

Repository: cuappdev/resell-android

Length of output: 378


Use ISO_LOCAL_DATE_TIME to match the repository's serialization format.

AvailabilityRepository.updateAvailability formats both startDate and endDate with DateTimeFormatter.ISO_LOCAL_DATE_TIME (lines 27–29). Parsing here with ISO_DATE_TIME happens to work because it accepts both local and offset date-times, but the inconsistency obscures intent. Using ISO_LOCAL_DATE_TIME ensures the formatter matches the source and will fail fast if the backend ever starts sending offset-bearing strings.

Note: The current implementation correctly uses only startDate because AvailabilityRepository creates each slot as exactly 30 minutes (endDate = startDate + 30 minutes), so each slot corresponds to exactly one grid cell. The comment on lines 100–104 documents this design intentionally.

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

In
`@app/src/main/java/com/cornellappdev/resell/android/viewmodel/main/AvailabilityViewModel.kt`
around lines 105 - 108, Change the DateTimeFormatter used in
UserAvailability.toLocalDateTimes to match the repository serialization: replace
DateTimeFormatter.ISO_DATE_TIME with DateTimeFormatter.ISO_LOCAL_DATE_TIME when
parsing slot.startDate in the toLocalDateTimes() function so parsing
consistently uses the local-date-time format used by
AvailabilityRepository.updateAvailability.

Comment on lines +2 to +5
android:width="204dp"
android:height="186dp"
android:viewportWidth="204"
android:viewportHeight="186">
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

Use standard icon intrinsic size for menu assets.

204dp x 186dp is very large for a hamburger icon and can lead to inconsistent sizing where dimensions aren’t explicitly constrained. Prefer 24dp x 24dp (or your design-system icon size) and keep the existing viewport/path data.

Suggested update
-    android:width="204dp"
-    android:height="186dp"
+    android:width="24dp"
+    android:height="24dp"
📝 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
android:width="204dp"
android:height="186dp"
android:viewportWidth="204"
android:viewportHeight="186">
android:width="24dp"
android:height="24dp"
android:viewportWidth="204"
android:viewportHeight="186">
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@app/src/main/res/drawable/ic_hamburger.xml` around lines 2 - 5, The icon's
intrinsic size is set too large; update the android:width and android:height
attributes in ic_hamburger.xml from 204dp x 186dp to the standard icon size
(e.g., 24dp x 24dp) while leaving the android:viewportWidth,
android:viewportHeight and the existing path data unchanged so the visual scales
correctly to your design-system icon size.

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.

1 participant