Skip to content

[android] Added custom color picker for tracks#12723

Merged
vng merged 2 commits into
organicmaps:masterfrom
strider-dunadan:strider/color_picker
May 21, 2026
Merged

[android] Added custom color picker for tracks#12723
vng merged 2 commits into
organicmaps:masterfrom
strider-dunadan:strider/color_picker

Conversation

@strider-dunadan
Copy link
Copy Markdown
Contributor

@strider-dunadan strider-dunadan commented May 7, 2026

Summary

Replaces the old predefined-color dropdown for tracks with a full custom color picker.

  • Three color picker modes: Grid (palette), Spectrum (HSV wheel), Sliders (RGB + hex input)
  • Preset colors: save up to 20 custom presets, long-press to delete
  • Custom ARGB via JNI: Android uses dp::Color::FromARGB directly instead of predefined color indices. Note: iOS still uses the predefined-color path via bookmark_manager.hpp; the indexed-color SetCategoryTracksColor overload is kept for iOS, while Android calls the new SetCategoryTracksColor(groupId, dp::Color) overload
  • Full landscape support, dark/light themes, localized to 40+ languages
image image image image image image image

@strider-dunadan strider-dunadan force-pushed the strider/color_picker branch 5 times, most recently from ba49f42 to 33706b7 Compare May 7, 2026 13:47
Copy link
Copy Markdown
Member

@biodranik biodranik left a comment

Choose a reason for hiding this comment

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

This is an experimental LLM code review.

Confirmed issues with the new track color picker:

  • onDismiss fires on configuration change, prematurely committing in-progress colors to native (mCategory.setCategoryTracksCustomColor, track.setColor) and delivering callbacks to a dying parent fragment. Needs an isChangingConfigurations guard, plus an explicit cancel path on btn_close.
  • BookmarkCategorySettingsFragment.showTrackColorPicker() doesn't pass EXTRA_INITIAL_COLOR, so this entry point always opens at red (the other three call sites pass the current color).
  • IME insets are not handled — tapping the hex EditText on a small device hides it behind the keyboard.
  • hexInput.setText re-set in updateUI jumps the caret to the end on every keystroke once the user reaches a valid 6-char string.
  • English source string uses British "Colour" while every other new string and the rest of values/strings.xml use American "Color"; this leaks into auto-generated translations.
  • AppCompatResources.getDrawable(R.drawable.ic_plus) is unwrapped without null check — passing a Drawable? into a LayerDrawable(arrayOf<Drawable>(...)) will NPE if the resource fails to resolve.
  • Cross-view echo causes redundant work — only SpectrumColorView guards against re-applying its own emission with isTracking; ColorGridView and ColorSlidersView re-run their full update path (including hex setText and shader rebuilds) on every spectrum drag sample.
  • rebuildPresetViews recreates all preset views on every selectedPresetIndex change, allocating drawables and re-running FlowLayout measure/layout twice per drag through a preset color.
  • ColorGridView.setColor calls invalidate() even when selection is already -1,-1, redrawing the 9*12 grid on every echoed non-matching emission.
  • TrackColorPickerViewModel.loadPresets() does SharedPreferences I/O on the main thread in init { ... }; preset format also encodes a redundant alpha byte that is always FF.
  • EXTRA_INITIAL_COLOR = "ExtraInitialColor" is reused as both an arguments-Bundle key and a SavedStateHandle slot — namespace it (e.g. app.organicmaps.color_picker.initial_color).
  • JNI rename: the indexed nativeSetCategoryTracksColor was deleted on Android in favor of nativeSetCategoryTracksCustomColor, while iOS still uses the predefined-color path. Worth a sentence in the commit body so the asymmetry is captured.

Minor / not posted inline:

  • The rebuildPresetViews long-press popup uses Color.RED for the "Delete" label without a theme attribute — fine in light theme, slightly off-brand in dark theme.
  • The fragment's bottom-sheet OnLayoutChangeListener is added once and never explicitly removed; it relies on the dialog window being torn down to free it. Works today but is easy to regress if the sheet view is ever reused.
  • ColorPickerState.colorChanged is persisted across process death, so even a recreated picker with no user interaction will still callback on dismiss if the previous instance had touched a control. The isChangingConfigurations fix above also helps here, but consider whether colorChanged should be reset on restore.

Tests: there are no unit tests for the view-model state transitions (selectColor, selectPreset, addCurrentColorToPresets, removePreset index-shift logic) — these are pure data and would be cheap to cover.


Generated by Claude Code

Comment thread android/app/src/main/res/values/strings.xml Outdated
@strider-dunadan strider-dunadan force-pushed the strider/color_picker branch 3 times, most recently from dd24a37 to dcbabe7 Compare May 8, 2026 13:53
@strider-dunadan strider-dunadan marked this pull request as ready for review May 8, 2026 13:58
@strider-dunadan strider-dunadan requested review from a team as code owners May 8, 2026 13:58
Copy link
Copy Markdown
Member

@biodranik biodranik left a comment

Choose a reason for hiding this comment

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

This is an experimental LLM code review.

Re-review across Android/Kotlin, Graphics, and C++/JNI/architecture lenses; nothing on iOS as this PR doesn't touch it (intentional asymmetry: Android now sets tracks via dp::Color::FromARGB through nativeSetCategoryTracksCustomColor, iOS still goes through kml::PredefinedColor via the kept overload in bookmark_manager.hpp). The split is sound and the JNI/ARGB byte order matches Android's @ColorInt (drape/color.hpp:57 extracts byte 2/1/0/3 = R/G/B/A, which is exactly the layout of Color.argb). No layer-violation or dependency concerns at the C++ side.

Inline comments above cover the issues I'd want addressed before merge. The only one that's a real correctness bug is the SharedPreferences write race; the others are polish (cursor-vs-displayed-pixel mismatch on Spectrum/Grid for off-rail colors, no-op listener firing from BookmarkCategorySettingsFragment after a re-tap on the selected preset, selector ring drawn outside the rounded clip, SOFT_INPUT_ADJUST_PAN panning the toolbar off-screen, hasFocus() as a too-coarse repaint guard, and a redundant linear scan inside the distinctUntilChanged predicate).

PR description-wise: 70+ files / ~3.1k lines added with no Fixes #NNN link, no test plan, and no note on the iOS/Android asymmetry the JNI rename introduces — please add at least the issue link and a one-paragraph description per docs/PR_GUIDE.md. The earlier reviewer asked for the JNI-rename note in the commit body too; both still pending.


Generated by Claude Code

@biodranik
Copy link
Copy Markdown
Member

LGTM from LLM


Generated by Claude Code

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Added color selectors

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Sliders refactoring

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Added landscape

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Added saving state for color

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Restore color after got reset

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Refactoring reset state

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Colors refactoring

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Refactoring

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Refactoring spectrum invalidate

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Fixed sliders landscape

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Fixed scroll

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Refactoring

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Refactoring colors picker

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Fixed insets

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Added color update for track category

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Refactoring

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Refactoring

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Refactoring ColorGridView

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Fixed onDraw allocation

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Fixed spectrum tracking

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Updated dimens

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Refactoring

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Small fixes

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Fixed dismiss

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Selected first default preset color

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Fixed cursor

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Fixed early return

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Added io thread

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Added tracking guard

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Updated sttrings.txt to Color

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Fixed preset update

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Fixed opening keyboard for small screens

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Refactoring distinctUntilChanged

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Refactoring preset saving

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[android] Sliders hex fix

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>
Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>

[strings] Updated sttrings.xml to Color

Signed-off-by: strider-dunadan <emerald.dunadan@gmail.com>
@vng vng merged commit 25a4c54 into organicmaps:master May 21, 2026
17 of 18 checks passed
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.

3 participants