From f975522e635d8c7536795b4d5a43144540d5b4de Mon Sep 17 00:00:00 2001 From: Konrad Pozniak Date: Thu, 25 Jul 2019 12:15:54 +0200 Subject: [PATCH] fix shouldTrimStatus and add tests (#1404) --- .../conversation/ConversationEntity.kt | 2 +- .../report/adapter/StatusViewHolder.kt | 2 +- .../tusky/fragment/ViewThreadFragment.java | 2 - .../tusky/util/SmartLengthInputFilter.kt | 25 +++--- .../tusky/util/StatusExtensions.kt | 23 ------ .../tusky/util/ViewDataUtils.java | 2 +- .../tusky/util/SmartLengthInputFilterTest.kt | 81 +++++++++++++++++++ 7 files changed, 96 insertions(+), 41 deletions(-) delete mode 100644 app/src/main/java/com/keylesspalace/tusky/util/StatusExtensions.kt create mode 100644 app/src/test/java/com/keylesspalace/tusky/util/SmartLengthInputFilterTest.kt diff --git a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationEntity.kt b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationEntity.kt index 71010b5c..754a22ea 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationEntity.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/conversation/ConversationEntity.kt @@ -176,7 +176,7 @@ fun Status.toEntity() = spoilerText, attachments, mentions, false, false, - !shouldTrimStatus(content), + shouldTrimStatus(content), true, poll ) diff --git a/app/src/main/java/com/keylesspalace/tusky/components/report/adapter/StatusViewHolder.kt b/app/src/main/java/com/keylesspalace/tusky/components/report/adapter/StatusViewHolder.kt index d8c86d8f..be24070f 100644 --- a/app/src/main/java/com/keylesspalace/tusky/components/report/adapter/StatusViewHolder.kt +++ b/app/src/main/java/com/keylesspalace/tusky/components/report/adapter/StatusViewHolder.kt @@ -79,7 +79,7 @@ class StatusViewHolder(itemView: View, private fun updateTextView() { status()?.let { status -> - setupCollapsedState(status.isCollapsible(), viewState.isCollapsed(status.id, true), + setupCollapsedState(shouldTrimStatus(status.content), viewState.isCollapsed(status.id, true), viewState.isContentShow(status.id, status.sensitive), status.spoilerText) if (status.spoilerText.isBlank()) { diff --git a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java index 52563375..b5e8878f 100644 --- a/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java +++ b/app/src/main/java/com/keylesspalace/tusky/fragment/ViewThreadFragment.java @@ -48,7 +48,6 @@ import com.keylesspalace.tusky.interfaces.StatusActionListener; import com.keylesspalace.tusky.network.MastodonApi; import com.keylesspalace.tusky.util.ListStatusAccessibilityDelegate; import com.keylesspalace.tusky.util.PairedList; -import com.keylesspalace.tusky.util.SmartLengthInputFilterKt; import com.keylesspalace.tusky.util.ThemeUtils; import com.keylesspalace.tusky.util.ViewDataUtils; import com.keylesspalace.tusky.view.ConversationLineItemDecoration; @@ -360,7 +359,6 @@ public final class ViewThreadFragment extends SFragment implements } StatusViewData.Concrete updatedStatus = new StatusViewData.Builder(status) - .setCollapsible(!SmartLengthInputFilterKt.shouldTrimStatus(status.getContent())) .setCollapsed(isCollapsed) .createStatusViewData(); statuses.setPairedItem(position, updatedStatus); diff --git a/app/src/main/java/com/keylesspalace/tusky/util/SmartLengthInputFilter.kt b/app/src/main/java/com/keylesspalace/tusky/util/SmartLengthInputFilter.kt index eb738b06..ba9c4203 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/SmartLengthInputFilter.kt +++ b/app/src/main/java/com/keylesspalace/tusky/util/SmartLengthInputFilter.kt @@ -38,8 +38,7 @@ private const val LENGTH_DEFAULT = 500 * @return Whether the message should be trimmed or not. */ fun shouldTrimStatus(message: Spanned): Boolean { - // Check for emptiness so that we don't divide by zero - return message.isNotEmpty() && LENGTH_DEFAULT.toFloat() / message.length > 0.75 + return message.isNotEmpty() && LENGTH_DEFAULT.toFloat() / message.length < 0.75 } /** @@ -60,7 +59,7 @@ object SmartLengthInputFilter : InputFilter { // https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/text/InputFilter.java#175 val sourceLength = source.length - var keep = LENGTH_DEFAULT - dest.length - dend - dstart + var keep = LENGTH_DEFAULT - (dest.length - (dend - dstart)) if (keep <= 0) return "" if (keep >= end - start) return null // Keep original @@ -78,17 +77,17 @@ object SmartLengthInputFilter : InputFilter { // those without having to add the ICU4J library at a minimum Api trade-off. if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) { val iterator = android.icu.text.BreakIterator.getWordInstance() - iterator.setText(source.toString()) - boundary = iterator.following(keep) - if (keep - boundary > RUNWAY) boundary = iterator.preceding(keep) - } else { - val iterator = java.text.BreakIterator.getWordInstance() - iterator.setText(source.toString()) - boundary = iterator.following(keep) - if (keep - boundary > RUNWAY) boundary = iterator.preceding(keep) - } + iterator.setText(source.toString()) + boundary = iterator.following(keep) + if (keep - boundary > RUNWAY) boundary = iterator.preceding(keep) + } else { + val iterator = java.text.BreakIterator.getWordInstance() + iterator.setText(source.toString()) + boundary = iterator.following(keep) + if (keep - boundary > RUNWAY) boundary = iterator.preceding(keep) + } - keep = boundary + keep = boundary } else { // If no runway is allowed simply remove whitespaces if present diff --git a/app/src/main/java/com/keylesspalace/tusky/util/StatusExtensions.kt b/app/src/main/java/com/keylesspalace/tusky/util/StatusExtensions.kt deleted file mode 100644 index 0c4b5e79..00000000 --- a/app/src/main/java/com/keylesspalace/tusky/util/StatusExtensions.kt +++ /dev/null @@ -1,23 +0,0 @@ -/* Copyright 2019 Joel Pyska - * - * This file is a part of Tusky. - * - * This program is free software; you can redistribute it and/or modify it under the terms of the - * GNU General Public License as published by the Free Software Foundation; either version 3 of the - * License, or (at your option) any later version. - * - * Tusky is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even - * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General - * Public License for more details. - * - * You should have received a copy of the GNU General Public License along with Tusky; if not, - * see . */ - -package com.keylesspalace.tusky.util - -import com.keylesspalace.tusky.entity.Status - -fun Status.isCollapsible(): Boolean { - return !shouldTrimStatus(content) -} - diff --git a/app/src/main/java/com/keylesspalace/tusky/util/ViewDataUtils.java b/app/src/main/java/com/keylesspalace/tusky/util/ViewDataUtils.java index ebd56eab..5e213068 100644 --- a/app/src/main/java/com/keylesspalace/tusky/util/ViewDataUtils.java +++ b/app/src/main/java/com/keylesspalace/tusky/util/ViewDataUtils.java @@ -58,7 +58,7 @@ public final class ViewDataUtils { .setApplication(visibleStatus.getApplication()) .setStatusEmojis(visibleStatus.getEmojis()) .setAccountEmojis(visibleStatus.getAccount().getEmojis()) - .setCollapsible(!SmartLengthInputFilterKt.shouldTrimStatus(visibleStatus.getContent())) + .setCollapsible(SmartLengthInputFilterKt.shouldTrimStatus(visibleStatus.getContent())) .setCollapsed(true) .setPoll(visibleStatus.getPoll()) .setCard(visibleStatus.getCard()) diff --git a/app/src/test/java/com/keylesspalace/tusky/util/SmartLengthInputFilterTest.kt b/app/src/test/java/com/keylesspalace/tusky/util/SmartLengthInputFilterTest.kt new file mode 100644 index 00000000..f11658b0 --- /dev/null +++ b/app/src/test/java/com/keylesspalace/tusky/util/SmartLengthInputFilterTest.kt @@ -0,0 +1,81 @@ +package com.keylesspalace.tusky.util + +import android.text.SpannableStringBuilder +import androidx.test.ext.junit.runners.AndroidJUnit4 +import com.keylesspalace.tusky.FakeTuskyApplication +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Test +import org.junit.runner.RunWith +import org.robolectric.annotation.Config + +@Config(application = FakeTuskyApplication::class) +@RunWith(AndroidJUnit4::class) +class SmartLengthInputFilterTest { + + + @Test + fun shouldNotTrimStatusWithLength0() { + assertFalse(shouldTrimStatus(SpannableStringBuilder(""))) + } + + @Test + fun shouldNotTrimStatusWithLength10() { + assertFalse(shouldTrimStatus(SpannableStringBuilder("0123456789"))) + } + + @Test + fun shouldNotTrimStatusWithLength500() { + assertFalse(shouldTrimStatus(SpannableStringBuilder("u1Pc5TbDVYFnzIdqlQkb3xuZ2S61fFD1K4u" + + "cb3q40dnELjAsWxnSH59jqly249Spr0Vod029zfwFHYQ0PkBCNQ7tuk90h6aY661RFC7vhIKJna4yDYOBFj" + + "RR9u0CsUa6vlgEE5yUrk5LKn3bmnnzRCXmU6HyT2bFu256qoUWbmMQ6GFXUXjO28tru8Q3UiXKLgrotKdSH" + + "mmqPwQgtatbMykTW4RZdKTE46nzlbD3mXHdWQkf4uVPYhVT1CMvVbCPMaimfQ0xuU8CpxyVqA8a6lCL3YX9" + + "pNnZjD7DoCg2FCejANnjXsTF6vuqPSHjQZDjy696nSAFy95p9kBeJkc70fHzX5TcfUqSaNtvx3LUtpIkwh4" + + "q2EYmKISPsxlANaspEMPuX6r9fSACiEwmHsitZkp4RMKZq5NqRsGPCiAXcNIN3jj9fCYVGxUwVxVeCescDG" + + "5naEEszIR3FT1RO4MSn9c2ZZi0UdLizd8ciJAIuwwmcVyYyyM4"))) + } + + @Test + fun shouldNotTrimStatusWithLength666() { + assertFalse(shouldTrimStatus(SpannableStringBuilder("hIAXqY7DYynQGcr3zxcjCjNZFcdwAzwnWv" + + "NHONtT55rO3r2faeMRZLTG3JlOshq8M1mtLRn0Ca8M9w82nIjJDm1jspxhFc4uLFpOjb9Gm2BokgRftA8ih" + + "pv6wvMwF5Fg8V4qa8GcXcqt1q7S9g09S3PszCXG4wnrR6dp8GGc9TqVArgmoLSc9EVREIRcLPdzkhV1WWM9" + + "ZWw7josT27BfBdMWk0ckQkClHAyqLtlKZ84WamxK2q3NtHR5gr7ohIjU8CZoKDjv1bA8ZI8wBesyOhqbmHf" + + "0Ltypq39WKZ63VTGSf5Dd9kuTEjlXJtxZD1DXH4FFplY45DH5WuQ61Ih5dGx0WFEEVb1L3aku3Ht8rKG7YU" + + "bOPeanGMBmeI9YRdiD4MmuTUkJfVLkA9rrpRtiEYw8RS3Jf9iqDkTpES9aLQODMip5xTsT4liIcUbLo0Z1d" + + "NhHk7YKubigNQIm1mmh2iU3Q0ZEm8TraDpKu2o27gIwSKbAnTllrOokprPxWQWDVrN9bIliwGHzgTKPI5z8" + + "gUybaqewxUYe12GvxnzqpfPFvvHricyZAC9i6Fkil5VmFdae75tLFWRBfE8Wfep0dSjL751m2yzvzZTc6uZ" + + "RTcUiipvl42DaY8Z5eG2b6xPVhvXshMORvHzwhJhPkHSbnwXX5K"))) + } + + @Test + fun shouldTrimStatusWithLength667() { + assertTrue(shouldTrimStatus(SpannableStringBuilder("hIAXqY7DYynQGcr3zxcjCjNZFcdwAzwnWv" + + "NHONtT55rO3r2faeMRZLTG3JlOshq8M1mtLRn0Ca8M9w82nIjJDm1jspxhFc4uLFpOjb9Gm2BokgRftA8ih" + + "pv6wvMwF5Fg8V4qa8GcXcqt1q7S9g09S3PszCXG4wnrR6dp8GGc9TqVArgmoLSc9EVREIRcLPdzkhV1WWM9" + + "ZWw7josT27BfBdMWk0ckQkClHAyqLtlKZ84WamxK2q3NtHR5gr7ohIjU8CZoKDjv1bA8ZI8wBesyOhqbmHf" + + "0Ltypq39WKZ63VTGSf5Dd9kuTEjlXJtxZD1DXH4FFplY45DH5WuQ61Ih5dGx0WFEEVb1L3aku3Ht8rKG7YU" + + "bOPeanGMBmeI9YRdiD4MmuTUkJfVLkA9rrpRtiEYw8RS3Jf9iqDkTpES9aLQODMip5xTsT4liIcUbLo0Z1d" + + "NhHk7YKubigNQIm1mmh2iU3Q0ZEm8TraDpKu2o27gIwSKbAnTllrOokprPxWQWDVrN9bIliwGHzgTKPI5z8" + + "gUybaqewxUYe12GvxnzqpfPFvvHricyZAC9i6Fkil5VmFdae75tLFWRBfE8Wfep0dSjL751m2yzvzZTc6uZ" + + "RTcUiipvl42DaY8Z5eG2b6xPVhvXshMORvHzwhJhPkHSbnwXX5K1"))) + } + + @Test + fun shouldTrimStatusWithLength1000() { + assertTrue(shouldTrimStatus(SpannableStringBuilder("u1Pc5TbDVYFnzIdqlQkb3xuZ2S61fFD1K4u" + + "cb3q40dnELjAsWxnSH59jqly249Spr0Vod029zfwFHYQ0PkBCNQ7tuk90h6aY661RFC7vhIKJna4yDYOBFj" + + "RR9u0CsUa6vlgEE5yUrk5LKn3bmnnzRCXmU6HyT2bFu256qoUWbmMQ6GFXUXjO28tru8Q3UiXKLgrotKdSH" + + "mmqPwQgtatbMykTW4RZdKTE46nzlbD3mXHdWQkf4uVPYhVT1CMvVbCPMaimfQ0xuU8CpxyVqA8a6lCL3YX9" + + "pNnZjD7DoCg2FCejANnjXsTF6vuqPSHjQZDjy696nSAFy95p9kBeJkc70fHzX5TcfUqSaNtvx3LUtpIkwh4" + + "q2EYmKISPsxlANaspEMPuX6r9fSACiEwmHsitZkp4RMKZq5NqRsGPCiAXcNIN3jj9fCYVGxUwVxVeCescDG" + + "5naEEszIR3FT1RO4MSn9c2ZZi0UdLizd8ciJAIuwwmcVyYyyM4"+ + "u1Pc5TbDVYFnzIdqlQkb3xuZ2S61fFD1K4u" + + "cb3q40dnELjAsWxnSH59jqly249Spr0Vod029zfwFHYQ0PkBCNQ7tuk90h6aY661RFC7vhIKJna4yDYOBFj" + + "RR9u0CsUa6vlgEE5yUrk5LKn3bmnnzRCXmU6HyT2bFu256qoUWbmMQ6GFXUXjO28tru8Q3UiXKLgrotKdSH" + + "mmqPwQgtatbMykTW4RZdKTE46nzlbD3mXHdWQkf4uVPYhVT1CMvVbCPMaimfQ0xuU8CpxyVqA8a6lCL3YX9" + + "pNnZjD7DoCg2FCejANnjXsTF6vuqPSHjQZDjy696nSAFy95p9kBeJkc70fHzX5TcfUqSaNtvx3LUtpIkwh4" + + "q2EYmKISPsxlANaspEMPuX6r9fSACiEwmHsitZkp4RMKZq5NqRsGPCiAXcNIN3jj9fCYVGxUwVxVeCescDG" + + "5naEEszIR3FT1RO4MSn9c2ZZi0UdLizd8ciJAIuwwmcVyYyyM4"))) + } +}