Skip to content

Commit 2f1681b

Browse files
committed
fix(Whiteboard): broken color picker in RTL layout
Fixes: #19237 replace existing color picker from another library
1 parent f573936 commit 2f1681b

File tree

7 files changed

+82
-52
lines changed

7 files changed

+82
-52
lines changed

AnkiDroid/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -421,7 +421,7 @@ dependencies {
421421
implementation libs.jsoup
422422
implementation libs.java.semver // For AnkiDroid JS API Versioning
423423
implementation libs.drakeet.drawer
424-
implementation libs.colorpicker
424+
implementation libs.skydoves.colorpickerview
425425
implementation libs.kotlin.reflect
426426
implementation libs.kotlin.test
427427
implementation libs.search.preference

AnkiDroid/src/main/java/com/ichi2/anki/Whiteboard.kt

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ import com.ichi2.anki.common.time.Time
4545
import com.ichi2.anki.common.time.getTimestamp
4646
import com.ichi2.anki.dialogs.WhiteBoardWidthDialog
4747
import com.ichi2.anki.preferences.sharedPrefs
48+
import com.ichi2.anki.ui.windows.reviewer.whiteboard.showColorPickerDialog
4849
import com.ichi2.compat.CompatHelper
4950
import com.ichi2.themes.Themes.currentTheme
5051
import com.ichi2.utils.DisplayUtils.getDisplayDimensions
51-
import com.mrudultora.colorpicker.ColorPickerPopUp
5252
import timber.log.Timber
5353
import java.io.FileNotFoundException
5454
import kotlin.math.abs
@@ -395,22 +395,7 @@ class Whiteboard(
395395
penColor = yellowPenColor
396396
}
397397
R.id.pen_color_custom -> {
398-
ColorPickerPopUp(context).run {
399-
setShowAlpha(true)
400-
setDefaultColor(penColor)
401-
setOnPickColorListener(
402-
object : ColorPickerPopUp.OnPickColorListener {
403-
override fun onColorPicked(color: Int) {
404-
penColor = color
405-
}
406-
407-
override fun onCancel() {
408-
// unused
409-
}
410-
},
411-
)
412-
show()
413-
}
398+
context.showColorPickerDialog(penColor) { penColor = it }
414399
}
415400
R.id.stroke_width -> {
416401
handleWidthChangeDialog()
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright (c) 2025 Divyansh Kushwaha <[email protected]>
3+
*
4+
* This program is free software; you can redistribute it and/or modify it under
5+
* the terms of the GNU General Public License as published by the Free Software
6+
* Foundation; either version 3 of the License, or (at your option) any later
7+
* version.
8+
*
9+
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
10+
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
11+
* PARTICULAR PURPOSE. See the GNU General Public License for more details.
12+
*
13+
* You should have received a copy of the GNU General Public License along with
14+
* this program. If not, see <http://www.gnu.org/licenses/>.
15+
*/
16+
17+
package com.ichi2.anki.ui.windows.reviewer.whiteboard
18+
19+
import android.content.Context
20+
import com.ichi2.anki.R
21+
import com.ichi2.utils.show
22+
import com.skydoves.colorpickerview.ColorEnvelope
23+
import com.skydoves.colorpickerview.ColorPickerDialog
24+
import com.skydoves.colorpickerview.listeners.ColorEnvelopeListener
25+
26+
/**
27+
* Shows a customizable color picker dialog with optional alpha and brightness controls.
28+
*
29+
* @receiver The Android context used to create the dialog.
30+
* @param initialColor The initial color to display in the picker as an `AARRGGBB` integer.
31+
* @param onColorSelected Callback invoked when the user confirms their color selection.
32+
* Receives the selected color as an `AARRGGBB` integer.
33+
*
34+
*/
35+
fun Context.showColorPickerDialog(
36+
initialColor: Int,
37+
onColorSelected: (Int) -> Unit,
38+
) {
39+
ColorPickerDialog
40+
.Builder(this)
41+
.show {
42+
// Use post() so setInitialColor() runs after the view is laid out.
43+
// This ensures the BrightnessSlideBar is fully initialized before applying
44+
// the initial color. Calling it too early causes the slider to use its
45+
// default position, resulting in an incorrect displayed color.
46+
colorPickerView.post { colorPickerView.setInitialColor(initialColor) }
47+
setPositiveButton(
48+
R.string.dialog_ok,
49+
object : ColorEnvelopeListener {
50+
override fun onColorSelected(
51+
envelope: ColorEnvelope?,
52+
fromUser: Boolean,
53+
) {
54+
envelope?.color?.let(onColorSelected)
55+
}
56+
},
57+
)
58+
setTitle(R.string.choose_color)
59+
setNegativeButton(R.string.dialog_cancel, null)
60+
setBottomSpace(12) // 12Dp
61+
}
62+
}

AnkiDroid/src/main/java/com/ichi2/anki/ui/windows/reviewer/whiteboard/WhiteboardFragment.kt

Lines changed: 10 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@ import com.ichi2.themes.Themes
4646
import com.ichi2.utils.dp
4747
import com.ichi2.utils.increaseHorizontalPaddingOfMenuIcons
4848
import com.ichi2.utils.toRGBAHex
49-
import com.mrudultora.colorpicker.ColorPickerPopUp
5049
import dev.androidbroadcast.vbpd.viewBinding
5150
import kotlinx.coroutines.flow.combine
5251
import kotlinx.coroutines.flow.launchIn
@@ -273,21 +272,11 @@ class WhiteboardFragment :
273272
* Shows a popup for adding a new brush color.
274273
*/
275274
private fun showAddColorDialog() {
276-
ColorPickerPopUp(context).run {
277-
setShowAlpha(true)
278-
setDefaultColor(viewModel.brushColor.value)
279-
setOnPickColorListener(
280-
object : ColorPickerPopUp.OnPickColorListener {
281-
override fun onColorPicked(color: Int) {
282-
Timber.i("Added brush with color ${color.toRGBAHex()}")
283-
viewModel.addBrush(color)
284-
}
285-
286-
override fun onCancel() {}
287-
},
288-
)
289-
show()
290-
}
275+
requireContext()
276+
.showColorPickerDialog(viewModel.brushColor.value) { color ->
277+
Timber.i("Added brush with color ${color.toRGBAHex()}")
278+
viewModel.addBrush(color)
279+
}
291280
}
292281

293282
/**
@@ -367,19 +356,11 @@ class WhiteboardFragment :
367356
* Shows a color picker popup to change the active brush's color.
368357
*/
369358
private fun showChangeColorDialog() {
370-
ColorPickerPopUp(requireContext())
371-
.setShowAlpha(true)
372-
.setDefaultColor(viewModel.brushColor.value)
373-
.setOnPickColorListener(
374-
object : ColorPickerPopUp.OnPickColorListener {
375-
override fun onColorPicked(color: Int) {
376-
viewModel.updateBrushColor(color)
377-
strokeWidthPopup?.dismiss()
378-
}
379-
380-
override fun onCancel() {}
381-
},
382-
).show()
359+
requireContext()
360+
.showColorPickerDialog(viewModel.brushColor.value) { color ->
361+
viewModel.updateBrushColor(color)
362+
strokeWidthPopup?.dismiss()
363+
}
383364
}
384365

385366
/**

AnkiDroid/src/main/java/com/ichi2/utils/AlertDialogFacade.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -144,9 +144,9 @@ fun AlertDialog.Builder.cancelable(cancelable: Boolean): AlertDialog.Builder = t
144144
* Executes the provided block, then creates an [AlertDialog] with the arguments supplied
145145
* and immediately displays the dialog
146146
*/
147-
inline fun AlertDialog.Builder.show(
147+
inline fun <T : AlertDialog.Builder> T.show(
148148
enableEnterKeyHandler: Boolean = false, // Make it opt-in
149-
block: AlertDialog.Builder.() -> Unit,
149+
block: T.() -> Unit,
150150
): AlertDialog {
151151
this.apply { block() }
152152
val dialog = this.show()
@@ -187,7 +187,7 @@ fun AlertDialog.Builder.createAndApply(block: AlertDialog.() -> Unit): AlertDial
187187
/**
188188
* Executes [block] on the [AlertDialog.Builder] instance and returns the initialized [AlertDialog].
189189
*/
190-
fun AlertDialog.Builder.create(block: AlertDialog.Builder.() -> Unit): AlertDialog {
190+
fun <T : AlertDialog.Builder> T.create(block: T.() -> Unit): AlertDialog {
191191
block()
192192
return create()
193193
}

AnkiDroid/src/main/res/values/03-dialogs.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,4 +268,6 @@ also changes the interval of the card"
268268
<string name="tts_error_dialog_reason_text">The text to speech engine <b>%1$s</b> does not support the following language: <b>%2$s</b></string>
269269
<string name="tts_error_dialog_change_button_text">Change engine</string>
270270
<string name="tts_error_dialog_supported_voices_button_text">Voice options</string>
271+
272+
<string name="choose_color">Choose color</string>
271273
</resources>

gradle/libs.versions.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ androidxWork = "2.11.0"
6262
ankiBackend = '0.1.62-anki25.09.2'
6363
autoService = "1.1.1"
6464
autoServiceAnnotations = "1.1.1"
65-
colorpicker = "1.2.0"
65+
colorPickerView = "2.3.0"
6666
# https://commons.apache.org/proper/commons-collections/changes.html
6767
commonsCollections4 = "4.5.0"
6868
# https://commons.apache.org/proper/commons-compress/changes-report.html
@@ -143,7 +143,7 @@ androidx-recyclerview = { module = "androidx.recyclerview:recyclerview", version
143143
auto-service = { module = "com.google.auto.service:auto-service", version.ref = "autoService" }
144144
auto-service-annotations = { module = "com.google.auto.service:auto-service-annotations", version.ref = "autoServiceAnnotations" }
145145
jetbrains-annotations = { module = "org.jetbrains:annotations", version.ref = "jetbrainsAnnotations" }
146-
colorpicker = { module = "com.github.mrudultora:Colorpicker", version.ref = "colorpicker" }
146+
skydoves-colorpickerview = { module = "com.github.skydoves:colorpickerview", version.ref = "colorPickerView" }
147147
commons-io = { module = "commons-io:commons-io", version.ref = "commonsIo" }
148148
commons-collections4 = { module = "org.apache.commons:commons-collections4", version.ref = "commonsCollections4" }
149149
commons-compress = { module = "org.apache.commons:commons-compress", version.ref = "commonsCompress" }

0 commit comments

Comments
 (0)