Skip to content

Commit 78648d2

Browse files
author
farewelltospring
committed
Fix the fix to the fix to the recentering algorithm
I had a big brain realisation to use the power of RxJava to make things work in a clean way that is probably more technically correct than manually invoking measure and layout.
1 parent f0d0750 commit 78648d2

2 files changed

Lines changed: 57 additions & 18 deletions

File tree

app/src/main/java/org/thoughtcrime/securesms/conversation/AttachmentButtonCenterHelper.kt

Lines changed: 52 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
package org.thoughtcrime.securesms.conversation
22

33
import android.view.View
4+
import android.view.View.OnLayoutChangeListener
5+
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
6+
import io.reactivex.rxjava3.core.Observable
7+
import io.reactivex.rxjava3.disposables.Disposable
8+
import io.reactivex.rxjava3.subjects.PublishSubject
49
import org.signal.core.util.DimensionUnit
510
import org.signal.core.util.logging.Log
611

@@ -11,17 +16,55 @@ import org.signal.core.util.logging.Log
1116
* then put a basic amount of padding on each side so that it looks nice when scrolling
1217
* to either end.
1318
*/
14-
object AttachmentButtonCenterHelper {
19+
class AttachmentButtonCenterHelper(val buttonHolder: View, val wrapper: View) {
1520

16-
private val TAG = Log.tag(AttachmentButtonCenterHelper::class)
17-
private val DEFAULT_PADDING = DimensionUnit.DP.toPixels(16f).toInt()
21+
companion object {
22+
val TAG = Log.tag(AttachmentButtonCenterHelper::class)
23+
private val DEFAULT_PADDING = DimensionUnit.DP.toPixels(16f).toInt()
24+
}
25+
26+
/** The wrapper width is the maximum size of the button holder before scrollbars appear. */
27+
private val wrapperWidthObservable: PublishSubject<Int> = PublishSubject.create()
28+
private val emitNewWrapperWidth = OnLayoutChangeListener { _, left, _, right, _, oldLeft, _, oldRight, _ ->
29+
if (oldRight - oldLeft == right - left)
30+
return@OnLayoutChangeListener
31+
wrapperWidthObservable.onNext(right - left)
32+
}
33+
34+
/** The "core width" of the button holder is the size of its contents. */
35+
private val coreWidthObservable: PublishSubject<Int> = PublishSubject.create()
36+
private val emitNewCoreWidth = OnLayoutChangeListener { view, left, _, right, _, oldLeft, _, oldRight, _ ->
37+
val newCoreWidth = view.run { width - (paddingLeft + paddingRight) }
38+
coreWidthObservable.onNext(newCoreWidth)
39+
}
40+
41+
private var listener: Disposable? = null
42+
43+
fun attach() {
44+
wrapper.addOnLayoutChangeListener(emitNewWrapperWidth)
45+
buttonHolder.addOnLayoutChangeListener(emitNewCoreWidth)
46+
47+
listener?.dispose()
48+
listener = Observable.combineLatest(wrapperWidthObservable, coreWidthObservable, ::Pair)
49+
.distinctUntilChanged()
50+
.observeOn(AndroidSchedulers.mainThread())
51+
.subscribe { widths ->
52+
val wrapperWidth = widths.first
53+
val coreWidth = widths.second
54+
Log.d(TAG, "wrapperWidth: $wrapperWidth, coreWidth: $coreWidth")
55+
recenter(coreWidth, wrapperWidth)
56+
}
57+
}
58+
59+
fun detach() {
60+
wrapper.removeOnLayoutChangeListener(emitNewWrapperWidth)
61+
buttonHolder.removeOnLayoutChangeListener(emitNewCoreWidth)
62+
listener?.dispose()
63+
listener = null
64+
}
1865

19-
@Synchronized
20-
fun recenter(buttonHolder: View, wrapper: View) {
21-
buttonHolder.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)
22-
buttonHolder.layout(0, 0, buttonHolder.measuredWidth, buttonHolder.measuredHeight)
23-
val buttonHolderCoreWidth = buttonHolder.run { width - (paddingLeft + paddingRight) }
24-
val extraSpace = wrapper.width - buttonHolderCoreWidth
66+
fun recenter(buttonHolderCoreWidth: Int, wrapperWidth: Int) {
67+
val extraSpace = wrapperWidth - buttonHolderCoreWidth
2568
val horizontalPadding = if (extraSpace >= 0)
2669
(extraSpace / 2f).toInt()
2770
else

app/src/main/java/org/thoughtcrime/securesms/conversation/AttachmentKeyboardButtonList.kt

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,29 +28,26 @@ class AttachmentKeyboardButtonList @JvmOverloads constructor(
2828

2929
private val inflater = LayoutInflater.from(context)
3030
private val inner: LinearLayout
31-
private val recenterOnWidthChange: OnLayoutChangeListener
31+
32+
private val recenterHelper: AttachmentButtonCenterHelper
3233
var onButtonClicked: Consumer<AttachmentKeyboardButton> = Consumer { _ -> }
3334

3435
private var currentButtons: List<AttachmentKeyboardButton> = listOf()
3536

3637
init {
3738
inflate(context, R.layout.attachment_keyboard_button_list, this)
3839
inner = findViewById(R.id.attachment_keyboard_button_list_inner_linearlayout)
39-
recenterOnWidthChange = OnLayoutChangeListener { _, left, _, right, _, oldLeft, _, oldRight, _ ->
40-
if (oldRight - oldLeft == right - left)
41-
return@OnLayoutChangeListener
42-
AttachmentButtonCenterHelper.recenter(inner, this)
43-
}
40+
recenterHelper = AttachmentButtonCenterHelper(inner, this)
4441
}
4542

4643
override fun onAttachedToWindow() {
4744
super.onAttachedToWindow()
48-
addOnLayoutChangeListener(recenterOnWidthChange)
45+
recenterHelper.attach()
4946
}
5047

5148
override fun onDetachedFromWindow() {
5249
super.onDetachedFromWindow()
53-
removeOnLayoutChangeListener(recenterOnWidthChange)
50+
recenterHelper.detach()
5451
}
5552

5653
fun setButtons(newButtons: List<AttachmentKeyboardButton>) {
@@ -60,7 +57,6 @@ class AttachmentKeyboardButtonList @JvmOverloads constructor(
6057
currentButtons = newButtons
6158
inner.removeAllViews()
6259
newButtons.forEach { inner += inflateButton(it) }
63-
inner.post { AttachmentButtonCenterHelper.recenter(inner, this) }
6460
}
6561

6662
private fun inflateButton(button: AttachmentKeyboardButton): ButtonStripItemView {

0 commit comments

Comments
 (0)