diff --git a/twidere/src/androidTest/res/raw/account_200092_mastodon_social.json b/twidere/src/androidTest/res/raw/account_200092_mastodon_social.json new file mode 100644 index 000000000..82900f80b --- /dev/null +++ b/twidere/src/androidTest/res/raw/account_200092_mastodon_social.json @@ -0,0 +1,51 @@ +{ + "account": { + "name": "mariotaku@mastodon.social", + "type": "org.mariotaku.twidere.account" + }, + "activated": true, + "color": "#000000", + "credentials": { + "access_token": "REDACTED", + "api_url_format": "https:\/\/mastodon.social\/api\/", + "no_version_suffix": true + }, + "credentials_type": "oauth2", + "dummy": false, + "extras": { + "status_text_limit": 500 + }, + "key": "200092@mastodon.social", + "position": 1, + "test": true, + "type": "mastodon", + "user": { + "account_id": "200092@mastodon.social", + "background_color": null, + "created_at": 1505290270613, + "description_plain": "", + "description_spans": [], + "description_unescaped": "", + "favorites_count": -1, + "followers_count": 0, + "friends_count": 10, + "is_basic": false, + "is_cache": true, + "is_follow_request_sent": false, + "is_following": false, + "is_protected": false, + "is_verified": false, + "id": "200092@mastodon.social", + "link_color": null, + "listed_count": -1, + "media_count": -1, + "name": "Mariotaku Lee", + "position": 0, + "profile_banner_url": "https:\/\/mastodon.social\/headers\/original\/missing.png", + "profile_image_url": "https:\/\/files.mastodon.social\/accounts\/avatars\/000\/200\/092\/original\/pnc__picked_media_7f031c49-be65-4cbb-a949-2711564eacfd.jpeg", + "screen_name": "mariotaku", + "statuses_count": 2, + "text_color": null, + "url": "https:\/\/mastodon.social\/@mariotaku" + } +} \ No newline at end of file diff --git a/twidere/src/main/kotlin/org/mariotaku/ktextension/TextExtensions.kt b/twidere/src/main/kotlin/org/mariotaku/ktextension/TextExtensions.kt index 1fbbebd00..dbe09c061 100644 --- a/twidere/src/main/kotlin/org/mariotaku/ktextension/TextExtensions.kt +++ b/twidere/src/main/kotlin/org/mariotaku/ktextension/TextExtensions.kt @@ -19,8 +19,14 @@ package org.mariotaku.ktextension +import java.text.Normalizer + fun CharSequence.appendTo(sb: StringBuilder) { sb.append(this) } -operator fun CharSequence.times(n: Int): String = repeat(n) \ No newline at end of file +operator fun CharSequence.times(n: Int): String = repeat(n) + +fun CharSequence.normalized(form: Normalizer.Form): String { + return Normalizer.normalize(this, form) +} \ No newline at end of file diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt index 53ecfbe2e..5b345d2ef 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/activity/ComposeActivity.kt @@ -57,7 +57,6 @@ import android.widget.ImageView import android.widget.Toast import com.bumptech.glide.Glide import com.twitter.Extractor -import com.twitter.Validator import kotlinx.android.synthetic.main.activity_compose.* import nl.komponents.kovenant.combine.and import nl.komponents.kovenant.task @@ -126,8 +125,6 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener @Inject lateinit var extractor: Extractor @Inject - lateinit var validator: Validator - @Inject lateinit var locationManager: LocationManager private lateinit var itemTouchHelper: ItemTouchHelper @@ -1477,13 +1474,23 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener getStatusUpdate(true) } catch (e: NoAccountException) { editText.error = getString(R.string.message_toast_no_account_selected) + editText.requestFocus() return } catch (e: NoContentException) { editText.error = getString(R.string.error_message_no_content) + editText.requestFocus() return } catch (e: StatusTooLongException) { editText.error = getString(R.string.error_message_status_too_long) - editText.setSelection(e.exceededStartIndex, editText.length()) + editSummary.string = e.summary + editText.string = e.text + if (e.textExceededStartIndex >= 0) { + editText.setSelection(e.textExceededStartIndex, editText.length()) + editText.requestFocus() + } else if (e.summaryExceededStartIndex >= 0) { + editSummary.setSelection(e.summaryExceededStartIndex, editSummary.length()) + editSummary.requestFocus() + } return } @@ -1528,15 +1535,8 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener if (accounts.isEmpty()) throw NoAccountException() val update = ParcelableStatusUpdate() val media = this.media - val text = editText.string?.let { Normalizer.normalize(it, Normalizer.Form.NFC) }.orEmpty() - var summary: String? = null - var summaryLength = 0 - if (editSummary.visibility == View.VISIBLE) { - summary = editSummary.string?.takeIf(String::isNotEmpty)?.let { - Normalizer.normalize(it, Normalizer.Form.NFC) - } - summaryLength = summary?.let { validator.getTweetLength(it) } ?: 0 - } + val summary = editSummary.textIfVisible?.normalized(Normalizer.Form.NFC) + val text = editText.text?.normalized(Normalizer.Form.NFC).orEmpty() val maxLength = statusTextCount.maxLength val inReplyTo = inReplyToStatus val replyTextAndMentions = getTwitterReplyTextAndMentions(text, accounts) @@ -1544,10 +1544,15 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener val (replyStartIndex, replyText, _, excludedMentions, replyToOriginalUser) = replyTextAndMentions if (replyText.isEmpty() && media.isEmpty()) throw NoContentException() - val totalLength = summaryLength + validator.getTweetLength(replyText) + val totalLength = StatusTextValidator.calculateLength(accounts, summary, text) if (checkLength && !statusShortenerUsed && maxLength > 0 && totalLength > maxLength) { - throw StatusTooLongException(replyStartIndex + - replyText.offsetByCodePoints(0, maxLength - summaryLength)) + val summaryLength = StatusTextValidator.calculateSummaryLength(accounts, summary) + if (summary != null && summaryLength > maxLength) { + throw StatusTooLongException(summary.offsetByCodePoints(0, maxLength), + if (text.isEmpty()) -1 else 0, summary, text) + } + throw StatusTooLongException(-1, replyStartIndex + replyText.offsetByCodePoints(0, + maxLength - summaryLength), summary, text) } update.text = replyText update.extended_reply_mode = true @@ -1559,9 +1564,15 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener } } else { if (text.isEmpty() && media.isEmpty()) throw NoContentException() - val totalLength = summaryLength + validator.getTweetLength(text) + val totalLength = StatusTextValidator.calculateLength(accounts, summary, text) if (checkLength && !statusShortenerUsed && maxLength > 0 && totalLength > maxLength) { - throw StatusTooLongException(text.offsetByCodePoints(0, maxLength - summaryLength)) + val summaryLength = StatusTextValidator.calculateSummaryLength(accounts, summary) + if (summary != null && summaryLength > maxLength) { + throw StatusTooLongException(summary.offsetByCodePoints(0, maxLength), + if (text.isEmpty()) -1 else 0, summary, text) + } + throw StatusTooLongException(-1, text.offsetByCodePoints(0, + maxLength - summaryLength), summary, text) } update.text = text update.extended_reply_mode = false @@ -1595,24 +1606,21 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener if (textAndMentions == null) { hintLabel.visibility = View.GONE editable.clearSpans(MentionColorSpan::class.java) - val lengths = StatusTextValidator.calculateLengths(accounts, summary, text, + statusTextCount.textCount = StatusTextValidator.calculateLength(accounts, summary, text, false, null) - statusTextCount.textCount = lengths.max() ?: 0 } else if (textAndMentions.replyToOriginalUser || replyToSelf) { hintLabel.visibility = View.GONE val mentionColor = ThemeUtils.getTextColorSecondary(this) editable.clearSpans(MentionColorSpan::class.java) editable.setSpan(MentionColorSpan(mentionColor), 0, textAndMentions.replyStartIndex, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE) - val lengths = StatusTextValidator.calculateLengths(accounts, summary, textAndMentions.replyText, - false, null) - statusTextCount.textCount = lengths.max() ?: 0 + statusTextCount.textCount = StatusTextValidator.calculateLength(accounts, summary, + textAndMentions.replyText, false, null) } else { hintLabel.visibility = View.VISIBLE editable.clearSpans(MentionColorSpan::class.java) - val lengths = StatusTextValidator.calculateLengths(accounts, summary, textAndMentions.replyText, - false, null) - statusTextCount.textCount = lengths.max() ?: 0 + statusTextCount.textCount = StatusTextValidator.calculateLength(accounts, summary, + textAndMentions.replyText, false, null) } } @@ -2168,7 +2176,13 @@ class ComposeActivity : BaseActivity(), OnMenuItemClickListener, OnClickListener private open class ComposeException : Exception() - private class StatusTooLongException(val exceededStartIndex: Int) : ComposeException() + private class StatusTooLongException( + val summaryExceededStartIndex: Int, + val textExceededStartIndex: Int, + val summary: String?, + val text: String + ) : ComposeException() + private class NoContentException : ComposeException() private class NoAccountException : ComposeException() diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/dagger/module/ApplicationModule.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/dagger/module/ApplicationModule.kt index 6a8a4ff9d..38120765a 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/dagger/module/ApplicationModule.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/dagger/module/ApplicationModule.kt @@ -35,7 +35,6 @@ import com.google.android.exoplayer2.upstream.DataSource import com.squareup.otto.Bus import com.squareup.otto.ThreadEnforcer import com.twitter.Extractor -import com.twitter.Validator import dagger.Module import dagger.Provides import okhttp3.Cache @@ -69,7 +68,7 @@ import org.mariotaku.twidere.util.text.TwitterValidator import java.io.File import javax.inject.Singleton -@Module() +@Module class ApplicationModule(private val application: Application) { init { @@ -195,12 +194,6 @@ class ApplicationModule(private val application: Application) { return TwidereMediaDownloader(application, client, thumbor) } - @Provides - @Singleton - fun validator(): Validator { - return TwitterValidator() - } - @Provides @Singleton fun extractor(): Extractor { diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/extension/model/AccountDetailsExtensions.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/extension/model/AccountDetailsExtensions.kt index b74ebd991..5fab85897 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/extension/model/AccountDetailsExtensions.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/extension/model/AccountDetailsExtensions.kt @@ -1,7 +1,6 @@ package org.mariotaku.twidere.extension.model import android.content.Context -import com.twitter.Validator import org.mariotaku.microblog.library.twitter.annotation.MediaCategory import org.mariotaku.twidere.annotation.AccountType import org.mariotaku.twidere.model.AccountDetails @@ -13,6 +12,9 @@ import org.mariotaku.twidere.model.account.cred.Credentials import org.mariotaku.twidere.model.account.cred.OAuthCredentials import org.mariotaku.twidere.task.status.UpdateStatusTask import org.mariotaku.twidere.util.InternalTwitterContentUtils +import org.mariotaku.twidere.util.text.FanfouValidator +import org.mariotaku.twidere.util.text.MastodonValidator +import org.mariotaku.twidere.util.text.TwitterValidator fun AccountDetails.isOfficial(context: Context): Boolean { val extra = this.extras @@ -77,27 +79,23 @@ fun AccountDetails.getMediaSizeLimit(@MediaCategory mediaCategory: String? = nul * Text limit when composing a status, 0 for no limit */ val AccountDetails.textLimit: Int - get() { - if (type == null) { - return Validator.MAX_TWEET_LENGTH + get() = when (type) { + AccountType.STATUSNET -> { + (this.extras as? StatusNetAccountExtras)?.textLimit ?: 140 } - when (type) { - AccountType.STATUSNET -> { - val extras = this.extras as? StatusNetAccountExtras - if (extras != null) { - return extras.textLimit - } - } - AccountType.MASTODON -> { - val extras = this.extras as? MastodonAccountExtras - if (extras != null) { - return extras.statusTextLimit - } - } + AccountType.MASTODON -> { + (this.extras as? MastodonAccountExtras)?.statusTextLimit ?: MastodonValidator.textLimit } - return Validator.MAX_TWEET_LENGTH + AccountType.FANFOU -> { + FanfouValidator.textLimit + } + AccountType.TWITTER -> { + TwitterValidator.maxWeightedTweetLength + } + else -> 140 } + val Array.textLimit: Int get() { var limit = -1 diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/BaseDialogFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/BaseDialogFragment.kt index 9aca90819..587b915b7 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/BaseDialogFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/BaseDialogFragment.kt @@ -26,7 +26,6 @@ import android.support.v4.app.DialogFragment import com.bumptech.glide.Glide import com.bumptech.glide.RequestManager import com.squareup.otto.Bus -import com.twitter.Validator import okhttp3.Dns import org.mariotaku.kpreferences.KPreferences import org.mariotaku.restfu.http.RestHttpClient @@ -49,8 +48,6 @@ open class BaseDialogFragment : DialogFragment() { @Inject lateinit var kPreferences: KPreferences @Inject - lateinit var validator: Validator - @Inject lateinit var keyboardShortcutsHandler: KeyboardShortcutsHandler @Inject lateinit var bus: Bus diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/BaseFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/BaseFragment.kt index cf0b0eaef..e2f588987 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/BaseFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/BaseFragment.kt @@ -28,7 +28,6 @@ import android.view.View import com.bumptech.glide.Glide import com.bumptech.glide.RequestManager import com.squareup.otto.Bus -import com.twitter.Validator import nl.komponents.kovenant.Promise import okhttp3.Dns import org.mariotaku.restfu.http.RestHttpClient @@ -66,8 +65,6 @@ open class BaseFragment : Fragment(), IBaseFragment { @Inject lateinit var errorInfoStore: ErrorInfoStore @Inject - lateinit var validator: Validator - @Inject lateinit var extraFeaturesService: ExtraFeaturesService @Inject lateinit var permissionsManager: PermissionsManager diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/status/RetweetQuoteDialogFragment.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/status/RetweetQuoteDialogFragment.kt index ab510ee9c..8510fc825 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/status/RetweetQuoteDialogFragment.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/fragment/status/RetweetQuoteDialogFragment.kt @@ -31,7 +31,6 @@ import android.view.View import android.widget.CheckBox import android.widget.RelativeLayout import android.widget.Toast -import com.twitter.Validator import org.mariotaku.kpreferences.get import org.mariotaku.ktextension.* import org.mariotaku.library.objectcursor.ObjectCursor @@ -54,6 +53,7 @@ import org.mariotaku.twidere.provider.TwidereDataStore.Drafts import org.mariotaku.twidere.service.LengthyOperationsService import org.mariotaku.twidere.util.EditTextEnterHandler import org.mariotaku.twidere.util.LinkCreator +import org.mariotaku.twidere.util.text.FanfouValidator import org.mariotaku.twidere.util.text.StatusTextValidator import org.mariotaku.twidere.util.view.SimpleTextWatcher import org.mariotaku.twidere.view.ComposeEditText @@ -187,7 +187,7 @@ class RetweetQuoteDialogFragment : AbsStatusDialogFragment() { positiveButton.isEnabled = status.can_retweet } textCountView.textCount = StatusTextValidator.calculateLength(account.type, account.key, - null, text.toString(), false, null) + null, text.toString()) } private fun DialogInterface.shouldQuoteRetweet(account: AccountDetails): Boolean { @@ -227,8 +227,8 @@ class RetweetQuoteDialogFragment : AbsStatusDialogFragment() { status.quoted_user_screen_name, status.quoted_text_plain) update.repost_status_id = status.quoted_id } - if (commentText.length > Validator.MAX_TWEET_LENGTH) { - commentText = commentText.substring(0, Math.max(Validator.MAX_TWEET_LENGTH, + if (FanfouValidator.calculateLength(commentText) > FanfouValidator.textLimit) { + commentText = commentText.substring(0, Math.max(FanfouValidator.textLimit, editingComment.length)) } } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/service/BaseIntentService.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/service/BaseIntentService.kt index 8719a7d78..e17da56f3 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/service/BaseIntentService.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/service/BaseIntentService.kt @@ -3,7 +3,6 @@ package org.mariotaku.twidere.service import android.app.IntentService import android.content.SharedPreferences import com.twitter.Extractor -import com.twitter.Validator import org.mariotaku.twidere.util.AsyncTwitterWrapper import org.mariotaku.twidere.util.NotificationManagerWrapper import org.mariotaku.twidere.util.UserColorNameManager @@ -19,8 +18,6 @@ abstract class BaseIntentService(tag: String) : IntentService(tag) { @Inject lateinit var notificationManager: NotificationManagerWrapper @Inject - lateinit var validator: Validator - @Inject lateinit var extractor: Extractor @Inject lateinit var userColorNameManager: UserColorNameManager diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/service/BaseService.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/service/BaseService.kt index a9d0a16df..7ff5b119b 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/service/BaseService.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/service/BaseService.kt @@ -23,7 +23,6 @@ import android.app.Service import android.content.SharedPreferences import android.net.ConnectivityManager import com.twitter.Extractor -import com.twitter.Validator import org.mariotaku.twidere.util.* import org.mariotaku.twidere.util.dagger.GeneralComponent import org.mariotaku.twidere.util.notification.ContentNotificationManager @@ -38,8 +37,6 @@ abstract class BaseService : Service() { @Inject lateinit var notificationManager: NotificationManagerWrapper @Inject - lateinit var validator: Validator - @Inject lateinit var extractor: Extractor @Inject lateinit var userColorNameManager: UserColorNameManager diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/task/status/UpdateStatusTask.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/task/status/UpdateStatusTask.kt index 5e8689985..0f766405d 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/task/status/UpdateStatusTask.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/task/status/UpdateStatusTask.kt @@ -61,7 +61,6 @@ import org.mariotaku.twidere.extension.calculateInSampleSize import org.mariotaku.twidere.extension.model.* import org.mariotaku.twidere.extension.model.api.mastodon.toParcelable import org.mariotaku.twidere.extension.model.api.toParcelable -import org.mariotaku.twidere.extension.text.twitter.getTweetLength import org.mariotaku.twidere.model.* import org.mariotaku.twidere.model.account.AccountExtras import org.mariotaku.twidere.model.analyzer.UpdateStatus @@ -73,7 +72,7 @@ import org.mariotaku.twidere.task.BaseAbstractTask import org.mariotaku.twidere.util.* import org.mariotaku.twidere.util.io.ContentLengthInputStream import org.mariotaku.twidere.util.premium.ExtraFeaturesService -import org.mariotaku.twidere.util.text.TwitterValidator +import org.mariotaku.twidere.util.text.StatusTextValidator import java.io.Closeable import java.io.File import java.io.FileNotFoundException @@ -241,7 +240,6 @@ class UpdateStatusTask( update: ParcelableStatusUpdate, pending: PendingStatusUpdate) { if (shortener == null) return - val validator = TwitterValidator() stateCallback.onShorteningStatus() val sharedShortened = HashMap() for (i in 0 until pending.length) { @@ -249,8 +247,8 @@ class UpdateStatusTask( val text = pending.overrideTexts[i] val textLimit = account.textLimit val ignoreMentions = account.type == AccountType.TWITTER - if (textLimit >= 0 && validator.getTweetLength(text, ignoreMentions, - update.in_reply_to_status, account.key) <= textLimit) { + if (textLimit >= 0 && StatusTextValidator.calculateLength(account.type, account.key, + update.summary, text, ignoreMentions, update.in_reply_to_status) <= textLimit) { continue } shortener.waitForService() diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/DependencyHolder.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/DependencyHolder.kt index cbf7686b5..f60e4a723 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/DependencyHolder.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/dagger/DependencyHolder.kt @@ -21,7 +21,6 @@ package org.mariotaku.twidere.util.dagger import android.content.Context import android.content.SharedPreferences -import com.twitter.Validator import okhttp3.Cache import okhttp3.ConnectionPool import okhttp3.Dns @@ -55,9 +54,6 @@ class DependencyHolder internal constructor(context: Context) { lateinit var dns: Dns internal set @Inject - lateinit var validator: Validator - internal set - @Inject lateinit var preferences: SharedPreferences internal set @Inject diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/text/FanfouValidator.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/text/FanfouValidator.kt new file mode 100644 index 000000000..02a81ec52 --- /dev/null +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/text/FanfouValidator.kt @@ -0,0 +1,30 @@ +/* + * Twidere - Twitter client for Android + * + * Copyright (C) 2012-2017 Mariotaku Lee + * + * 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. + * + * This program 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 this program. If not, see . + */ + +package org.mariotaku.twidere.util.text + +object FanfouValidator { + + const val textLimit = 140 + + fun calculateLength(text: String): Int { + return text.codePointCount(0, text.length) + } + +} diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/text/MastodonValidator.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/text/MastodonValidator.kt index 92392660b..7a0545ac9 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/util/text/MastodonValidator.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/text/MastodonValidator.kt @@ -23,9 +23,12 @@ import org.mariotaku.ktextension.times import org.mariotaku.twidere.alias.TwitterRegex -class MastodonValidator { +object MastodonValidator { + + const val textLimit: Int = 500 private val mentionRegex = Regex("(?<=^|[^/[\\w]])@(([a-z0-9_]+)(?:@[a-z0-9.\\-]+[a-z0-9]+)?)", RegexOption.IGNORE_CASE) + private val urlRegex = TwitterRegex.VALID_URL.toRegex() fun getCountableLength(summary: String?, text: String): Int { diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/text/StatusTextValidator.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/text/StatusTextValidator.kt index 20291a350..8d0e3edb6 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/util/text/StatusTextValidator.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/text/StatusTextValidator.kt @@ -28,35 +28,52 @@ import org.mariotaku.twidere.model.UserKey object StatusTextValidator { - private val twitterValidator = TwitterValidator() - private val mastodonValidator = MastodonValidator() + fun calculateLength(@AccountType accountType: String, accountKey: UserKey?, summary: String?, + text: String, ignoreMentions: Boolean = false, inReplyTo: ParcelableStatus? = null) = when (accountType) { + AccountType.TWITTER -> { + TwitterValidator.getTweetLength(text, ignoreMentions, inReplyTo, accountKey) + } + AccountType.MASTODON -> { + MastodonValidator.getCountableLength(summary, text) + } + AccountType.FANFOU -> { + FanfouValidator.calculateLength(text) + } + AccountType.STATUSNET -> { + text.codePointCount(0, text.length) + } + else -> { + text.codePointCount(0, text.length) + } + } fun calculateLengths(accounts: Array, summary: String?, text: String, - ignoreMentions: Boolean, inReplyTo: ParcelableStatus?): IntArray { + ignoreMentions: Boolean = false, inReplyTo: ParcelableStatus? = null): IntArray { return accounts.mapToIntArray { calculateLength(it.type, it.key, summary, text, ignoreMentions, inReplyTo) } } - fun calculateLength(@AccountType accountType: String, accountKey: UserKey?, summary: String?, - text: String, ignoreMentions: Boolean, inReplyTo: ParcelableStatus?): Int { - when (accountType) { - AccountType.TWITTER -> { - return twitterValidator.getTweetLength(text, ignoreMentions, inReplyTo, accountKey) - } - AccountType.MASTODON -> { - // TODO Algorithm according to https://github.com/tootsuite/mastodon/blob/master/app/validators/status_length_validator.rb - return mastodonValidator.getCountableLength(summary, text) - } - AccountType.FANFOU -> { - return text.codePointCount(0, text.length) - } - AccountType.STATUSNET -> { - return text.codePointCount(0, text.length) - } - else -> { - return text.codePointCount(0, text.length) - } + fun calculateLength(accounts: Array, summary: String?, text: String, + ignoreMentions: Boolean = false, inReplyTo: ParcelableStatus? = null): Int { + return calculateLengths(accounts, summary, text, ignoreMentions, inReplyTo).max() ?: 0 + } + + fun calculateSummaryLength(@AccountType accountType: String, + summary: String?) = when (accountType) { + AccountType.MASTODON -> { + MastodonValidator.getCountableLength(summary, "") + } + else -> 0 + } + + fun calculateSummaryLengths(accounts: Array, summary: String?): IntArray { + return accounts.mapToIntArray { + calculateSummaryLength(it.type, summary) } } + + fun calculateSummaryLength(accounts: Array, summary: String?): Int { + return calculateSummaryLengths(accounts, summary).max() ?: 0 + } } diff --git a/twidere/src/main/kotlin/org/mariotaku/twidere/util/text/TwitterValidator.kt b/twidere/src/main/kotlin/org/mariotaku/twidere/util/text/TwitterValidator.kt index 18c5d93f5..cb1a255b5 100644 --- a/twidere/src/main/kotlin/org/mariotaku/twidere/util/text/TwitterValidator.kt +++ b/twidere/src/main/kotlin/org/mariotaku/twidere/util/text/TwitterValidator.kt @@ -23,10 +23,11 @@ import com.twitter.Extractor import com.twitter.Validator import java.text.Normalizer -class TwitterValidator: Validator() { - val maxWeightedTweetLength: Int = 280 +object TwitterValidator : Validator() { - val defaultWeight: Int = 200 + const val maxWeightedTweetLength: Int = 280 + + const val defaultWeight: Int = 200 var ranges: Array = arrayOf( WeightRange(0, 4351, 100),