kopia lustrzana https://github.com/ryukoposting/Signal-Android
Increase stories caption limit to 1500 grapheme clusters.
rodzic
654b602cef
commit
9326c1726a
|
@ -3,10 +3,8 @@ package org.thoughtcrime.securesms.components
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.lifecycle.DefaultLifecycleObserver
|
import androidx.lifecycle.DefaultLifecycleObserver
|
||||||
import androidx.lifecycle.Lifecycle
|
|
||||||
import androidx.lifecycle.LifecycleOwner
|
import androidx.lifecycle.LifecycleOwner
|
||||||
import androidx.viewbinding.ViewBinding
|
import androidx.viewbinding.ViewBinding
|
||||||
import org.whispersystems.signalservice.api.util.Preconditions
|
|
||||||
import kotlin.reflect.KProperty
|
import kotlin.reflect.KProperty
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -18,8 +16,6 @@ class ViewBinderDelegate<T : ViewBinding>(private val bindingFactory: (View) ->
|
||||||
private var binding: T? = null
|
private var binding: T? = null
|
||||||
|
|
||||||
operator fun getValue(thisRef: Fragment, property: KProperty<*>): T {
|
operator fun getValue(thisRef: Fragment, property: KProperty<*>): T {
|
||||||
Preconditions.checkState(thisRef.viewLifecycleOwner.lifecycle.currentState.isAtLeast(Lifecycle.State.CREATED))
|
|
||||||
|
|
||||||
if (binding == null) {
|
if (binding == null) {
|
||||||
thisRef.viewLifecycleOwner.lifecycle.addObserver(this@ViewBinderDelegate)
|
thisRef.viewLifecycleOwner.lifecycle.addObserver(this@ViewBinderDelegate)
|
||||||
binding = bindingFactory(thisRef.requireView())
|
binding = bindingFactory(thisRef.requireView())
|
||||||
|
|
|
@ -164,7 +164,7 @@ class MediaSelectionRepository(context: Context) {
|
||||||
} else {
|
} else {
|
||||||
val iterator = BreakIteratorCompat.getInstance()
|
val iterator = BreakIteratorCompat.getInstance()
|
||||||
iterator.setText(body)
|
iterator.setText(body)
|
||||||
iterator.take(Stories.MAX_BODY_SIZE).toString()
|
iterator.take(Stories.MAX_CAPTION_SIZE).toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,21 +5,27 @@ import android.os.Bundle
|
||||||
import androidx.lifecycle.LiveData
|
import androidx.lifecycle.LiveData
|
||||||
import androidx.lifecycle.ViewModel
|
import androidx.lifecycle.ViewModel
|
||||||
import androidx.lifecycle.ViewModelProvider
|
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.Maybe
|
||||||
import io.reactivex.rxjava3.core.Observable
|
import io.reactivex.rxjava3.core.Observable
|
||||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxjava3.disposables.Disposable
|
import io.reactivex.rxjava3.disposables.Disposable
|
||||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||||
import io.reactivex.rxjava3.kotlin.subscribeBy
|
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.BehaviorSubject
|
||||||
import io.reactivex.rxjava3.subjects.PublishSubject
|
import io.reactivex.rxjava3.subjects.PublishSubject
|
||||||
import io.reactivex.rxjava3.subjects.Subject
|
import io.reactivex.rxjava3.subjects.Subject
|
||||||
|
import org.signal.core.util.BreakIteratorCompat
|
||||||
import org.thoughtcrime.securesms.components.mention.MentionAnnotation
|
import org.thoughtcrime.securesms.components.mention.MentionAnnotation
|
||||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
|
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
|
||||||
import org.thoughtcrime.securesms.conversation.MessageSendType
|
import org.thoughtcrime.securesms.conversation.MessageSendType
|
||||||
import org.thoughtcrime.securesms.mediasend.Media
|
import org.thoughtcrime.securesms.mediasend.Media
|
||||||
import org.thoughtcrime.securesms.mediasend.MediaSendActivityResult
|
import org.thoughtcrime.securesms.mediasend.MediaSendActivityResult
|
||||||
import org.thoughtcrime.securesms.mediasend.VideoEditorFragment
|
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.MediaConstraints
|
||||||
import org.thoughtcrime.securesms.mms.SentMediaQuality
|
import org.thoughtcrime.securesms.mms.SentMediaQuality
|
||||||
import org.thoughtcrime.securesms.recipients.Recipient
|
import org.thoughtcrime.securesms.recipients.Recipient
|
||||||
|
@ -53,6 +59,8 @@ class MediaSelectionViewModel(
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private val addAMessageUpdatePublisher = BehaviorProcessor.create<CharSequence>()
|
||||||
|
|
||||||
val isContactSelectionRequired = destination == MediaSelectionDestination.ChooseAfterMediaSelection
|
val isContactSelectionRequired = destination == MediaSelectionDestination.ChooseAfterMediaSelection
|
||||||
|
|
||||||
val state: LiveData<MediaSelectionState> = store.stateLiveData
|
val state: LiveData<MediaSelectionState> = store.stateLiveData
|
||||||
|
@ -64,6 +72,22 @@ class MediaSelectionViewModel(
|
||||||
|
|
||||||
private val disposables = CompositeDisposable()
|
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 ->
|
private val isMeteredDisposable: Disposable = repository.isMetered.subscribe { metered ->
|
||||||
store.update {
|
store.update {
|
||||||
it.copy(
|
it.copy(
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import android.view.KeyEvent
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
import androidx.core.widget.addTextChangedListener
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
import androidx.fragment.app.viewModels
|
import androidx.fragment.app.viewModels
|
||||||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||||
|
@ -14,10 +15,8 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||||
import org.signal.core.util.EditTextUtil
|
import org.signal.core.util.EditTextUtil
|
||||||
import org.thoughtcrime.securesms.R
|
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.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.emoji.MediaKeyboard
|
||||||
import org.thoughtcrime.securesms.components.mention.MentionAnnotation
|
import org.thoughtcrime.securesms.components.mention.MentionAnnotation
|
||||||
import org.thoughtcrime.securesms.conversation.ui.inlinequery.InlineQuery
|
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.inlinequery.InlineQueryViewModel
|
||||||
import org.thoughtcrime.securesms.conversation.ui.mentions.MentionsPickerFragment
|
import org.thoughtcrime.securesms.conversation.ui.mentions.MentionsPickerFragment
|
||||||
import org.thoughtcrime.securesms.conversation.ui.mentions.MentionsPickerViewModel
|
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.KeyboardPage
|
||||||
import org.thoughtcrime.securesms.keyboard.KeyboardPagerViewModel
|
import org.thoughtcrime.securesms.keyboard.KeyboardPagerViewModel
|
||||||
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
import org.thoughtcrime.securesms.keyvalue.SignalStore
|
||||||
|
@ -58,11 +58,8 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a
|
||||||
ownerProducer = { requireActivity() }
|
ownerProducer = { requireActivity() }
|
||||||
)
|
)
|
||||||
|
|
||||||
private lateinit var input: ComposeText
|
private val binding by ViewBinderDelegate(V2MediaAddMessageDialogFragmentBinding::bind)
|
||||||
private lateinit var emojiDrawerToggle: EmojiToggle
|
|
||||||
private lateinit var emojiDrawerStub: Stub<MediaKeyboard>
|
private lateinit var emojiDrawerStub: Stub<MediaKeyboard>
|
||||||
private lateinit var hud: InputAwareLayout
|
|
||||||
private lateinit var mentionsContainer: ViewGroup
|
|
||||||
private lateinit var inlineQueryResultsController: InlineQueryResultsController
|
private lateinit var inlineQueryResultsController: InlineQueryResultsController
|
||||||
|
|
||||||
private var requestedEmojiDrawer: Boolean = false
|
private var requestedEmojiDrawer: Boolean = false
|
||||||
|
@ -79,28 +76,34 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||||
input = view.findViewById(R.id.add_a_message_input)
|
emojiDrawerStub = Stub(binding.content.emojiDrawerStub)
|
||||||
|
|
||||||
if (Stories.isFeatureEnabled()) {
|
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) {
|
if (SignalStore.settings().isPreferSystemEmoji) {
|
||||||
emojiDrawerToggle.visible = false
|
binding.content.emojiToggle.visible = false
|
||||||
} else {
|
} else {
|
||||||
emojiDrawerToggle.setOnClickListener { onEmojiToggleClicked() }
|
binding.content.emojiToggle.setOnClickListener { onEmojiToggleClicked() }
|
||||||
}
|
}
|
||||||
|
|
||||||
hud = view.findViewById(R.id.hud)
|
binding.hud.setOnClickListener { dismissAllowingStateLoss() }
|
||||||
hud.setOnClickListener { dismissAllowingStateLoss() }
|
|
||||||
|
|
||||||
val confirm: View = view.findViewById(R.id.confirm_button)
|
val confirm: View = view.findViewById(R.id.confirm_button)
|
||||||
confirm.setOnClickListener { dismissAllowingStateLoss() }
|
confirm.setOnClickListener { dismissAllowingStateLoss() }
|
||||||
|
|
||||||
|
disposables += viewModel.watchAddAMessageCount().subscribe { count ->
|
||||||
|
binding.content.addAMessageLimit.visible = count.shouldDisplayCount()
|
||||||
|
binding.content.addAMessageLimit.text = count.getRemaining().toString()
|
||||||
|
}
|
||||||
|
|
||||||
disposables.add(
|
disposables.add(
|
||||||
viewModel.hudCommands.observeOn(AndroidSchedulers.mainThread()).subscribe {
|
viewModel.hudCommands.observeOn(AndroidSchedulers.mainThread()).subscribe {
|
||||||
when (it) {
|
when (it) {
|
||||||
|
@ -120,18 +123,18 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a
|
||||||
super.onResume()
|
super.onResume()
|
||||||
|
|
||||||
requestedEmojiDrawer = false
|
requestedEmojiDrawer = false
|
||||||
ViewUtil.focusAndShowKeyboard(input)
|
ViewUtil.focusAndShowKeyboard(binding.content.addAMessageInput)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onPause() {
|
override fun onPause() {
|
||||||
super.onPause()
|
super.onPause()
|
||||||
|
|
||||||
ViewUtil.hideKeyboard(requireContext(), input)
|
ViewUtil.hideKeyboard(requireContext(), binding.content.addAMessageInput)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDismiss(dialog: DialogInterface) {
|
override fun onDismiss(dialog: DialogInterface) {
|
||||||
super.onDismiss(dialog)
|
super.onDismiss(dialog)
|
||||||
viewModel.setMessage(input.text)
|
viewModel.setMessage(binding.content.addAMessageInput.text)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onKeyboardHidden() {
|
override fun onKeyboardHidden() {
|
||||||
|
@ -151,23 +154,21 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
disposables.dispose()
|
disposables.dispose()
|
||||||
|
|
||||||
input.setInlineQueryChangedListener(null)
|
binding.content.addAMessageInput.setInlineQueryChangedListener(null)
|
||||||
input.setMentionValidator(null)
|
binding.content.addAMessageInput.setMentionValidator(null)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun initializeMentions() {
|
private fun initializeMentions() {
|
||||||
mentionsContainer = requireView().findViewById(R.id.mentions_picker_container)
|
|
||||||
|
|
||||||
inlineQueryResultsController = InlineQueryResultsController(
|
inlineQueryResultsController = InlineQueryResultsController(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
inlineQueryViewModel,
|
inlineQueryViewModel,
|
||||||
requireView().findViewById(R.id.background_holder),
|
requireView().findViewById(R.id.background_holder),
|
||||||
(requireView() as ViewGroup),
|
(requireView() as ViewGroup),
|
||||||
input,
|
binding.content.addAMessageInput,
|
||||||
viewLifecycleOwner
|
viewLifecycleOwner
|
||||||
)
|
)
|
||||||
|
|
||||||
input.setInlineQueryChangedListener(object : InlineQueryChangedListener {
|
binding.content.addAMessageInput.setInlineQueryChangedListener(object : InlineQueryChangedListener {
|
||||||
override fun onQueryChanged(inlineQuery: InlineQuery) {
|
override fun onQueryChanged(inlineQuery: InlineQuery) {
|
||||||
when (inlineQuery) {
|
when (inlineQuery) {
|
||||||
is InlineQuery.Mention -> {
|
is InlineQuery.Mention -> {
|
||||||
|
@ -196,7 +197,7 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a
|
||||||
disposables += inlineQueryViewModel
|
disposables += inlineQueryViewModel
|
||||||
.selection
|
.selection
|
||||||
.observeOn(AndroidSchedulers.mainThread())
|
.observeOn(AndroidSchedulers.mainThread())
|
||||||
.subscribe { r -> input.replaceText(r) }
|
.subscribe { r -> binding.content.addAMessageInput.replaceText(r) }
|
||||||
|
|
||||||
val recipientId: RecipientId = viewModel.destination.getRecipientSearchKey()?.recipientId ?: return
|
val recipientId: RecipientId = viewModel.destination.getRecipientSearchKey()?.recipientId ?: return
|
||||||
|
|
||||||
|
@ -204,7 +205,7 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a
|
||||||
this.recipient = recipient
|
this.recipient = recipient
|
||||||
mentionsViewModel.onRecipientChange(recipient)
|
mentionsViewModel.onRecipientChange(recipient)
|
||||||
|
|
||||||
input.setMentionValidator { annotations ->
|
binding.content.addAMessageInput.setMentionValidator { annotations ->
|
||||||
if (!recipient.isPushV2Group) {
|
if (!recipient.isPushV2Group) {
|
||||||
annotations
|
annotations
|
||||||
} else {
|
} else {
|
||||||
|
@ -221,7 +222,7 @@ class AddMessageDialogFragment : KeyboardEntryDialogFragment(R.layout.v2_media_a
|
||||||
}
|
}
|
||||||
|
|
||||||
mentionsViewModel.selectedRecipient.observe(viewLifecycleOwner) { recipient ->
|
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()) {
|
if (!emojiDrawerStub.resolved()) {
|
||||||
keyboardPagerViewModel.setOnlyPage(KeyboardPage.EMOJI)
|
keyboardPagerViewModel.setOnlyPage(KeyboardPage.EMOJI)
|
||||||
emojiDrawerStub.get().setFragmentManager(childFragmentManager)
|
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
|
requestedEmojiDrawer = false
|
||||||
hud.showSoftkey(input)
|
binding.hud.showSoftkey(binding.content.addAMessageInput)
|
||||||
} else {
|
} else {
|
||||||
requestedEmojiDrawer = true
|
requestedEmojiDrawer = true
|
||||||
hud.hideSoftkey(input) {
|
binding.hud.hideSoftkey(binding.content.addAMessageInput) {
|
||||||
hud.post {
|
binding.hud.post {
|
||||||
hud.show(input, emojiDrawerStub.get())
|
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?) {
|
private fun onEmojiSelected(emoji: String?) {
|
||||||
input.insertEmoji(emoji)
|
binding.content.addAMessageInput.insertEmoji(emoji)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onKeyEvent(keyEvent: KeyEvent?) {
|
private fun onKeyEvent(keyEvent: KeyEvent?) {
|
||||||
input.dispatchKeyEvent(keyEvent)
|
binding.content.addAMessageInput.dispatchKeyEvent(keyEvent)
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
|
@ -168,7 +168,7 @@ public final class MultiShareArgs implements Parcelable {
|
||||||
BreakIteratorCompat breakIteratorCompat = BreakIteratorCompat.getInstance();
|
BreakIteratorCompat breakIteratorCompat = BreakIteratorCompat.getInstance();
|
||||||
breakIteratorCompat.setText(getDraftText());
|
breakIteratorCompat.setText(getDraftText());
|
||||||
|
|
||||||
if (breakIteratorCompat.countBreaks() > Stories.MAX_BODY_SIZE) {
|
if (breakIteratorCompat.countBreaks() > Stories.MAX_TEXT_STORY_SIZE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -432,7 +432,7 @@ public final class MultiShareSender {
|
||||||
BreakIteratorCompat breakIteratorCompat = BreakIteratorCompat.getInstance();
|
BreakIteratorCompat breakIteratorCompat = BreakIteratorCompat.getInstance();
|
||||||
breakIteratorCompat.setText(draftText);
|
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) {
|
if (linkPreview == null) {
|
||||||
return trimmed;
|
return trimmed;
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,8 @@ object Stories {
|
||||||
|
|
||||||
private val TAG = Log.tag(Stories::class.java)
|
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
|
@JvmField
|
||||||
val MAX_VIDEO_DURATION_MILLIS = TimeUnit.SECONDS.toMillis(30)
|
val MAX_VIDEO_DURATION_MILLIS = TimeUnit.SECONDS.toMillis(30)
|
||||||
|
|
|
@ -12,7 +12,9 @@ import android.media.AudioManager
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
|
import android.text.method.ScrollingMovementMethod
|
||||||
import android.view.GestureDetector
|
import android.view.GestureDetector
|
||||||
|
import android.view.GestureDetector.SimpleOnGestureListener
|
||||||
import android.view.MotionEvent
|
import android.view.MotionEvent
|
||||||
import android.view.ScaleGestureDetector
|
import android.view.ScaleGestureDetector
|
||||||
import android.view.View
|
import android.view.View
|
||||||
|
@ -826,9 +828,16 @@ class StoryViewerPageFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onShowCaptionOverlay(caption: TextView, largeCaption: TextView, largeCaptionOverlay: View) {
|
private fun onShowCaptionOverlay(caption: TextView, largeCaption: TextView, largeCaptionOverlay: View) {
|
||||||
|
sharedViewModel.setIsChildScrolling(true)
|
||||||
|
|
||||||
caption.visible = false
|
caption.visible = false
|
||||||
largeCaption.visible = true
|
largeCaption.visible = true
|
||||||
largeCaptionOverlay.visible = true
|
largeCaptionOverlay.visible = true
|
||||||
|
largeCaption.movementMethod = ScrollingMovementMethod()
|
||||||
|
largeCaption.scrollY = 0
|
||||||
|
largeCaption.setOnClickListener {
|
||||||
|
onHideCaptionOverlay(caption, largeCaption, largeCaptionOverlay)
|
||||||
|
}
|
||||||
largeCaptionOverlay.setOnClickListener {
|
largeCaptionOverlay.setOnClickListener {
|
||||||
onHideCaptionOverlay(caption, largeCaption, largeCaptionOverlay)
|
onHideCaptionOverlay(caption, largeCaption, largeCaptionOverlay)
|
||||||
}
|
}
|
||||||
|
@ -839,8 +848,10 @@ class StoryViewerPageFragment :
|
||||||
caption.visible = true
|
caption.visible = true
|
||||||
largeCaption.visible = false
|
largeCaption.visible = false
|
||||||
largeCaptionOverlay.visible = false
|
largeCaptionOverlay.visible = false
|
||||||
|
largeCaption.setOnClickListener(null)
|
||||||
largeCaptionOverlay.setOnClickListener(null)
|
largeCaptionOverlay.setOnClickListener(null)
|
||||||
viewModel.setIsDisplayingCaptionOverlay(false)
|
viewModel.setIsDisplayingCaptionOverlay(false)
|
||||||
|
sharedViewModel.setIsChildScrolling(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun presentFrom(from: TextView, storyPost: StoryPost) {
|
private fun presentFrom(from: TextView, storyPost: StoryPost) {
|
||||||
|
|
|
@ -25,7 +25,10 @@ data class StoryViewerPlaybackState(
|
||||||
) {
|
) {
|
||||||
val hideChromeImmediate: Boolean = isRunningSharedElementAnimation
|
val hideChromeImmediate: Boolean = isRunningSharedElementAnimation
|
||||||
|
|
||||||
val hideChrome: Boolean = isRunningSharedElementAnimation || isUserLongTouching || isUserScrollingChild || isUserScaling
|
val hideChrome: Boolean = isRunningSharedElementAnimation ||
|
||||||
|
isUserLongTouching ||
|
||||||
|
(isUserScrollingChild && !isDisplayingCaptionOverlay) ||
|
||||||
|
isUserScaling
|
||||||
|
|
||||||
val isPaused: Boolean = !areSegmentsInitialized ||
|
val isPaused: Boolean = !areSegmentsInitialized ||
|
||||||
isUserTouching ||
|
isUserTouching ||
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
|
<shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" >
|
||||||
<solid android:color="@color/core_grey_75"/>
|
<solid android:color="@color/signal_dark_colorSurfaceVariant"/>
|
||||||
<corners android:radius="20dp"/>
|
<corners android:radius="18dp"/>
|
||||||
</shape>
|
</shape>
|
|
@ -132,14 +132,14 @@
|
||||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||||
android:id="@+id/story_large_caption"
|
android:id="@+id/story_large_caption"
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="0dp"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="24dp"
|
android:layout_marginTop="24dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
android:layout_marginBottom="24dp"
|
android:layout_marginBottom="24dp"
|
||||||
android:gravity="bottom"
|
|
||||||
android:textAppearance="@style/Signal.Text.Body"
|
android:textAppearance="@style/Signal.Text.Body"
|
||||||
android:visibility="gone"
|
android:visibility="gone"
|
||||||
|
android:scrollbars="vertical"
|
||||||
app:layout_constrainedHeight="true"
|
app:layout_constrainedHeight="true"
|
||||||
app:layout_constraintBottom_toTopOf="@id/story_from_barrier"
|
app:layout_constraintBottom_toTopOf="@id/story_from_barrier"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
|
|
@ -1,11 +1,8 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<org.thoughtcrime.securesms.components.InputAwareLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<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:id="@+id/hud"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="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>
|
</org.thoughtcrime.securesms.components.InputAwareLayout>
|
|
@ -1,8 +1,7 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<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:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent">
|
android:layout_height="match_parent">
|
||||||
|
|
||||||
|
@ -26,7 +25,7 @@
|
||||||
android:layout_height="0dp"
|
android:layout_height="0dp"
|
||||||
android:background="@drawable/rounded_rectangle_secondary_dark"
|
android:background="@drawable/rounded_rectangle_secondary_dark"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/add_a_message_input"
|
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_constraintStart_toStartOf="@id/emoji_toggle"
|
||||||
app:layout_constraintTop_toTopOf="@id/add_a_message_input" />
|
app:layout_constraintTop_toTopOf="@id/add_a_message_input" />
|
||||||
|
|
||||||
|
@ -49,7 +48,7 @@
|
||||||
android:layout_width="0dp"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:layout_marginEnd="6dp"
|
app:layout_goneMarginEnd="6dp"
|
||||||
android:layout_marginBottom="8dp"
|
android:layout_marginBottom="8dp"
|
||||||
android:background="@null"
|
android:background="@null"
|
||||||
android:hint="@string/MediaReviewFragment__add_a_message"
|
android:hint="@string/MediaReviewFragment__add_a_message"
|
||||||
|
@ -61,11 +60,25 @@
|
||||||
android:paddingEnd="10dp"
|
android:paddingEnd="10dp"
|
||||||
android:textAppearance="@style/Signal.Text.Body"
|
android:textAppearance="@style/Signal.Text.Body"
|
||||||
app:layout_constraintBottom_toTopOf="@id/emoji_drawer_stub"
|
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_constraintStart_toEndOf="@id/emoji_toggle"
|
||||||
app:layout_constraintTop_toTopOf="@id/input_barrier"
|
app:layout_constraintTop_toTopOf="@id/input_barrier"
|
||||||
app:layout_goneMarginStart="12dp" />
|
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
|
<androidx.appcompat.widget.AppCompatImageView
|
||||||
android:id="@+id/confirm_button"
|
android:id="@+id/confirm_button"
|
||||||
android:layout_width="48dp"
|
android:layout_width="48dp"
|
||||||
|
|
Ładowanie…
Reference in New Issue