Skip to content

[Feature]: Improvements to the picker state management#22

Merged
kez-lab merged 8 commits intomainfrom
feature/divide_state
Dec 12, 2025
Merged

[Feature]: Improvements to the picker state management#22
kez-lab merged 8 commits intomainfrom
feature/divide_state

Conversation

@kez-lab
Copy link
Copy Markdown
Owner

@kez-lab kez-lab commented Nov 21, 2025

This pull request introduces significant improvements to the picker state management in the datetime picker library. It centralizes and simplifies the handling of complex picker states (such as year/month and time pickers) by introducing new state holder classes and composable state creators. This leads to cleaner, more maintainable code and easier integration in UI screens. Additionally, the Picker component is made more flexible by allowing custom item content rendering.

State Management Refactoring:

  • Introduced YearMonthPickerState and TimePickerState classes, along with their corresponding rememberYearMonthPickerState and rememberTimePickerState composable creators, to encapsulate year/month and time picker state logic in a single object. This replaces the previous pattern of passing multiple PickerState objects for each part of the picker. (datetimepicker/src/commonMain/kotlin/com/kez/picker/PickerState.kt)
  • Updated the YearMonthPicker and TimePicker components to accept the new state holder objects, simplifying their APIs and usage. (datetimepicker/src/commonMain/kotlin/com/kez/picker/date/YearMonthPicker.kt, datetimepicker/src/commonMain/kotlin/com/kez/picker/time/TimePicker.kt) [1] [2]

Picker Component Enhancements:

  • Added a content parameter to the generic Picker composable, allowing consumers to provide custom composable content for each item, increasing flexibility in UI rendering. (datetimepicker/src/commonMain/kotlin/com/kez/picker/Picker.kt) [1] [2]

Sample Code Updates:

  • Refactored all sample screens to use the new state holder objects (YearMonthPickerState and TimePickerState) instead of managing individual picker states. This results in more concise and less error-prone sample code. (sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/BackgroundStylePickerScreen.kt, sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/BottomSheetSampleScreen.kt) [1] [2]

Internal Improvements:

  • Marked PickerState, YearMonthPickerState, and TimePickerState as @Stable to improve Compose state handling and performance. (datetimepicker/src/commonMain/kotlin/com/kez/picker/PickerState.kt)

Minor Cleanups:

  • Reordered parameters in the Picker composable for improved consistency and clarity. (datetimepicker/src/commonMain/kotlin/com/kez/picker/Picker.kt)

These changes make the picker components easier to use, more robust, and more flexible for future enhancements.

Summary by CodeRabbit

  • New Features

    • Optional custom rendering for picker items
    • Composite date/time state objects with remember helpers and sensible defaults
  • Improvements

    • Simplified picker APIs to accept bundled state objects
    • Stable state accessors for selected date/time values; sample screens updated to use new state APIs
  • Documentation

    • README rewritten with concise examples and usage
    • Added Korean README with examples and API summary

✏️ Tip: You can customize this high-level summary in your review settings.

@kez-lab kez-lab requested a review from Copilot November 21, 2025 13:50
@kez-lab kez-lab self-assigned this Nov 21, 2025
@kez-lab kez-lab added the enhancement New feature or request label Nov 21, 2025
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Nov 21, 2025

Caution

Review failed

The pull request is closed.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Consolidates multiple picker states into composite state holders (YearMonthPickerState, TimePickerState), adds an optional content composable parameter to Picker for custom per-item rendering, and updates picker composables and sample screens to use the new state APIs and rendering option.

Changes

Cohort / File(s) Summary
Core Picker API
datetimepicker/src/commonMain/kotlin/com/kez/picker/Picker.kt
Added optional parameter content: @composable ((T) -> Unit)? = null to allow custom per-item rendering; preserved text fallback, animation/fraction styling, and click/enable behavior while using a local item variable for null-safety.
State Management Foundation
datetimepicker/src/commonMain/kotlin/com/kez/picker/PickerState.kt
Marked PickerState<T> as @Stable. Added composite public state types and rememberers: YearMonthPickerState / rememberYearMonthPickerState(...) and TimePickerState / rememberTimePickerState(...), exposing selected value accessors and initial-value derivation (current date/time and AM/PM logic).
Picker Composables
datetimepicker/src/commonMain/kotlin/com/kez/picker/date/YearMonthPicker.kt, datetimepicker/src/commonMain/kotlin/com/kez/picker/time/TimePicker.kt
Replaced multiple individual PickerState parameters with single composite state: YearMonthPickerState = rememberYearMonthPickerState() and state: TimePickerState = rememberTimePickerState(); updated internals to use state.*State and state.timeFormat.
Sample UI Integration
sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/...
BackgroundStylePickerScreen.kt, BottomSheetSampleScreen.kt, DatePickerSampleScreen.kt, IntegratedPickerScreen.kt, TimePickerSampleScreen.kt
Migrated samples from multiple rememberPickerState(...) usages to rememberYearMonthPickerState(...) / rememberTimePickerState(...); updated display strings and component calls to use state.selected* properties and pass single state arguments.
Documentation
README.md, README_KO.md
Rewrote README, added Korean README; updated examples and documented new state APIs and usage patterns (24h/12h examples, YearMonthPicker usage).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

  • Pay extra attention to:
    • Picker.kt — correct null-handling, content branching, and that click/enable use the local item.
    • PickerState.kt@Stable annotations and initial-value logic (AM/PM, current date/time).
    • TimePicker.kt / YearMonthPicker.kt — substitutions to state.*State and state.timeFormat with preserved semantics.
    • Sample screens — consistency of displayed values using state.selected* accessors.

Possibly related PRs

Poem

🐰
I nibble states — year, month, hour, and minute too,
One basket holds them whole, tidy and true.
Paint each item if you like — my brush is yours to lend,
I hop through samples and stitch the seams to mend.
Hooray for pickers — small hops, big joy without end!

Pre-merge checks and finishing touches

❌ Failed checks (1 warning)
Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 13.33% which is insufficient. The required threshold is 80.00%. You can run @coderabbitai generate docstrings to improve docstring coverage.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main objective of the pull request: introducing consolidated state holders and improving picker state management across the codebase.

📜 Recent review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1b1293d and 1de63db.

📒 Files selected for processing (1)
  • datetimepicker/src/commonMain/kotlin/com/kez/picker/PickerState.kt (2 hunks)

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

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull Request Overview

This PR refactors the picker state management in the datetime picker library by introducing dedicated state holder classes (YearMonthPickerState and TimePickerState) that encapsulate multiple picker states into single objects. This simplifies the API and makes the components easier to use.

  • Introduced YearMonthPickerState and TimePickerState classes with corresponding remember* composable functions to centralize state management
  • Enhanced the Picker component with an optional content parameter for custom item rendering
  • Updated all sample screens to use the new simplified state management API

Reviewed Changes

Copilot reviewed 9 out of 9 changed files in this pull request and generated 7 comments.

Show a summary per file
File Description
datetimepicker/src/commonMain/kotlin/com/kez/picker/PickerState.kt Added new state holder classes (YearMonthPickerState, TimePickerState) and their composable creators with @Stable annotations
datetimepicker/src/commonMain/kotlin/com/kez/picker/Picker.kt Reordered parameters and added optional content parameter for custom item rendering
datetimepicker/src/commonMain/kotlin/com/kez/picker/date/YearMonthPicker.kt Updated to accept single YearMonthPickerState instead of separate year and month states
datetimepicker/src/commonMain/kotlin/com/kez/picker/time/TimePicker.kt Updated to accept single TimePickerState instead of separate hour, minute, and period states
sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/TimePickerSampleScreen.kt Refactored to use new rememberTimePickerState for both 12-hour and 24-hour formats
sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/IntegratedPickerScreen.kt Refactored to use new state holders for both date and time pickers
sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/DatePickerSampleScreen.kt Refactored to use new rememberYearMonthPickerState
sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/BottomSheetSampleScreen.kt Refactored to use new state holders for bottom sheet integration
sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/BackgroundStylePickerScreen.kt Refactored to use new state holders with custom styling

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +40 to +48
@Composable
fun rememberYearMonthPickerState(
initialYear: Int = currentDate.year,
initialMonth: Int = currentDate.month.number
): YearMonthPickerState {
return remember(initialYear, initialMonth) {
YearMonthPickerState(initialYear, initialMonth)
}
}
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

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

Missing documentation for the rememberYearMonthPickerState function. Consider adding a KDoc comment similar to other composable functions in this file, explaining the purpose, parameters, and return value.

Copilot uses AI. Check for mistakes.
Comment on lines +50 to +63
@Stable
class YearMonthPickerState(
initialYear: Int,
initialMonth: Int
) {
val yearState = PickerState(initialYear)
val monthState = PickerState(initialMonth)

val selectedYear: Int
get() = yearState.selectedItem

val selectedMonth: Int
get() = monthState.selectedItem
}
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

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

Missing documentation for the YearMonthPickerState class. Consider adding a KDoc comment similar to PickerState, explaining the purpose and the constructor parameters.

Copilot uses AI. Check for mistakes.
Comment on lines +65 to +74
@Composable
fun rememberTimePickerState(
initialHour: Int = currentHour,
initialMinute: Int = currentMinute,
initialPeriod: TimePeriod = if (currentHour >= 12) TimePeriod.PM else TimePeriod.AM
): TimePickerState {
return remember(initialHour, initialMinute, initialPeriod) {
TimePickerState(initialHour, initialMinute, initialPeriod)
}
}
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

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

Missing documentation for the rememberTimePickerState function. Consider adding a KDoc comment similar to other composable functions in this file, explaining the purpose, parameters, and return value.

Copilot uses AI. Check for mistakes.
Comment on lines +76 to +94
@Stable
class TimePickerState(
initialHour: Int,
initialMinute: Int,
initialPeriod: TimePeriod
) {
val hourState = PickerState(initialHour)
val minuteState = PickerState(initialMinute)
val periodState = PickerState(initialPeriod)

val selectedHour: Int
get() = hourState.selectedItem

val selectedMinute: Int
get() = minuteState.selectedItem

val selectedPeriod: TimePeriod
get() = periodState.selectedItem
} No newline at end of file
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

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

Missing documentation for the TimePickerState class. Consider adding a KDoc comment similar to PickerState, explaining the purpose and the constructor parameters.

Copilot uses AI. Check for mistakes.
Comment on lines +234 to +257
if (item != null) {
if (content != null) {
content(item)
} else {
Text(
text = item.toString(),
maxLines = 1,
overflow = TextOverflow.Ellipsis,
style = textStyle.copy(
fontSize = lerp(
selectedTextStyle.fontSize,
textStyle.fontSize,
fraction
),
color = lerp(
selectedTextStyle.color,
textStyle.color,
fraction
),
),
textAlign = TextAlign.Center
)
}
}
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

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

[nitpick] When custom content is provided, the text styling effects (fontSize and color interpolation based on scroll position) are not applied. This could create inconsistent visual behavior compared to the default text rendering. Consider either documenting this limitation clearly or providing a way to pass the fraction value to the custom content so consumers can apply similar styling if desired.

Copilot uses AI. Check for mistakes.
initialMonth = currentDate.monthNumber
)
val timeState = rememberTimePickerState(
initialHour = currentHour,
Copy link

Copilot AI Nov 21, 2025

Choose a reason for hiding this comment

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

The timeState is initialized with currentHour (24-hour format), but the TimePicker is configured to use TimeFormat.HOUR_12. This creates an inconsistency where the initial hour value might be outside the expected range for 12-hour format (1-12). Consider converting currentHour to 12-hour format during initialization, similar to how it's done in TimePickerSampleScreen.kt and BottomSheetSampleScreen.kt:

initialHour = if (currentHour > 12) currentHour - 12 else if (currentHour == 0) 12 else currentHour
Suggested change
initialHour = currentHour,
initialHour = if (currentHour > 12) currentHour - 12 else if (currentHour == 0) 12 else currentHour,

Copilot uses AI. Check for mistakes.
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: 0

Caution

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

⚠️ Outside diff range comments (2)
datetimepicker/src/commonMain/kotlin/com/kez/picker/time/TimePicker.kt (1)

36-63: Update the KDoc to reflect the new API.

The documentation still references the old parameters (minutePickerState, hourPickerState, periodPickerState) that have been replaced with a single state: TimePickerState parameter.

Apply this diff to update the documentation:

  * @param modifier The modifier to be applied to the component.
  * @param pickerModifier The modifier to be applied to each picker.
- * @param minutePickerState The state for the minute picker.
- * @param hourPickerState The state for the hour picker.
- * @param periodPickerState The state for the AM/PM period picker.
+ * @param state The state holder for the time picker, containing hour, minute, and period states.
  * @param timeFormat The time format (12-hour or 24-hour).
datetimepicker/src/commonMain/kotlin/com/kez/picker/date/YearMonthPicker.kt (1)

35-38: Update the KDoc to reflect the new API.

The documentation still references the old parameters (yearPickerState, monthPickerState) that have been replaced with a single state: YearMonthPickerState parameter.

Apply this diff:

  * @param modifier The modifier to be applied to the component.
  * @param pickerModifier The modifier to be applied to each picker.
- * @param yearPickerState The state for the year picker.
- * @param monthPickerState The state for the month picker.
+ * @param state The state holder for the year/month picker, containing year and month states.
  * @param startLocalDate The initial date to display.
🧹 Nitpick comments (1)
datetimepicker/src/commonMain/kotlin/com/kez/picker/Picker.kt (1)

98-98: Consider exposing the animation fraction to custom content.

The content parameter allows custom item rendering, but it doesn't receive the fraction value that's used for animating size and color in the default text rendering (lines 243-252). This prevents custom content from replicating the built-in animation behavior.

If animation support for custom content is desired, consider changing the signature to:

content: @Composable ((T, Float) -> Unit)? = null

Then pass the fraction when invoking custom content:

if (content != null) {
    content(item, fraction)
}

This would allow custom renderers to apply similar lerp-based animations while maintaining backward compatibility if users ignore the fraction parameter.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 204adf7 and e08ee11.

📒 Files selected for processing (9)
  • datetimepicker/src/commonMain/kotlin/com/kez/picker/Picker.kt (4 hunks)
  • datetimepicker/src/commonMain/kotlin/com/kez/picker/PickerState.kt (2 hunks)
  • datetimepicker/src/commonMain/kotlin/com/kez/picker/date/YearMonthPicker.kt (4 hunks)
  • datetimepicker/src/commonMain/kotlin/com/kez/picker/time/TimePicker.kt (5 hunks)
  • sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/BackgroundStylePickerScreen.kt (4 hunks)
  • sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/BottomSheetSampleScreen.kt (7 hunks)
  • sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/DatePickerSampleScreen.kt (3 hunks)
  • sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/IntegratedPickerScreen.kt (4 hunks)
  • sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/TimePickerSampleScreen.kt (5 hunks)
🧰 Additional context used
🧬 Code graph analysis (7)
sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/DatePickerSampleScreen.kt (2)
datetimepicker/src/commonMain/kotlin/com/kez/picker/PickerState.kt (1)
  • rememberYearMonthPickerState (40-48)
sample/src/commonMain/kotlin/com/kez/picker/sample/StringUtils.kt (1)
  • getMonthName (27-43)
sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/BackgroundStylePickerScreen.kt (2)
datetimepicker/src/commonMain/kotlin/com/kez/picker/PickerState.kt (2)
  • rememberYearMonthPickerState (40-48)
  • rememberTimePickerState (65-74)
sample/src/commonMain/kotlin/com/kez/picker/sample/StringUtils.kt (2)
  • getMonthName (27-43)
  • formatTime12 (8-13)
sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/IntegratedPickerScreen.kt (2)
datetimepicker/src/commonMain/kotlin/com/kez/picker/PickerState.kt (2)
  • rememberYearMonthPickerState (40-48)
  • rememberTimePickerState (65-74)
sample/src/commonMain/kotlin/com/kez/picker/sample/StringUtils.kt (2)
  • getMonthName (27-43)
  • formatTime12 (8-13)
sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/TimePickerSampleScreen.kt (2)
datetimepicker/src/commonMain/kotlin/com/kez/picker/PickerState.kt (1)
  • rememberTimePickerState (65-74)
datetimepicker/src/commonMain/kotlin/com/kez/picker/time/TimePicker.kt (1)
  • TimePicker (64-194)
datetimepicker/src/commonMain/kotlin/com/kez/picker/date/YearMonthPicker.kt (1)
datetimepicker/src/commonMain/kotlin/com/kez/picker/PickerState.kt (1)
  • rememberYearMonthPickerState (40-48)
datetimepicker/src/commonMain/kotlin/com/kez/picker/time/TimePicker.kt (1)
datetimepicker/src/commonMain/kotlin/com/kez/picker/PickerState.kt (1)
  • rememberTimePickerState (65-74)
sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/BottomSheetSampleScreen.kt (1)
datetimepicker/src/commonMain/kotlin/com/kez/picker/PickerState.kt (2)
  • rememberYearMonthPickerState (40-48)
  • rememberTimePickerState (65-74)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (5)
  • GitHub Check: Agent
  • GitHub Check: macOS • iOS Simulator Test
  • GitHub Check: Linux • android
  • GitHub Check: Linux • wasm
  • GitHub Check: Linux • desktop
🔇 Additional comments (19)
datetimepicker/src/commonMain/kotlin/com/kez/picker/time/TimePicker.kt (2)

26-27: LGTM: Clean state consolidation.

The refactoring successfully consolidates multiple picker states into a single TimePickerState, simplifying the API and improving ergonomics.

Also applies to: 68-68


129-149: LGTM: Consistent state access pattern.

The internal usage correctly accesses the composite state properties (state.periodState, state.hourState, state.minuteState), maintaining the existing behavior while using the new state structure.

Also applies to: 152-170, 172-190

datetimepicker/src/commonMain/kotlin/com/kez/picker/Picker.kt (2)

79-79: LGTM: Enhanced flexibility with custom content.

The addition of the content parameter provides a clean extension point for custom item rendering. Parameter reordering places optional/advanced parameters at the end, which is a good API design practice.

Also applies to: 97-98


234-257: LGTM: Correct null-safety and rendering logic.

The rendering logic properly handles null items and delegates to custom content when provided, falling back to default text rendering otherwise.

datetimepicker/src/commonMain/kotlin/com/kez/picker/PickerState.kt (3)

30-38: LGTM: Proper @stable annotation.

Adding @Stable to PickerState enables Compose to optimize recomposition by treating the class as stable when its observable state doesn't change.


40-63: LGTM: Well-designed composite state.

YearMonthPickerState effectively encapsulates related picker states and provides convenient computed properties (selectedYear, selectedMonth). The rememberYearMonthPickerState factory correctly uses remember with proper keys.


65-94: LGTM: Consistent time state design.

TimePickerState follows the same clean pattern as YearMonthPickerState, encapsulating hour, minute, and period states with convenient accessors.

sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/BottomSheetSampleScreen.kt (2)

41-42: LGTM: Clean state consolidation.

The migration from separate picker states to composite YearMonthPickerState and TimePickerState simplifies state management and aligns with the new API.

Also applies to: 64-72


81-86: LGTM: Consistent state access.

The code correctly reads from the new composite state properties (selectedYear, selectedMonth, selectedHour, selectedMinute, selectedPeriod) throughout the component.

Also applies to: 267-267, 332-335

sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/IntegratedPickerScreen.kt (2)

54-55: LGTM: Proper state initialization.

The composite states are correctly created with appropriate initial values.

Also applies to: 74-82


86-92: LGTM: Reactive state derivation.

The derived text values correctly depend on the composite state properties, ensuring proper recomposition when the selection changes.

Also applies to: 169-169, 183-183

sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/DatePickerSampleScreen.kt (1)

33-33: LGTM: Simplified date picker usage.

The migration to YearMonthPickerState reduces boilerplate and makes the code more maintainable.

Also applies to: 46-56, 110-110

datetimepicker/src/commonMain/kotlin/com/kez/picker/date/YearMonthPicker.kt (2)

24-25: LGTM: Clean API consolidation.

The refactoring to a single YearMonthPickerState parameter mirrors the TimePicker changes and provides a consistent, simplified API.

Also applies to: 61-61


105-123: LGTM: Correct internal state access.

The pickers correctly access state.yearState and state.monthState from the composite state holder.

Also applies to: 124-142

sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/BackgroundStylePickerScreen.kt (1)

34-35: LGTM: Consistent state management refactoring.

The migration to composite state holders is implemented correctly and consistently with the other sample screens.

Also applies to: 53-69, 125-125, 158-158

sample/src/commonMain/kotlin/com/kez/picker/sample/ui/screen/TimePickerSampleScreen.kt (4)

37-37: LGTM: Import updated for new API.

The import correctly reflects the migration to the consolidated state holder API.


57-65: LGTM: State initialization correctly handles 24-hour to 12-hour conversion.

The hour conversion logic accurately handles all cases (midnight as 12 AM, noon as 12 PM, and afternoon/evening hours by subtracting 12). The period is correctly assigned based on the 24-hour value.


81-101: LGTM: Time formatting logic is accurate.

The derivedStateOf correctly accesses the unified state properties and accurately converts between 12-hour and 24-hour formats for display purposes.


164-175: LGTM: TimePicker usage migrated correctly to unified state API.

Both TimePicker instances correctly use the new single state parameter instead of separate picker states, aligning with the refactored API.

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: 3

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e08ee11 and a33badf.

📒 Files selected for processing (3)
  • README.md (2 hunks)
  • README_KO.md (1 hunks)
  • datetimepicker/src/commonMain/kotlin/com/kez/picker/PickerState.kt (2 hunks)
🧰 Additional context used
🪛 markdownlint-cli2 (0.18.1)
README_KO.md

182-182: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🔇 Additional comments (6)
README_KO.md (2)

40-154: Documentation examples accurately reflect new state management APIs.

The usage examples correctly demonstrate rememberTimePickerState() and rememberYearMonthPickerState() with appropriate parameters and imports. All code samples follow proper Compose patterns.


156-179: API Reference tables are comprehensive and accurate.

The parameter documentation clearly specifies the new state parameter as the control mechanism, with appropriate defaults and descriptions aligned with the refactored state management architecture.

README.md (2)

3-154: Documentation updates accurately reflect the new state management API.

The installation, usage examples, and code samples have been correctly updated to demonstrate the new rememberTimePickerState() and rememberYearMonthPickerState() APIs. Examples are clear, follow Compose best practices, and are consistent with the refactored state architecture. The inclusion of the Korean README badge (Line 3) improves accessibility.


156-179: API Reference accurately documents new state management parameters.

The parameter tables properly highlight the state parameter as the primary control mechanism with sensible defaults and clear descriptions matching the state management refactor.

datetimepicker/src/commonMain/kotlin/com/kez/picker/PickerState.kt (2)

4-4: @stable annotation on PickerState is appropriate

Marking PickerState<T> as @Stable is correct here: the only mutable field is a mutableStateOf property, and the class itself has stable identity, which will help Compose avoid unnecessary recompositions when the holder itself is passed around.

Also applies to: 29-37


9-13: Year/month composite state holder looks solid

rememberYearMonthPickerState and YearMonthPickerState are well-structured: defaults based on currentDate, proper use of Month.number, and remember(initialYear, initialMonth) so callers can opt into re-creating state when initial values change. The derived selectedYear / selectedMonth accessors make consuming code cleaner without hiding the underlying PickerStates.

Also applies to: 39-77


## 라이선스

```
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

Add language specifier to fenced code block.

The license text code block at Line 182 is missing a language specifier. Markdown linters expect fenced code blocks to declare a language.

Apply this diff to fix the code block:

-```
+```text
 Copyright 2024 KEZ Lab
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

182-182: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In README_KO.md around line 182, the fenced code block containing the license
text has no language specifier; update the opening fence from ``` to ```text so
the block becomes a text-coded fenced block (leave the license content and
closing ``` intact).

## 📄 License
## License

```
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

Add language specifier to fenced code block.

The license text code block at Line 182 is missing a language specifier. Apply the same fix as README_KO.md to maintain consistency across documentation.

Apply this diff to fix the code block:

-```
+```text
 Copyright 2024 KEZ Lab
🧰 Tools
🪛 markdownlint-cli2 (0.18.1)

182-182: Fenced code blocks should have a language specified

(MD040, fenced-code-language)

🤖 Prompt for AI Agents
In README.md around line 182 the fenced code block containing the license text
lacks a language specifier; update that fence to include the language token
"text" (i.e., change the opening ``` to ```text) so the block matches
README_KO.md and maintains documentation consistency.

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: 1

🧹 Nitpick comments (3)
datetimepicker/src/commonMain/kotlin/com/kez/picker/PickerState.kt (3)

23-23: rememberPickerState(initialItem) should key on initialItem for consistency with the other remember helpers.
Right now, changing initialItem won’t recreate the state, while rememberYearMonthPickerState / rememberTimePickerState do reset on parameter change.

-@Composable
-fun <T> rememberPickerState(initialItem: T) = remember { PickerState(initialItem) }
+@Composable
+fun <T> rememberPickerState(initialItem: T) = remember(initialItem) { PickerState(initialItem) }

65-78: Validate initialMonth (and optionally initialYear) to prevent invalid state.
Without guards, callers can create a YearMonthPickerState with initialMonth outside 1..12, which may break downstream assumptions.

 @Stable
 class YearMonthPickerState(
     initialYear: Int,
     initialMonth: Int
 ) {
+    init {
+        require(initialMonth in 1..12) { "initialMonth must be in 1..12 (was $initialMonth)" }
+    }
     val yearState = PickerState(initialYear)
     val monthState = PickerState(initialMonth)

125-144: Validate initialHour / initialMinute (and consider enforcing hour-range by timeFormat).
This prevents constructing states like minute=99 or hour=23 while timeFormat=HOUR_12, which can leak invalid selections via selectedHour/selectedMinute.

 @Stable
 class TimePickerState(
     initialHour: Int,
     initialMinute: Int,
     initialPeriod: TimePeriod,
     val timeFormat: TimeFormat
 ) {
+    init {
+        require(initialMinute in 0..59) { "initialMinute must be in 0..59 (was $initialMinute)" }
+        when (timeFormat) {
+            TimeFormat.HOUR_24 -> require(initialHour in 0..23) { "initialHour must be in 0..23 (was $initialHour)" }
+            TimeFormat.HOUR_12 -> require(initialHour in 1..12) { "initialHour must be in 1..12 (was $initialHour)" }
+        }
+    }
     val hourState = PickerState(initialHour)
     val minuteState = PickerState(initialMinute)
     val periodState = PickerState(initialPeriod)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f4d6170 and 1b1293d.

📒 Files selected for processing (1)
  • datetimepicker/src/commonMain/kotlin/com/kez/picker/PickerState.kt (2 hunks)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (3)
  • GitHub Check: Linux • wasm
  • GitHub Check: Linux • android
  • GitHub Check: macOS • iOS Simulator Test

@kez-lab kez-lab merged commit 58a078c into main Dec 12, 2025
4 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Jan 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants