diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/AutoSizeEmojiEditText.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/AutoSizeEmojiEditText.kt deleted file mode 100644 index 5aa78e5a80..0000000000 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/AutoSizeEmojiEditText.kt +++ /dev/null @@ -1,156 +0,0 @@ -package org.thoughtcrime.securesms.mediasend.v2.text - -import android.content.Context -import android.text.Editable -import android.text.TextWatcher -import android.util.AttributeSet -import android.util.TypedValue -import androidx.core.content.res.use -import androidx.core.view.doOnNextLayout -import org.signal.core.util.DimensionUnit -import org.signal.core.util.EditTextUtil -import org.thoughtcrime.securesms.R -import org.thoughtcrime.securesms.components.emoji.EmojiEditText -import kotlin.math.abs -import kotlin.math.max -import kotlin.math.min - -class AutoSizeEmojiEditText @JvmOverloads constructor( - context: Context, - attrs: AttributeSet? = null -) : EmojiEditText(context, attrs) { - - private val maxTextSize = DimensionUnit.DP.toPixels(32f) - private val minTextSize = DimensionUnit.DP.toPixels(6f) - private var lowerBounds = minTextSize - private var upperBounds = maxTextSize - - private val sizeSet: MutableSet = mutableSetOf() - - private var beforeText: String? = null - private var beforeCursorPosition = 0 - - private val watcher: TextWatcher = object : TextWatcher { - - override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) = Unit - - override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { - beforeText = s.toString() - beforeCursorPosition = start - } - - override fun afterTextChanged(s: Editable) { - if (lineCount == 0) { - doOnNextLayout { - checkCountAndAddListener() - } - } else { - checkCountAndAddListener() - } - } - } - - init { - EditTextUtil.addGraphemeClusterLimitFilter(this, 700) - - if (attrs != null) { - context.obtainStyledAttributes(attrs, R.styleable.AutoSizeEmojiEditText).use { typedArray -> - if (typedArray.getBoolean(R.styleable.AutoSizeEmojiEditText_aseet_EnforceLineCount, true)) { - addTextChangedListener(watcher) - } - } - } else { - addTextChangedListener(watcher) - } - } - - override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { - super.onMeasure(widthMeasureSpec, heightMeasureSpec) - - if (isInEditMode) return - - try { - val operation = getNextAutoSizeOperation() - val newSize = when (operation) { - AutoSizeOperation.INCREASE -> { - lowerBounds = textSize - val midpoint = abs(lowerBounds - upperBounds) / 2f + lowerBounds - min(maxTextSize, midpoint) - } - AutoSizeOperation.DECREASE -> { - upperBounds = textSize - val midpoint = abs(lowerBounds - upperBounds) / 2f + lowerBounds - max(minTextSize, midpoint) - } - AutoSizeOperation.NONE -> return - } - - if (abs(upperBounds - lowerBounds) < 1f) { - setTextSize(TypedValue.COMPLEX_UNIT_PX, lowerBounds) - return - } else if (sizeSet.add(newSize) || operation == AutoSizeOperation.INCREASE) { - setTextSize(TypedValue.COMPLEX_UNIT_PX, newSize) - measure(widthMeasureSpec, heightMeasureSpec) - } else { - return - } - } finally { - upperBounds = maxTextSize - lowerBounds = minTextSize - sizeSet.clear() - } - } - - private fun getNextAutoSizeOperation(): AutoSizeOperation { - if (lineCount == 0) { - return AutoSizeOperation.NONE - } - - val availableHeight = measuredHeight - paddingTop - paddingBottom - if (availableHeight <= 0) { - return AutoSizeOperation.NONE - } - - val pixelsRequired = lineHeight * lineCount - - return if (pixelsRequired > availableHeight) { - if (textSize > minTextSize) { - AutoSizeOperation.DECREASE - } else { - AutoSizeOperation.NONE - } - } else if (pixelsRequired < availableHeight) { - if (textSize < maxTextSize) { - AutoSizeOperation.INCREASE - } else { - AutoSizeOperation.NONE - } - } else { - AutoSizeOperation.NONE - } - } - - private fun checkCountAndAddListener(): Boolean { - removeTextChangedListener(watcher) - - if (lineCount > 12) { - setText(beforeText) - setSelection(beforeCursorPosition) - addTextChangedListener(watcher) - return true - } - - if (getNextAutoSizeOperation() != AutoSizeOperation.NONE) { - requestLayout() - } - - addTextChangedListener(watcher) - return false - } - - private enum class AutoSizeOperation { - INCREASE, - DECREASE, - NONE - } -} diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/TextStoryPostTextEntryFragment.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/TextStoryPostTextEntryFragment.kt index 113ae23c33..4caa1c8254 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/TextStoryPostTextEntryFragment.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/TextStoryPostTextEntryFragment.kt @@ -104,6 +104,8 @@ class TextStoryPostTextEntryFragment : KeyboardEntryDialogFragment( } private fun initializeInput() { + TextStoryTextWatcher.install(input) + input.filters = input.filters + bufferFilter input.doOnTextChanged { _, _, _, _ -> presentHint() diff --git a/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/TextStoryTextWatcher.kt b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/TextStoryTextWatcher.kt new file mode 100644 index 0000000000..ad0791ef9e --- /dev/null +++ b/app/src/main/java/org/thoughtcrime/securesms/mediasend/v2/text/TextStoryTextWatcher.kt @@ -0,0 +1,46 @@ +package org.thoughtcrime.securesms.mediasend.v2.text + +import android.text.Editable +import android.text.TextWatcher +import android.util.TypedValue +import android.widget.EditText +import android.widget.TextView +import org.signal.core.util.BreakIteratorCompat +import org.signal.core.util.DimensionUnit +import org.signal.core.util.EditTextUtil + +class TextStoryTextWatcher private constructor(private val textView: TextView) : TextWatcher { + + override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { + ensureProperTextSize(textView) + } + + override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) = Unit + + override fun afterTextChanged(s: Editable) = Unit + + companion object { + fun ensureProperTextSize(textView: TextView) { + val breakIteratorCompat = BreakIteratorCompat.getInstance() + breakIteratorCompat.setText(textView.text) + val length = breakIteratorCompat.countBreaks() + val expectedTextSize = when { + length < 50 -> 36f + length < 200 -> 24f + else -> 18f + } + + textView.setTextSize(TypedValue.COMPLEX_UNIT_PX, DimensionUnit.DP.toPixels(expectedTextSize)) + } + + fun install(textView: TextView) { + val watcher = TextStoryTextWatcher(textView) + + if (textView is EditText) { + EditTextUtil.addGraphemeClusterLimitFilter(textView, 700) + } + + textView.addTextChangedListener(watcher) + } + } +} diff --git a/app/src/main/java/org/thoughtcrime/securesms/stories/StoryTextPostView.kt b/app/src/main/java/org/thoughtcrime/securesms/stories/StoryTextPostView.kt index 9d1093a61f..93dcd942f2 100644 --- a/app/src/main/java/org/thoughtcrime/securesms/stories/StoryTextPostView.kt +++ b/app/src/main/java/org/thoughtcrime/securesms/stories/StoryTextPostView.kt @@ -28,6 +28,7 @@ import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel import org.thoughtcrime.securesms.mediasend.v2.text.TextAlignment import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryPostCreationState import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryScale +import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryTextWatcher import org.thoughtcrime.securesms.util.ViewUtil import org.thoughtcrime.securesms.util.concurrent.ListenableFuture import org.thoughtcrime.securesms.util.visible @@ -59,6 +60,7 @@ class StoryTextPostView @JvmOverloads constructor( } } + TextStoryTextWatcher.install(textView) textView.doAfterTextChanged { textAlignment?.apply { adjustTextTranslationX(this) diff --git a/app/src/main/res/layout/stories_text_post_text_entry_content.xml b/app/src/main/res/layout/stories_text_post_text_entry_content.xml index fe847a4259..b73a043522 100644 --- a/app/src/main/res/layout/stories_text_post_text_entry_content.xml +++ b/app/src/main/res/layout/stories_text_post_text_entry_content.xml @@ -18,7 +18,7 @@ app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent"> - + tools:text="THIS IS SOME TEXT THAT I AM ENTERING" /> - + tools:text="TEST" /> - - - -