Repository navigation
Stability improvements requiring source/binary breaks (queued for next major) #67
Description
Collecting follow-ups found during the audit in #66 that were intentionally deferred because they change the public API of the library. These should ship together in the next major version (e.g. 5.0) so consumers only migrate once.
1. JetLimeEventStyle.position / pointPlacement should be val
Current: both are public var properties on an @Immutable class and are mutated via setPosition / setPointPlacement / JetLimeEventDefaults.eventStyle(...).apply { ... }.
Problem: @Immutable annotation is dishonest; Compose compiler trusts it, but the mutable backing fields are observable through public setters. Any consumer that hoists a style and calls .position = X directly is relying on that mutability.
Proposed fix:
- Move
positionandpointPlacementinto the primary constructor asval. - Keep
setPosition/setPointPlacementbut have them return a new instance (they already document "returns a JetLimeEventStyle instance with the updated value"). - Update
JetLimeEventDefaults.eventStyle(...)to pass values through the constructor instead of.apply { this.position = ... }.
Break: source and binary break for any caller that writes style.position = X directly.
2. ItemsList backed by ImmutableList<T>
Current: class ItemsList<T>(val items: List<T>) — the Compose compiler treats List<T> as unstable; @Immutable on the class papers over it.
Proposed fix:
- Change
itemsproperty type tokotlinx.collections.immutable.ImmutableList<T>. - Add a secondary convenience constructor
ItemsList(list: List<T>)that wraps viatoImmutableList(), and / or a varargs factory.
Break: source break for anyone reading itemsList.items as a List<T> in a non-covariant context; binary break via getter signature change.
3. EventPointType.equals over Painter
Current: equals / hashCode include icon: Painter?. Painter does not override equals by content — it falls back to referential identity. Two different painter instances with identical content are considered "not equal", defeating stability if the caller doesn't hoist / remember the painter.
Proposed fix (pick one):
- Drop
iconfromequals/hashCodeand document that callers mustrememberthe painter upstream. - Or use a small content key (e.g. a user-supplied
id) for equality.
Break: behavior change that could alter recomposition-skipping semantics for existing users.
4. Convert EventPosition to enum class
Current: class EventPosition internal constructor(val name: String) with three singletons in the companion (START private, MIDDLE private, END internal) and a dynamic(index, listSize) factory.
Proposed fix:
enum class EventPosition {
START, MIDDLE, END;
fun isNotEnd() = this != END
fun isNotStart() = this != START
companion object {
fun dynamic(index: Int, listSize: Int): EventPosition = when (index) {
listSize - 1 -> END
0 -> START
else -> MIDDLE
}
}
}Benefits: real compiler-level stability, removes the fragile string-literal comparisons, simpler equals / hashCode.
Break: widens visibility of START / MIDDLE / END (now public). Class → enum also changes compiled bytecode flags; reflective users may break.
5. Per-item eventStyle(...) should be remembered
Current: the sample and README call JetLimeEventDefaults.eventStyle(position = position) fresh inside every lazy item on every recomposition, allocating a new JetLimeEventStyle. With the stability fixes above, value equality would still let the item skip — but the allocation is wasted.
Proposed fix:
- Update the sample and README snippets to
remember(position) { eventStyle(position) }where appropriate. - Consider adding an overload or helper in
JetLimeEventDefaultsthat memoizes by position.
Break: documentation / sample only; no library break.
Tracking
- Setup CI/CD #1
JetLimeEventStylefields →val - Intrinsics in custom layouts #2
ItemsList→ImmutableList<T> - Add support for Horizontal view #3
EventPointTypeequality semantics - Update to Compose 1.1 #4
EventPosition→enum class - Update to compose 1.1.0 #5 Sample / docs:
remember(position) { eventStyle(...) }
Target: next major version.
🤖 Generated with Claude Code
Activity