Increase stories caption limit to 1500 grapheme clusters.

fork-5.53.8
Alex Hart 2022-09-19 14:24:44 -03:00 zatwierdzone przez Cody Henthorne
rodzic 654b602cef
commit 9326c1726a
14 zmienionych plików z 125 dodań i 58 usunięć

Wyświetl plik

@ -3,10 +3,8 @@ package org.thoughtcrime.securesms.components
import android.view.View
import androidx.fragment.app.Fragment
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleOwner
import androidx.viewbinding.ViewBinding
import org.whispersystems.signalservice.api.util.Preconditions
import kotlin.reflect.KProperty
/**
@ -18,8 +16,6 @@ class ViewBinderDelegate<T : ViewBinding>(private val bindingFactory: (View) ->
private var binding: T? = null
operator fun getValue(thisRef: Fragment, property: KProperty<*>): T {
Preconditions.checkState(thisRef.viewLifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED))
if (binding == null) {
thisRef.viewLifecycleOwner.lifecycle.addObserver(this@ViewBinderDelegate)
binding = bindingFactory(thisRef.requireView())

Wyświetl plik

@ -164,7 +164,7 @@ class MediaSelectionRepository(context: Context) {
} else {
val iterator = BreakIteratorCompat.getInstance()
iterator.setText(body)
iterator.take(Stories.MAX_BODY_SIZE).toString()
iterator.take(Stories.MAX_CAPTION_SIZE).toString()
}
}

Wyświetl plik

@ -5,21 +5,27 @@ import android.os.Bundle
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Flowable
import io.reactivex.rxjava3.core.Maybe
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.disposables.Disposable
import io.reactivex.rxjava3.kotlin.plusAssign
import io.reactivex.rxjava3.kotlin.subscribeBy
import io.reactivex.rxjava3.processors.BehaviorProcessor
import io.reactivex.rxjava3.schedulers.Schedulers
import io.reactivex.rxjava3.subjects.BehaviorSubject
import io.reactivex.rxjava3.subjects.PublishSubject
import io.reactivex.rxjava3.subjects.Subject
import org.signal.core.util.BreakIteratorCompat
import org.thoughtcrime.securesms.components.mention.MentionAnnotation
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
import org.thoughtcrime.securesms.conversation.MessageSendType
import org.thoughtcrime.securesms.mediasend.Media
import org.thoughtcrime.securesms.mediasend.MediaSendActivityResult
import org.thoughtcrime.securesms.mediasend.VideoEditorFragment
import org.thoughtcrime.securesms.mediasend.v2.review.AddMessageCharacterCount
import org.thoughtcrime.securesms.mms.MediaConstraints
import org.thoughtcrime.securesms.mms.SentMediaQuality
import org.thoughtcrime.securesms.recipients.Recipient
@ -53,6 +59,8 @@ class MediaSelectionViewModel(
)
)
private val addAMessageUpdatePublisher = BehaviorProcessor.create<CharSequence>()
val isContactSelectionRequired = destination == MediaSelectionDestination.ChooseAfterMediaSelection
val state: LiveData<MediaSelectionState> = store.stateLiveData
@ -64,6 +72,22 @@ class MediaSelectionViewModel(
private val disposables = CompositeDisposable()
fun watchAddAMessageCount(): Flowable<AddMessageCharacterCount> {
return addAMessageUpdatePublisher
.onBackpressureLatest()
.map {
val iterator = BreakIteratorCompat.getInstance()
iterator.setText(it)
AddMessageCharacterCount(iterator.countBreaks())
}
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
}
fun updateAddAMessageCount(input: CharSequence?) {
addAMessageUpdatePublisher.onNext(input ?: "")
}
private val isMeteredDisposable: Disposable = repository.isMetered.subscribe { metered ->
store.update {
it.copy(

Wyświetl plik

@ -0,0 +1,21 @@
package org.thoughtcrime.securesms.mediasend.v2.review
import org.thoughtcrime.securesms.stories.Stories
import kotlin.math.max
/**
* Manages the current character count for the add-message input.
*
* We only want to display the count if DISPLAY_COUNT or less characters remain.
* The actual count is calculated in the background by the ViewModel.
*/
@JvmInline
value class AddMessageCharacterCount(private val count: Int) {
fun getRemaining(): Int = max(Stories.MAX_CAPTION_SIZE - count, 0)
fun shouldDisplayCount(): Boolean = getRemaining() <= DISPLAY_COUNT_THRESHOLD
companion object {
private const val DISPLAY_COUNT_THRESHOLD = 50
}
}

Wyświetl plik

@ -7,6 +7,7 @@ import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.FragmentManager
import androidx.fragment.app.viewModels
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
@ -14,10 +15,8 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign
import org.signal.core.util.EditTextUtil
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.ComposeText
import org.thoughtcrime.securesms.components.InputAwareLayout
import org.thoughtcrime.securesms.components.KeyboardEntryDialogFragment
import org.thoughtcrime.securesms.components.emoji.EmojiToggle
import org.thoughtcrime.securesms.components.ViewBinderDelegate
import org.thoughtcrime.securesms.components.emoji.MediaKeyboard
import org.thoughtcrime.securesms.components.mention.MentionAnnotation
import org.thoughtcrime.securesms.conversation.ui.inlinequery.InlineQuery
@ -27,6 +26,7 @@ import org.thoughtcrime.securesms.conversation.ui.inlinequery.InlineQueryResults
import org.thoughtcrime.securesms.conversation.ui.inlinequery.InlineQueryViewModel
import org.thoughtcrime.securesms.conversation.ui.mentions.MentionsPickerFragment
import org.thoughtcrime.securesms.conversation.ui.mentions.MentionsPickerViewModel
import org.thoughtcrime.securesms.databinding.V2MediaAddMessageDialogFragmentBinding
import org.thoughtcrime.securesms.keyboard.KeyboardPage
import org.thoughtcrime.securesms.keyboard.KeyboardPagerViewModel
import org.thoughtcrime.securesms.keyvalue.SignalStore
@ -58,11 +58,8 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a
ownerProducer = { requireActivity() }
)
private lateinit var input: ComposeText
private lateinit var emojiDrawerToggle: EmojiToggle
private val binding by ViewBinderDelegate(V2MediaAddMessageDialogFragmentBinding::bind)
private lateinit var emojiDrawerStub: Stub<MediaKeyboard>
private lateinit var hud: InputAwareLayout
private lateinit var mentionsContainer: ViewGroup
private lateinit var inlineQueryResultsController: InlineQueryResultsController
private var requestedEmojiDrawer: Boolean = false
@ -79,28 +76,34 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
input = view.findViewById(R.id.add_a_message_input)
emojiDrawerStub = Stub(binding.content.emojiDrawerStub)
if (Stories.isFeatureEnabled()) {
EditTextUtil.addGraphemeClusterLimitFilter(input, Stories.MAX_BODY_SIZE)
EditTextUtil.addGraphemeClusterLimitFilter(binding.content.addAMessageInput, Stories.MAX_CAPTION_SIZE)
}
input.setText(requireArguments().getCharSequence(ARG_INITIAL_TEXT))
binding.content.addAMessageInput.addTextChangedListener(afterTextChanged = {
viewModel.updateAddAMessageCount(it)
})
binding.content.addAMessageInput.setText(requireArguments().getCharSequence(ARG_INITIAL_TEXT))
emojiDrawerToggle = view.findViewById(R.id.emoji_toggle)
emojiDrawerStub = Stub(view.findViewById(R.id.emoji_drawer_stub))
if (SignalStore.settings().isPreferSystemEmoji) {
emojiDrawerToggle.visible = false
binding.content.emojiToggle.visible = false
} else {
emojiDrawerToggle.setOnClickListener { onEmojiToggleClicked() }
binding.content.emojiToggle.setOnClickListener { onEmojiToggleClicked() }
}
hud = view.findViewById(R.id.hud)
hud.setOnClickListener { dismissAllowingStateLoss() }
binding.hud.setOnClickListener { dismissAllowingStateLoss() }
val confirm: View = view.findViewById(R.id.confirm_button)
confirm.setOnClickListener { dismissAllowingStateLoss() }
disposables += viewModel.watchAddAMessageCount().subscribe { count ->
binding.content.addAMessageLimit.visible = count.shouldDisplayCount()
binding.content.addAMessageLimit.text = count.getRemaining().toString()
}
disposables.add(
viewModel.hudCommands.observeOn(AndroidSchedulers.mainThread()).subscribe {
when (it) {
@ -120,18 +123,18 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a
super.onResume()
requestedEmojiDrawer = false
ViewUtil.focusAndShowKeyboard(input)
ViewUtil.focusAndShowKeyboard(binding.content.addAMessageInput)
}
override fun onPause() {
super.onPause()
ViewUtil.hideKeyboard(requireContext(), input)
ViewUtil.hideKeyboard(requireContext(), binding.content.addAMessageInput)
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
viewModel.setMessage(input.text)
viewModel.setMessage(binding.content.addAMessageInput.text)
}
override fun onKeyboardHidden() {
@ -151,23 +154,21 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a
super.onDestroyView()
disposables.dispose()
input.setInlineQueryChangedListener(null)
input.setMentionValidator(null)
binding.content.addAMessageInput.setInlineQueryChangedListener(null)
binding.content.addAMessageInput.setMentionValidator(null)
}
private fun initializeMentions() {
mentionsContainer = requireView().findViewById(R.id.mentions_picker_container)
inlineQueryResultsController = InlineQueryResultsController(
requireContext(),
inlineQueryViewModel,
requireView().findViewById(R.id.background_holder),
(requireView() as ViewGroup),
input,
binding.content.addAMessageInput,
viewLifecycleOwner
)
input.setInlineQueryChangedListener(object : InlineQueryChangedListener {
binding.content.addAMessageInput.setInlineQueryChangedListener(object : InlineQueryChangedListener {
override fun onQueryChanged(inlineQuery: InlineQuery) {
when (inlineQuery) {
is InlineQuery.Mention -> {
@ -196,7 +197,7 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a
disposables += inlineQueryViewModel
.selection
.observeOn(AndroidSchedulers.mainThread())
.subscribe { r -> input.replaceText(r) }
.subscribe { r -> binding.content.addAMessageInput.replaceText(r) }
val recipientId: RecipientId = viewModel.destination.getRecipientSearchKey()?.recipientId ?: return
@ -204,7 +205,7 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a
this.recipient = recipient
mentionsViewModel.onRecipientChange(recipient)
input.setMentionValidator { annotations ->
binding.content.addAMessageInput.setMentionValidator { annotations ->
if (!recipient.isPushV2Group) {
annotations
} else {
@ -221,7 +222,7 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a
}
mentionsViewModel.selectedRecipient.observe(viewLifecycleOwner) { recipient ->
input.replaceTextWithMention(recipient.getDisplayName(requireContext()), recipient.id)
binding.content.addAMessageInput.replaceTextWithMention(recipient.getDisplayName(requireContext()), recipient.id)
}
}
@ -239,17 +240,17 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a
if (!emojiDrawerStub.resolved()) {
keyboardPagerViewModel.setOnlyPage(KeyboardPage.EMOJI)
emojiDrawerStub.get().setFragmentManager(childFragmentManager)
emojiDrawerToggle.attach(emojiDrawerStub.get())
binding.content.emojiToggle.attach(emojiDrawerStub.get())
}
if (hud.currentInput == emojiDrawerStub.get()) {
if (binding.hud.currentInput == emojiDrawerStub.get()) {
requestedEmojiDrawer = false
hud.showSoftkey(input)
binding.hud.showSoftkey(binding.content.addAMessageInput)
} else {
requestedEmojiDrawer = true
hud.hideSoftkey(input) {
hud.post {
hud.show(input, emojiDrawerStub.get())
binding.hud.hideSoftkey(binding.content.addAMessageInput) {
binding.hud.post {
binding.hud.show(binding.content.addAMessageInput, emojiDrawerStub.get())
}
}
}
@ -268,11 +269,11 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a
}
private fun onEmojiSelected(emoji: String?) {
input.insertEmoji(emoji)
binding.content.addAMessageInput.insertEmoji(emoji)
}
private fun onKeyEvent(keyEvent: KeyEvent?) {
input.dispatchKeyEvent(keyEvent)
binding.content.addAMessageInput.dispatchKeyEvent(keyEvent)
}
companion object {

Wyświetl plik

@ -168,7 +168,7 @@ public final class MultiShareArgs implements Parcelable {
BreakIteratorCompat breakIteratorCompat = BreakIteratorCompat.getInstance();
breakIteratorCompat.setText(getDraftText());
if (breakIteratorCompat.countBreaks() > Stories.MAX_BODY_SIZE) {
if (breakIteratorCompat.countBreaks() > Stories.MAX_TEXT_STORY_SIZE) {
return false;
}
}

Wyświetl plik

@ -432,7 +432,7 @@ public final class MultiShareSender {
BreakIteratorCompat breakIteratorCompat = BreakIteratorCompat.getInstance();
breakIteratorCompat.setText(draftText);
String trimmed = breakIteratorCompat.take(Stories.MAX_BODY_SIZE).toString();
String trimmed = breakIteratorCompat.take(Stories.MAX_TEXT_STORY_SIZE).toString();
if (linkPreview == null) {
return trimmed;
}

Wyświetl plik

@ -47,7 +47,8 @@ object Stories {
private val TAG = Log.tag(Stories::class.java)
const val MAX_BODY_SIZE = 700
const val MAX_TEXT_STORY_SIZE = 700
const val MAX_CAPTION_SIZE = 1500
@JvmField
val MAX_VIDEO_DURATION_MILLIS = TimeUnit.SECONDS.toMillis(30)

Wyświetl plik

@ -12,7 +12,9 @@ import android.media.AudioManager
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.text.method.ScrollingMovementMethod
import android.view.GestureDetector
import android.view.GestureDetector.SimpleOnGestureListener
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import android.view.View
@ -826,9 +828,16 @@ class StoryViewerPageFragment :
}
private fun onShowCaptionOverlay(caption: TextView, largeCaption: TextView, largeCaptionOverlay: View) {
sharedViewModel.setIsChildScrolling(true)
caption.visible = false
largeCaption.visible = true
largeCaptionOverlay.visible = true
largeCaption.movementMethod = ScrollingMovementMethod()
largeCaption.scrollY = 0
largeCaption.setOnClickListener {
onHideCaptionOverlay(caption, largeCaption, largeCaptionOverlay)
}
largeCaptionOverlay.setOnClickListener {
onHideCaptionOverlay(caption, largeCaption, largeCaptionOverlay)
}
@ -839,8 +848,10 @@ class StoryViewerPageFragment :
caption.visible = true
largeCaption.visible = false
largeCaptionOverlay.visible = false
largeCaption.setOnClickListener(null)
largeCaptionOverlay.setOnClickListener(null)
viewModel.setIsDisplayingCaptionOverlay(false)
sharedViewModel.setIsChildScrolling(false)
}
private fun presentFrom(from: TextView, storyPost: StoryPost) {

Wyświetl plik

@ -25,7 +25,10 @@ data class StoryViewerPlaybackState(
) {
val hideChromeImmediate: Boolean = isRunningSharedElementAnimation
val hideChrome: Boolean = isRunningSharedElementAnimation || isUserLongTouching || isUserScrollingChild || isUserScaling
val hideChrome: Boolean = isRunningSharedElementAnimation ||
isUserLongTouching ||
(isUserScrollingChild && !isDisplayingCaptionOverlay) ||
isUserScaling
val isPaused: Boolean = !areSegmentsInitialized ||
isUserTouching ||

Wyświetl plik

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
<solid android:color="@color/core_grey_75"/>
<corners android:radius="20dp"/>
<solid android:color="@color/signal_dark_colorSurfaceVariant"/>
<corners android:radius="18dp"/>
</shape>

Wyświetl plik

@ -132,14 +132,14 @@
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
android:id="@+id/story_large_caption"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="24dp"
android:gravity="bottom"
android:textAppearance="@style/Signal.Text.Body"
android:visibility="gone"
android:scrollbars="vertical"
app:layout_constrainedHeight="true"
app:layout_constraintBottom_toTopOf="@id/story_from_barrier"
app:layout_constraintEnd_toEndOf="parent"

Wyświetl plik

@ -1,11 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<org.thoughtcrime.securesms.components.InputAwareLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:viewBindingIgnore="true"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/hud"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/v2_media_add_message_dialog_fragment_content" />
<include android:id="@+id/content" layout="@layout/v2_media_add_message_dialog_fragment_content" />
</org.thoughtcrime.securesms.components.InputAwareLayout>

Wyświetl plik

@ -1,8 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:viewBindingIgnore="true"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
@ -26,7 +25,7 @@
android:layout_height="0dp"
android:background="@drawable/rounded_rectangle_secondary_dark"
app:layout_constraintBottom_toBottomOf="@id/add_a_message_input"
app:layout_constraintEnd_toEndOf="@id/add_a_message_input"
app:layout_constraintEnd_toEndOf="@id/add_a_message_limit"
app:layout_constraintStart_toStartOf="@id/emoji_toggle"
app:layout_constraintTop_toTopOf="@id/add_a_message_input" />
@ -49,7 +48,7 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginEnd="6dp"
app:layout_goneMarginEnd="6dp"
android:layout_marginBottom="8dp"
android:background="@null"
android:hint="@string/MediaReviewFragment__add_a_message"
@ -61,11 +60,25 @@
android:paddingEnd="10dp"
android:textAppearance="@style/Signal.Text.Body"
app:layout_constraintBottom_toTopOf="@id/emoji_drawer_stub"
app:layout_constraintEnd_toStartOf="@id/confirm_button"
app:layout_constraintEnd_toStartOf="@id/add_a_message_limit"
app:layout_constraintStart_toEndOf="@id/emoji_toggle"
app:layout_constraintTop_toTopOf="@id/input_barrier"
app:layout_goneMarginStart="12dp" />
<TextView
android:id="@+id/add_a_message_limit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="6dp"
android:paddingEnd="12dp"
android:textAppearance="@style/Signal.Text.BodySmall"
android:textColor="@color/signal_colorOnSurfaceVariant"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="@id/add_a_message_input"
app:layout_constraintEnd_toStartOf="@id/confirm_button"
tools:text="50"
tools:visibility="visible" />
<androidx.appcompat.widget.AppCompatImageView
android:id="@+id/confirm_button"
android:layout_width="48dp"