@@ -7,17 +7,19 @@ import android.graphics.drawable.Drawable
77import android.text.Editable
88import android.text.Layout
99import android.text.Spanned
10- import android.transition.TransitionManager
1110import android.util.Log
1211import android.view.MotionEvent
1312import android.view.View
1413import android.view.ViewTreeObserver
1514import android.widget.FrameLayout
1615import androidx.core.content.ContextCompat
16+ import androidx.core.view.updateLayoutParams
1717import kotlinx.coroutines.CoroutineScope
1818import kotlinx.coroutines.Dispatchers
1919import kotlinx.coroutines.Job
2020import kotlinx.coroutines.delay
21+ import kotlinx.coroutines.flow.MutableStateFlow
22+ import kotlinx.coroutines.flow.StateFlow
2123import kotlinx.coroutines.launch
2224import kotlinx.coroutines.runBlocking
2325import kotlinx.coroutines.sync.Mutex
@@ -126,9 +128,7 @@ class PlaceholderManager(
126128 val targetSpan = targetItem?.span
127129 val currentType = targetSpan?.attributes?.getValue(TYPE_ATTRIBUTE )
128130 if (currentType != null ) {
129- Log .d(" vojta" , " Item found: $currentType " )
130131 if (shouldMergeItem(currentType)) {
131- Log .d(" vojta" , " Updating item: $currentType " )
132132 updateSpan(type, targetItem.span, targetItem.placeAtStart, updateItem, currentType)
133133 } else {
134134 val (newLinePosition, targetSelection) = if (targetItem.placeAtStart) {
@@ -141,7 +141,6 @@ class PlaceholderManager(
141141 insertItem(type, * updateItem(null , null , false ).toList().toTypedArray())
142142 }
143143 } else {
144- Log .d(" vojta" , " Inserting item: $type " )
145144 insertItem(type, * updateItem(null , null , false ).toList().toTypedArray())
146145 }
147146 }
@@ -274,12 +273,10 @@ class PlaceholderManager(
274273 suspend fun reloadAllPlaceholders () {
275274 val tempPositionToId = positionToId.toList()
276275 tempPositionToId.forEach { placeholder ->
277- Log .d(" vojta" , " Looking up position to ID" )
278276 val isValid = positionToIdMutex.withLock {
279277 positionToId.contains(placeholder)
280278 }
281279 if (isValid) {
282- Log .d(" vojta" , " Reloading all placeholders" )
283280 insertContentOverSpanWithId(placeholder.uuid)
284281 }
285282 }
@@ -304,7 +301,6 @@ class PlaceholderManager(
304301 }
305302 }
306303 val targetPosition = aztecText.getElementPosition(predicate) ? : return
307- Log .d(" vojta" , " Inserting in position" )
308304 insertInPosition(aztecAttributes ? : return , targetPosition)
309305 }
310306
@@ -336,7 +332,6 @@ class PlaceholderManager(
336332 parentTextViewRect.top + = parentTextViewTopAndBottomOffset
337333 parentTextViewRect.bottom = parentTextViewRect.top + height
338334
339- Log .d(" vojta" , " Looking for a view with tag $uuid " )
340335 var box = container.findViewWithTag<View >(uuid)?.apply {
341336 id = uuid.hashCode()
342337 }
@@ -345,53 +340,59 @@ class PlaceholderManager(
345340 val padding = 10
346341 val newLeftPadding = parentTextViewRect.left + padding + aztecText.paddingStart
347342 val newTopPadding = parentTextViewRect.top + padding
348- Log .d( " vojta " , " Redrawing: top padding $newTopPadding , left padding $newLeftPadding , width $newWidth , height $newHeight " )
343+ var recreateView = box == null
349344 box?.let { existingView ->
350345 val currentParams = existingView.layoutParams as FrameLayout .LayoutParams
351346 val widthSame = currentParams.width == newWidth
352347 val heightSame = currentParams.height == newHeight
353348 val topMarginSame = currentParams.topMargin == newTopPadding
354349 val leftMarginSame = currentParams.leftMargin == newLeftPadding
355- Log .d(" vojta" , " Same: $widthSame , $heightSame , $topMarginSame , $leftMarginSame " )
356350 if (widthSame && heightSame && topMarginSame && leftMarginSame) {
357- Log .d(" vojta" , " Not redrawing" )
358351 return
359352 }
360- Log .d(" vojta" , " Redrawing" )
361- if (! widthSame || ! heightSame) {
362- TransitionManager .beginDelayedTransition(container)
363- }
364-
365- container.removeView(box)
366- positionToIdMutex.withLock {
367- positionToId.removeAll {
368- it.uuid == uuid
353+ val propertiesChanged = ! widthSame || ! heightSame
354+ recreateView = ! propertiesChanged || ! adapter.animateLayoutChanges()
355+ if (recreateView) {
356+ container.removeView(box)
357+ positionToIdMutex.withLock {
358+ positionToId.removeAll {
359+ it.uuid == uuid
360+ }
369361 }
370362 }
371363 }
364+ val paramsFlow = positionToId.find {
365+ it.uuid == uuid
366+ }?.viewParams ? : MutableStateFlow (Placeholder .ViewParams (newWidth, newHeight, attrs, initial = true ))
367+ if (box == null || recreateView) {
368+ Log .d(" vojta" , " Creating new view" )
369+ box = adapter.createView(container.context, uuid, paramsFlow)
370+ box.id = uuid.hashCode()
371+ box.setBackgroundColor(Color .TRANSPARENT )
372+ box.setOnTouchListener(adapter)
373+ box.tag = uuid
374+ box.layoutParams = FrameLayout .LayoutParams (
375+ newWidth,
376+ newHeight
377+ )
378+ } else {
379+ Log .d(" vojta" , " Updating params" )
380+ paramsFlow.emit(Placeholder .ViewParams (newWidth, newHeight, attrs, initial = false ))
381+ }
382+ Log .d(" vojta" , " Creating view with $newWidth x $newHeight " )
372383
373- box = adapter.createView(container.context, uuid, attrs)
374- box.id = uuid.hashCode()
375- Log .d(" vojta" , " Creating a new view with id: ${box.id} " )
376- box.setBackgroundColor(Color .TRANSPARENT )
377- box.setOnTouchListener(adapter)
378- box.tag = uuid
379- val params = FrameLayout .LayoutParams (
380- newWidth,
381- newHeight
382- )
383- params.setMargins(
384- newLeftPadding,
385- newTopPadding,
386- 0 ,
387- 0
388- )
389- box.layoutParams = params
384+ box.updateLayoutParams<FrameLayout .LayoutParams > {
385+ leftMargin = newLeftPadding
386+ topMargin = newTopPadding
387+ }
390388
391389 positionToIdMutex.withLock {
392- positionToId.add(Placeholder (targetPosition, uuid))
390+ positionToId.add(Placeholder (targetPosition, uuid, paramsFlow))
391+ }
392+ if (recreateView) {
393+ Log .d(" vojta" , " Adding view with $newWidth x $newHeight " )
394+ container.addView(box)
393395 }
394- container.addView(box)
395396 adapter.onViewCreated(box, uuid)
396397 }
397398
@@ -567,7 +568,7 @@ class PlaceholderManager(
567568 * @param placeholderUuid the placeholder UUID
568569 * @param attrs aztec attributes of the view
569570 */
570- suspend fun createView (context : Context , placeholderUuid : String , attrs : AztecAttributes ): View
571+ suspend fun createView (context : Context , placeholderUuid : String , viewParamsUpdate : StateFlow < Placeholder . ViewParams > ): View
571572
572573 /* *
573574 * Called after the view is measured. Use this method if you need the actual width and height of the view to
@@ -577,6 +578,8 @@ class PlaceholderManager(
577578 */
578579 suspend fun onViewCreated (view : View , placeholderUuid : String ) {}
579580
581+ fun animateLayoutChanges () = false
582+
580583 /* *
581584 * Called when the placeholder is deleted by the user. Use this method if you need to clear your data when the
582585 * item is deleted (for example delete an image in your DB).
@@ -668,7 +671,9 @@ class PlaceholderManager(
668671 }
669672 }
670673
671- data class Placeholder (val elementPosition : Int , val uuid : String )
674+ data class Placeholder (val elementPosition : Int , val uuid : String , val viewParams : MutableStateFlow <ViewParams >) {
675+ data class ViewParams (val width : Int , val height : Int , val attrs : AztecAttributes , val initial : Boolean = false )
676+ }
672677
673678 companion object {
674679 private const val TAG = " PlaceholderManager"
0 commit comments