Add new story send final screen.
This commit is contained in:
parent
3c78d8619a
commit
87cb2d6bf8
18 changed files with 282 additions and 468 deletions
|
@ -376,6 +376,11 @@
|
|||
android:windowSoftInputMode="stateAlwaysHidden|adjustNothing"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" />
|
||||
|
||||
<activity android:name=".mediasend.v2.stories.StoriesMultiselectForwardActivity"
|
||||
android:theme="@style/Signal.DayNight.NoActionBar"
|
||||
android:windowSoftInputMode="stateAlwaysHidden|adjustNothing"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" />
|
||||
|
||||
<activity android:name=".PassphraseChangeActivity"
|
||||
android:label="@string/AndroidManifest__change_passphrase"
|
||||
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
|
||||
|
|
|
@ -119,6 +119,14 @@ object ContactSearchItems {
|
|||
}
|
||||
}
|
||||
|
||||
override fun bindAvatar(model: StoryModel) {
|
||||
if (model.story.recipient.isMyStory) {
|
||||
avatar.setAvatarUsingProfile(Recipient.self())
|
||||
} else {
|
||||
super.bindAvatar(model)
|
||||
}
|
||||
}
|
||||
|
||||
override fun bindLongPress(model: StoryModel) {
|
||||
itemView.setOnLongClickListener {
|
||||
val actions: List<ActionItem> = when {
|
||||
|
@ -216,14 +224,18 @@ object ContactSearchItems {
|
|||
}
|
||||
|
||||
name.setText(getRecipient(model))
|
||||
avatar.setAvatar(getRecipient(model))
|
||||
badge.setBadgeFromRecipient(getRecipient(model))
|
||||
|
||||
bindAvatar(model)
|
||||
bindNumberField(model)
|
||||
bindLabelField(model)
|
||||
bindSmsTagField(model)
|
||||
}
|
||||
|
||||
protected open fun bindAvatar(model: T) {
|
||||
avatar.setAvatar(getRecipient(model))
|
||||
}
|
||||
|
||||
protected open fun bindNumberField(model: T) {
|
||||
number.visible = getRecipient(model).isGroup
|
||||
if (getRecipient(model).isGroup) {
|
||||
|
|
|
@ -12,7 +12,7 @@ import org.thoughtcrime.securesms.components.FragmentWrapperActivity
|
|||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
|
||||
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragment.Companion.RESULT_SELECTION
|
||||
|
||||
class MultiselectForwardActivity : FragmentWrapperActivity(), MultiselectForwardFragment.Callback {
|
||||
open class MultiselectForwardActivity : FragmentWrapperActivity(), MultiselectForwardFragment.Callback, SearchConfigurationProvider {
|
||||
|
||||
companion object {
|
||||
private const val ARGS = "args"
|
||||
|
|
|
@ -119,6 +119,7 @@ class MultiselectForwardFragment :
|
|||
disposables.bindTo(viewLifecycleOwner.lifecycle)
|
||||
|
||||
contactFilterView = view.findViewById(R.id.contact_filter_edit_text)
|
||||
contactFilterView.visible = args.isSearchEnabled
|
||||
|
||||
contactFilterView.setOnSearchInputFocusChangedListener { _, hasFocus ->
|
||||
if (hasFocus) {
|
||||
|
|
|
@ -44,7 +44,8 @@ data class MultiselectForwardFragmentArgs @JvmOverloads constructor(
|
|||
val forceSelectionOnly: Boolean = false,
|
||||
val selectSingleRecipient: Boolean = false,
|
||||
@ColorInt val sendButtonTint: Int = -1,
|
||||
val storySendRequirements: Stories.MediaTransform.SendRequirements = Stories.MediaTransform.SendRequirements.CAN_NOT_SEND
|
||||
val storySendRequirements: Stories.MediaTransform.SendRequirements = Stories.MediaTransform.SendRequirements.CAN_NOT_SEND,
|
||||
val isSearchEnabled: Boolean = true
|
||||
) : Parcelable {
|
||||
|
||||
fun withSendButtonTint(@ColorInt sendButtonTint: Int) = copy(sendButtonTint = sendButtonTint)
|
||||
|
|
|
@ -13,7 +13,6 @@ import androidx.appcompat.app.AppCompatDelegate
|
|||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import androidx.constraintlayout.widget.ConstraintSet
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.navigation.Navigation
|
||||
import androidx.navigation.fragment.NavHostFragment
|
||||
|
@ -25,11 +24,8 @@ import org.signal.core.util.logging.Log
|
|||
import org.thoughtcrime.securesms.PassphraseRequiredActivity
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.emoji.EmojiEventListener
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchConfiguration
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchState
|
||||
import org.thoughtcrime.securesms.conversation.MessageSendType
|
||||
import org.thoughtcrime.securesms.conversation.mutiselect.forward.SearchConfigurationProvider
|
||||
import org.thoughtcrime.securesms.keyboard.emoji.EmojiKeyboardPageFragment
|
||||
import org.thoughtcrime.securesms.keyboard.emoji.search.EmojiSearchFragment
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewUtil
|
||||
|
@ -49,8 +45,7 @@ class MediaSelectionActivity :
|
|||
MediaReviewFragment.Callback,
|
||||
EmojiKeyboardPageFragment.Callback,
|
||||
EmojiEventListener,
|
||||
EmojiSearchFragment.Callback,
|
||||
SearchConfigurationProvider {
|
||||
EmojiSearchFragment.Callback {
|
||||
|
||||
private var animateInShadowLayerValueAnimator: ValueAnimator? = null
|
||||
private var animateInTextColorValueAnimator: ValueAnimator? = null
|
||||
|
@ -311,24 +306,6 @@ class MediaSelectionActivity :
|
|||
viewModel.sendCommand(HudCommand.CloseEmojiSearch)
|
||||
}
|
||||
|
||||
override fun getSearchConfiguration(fragmentManager: FragmentManager, contactSearchState: ContactSearchState): ContactSearchConfiguration? {
|
||||
return if (isStory) {
|
||||
ContactSearchConfiguration.build {
|
||||
query = contactSearchState.query
|
||||
|
||||
addSection(
|
||||
ContactSearchConfiguration.Section.Stories(
|
||||
groupStories = contactSearchState.groupStories,
|
||||
includeHeader = true,
|
||||
headerAction = Stories.getHeaderAction(fragmentManager)
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
private inner class OnBackPressed : OnBackPressedCallback(true) {
|
||||
override fun handleOnBackPressed() {
|
||||
val navController = Navigation.findNavController(this@MediaSelectionActivity, R.id.fragment_container)
|
||||
|
|
|
@ -37,6 +37,7 @@ import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionNavigator.Companion
|
|||
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionState
|
||||
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionViewModel
|
||||
import org.thoughtcrime.securesms.mediasend.v2.MediaValidator
|
||||
import org.thoughtcrime.securesms.mediasend.v2.stories.StoriesMultiselectForwardActivity
|
||||
import org.thoughtcrime.securesms.mms.SentMediaQuality
|
||||
import org.thoughtcrime.securesms.permissions.Permissions
|
||||
import org.thoughtcrime.securesms.util.MediaUtil
|
||||
|
@ -137,7 +138,16 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment) {
|
|||
sharedViewModel.sendCommand(HudCommand.SaveMedia)
|
||||
}
|
||||
|
||||
val recipientSelectionLauncher = registerForActivityResult(MultiselectForwardActivity.SelectionContract()) { keys ->
|
||||
val multiselectContract = MultiselectForwardActivity.SelectionContract()
|
||||
val storiesContract = StoriesMultiselectForwardActivity.SelectionContract()
|
||||
|
||||
val multiselectLauncher = registerForActivityResult(multiselectContract) { keys ->
|
||||
if (keys.isNotEmpty()) {
|
||||
performSend(keys)
|
||||
}
|
||||
}
|
||||
|
||||
val storiesLauncher = registerForActivityResult(storiesContract) { keys ->
|
||||
if (keys.isNotEmpty()) {
|
||||
performSend(keys)
|
||||
}
|
||||
|
@ -148,9 +158,16 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment) {
|
|||
val args = MultiselectForwardFragmentArgs(
|
||||
false,
|
||||
title = R.string.MediaReviewFragment__send_to,
|
||||
storySendRequirements = sharedViewModel.getStorySendRequirements()
|
||||
storySendRequirements = sharedViewModel.getStorySendRequirements(),
|
||||
isSearchEnabled = !sharedViewModel.isStory()
|
||||
)
|
||||
recipientSelectionLauncher.launch(args)
|
||||
|
||||
if (sharedViewModel.isStory()) {
|
||||
val previews = sharedViewModel.state.value?.selectedMedia?.take(2)?.map { it.uri } ?: emptyList()
|
||||
storiesLauncher.launch(StoriesMultiselectForwardActivity.Args(args, previews))
|
||||
} else {
|
||||
multiselectLauncher.launch(args)
|
||||
}
|
||||
} else {
|
||||
performSend()
|
||||
}
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
package org.thoughtcrime.securesms.mediasend.v2.stories
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import android.os.Parcelable
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import androidx.activity.result.contract.ActivityResultContract
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import com.bumptech.glide.Glide
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchConfiguration
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchState
|
||||
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardActivity
|
||||
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs
|
||||
import org.thoughtcrime.securesms.mms.DecryptableStreamUriLoader
|
||||
import org.thoughtcrime.securesms.stories.Stories
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
|
||||
class StoriesMultiselectForwardActivity : MultiselectForwardActivity() {
|
||||
|
||||
companion object {
|
||||
private const val PREVIEW_MEDIA = "preview_media"
|
||||
}
|
||||
|
||||
override val contentViewId: Int = R.layout.stories_multiselect_forward_activity
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
|
||||
super.onCreate(savedInstanceState, ready)
|
||||
|
||||
val preview1View: ImageView = findViewById(R.id.preview_media_1)
|
||||
val preview2View: ImageView = findViewById(R.id.preview_media_2)
|
||||
val previewMedia: List<Uri> = intent.getParcelableArrayListExtra(PREVIEW_MEDIA)!!
|
||||
|
||||
preview1View.visible = previewMedia.isNotEmpty()
|
||||
preview2View.visible = previewMedia.size > 1
|
||||
|
||||
if (previewMedia.isNotEmpty()) {
|
||||
Glide.with(this)
|
||||
.load(DecryptableStreamUriLoader.DecryptableUri(previewMedia.first()))
|
||||
.into(preview1View)
|
||||
}
|
||||
|
||||
if (previewMedia.size > 1) {
|
||||
Glide.with(this).load(DecryptableStreamUriLoader.DecryptableUri(previewMedia[1])).into(preview2View)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getSearchConfiguration(fragmentManager: FragmentManager, contactSearchState: ContactSearchState): ContactSearchConfiguration? {
|
||||
return ContactSearchConfiguration.build {
|
||||
query = contactSearchState.query
|
||||
|
||||
addSection(
|
||||
ContactSearchConfiguration.Section.Stories(
|
||||
groupStories = contactSearchState.groupStories,
|
||||
includeHeader = true,
|
||||
headerAction = Stories.getHeaderAction(fragmentManager)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("WrongViewCast")
|
||||
override fun getContainer(): ViewGroup {
|
||||
return findViewById(R.id.content)
|
||||
}
|
||||
|
||||
class SelectionContract : ActivityResultContract<Args, List<ContactSearchKey.RecipientSearchKey>>() {
|
||||
|
||||
private val multiselectContract = MultiselectForwardActivity.SelectionContract()
|
||||
|
||||
override fun createIntent(context: Context, input: Args): Intent {
|
||||
return multiselectContract.createIntent(context, input.multiselectForwardFragmentArgs)
|
||||
.setClass(context, StoriesMultiselectForwardActivity::class.java)
|
||||
.putExtra(PREVIEW_MEDIA, ArrayList(input.previews))
|
||||
}
|
||||
|
||||
override fun parseResult(resultCode: Int, intent: Intent?): List<ContactSearchKey.RecipientSearchKey> {
|
||||
return multiselectContract.parseResult(resultCode, intent)
|
||||
}
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
class Args(
|
||||
val multiselectForwardFragmentArgs: MultiselectForwardFragmentArgs,
|
||||
val previews: List<Uri>
|
||||
) : Parcelable
|
||||
}
|
|
@ -14,16 +14,19 @@ import androidx.navigation.fragment.findNavController
|
|||
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
|
||||
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewRepository
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel
|
||||
import org.thoughtcrime.securesms.mediasend.v2.HudCommand
|
||||
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionViewModel
|
||||
import org.thoughtcrime.securesms.mediasend.v2.stories.StoriesMultiselectForwardActivity
|
||||
import org.thoughtcrime.securesms.mediasend.v2.text.send.TextStoryPostSendRepository
|
||||
import org.thoughtcrime.securesms.mediasend.v2.text.send.TextStoryPostSendResult
|
||||
import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet
|
||||
import org.thoughtcrime.securesms.stories.Stories
|
||||
import org.thoughtcrime.securesms.stories.StoryTextPostView
|
||||
import org.thoughtcrime.securesms.util.LifecycleDisposable
|
||||
import org.thoughtcrime.securesms.util.navigation.safeNavigate
|
||||
import org.thoughtcrime.securesms.util.visible
|
||||
|
||||
class TextStoryPostCreationFragment : Fragment(R.layout.stories_text_post_creation_fragment), TextStoryPostTextEntryFragment.Callback, SafetyNumberBottomSheet.Callbacks {
|
||||
|
||||
|
@ -31,6 +34,7 @@ class TextStoryPostCreationFragment : Fragment(R.layout.stories_text_post_creati
|
|||
private lateinit var backgroundButton: AppCompatImageView
|
||||
private lateinit var send: View
|
||||
private lateinit var storyTextPostView: StoryTextPostView
|
||||
private lateinit var sendInProgressCard: View
|
||||
|
||||
private val sharedViewModel: MediaSelectionViewModel by viewModels(
|
||||
ownerProducer = {
|
||||
|
@ -65,6 +69,7 @@ class TextStoryPostCreationFragment : Fragment(R.layout.stories_text_post_creati
|
|||
backgroundButton = view.findViewById(R.id.background_selector)
|
||||
send = view.findViewById(R.id.send)
|
||||
storyTextPostView = view.findViewById(R.id.story_text_post)
|
||||
sendInProgressCard = view.findViewById(R.id.send_in_progress_indicator)
|
||||
|
||||
val backgroundProtection: View = view.findViewById(R.id.background_protection)
|
||||
val addLinkProtection: View = view.findViewById(R.id.add_link_protection)
|
||||
|
@ -120,7 +125,19 @@ class TextStoryPostCreationFragment : Fragment(R.layout.stories_text_post_creati
|
|||
viewModel.setLinkPreview("")
|
||||
}
|
||||
|
||||
val launcher = registerForActivityResult(StoriesMultiselectForwardActivity.SelectionContract()) {
|
||||
if (it.isNotEmpty()) {
|
||||
performSend(it.toSet())
|
||||
} else {
|
||||
send.isClickable = true
|
||||
sendInProgressCard.visible = false
|
||||
}
|
||||
}
|
||||
|
||||
send.setOnClickListener {
|
||||
send.isClickable = false
|
||||
sendInProgressCard.visible = true
|
||||
|
||||
storyTextPostView.hideCloseButton()
|
||||
|
||||
val contacts = (sharedViewModel.destination.getRecipientSearchKeyList() + sharedViewModel.destination.getRecipientSearchKey())
|
||||
|
@ -128,10 +145,20 @@ class TextStoryPostCreationFragment : Fragment(R.layout.stories_text_post_creati
|
|||
.toSet()
|
||||
|
||||
if (contacts.isEmpty()) {
|
||||
viewModel.setBitmap(storyTextPostView.drawToBitmap())
|
||||
findNavController().safeNavigate(R.id.action_textStoryPostCreationFragment_to_textStoryPostSendFragment)
|
||||
val bitmap = storyTextPostView.drawToBitmap()
|
||||
viewModel.compressToBlob(bitmap).observeOn(AndroidSchedulers.mainThread()).subscribe { uri ->
|
||||
launcher.launch(
|
||||
StoriesMultiselectForwardActivity.Args(
|
||||
MultiselectForwardFragmentArgs(
|
||||
canSendToNonPush = false,
|
||||
storySendRequirements = Stories.MediaTransform.SendRequirements.VALID_DURATION,
|
||||
isSearchEnabled = false
|
||||
),
|
||||
listOf(uri)
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
send.isClickable = false
|
||||
performSend(contacts)
|
||||
}
|
||||
}
|
||||
|
@ -166,6 +193,8 @@ class TextStoryPostCreationFragment : Fragment(R.layout.stories_text_post_creati
|
|||
}
|
||||
is TextStoryPostSendResult.UntrustedRecordsError -> {
|
||||
send.isClickable = true
|
||||
sendInProgressCard.visible = false
|
||||
|
||||
SafetyNumberBottomSheet
|
||||
.forIdentityRecordsAndDestinations(result.untrustedRecords, contacts.toList())
|
||||
.show(childFragmentManager)
|
||||
|
|
|
@ -2,6 +2,7 @@ package org.thoughtcrime.securesms.mediasend.v2.text
|
|||
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.Typeface
|
||||
import android.net.Uri
|
||||
import android.os.Bundle
|
||||
import androidx.annotation.ColorInt
|
||||
import androidx.lifecycle.LiveData
|
||||
|
@ -32,9 +33,6 @@ class TextStoryPostCreationViewModel(private val repository: TextStoryPostSendRe
|
|||
private val temporaryBodySubject: Subject<String> = BehaviorSubject.createDefault("")
|
||||
private val disposables = CompositeDisposable()
|
||||
|
||||
private val internalThumbnail = MutableLiveData<Bitmap>()
|
||||
val thumbnail: LiveData<Bitmap> = internalThumbnail
|
||||
|
||||
private val internalTypeface = MutableLiveData<Typeface>()
|
||||
|
||||
val state: LiveData<TextStoryPostCreationState> = store.stateLiveData
|
||||
|
@ -55,14 +53,12 @@ class TextStoryPostCreationViewModel(private val repository: TextStoryPostSendRe
|
|||
}
|
||||
}
|
||||
|
||||
fun setBitmap(bitmap: Bitmap) {
|
||||
internalThumbnail.value?.recycle()
|
||||
internalThumbnail.value = bitmap
|
||||
fun compressToBlob(bitmap: Bitmap): Single<Uri> {
|
||||
return repository.compressToBlob(bitmap)
|
||||
}
|
||||
|
||||
override fun onCleared() {
|
||||
disposables.clear()
|
||||
thumbnail.value?.recycle()
|
||||
}
|
||||
|
||||
fun saveToInstanceState(outState: Bundle) {
|
||||
|
|
|
@ -1,213 +0,0 @@
|
|||
package org.thoughtcrime.securesms.mediasend.v2.text.send
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.View
|
||||
import android.widget.EditText
|
||||
import android.widget.ImageView
|
||||
import android.widget.Toast
|
||||
import androidx.appcompat.widget.Toolbar
|
||||
import androidx.core.widget.doAfterTextChanged
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.fragment.app.setFragmentResultListener
|
||||
import androidx.fragment.app.viewModels
|
||||
import androidx.navigation.fragment.findNavController
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.signal.core.util.DimensionUnit
|
||||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.components.WrapperDialogFragment
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchConfiguration
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchMediator
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreviewViewModel
|
||||
import org.thoughtcrime.securesms.mediasend.v2.stories.ChooseGroupStoryBottomSheet
|
||||
import org.thoughtcrime.securesms.mediasend.v2.stories.ChooseStoryTypeBottomSheet
|
||||
import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryPostCreationViewModel
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId
|
||||
import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet
|
||||
import org.thoughtcrime.securesms.sharing.ShareSelectionAdapter
|
||||
import org.thoughtcrime.securesms.sharing.ShareSelectionMappingModel
|
||||
import org.thoughtcrime.securesms.stories.Stories
|
||||
import org.thoughtcrime.securesms.stories.settings.create.CreateStoryFlowDialogFragment
|
||||
import org.thoughtcrime.securesms.stories.settings.create.CreateStoryWithViewersFragment
|
||||
import org.thoughtcrime.securesms.stories.settings.privacy.ChooseInitialMyStoryMembershipBottomSheetDialogFragment
|
||||
import org.thoughtcrime.securesms.util.BottomSheetUtil
|
||||
import org.thoughtcrime.securesms.util.FeatureFlags
|
||||
import org.thoughtcrime.securesms.util.LifecycleDisposable
|
||||
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil
|
||||
|
||||
class TextStoryPostSendFragment :
|
||||
Fragment(R.layout.stories_send_text_post_fragment),
|
||||
ChooseStoryTypeBottomSheet.Callback,
|
||||
WrapperDialogFragment.WrapperDialogFragmentCallback,
|
||||
ChooseInitialMyStoryMembershipBottomSheetDialogFragment.Callback,
|
||||
SafetyNumberBottomSheet.Callbacks {
|
||||
|
||||
private lateinit var shareListWrapper: View
|
||||
private lateinit var shareSelectionRecyclerView: RecyclerView
|
||||
private lateinit var shareConfirmButton: View
|
||||
|
||||
private val shareSelectionAdapter = ShareSelectionAdapter()
|
||||
private val disposables = LifecycleDisposable()
|
||||
|
||||
private lateinit var contactSearchMediator: ContactSearchMediator
|
||||
|
||||
private val viewModel: TextStoryPostSendViewModel by viewModels(
|
||||
factoryProducer = {
|
||||
TextStoryPostSendViewModel.Factory(TextStoryPostSendRepository())
|
||||
}
|
||||
)
|
||||
|
||||
private val creationViewModel: TextStoryPostCreationViewModel by viewModels(
|
||||
ownerProducer = {
|
||||
requireActivity()
|
||||
}
|
||||
)
|
||||
|
||||
private val linkPreviewViewModel: LinkPreviewViewModel by viewModels(
|
||||
ownerProducer = {
|
||||
requireActivity()
|
||||
}
|
||||
)
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
val toolbar: Toolbar = view.findViewById(R.id.toolbar)
|
||||
val viewPort: ImageView = view.findViewById(R.id.preview_viewport)
|
||||
val searchField: EditText = view.findViewById(R.id.search_field)
|
||||
|
||||
toolbar.setNavigationOnClickListener {
|
||||
findNavController().popBackStack()
|
||||
}
|
||||
|
||||
shareListWrapper = view.findViewById(R.id.list_wrapper)
|
||||
shareConfirmButton = view.findViewById(R.id.share_confirm)
|
||||
shareSelectionRecyclerView = view.findViewById(R.id.selected_list)
|
||||
shareSelectionRecyclerView.adapter = shareSelectionAdapter
|
||||
|
||||
disposables.bindTo(viewLifecycleOwner)
|
||||
|
||||
creationViewModel.thumbnail.observe(viewLifecycleOwner) { bitmap ->
|
||||
viewPort.setImageBitmap(bitmap)
|
||||
}
|
||||
|
||||
shareConfirmButton.setOnClickListener {
|
||||
viewModel.onSending()
|
||||
send()
|
||||
}
|
||||
|
||||
disposables += viewModel.untrustedIdentities.subscribe { records ->
|
||||
SafetyNumberBottomSheet
|
||||
.forIdentityRecordsAndDestinations(records, contactSearchMediator.getSelectedContacts().toList())
|
||||
.show(childFragmentManager)
|
||||
}
|
||||
|
||||
searchField.doAfterTextChanged {
|
||||
contactSearchMediator.onFilterChanged(it?.toString())
|
||||
}
|
||||
|
||||
setFragmentResultListener(CreateStoryWithViewersFragment.REQUEST_KEY) { _, bundle ->
|
||||
val recipientId: RecipientId = bundle.getParcelable(CreateStoryWithViewersFragment.STORY_RECIPIENT)!!
|
||||
contactSearchMediator.setKeysSelected(setOf(ContactSearchKey.RecipientSearchKey.Story(recipientId)))
|
||||
contactSearchMediator.onFilterChanged("")
|
||||
}
|
||||
|
||||
setFragmentResultListener(ChooseGroupStoryBottomSheet.GROUP_STORY) { _, bundle ->
|
||||
val groups: Set<RecipientId> = bundle.getParcelableArrayList<RecipientId>(ChooseGroupStoryBottomSheet.RESULT_SET)?.toSet() ?: emptySet()
|
||||
val keys: Set<ContactSearchKey.RecipientSearchKey.Story> = groups.map { ContactSearchKey.RecipientSearchKey.Story(it) }.toSet()
|
||||
contactSearchMediator.addToVisibleGroupStories(keys)
|
||||
contactSearchMediator.onFilterChanged("")
|
||||
contactSearchMediator.setKeysSelected(keys)
|
||||
}
|
||||
|
||||
val contactsRecyclerView: RecyclerView = view.findViewById(R.id.contacts_container)
|
||||
contactSearchMediator = ContactSearchMediator(this, contactsRecyclerView, FeatureFlags.shareSelectionLimit(), true, { contactSearchState ->
|
||||
ContactSearchConfiguration.build {
|
||||
query = contactSearchState.query
|
||||
|
||||
addSection(
|
||||
ContactSearchConfiguration.Section.Stories(
|
||||
groupStories = contactSearchState.groupStories,
|
||||
includeHeader = true,
|
||||
headerAction = Stories.getHeaderAction(childFragmentManager)
|
||||
)
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
contactSearchMediator.getSelectionState().observe(viewLifecycleOwner) { selection ->
|
||||
shareSelectionAdapter.submitList(selection.mapIndexed { index, contact -> ShareSelectionMappingModel(contact.requireShareContact(), index == 0) })
|
||||
if (selection.isNotEmpty()) {
|
||||
animateInSelection()
|
||||
} else {
|
||||
animateOutSelection()
|
||||
}
|
||||
}
|
||||
|
||||
val saveStateAndSelection = LiveDataUtil.combineLatest(viewModel.state, contactSearchMediator.getSelectionState(), ::Pair)
|
||||
saveStateAndSelection.observe(viewLifecycleOwner) { (state, selection) ->
|
||||
when (state) {
|
||||
TextStoryPostSendState.INIT -> shareConfirmButton.isEnabled = selection.isNotEmpty()
|
||||
TextStoryPostSendState.SENDING -> shareConfirmButton.isEnabled = false
|
||||
TextStoryPostSendState.SENT -> requireActivity().finish()
|
||||
else -> {
|
||||
Toast.makeText(requireContext(), R.string.TextStoryPostSendFragment__an_unexpected_error_occurred_try_again, Toast.LENGTH_SHORT).show()
|
||||
viewModel.onSendCancelled()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun send() {
|
||||
shareConfirmButton.isEnabled = false
|
||||
|
||||
val textStoryPostCreationState = creationViewModel.state.value
|
||||
|
||||
viewModel.onSend(
|
||||
contactSearchMediator.getSelectedContacts(),
|
||||
textStoryPostCreationState!!,
|
||||
linkPreviewViewModel.onSendWithErrorUrl().firstOrNull()
|
||||
)
|
||||
}
|
||||
|
||||
private fun animateInSelection() {
|
||||
shareListWrapper.animate()
|
||||
.alpha(1f)
|
||||
.translationY(0f)
|
||||
shareConfirmButton.animate()
|
||||
.alpha(1f)
|
||||
}
|
||||
|
||||
private fun animateOutSelection() {
|
||||
shareListWrapper.animate()
|
||||
.alpha(0f)
|
||||
.translationY(DimensionUnit.DP.toPixels(48f))
|
||||
shareConfirmButton.animate()
|
||||
.alpha(0f)
|
||||
}
|
||||
|
||||
override fun onNewStoryClicked() {
|
||||
CreateStoryFlowDialogFragment().show(parentFragmentManager, CreateStoryWithViewersFragment.REQUEST_KEY)
|
||||
}
|
||||
|
||||
override fun onGroupStoryClicked() {
|
||||
ChooseGroupStoryBottomSheet().show(parentFragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG)
|
||||
}
|
||||
|
||||
override fun onWrapperDialogFragmentDismissed() {
|
||||
contactSearchMediator.refresh()
|
||||
}
|
||||
|
||||
override fun onMyStoryConfigured(recipientId: RecipientId) {
|
||||
contactSearchMediator.setKeysSelected(setOf(ContactSearchKey.RecipientSearchKey.Story(recipientId)))
|
||||
contactSearchMediator.refresh()
|
||||
}
|
||||
|
||||
override fun sendAnywayAfterSafetyNumberChangedInBottomSheet(destinations: List<ContactSearchKey.RecipientSearchKey>) {
|
||||
send()
|
||||
}
|
||||
|
||||
override fun onMessageResentAfterSafetyNumberChangeInBottomSheet() = error("Not supported here")
|
||||
|
||||
override fun onCanceled() {
|
||||
viewModel.onSendCancelled()
|
||||
}
|
||||
}
|
|
@ -1,6 +1,9 @@
|
|||
package org.thoughtcrime.securesms.mediasend.v2.text.send
|
||||
|
||||
import android.graphics.Bitmap
|
||||
import android.net.Uri
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import io.reactivex.rxjava3.schedulers.Schedulers
|
||||
import org.signal.core.util.ThreadUtil
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
|
||||
|
@ -16,14 +19,25 @@ import org.thoughtcrime.securesms.mediasend.v2.UntrustedRecords
|
|||
import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryPostCreationState
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMediaMessage
|
||||
import org.thoughtcrime.securesms.mms.OutgoingSecureMediaMessage
|
||||
import org.thoughtcrime.securesms.providers.BlobProvider
|
||||
import org.thoughtcrime.securesms.recipients.Recipient
|
||||
import org.thoughtcrime.securesms.stories.Stories
|
||||
import org.thoughtcrime.securesms.util.Base64
|
||||
import java.io.ByteArrayOutputStream
|
||||
|
||||
private val TAG = Log.tag(TextStoryPostSendRepository::class.java)
|
||||
|
||||
class TextStoryPostSendRepository {
|
||||
|
||||
fun compressToBlob(bitmap: Bitmap): Single<Uri> {
|
||||
return Single.fromCallable {
|
||||
val outputStream = ByteArrayOutputStream()
|
||||
bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
|
||||
bitmap.recycle()
|
||||
BlobProvider.getInstance().forData(outputStream.toByteArray()).createForSingleUseInMemory()
|
||||
}.subscribeOn(Schedulers.computation())
|
||||
}
|
||||
|
||||
fun send(contactSearchKey: Set<ContactSearchKey>, textStoryPostCreationState: TextStoryPostCreationState, linkPreview: LinkPreview?): Single<TextStoryPostSendResult> {
|
||||
return UntrustedRecords
|
||||
.checkForBadIdentityRecords(contactSearchKey.filterIsInstance(ContactSearchKey.RecipientSearchKey::class.java).toSet())
|
||||
|
|
|
@ -1,8 +0,0 @@
|
|||
package org.thoughtcrime.securesms.mediasend.v2.text.send
|
||||
|
||||
enum class TextStoryPostSendState {
|
||||
INIT,
|
||||
SENDING,
|
||||
SENT,
|
||||
FAILED
|
||||
}
|
|
@ -1,77 +0,0 @@
|
|||
package org.thoughtcrime.securesms.mediasend.v2.text.send
|
||||
|
||||
import androidx.lifecycle.LiveData
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import io.reactivex.rxjava3.core.Observable
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import io.reactivex.rxjava3.kotlin.subscribeBy
|
||||
import io.reactivex.rxjava3.subjects.PublishSubject
|
||||
import org.signal.core.util.logging.Log
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
|
||||
import org.thoughtcrime.securesms.database.model.IdentityRecord
|
||||
import org.thoughtcrime.securesms.linkpreview.LinkPreview
|
||||
import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryPostCreationState
|
||||
import org.thoughtcrime.securesms.util.livedata.Store
|
||||
|
||||
private val TAG = Log.tag(TextStoryPostSendViewModel::class.java)
|
||||
|
||||
class TextStoryPostSendViewModel(private val repository: TextStoryPostSendRepository) : ViewModel() {
|
||||
|
||||
private val store = Store(TextStoryPostSendState.INIT)
|
||||
private val untrustedIdentitySubject = PublishSubject.create<List<IdentityRecord>>()
|
||||
private val disposables = CompositeDisposable()
|
||||
|
||||
val state: LiveData<TextStoryPostSendState> = store.stateLiveData
|
||||
val untrustedIdentities: Observable<List<IdentityRecord>> = untrustedIdentitySubject
|
||||
|
||||
override fun onCleared() {
|
||||
disposables.clear()
|
||||
}
|
||||
|
||||
fun onSending() {
|
||||
store.update {
|
||||
TextStoryPostSendState.SENDING
|
||||
}
|
||||
}
|
||||
|
||||
fun onSendCancelled() {
|
||||
store.update {
|
||||
TextStoryPostSendState.INIT
|
||||
}
|
||||
}
|
||||
|
||||
fun onSend(contactSearchKeys: Set<ContactSearchKey>, textStoryPostCreationState: TextStoryPostCreationState, linkPreview: LinkPreview?) {
|
||||
store.update {
|
||||
TextStoryPostSendState.SENDING
|
||||
}
|
||||
|
||||
disposables += repository.send(contactSearchKeys, textStoryPostCreationState, linkPreview).subscribeBy(
|
||||
onSuccess = {
|
||||
when (it) {
|
||||
is TextStoryPostSendResult.Success -> {
|
||||
store.update { TextStoryPostSendState.SENT }
|
||||
}
|
||||
is TextStoryPostSendResult.UntrustedRecordsError -> {
|
||||
untrustedIdentitySubject.onNext(it.untrustedRecords)
|
||||
store.update { TextStoryPostSendState.INIT }
|
||||
}
|
||||
is TextStoryPostSendResult.Failure -> {
|
||||
store.update { TextStoryPostSendState.FAILED }
|
||||
}
|
||||
}
|
||||
},
|
||||
onError = {
|
||||
Log.w(TAG, "Unexpected error occurred", it)
|
||||
store.update { TextStoryPostSendState.FAILED }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
class Factory(private val repository: TextStoryPostSendRepository) : ViewModelProvider.Factory {
|
||||
override fun <T : ViewModel> create(modelClass: Class<T>): T {
|
||||
return modelClass.cast(TextStoryPostSendViewModel(repository)) as T
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,76 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:id="@+id/content"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<org.thoughtcrime.securesms.util.views.DarkOverflowToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:navigationIcon="@drawable/ic_arrow_left_24"
|
||||
app:title="@string/conversation_activity__send" />
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:id="@+id/fragment_container_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/signal_colorBackground"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed">
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/preview_viewport"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingVertical="22.5dp"
|
||||
app:layout_collapseMode="parallax">
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/preview_media_2"
|
||||
android:layout_width="110dp"
|
||||
android:layout_height="177dp"
|
||||
android:layout_gravity="center"
|
||||
android:rotation="-15"
|
||||
android:scaleType="centerCrop"
|
||||
android:translationX="-28dp"
|
||||
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Signal.WallpaperPreview"
|
||||
tools:background="@color/red" />
|
||||
|
||||
<com.google.android.material.imageview.ShapeableImageView
|
||||
android:id="@+id/preview_media_1"
|
||||
android:layout_width="120dp"
|
||||
android:layout_height="215dp"
|
||||
android:layout_gravity="center"
|
||||
android:padding="1.5dp"
|
||||
android:scaleType="centerCrop"
|
||||
app:shapeAppearanceOverlay="@style/ShapeAppearanceOverlay.Signal.WallpaperPreview"
|
||||
app:strokeColor="@color/signal_colorBackground"
|
||||
app:strokeWidth="3dp"
|
||||
tools:background="@color/green" />
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/fragment_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
|
||||
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
</LinearLayout>
|
|
@ -1,118 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
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"
|
||||
android:orientation="vertical">
|
||||
|
||||
<org.thoughtcrime.securesms.util.views.DarkOverflowToolbar
|
||||
android:id="@+id/toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:navigationIcon="@drawable/ic_arrow_left_24"
|
||||
app:title="@string/conversation_activity__send" />
|
||||
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.appbar.AppBarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<com.google.android.material.appbar.CollapsingToolbarLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/core_grey_95"
|
||||
app:layout_scrollFlags="scroll|exitUntilCollapsed">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/preview_viewport"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="215dp"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="24dp"
|
||||
android:importantForAccessibility="no"
|
||||
android:scaleType="centerInside"
|
||||
app:layout_collapseMode="parallax" />
|
||||
|
||||
</com.google.android.material.appbar.CollapsingToolbarLayout>
|
||||
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
app:layout_behavior="@string/appbar_scrolling_view_behavior">
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiEditText
|
||||
android:id="@+id/search_field"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="12dp"
|
||||
android:background="@drawable/rounded_rectangle_secondary_18"
|
||||
android:hint="@string/TextStoryPostSendFragment__search"
|
||||
android:minHeight="44dp"
|
||||
android:paddingHorizontal="16dp"
|
||||
android:textAppearance="@style/Signal.Text.Body" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/contacts_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginTop="12dp"
|
||||
android:layout_weight="1"
|
||||
android:paddingBottom="44dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/contact_search_item" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/list_wrapper"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:alpha="0"
|
||||
android:orientation="vertical"
|
||||
android:translationY="48dp">
|
||||
|
||||
<View
|
||||
android:id="@+id/divider"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="1dp"
|
||||
android:background="@color/signal_divider_major"
|
||||
android:translationY="48dp" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/selected_list"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="44dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:background="@color/signal_background_primary"
|
||||
android:clipToPadding="false"
|
||||
android:orientation="horizontal"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="78dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
tools:listitem="@layout/share_contact_selection_item" />
|
||||
</LinearLayout>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/share_confirm"
|
||||
android:layout_width="56dp"
|
||||
android:layout_height="56dp"
|
||||
android:layout_gravity="bottom|end"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="16dp"
|
||||
android:contentDescription="@string/ShareActivity__share"
|
||||
app:backgroundTint="@color/core_ultramarine"
|
||||
app:srcCompat="@drawable/ic_send_24"
|
||||
app:tint="@color/core_white" />
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||
|
||||
</LinearLayout>
|
|
@ -112,4 +112,24 @@
|
|||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
<androidx.cardview.widget.CardView
|
||||
android:id="@+id/send_in_progress_indicator"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:cardCornerRadius="18dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
tools:visibility="visible">
|
||||
|
||||
<com.google.android.material.progressindicator.CircularProgressIndicator
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_margin="24dp"
|
||||
android:indeterminate="true"
|
||||
app:indicatorColor="@color/signal_colorPrimary" />
|
||||
</androidx.cardview.widget.CardView>
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -47,17 +47,7 @@
|
|||
android:id="@+id/textStoryPostCreationFragment"
|
||||
android:name="org.thoughtcrime.securesms.mediasend.v2.text.TextStoryPostCreationFragment"
|
||||
android:label="text_story_post_creation_fragment"
|
||||
tools:layout="@layout/stories_text_post_creation_fragment">
|
||||
<action
|
||||
android:id="@+id/action_textStoryPostCreationFragment_to_textStoryPostSendFragment"
|
||||
app:destination="@id/textStoryPostSendFragment" />
|
||||
</fragment>
|
||||
|
||||
<fragment
|
||||
android:id="@+id/textStoryPostSendFragment"
|
||||
android:name="org.thoughtcrime.securesms.mediasend.v2.text.send.TextStoryPostSendFragment"
|
||||
android:label="text_story_post_send_fragment"
|
||||
tools:layout="@layout/stories_send_text_post_fragment" />
|
||||
tools:layout="@layout/stories_text_post_creation_fragment" />
|
||||
|
||||
<action
|
||||
android:id="@+id/action_directly_to_mediaCaptureFragment"
|
||||
|
|
Loading…
Add table
Reference in a new issue