Allow media selection recipient selection fragment to display in user's chosen app theme.

fork-5.53.8
Alex Hart 2022-07-25 12:45:09 -03:00 zatwierdzone przez Cody Henthorne
rodzic 09b92a6559
commit b20658c829
11 zmienionych plików z 155 dodań i 76 usunięć

Wyświetl plik

@ -371,6 +371,11 @@
android:launchMode="singleTop" android:launchMode="singleTop"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>
<activity android:name=".conversation.mutiselect.forward.MultiselectForwardActivity"
android:theme="@style/Signal.DayNight.NoActionBar"
android:windowSoftInputMode="stateAlwaysHidden|adjustNothing"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize" />
<activity android:name=".PassphraseChangeActivity" <activity android:name=".PassphraseChangeActivity"
android:label="@string/AndroidManifest__change_passphrase" android:label="@string/AndroidManifest__change_passphrase"
android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/> android:configChanges="touchscreen|keyboard|keyboardHidden|orientation|screenLayout|screenSize"/>

Wyświetl plik

@ -13,10 +13,11 @@ import org.thoughtcrime.securesms.util.DynamicTheme
abstract class FragmentWrapperActivity : PassphraseRequiredActivity() { abstract class FragmentWrapperActivity : PassphraseRequiredActivity() {
protected open val dynamicTheme: DynamicTheme = DynamicNoActionBarTheme() protected open val dynamicTheme: DynamicTheme = DynamicNoActionBarTheme()
protected open val contentViewId: Int = R.layout.fragment_container
override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) { override fun onCreate(savedInstanceState: Bundle?, ready: Boolean) {
super.onCreate(savedInstanceState, ready) super.onCreate(savedInstanceState, ready)
setContentView(R.layout.fragment_container) setContentView(contentViewId)
dynamicTheme.onCreate(this) dynamicTheme.onCreate(this)
if (savedInstanceState == null) { if (savedInstanceState == null) {

Wyświetl plik

@ -0,0 +1,66 @@
package org.thoughtcrime.securesms.conversation.mutiselect.forward
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.ViewGroup
import androidx.activity.result.contract.ActivityResultContract
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import org.thoughtcrime.securesms.R
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 {
companion object {
private const val ARGS = "args"
}
private val args: MultiselectForwardFragmentArgs get() = intent.getParcelableExtra(ARGS)!!
override val contentViewId: Int = R.layout.multiselect_forward_activity
override fun getFragment(): Fragment {
return MultiselectForwardFragment.create(args)
}
override fun onFinishForwardAction() = Unit
override fun exitFlow() {
onBackPressedDispatcher.onBackPressed()
}
override fun onSearchInputFocused() = Unit
override fun setResult(bundle: Bundle) {
setResult(RESULT_OK, Intent().putExtras(bundle))
}
@Suppress("WrongViewCast")
override fun getContainer(): ViewGroup {
return findViewById(R.id.fragment_container_wrapper)
}
override fun getDialogBackgroundColor(): Int {
return ContextCompat.getColor(this, R.color.signal_colorBackground)
}
class SelectionContract : ActivityResultContract<MultiselectForwardFragmentArgs, List<ContactSearchKey.RecipientSearchKey>>() {
override fun createIntent(context: Context, input: MultiselectForwardFragmentArgs): Intent {
return Intent(context, MultiselectForwardActivity::class.java).putExtra(ARGS, input)
}
override fun parseResult(resultCode: Int, intent: Intent?): List<ContactSearchKey.RecipientSearchKey> {
return if (resultCode != RESULT_OK) {
emptyList()
} else if (intent == null || !intent.hasExtra(RESULT_SELECTION)) {
throw IllegalStateException("Selection contract requires a selection.")
} else {
val selection: List<ContactSearchKey.ParcelableRecipientSearchKey> = intent.getParcelableArrayListExtra(RESULT_SELECTION)!!
selection.map { it.asRecipientSearchKey() }
}
}
}
}

Wyświetl plik

@ -16,6 +16,7 @@ import android.widget.Toast
import androidx.annotation.PluralsRes import androidx.annotation.PluralsRes
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.os.bundleOf
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.doOnNextLayout import androidx.core.view.doOnNextLayout
import androidx.core.view.isVisible import androidx.core.view.isVisible
@ -41,7 +42,6 @@ import org.thoughtcrime.securesms.mediasend.v2.stories.ChooseGroupStoryBottomShe
import org.thoughtcrime.securesms.mediasend.v2.stories.ChooseStoryTypeBottomSheet import org.thoughtcrime.securesms.mediasend.v2.stories.ChooseStoryTypeBottomSheet
import org.thoughtcrime.securesms.recipients.RecipientId import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet
import org.thoughtcrime.securesms.sharing.MultiShareArgs
import org.thoughtcrime.securesms.sharing.ShareSelectionAdapter import org.thoughtcrime.securesms.sharing.ShareSelectionAdapter
import org.thoughtcrime.securesms.sharing.ShareSelectionMappingModel import org.thoughtcrime.securesms.sharing.ShareSelectionMappingModel
import org.thoughtcrime.securesms.stories.Stories import org.thoughtcrime.securesms.stories.Stories
@ -93,19 +93,12 @@ class MultiselectForwardFragment :
private var handler: Handler? = null private var handler: Handler? = null
private fun createViewModelFactory(): MultiselectForwardViewModel.Factory { private fun createViewModelFactory(): MultiselectForwardViewModel.Factory {
return MultiselectForwardViewModel.Factory(getMultiShareArgs(), isSelectionOnly, MultiselectForwardRepository()) return MultiselectForwardViewModel.Factory(args.storySendRequirements, args.multiShareArgs, args.forceSelectionOnly, MultiselectForwardRepository())
} }
private fun getMultiShareArgs(): ArrayList<MultiShareArgs> = requireNotNull(requireArguments().getParcelableArrayList(ARG_MULTISHARE_ARGS)) private val args: MultiselectForwardFragmentArgs by lazy {
requireArguments().getParcelable(ARGS)!!
private val forceDisableAddMessage: Boolean }
get() = requireArguments().getBoolean(ARG_FORCE_DISABLE_ADD_MESSAGE, false)
private val isSelectionOnly: Boolean
get() = requireArguments().getBoolean(ARG_FORCE_SELECTION_ONLY, false)
private val sendButtonTint: Int
get() = requireArguments().getInt(ARG_SEND_BUTTON_TINT, -1)
override fun onGetLayoutInflater(savedInstanceState: Bundle?): LayoutInflater { override fun onGetLayoutInflater(savedInstanceState: Bundle?): LayoutInflater {
return if (parentFragment != null) { return if (parentFragment != null) {
@ -119,7 +112,7 @@ class MultiselectForwardFragment :
view.minimumHeight = resources.displayMetrics.heightPixels view.minimumHeight = resources.displayMetrics.heightPixels
contactSearchRecycler = view.findViewById(R.id.contact_selection_list) contactSearchRecycler = view.findViewById(R.id.contact_selection_list)
contactSearchMediator = ContactSearchMediator(this, contactSearchRecycler, FeatureFlags.shareSelectionLimit(), !isSingleRecipientSelection(), this::getConfiguration, this::filterContacts) contactSearchMediator = ContactSearchMediator(this, contactSearchRecycler, FeatureFlags.shareSelectionLimit(), !args.selectSingleRecipient, this::getConfiguration, this::filterContacts)
callback = findListener()!! callback = findListener()!!
disposables.bindTo(viewLifecycleOwner.lifecycle) disposables.bindTo(viewLifecycleOwner.lifecycle)
@ -147,8 +140,8 @@ class MultiselectForwardFragment :
val sendButton: View = bottomBar.findViewById(R.id.share_confirm) val sendButton: View = bottomBar.findViewById(R.id.share_confirm)
val backgroundHelper: View = bottomBar.findViewById(R.id.background_helper) val backgroundHelper: View = bottomBar.findViewById(R.id.background_helper)
if (sendButtonTint != -1) { if (args.sendButtonTint != -1) {
ViewCompat.setBackgroundTintList(sendButton, ColorStateList.valueOf(sendButtonTint)) ViewCompat.setBackgroundTintList(sendButton, ColorStateList.valueOf(args.sendButtonTint))
} }
FullscreenHelper.configureBottomBarLayout(requireActivity(), bottomBarSpacer, bottomBar) FullscreenHelper.configureBottomBarLayout(requireActivity(), bottomBarSpacer, bottomBar)
@ -156,7 +149,7 @@ class MultiselectForwardFragment :
backgroundHelper.setBackgroundColor(callback.getDialogBackgroundColor()) backgroundHelper.setBackgroundColor(callback.getDialogBackgroundColor())
bottomBarSpacer.setBackgroundColor(callback.getDialogBackgroundColor()) bottomBarSpacer.setBackgroundColor(callback.getDialogBackgroundColor())
title?.setText(requireArguments().getInt(ARG_TITLE)) title?.setText(args.title)
addMessage = bottomBar.findViewById(R.id.add_message) addMessage = bottomBar.findViewById(R.id.add_message)
@ -174,7 +167,7 @@ class MultiselectForwardFragment :
onSend(it) onSend(it)
} }
sendButton.visible = !isSingleRecipientSelection() sendButton.visible = !args.selectSingleRecipient
shareSelectionRecycler.adapter = shareSelectionAdapter shareSelectionRecycler.adapter = shareSelectionAdapter
@ -183,14 +176,14 @@ class MultiselectForwardFragment :
container.addView(bottomBarAndSpacer) container.addView(bottomBarAndSpacer)
contactSearchMediator.getSelectionState().observe(viewLifecycleOwner) { contactSelection -> contactSearchMediator.getSelectionState().observe(viewLifecycleOwner) { contactSelection ->
if (contactSelection.isNotEmpty() && isSingleRecipientSelection()) { if (contactSelection.isNotEmpty() && args.selectSingleRecipient) {
onSend(sendButton) onSend(sendButton)
return@observe return@observe
} }
shareSelectionAdapter.submitList(contactSelection.mapIndexed { index, key -> ShareSelectionMappingModel(key.requireShareContact(), index == 0) }) shareSelectionAdapter.submitList(contactSelection.mapIndexed { index, key -> ShareSelectionMappingModel(key.requireShareContact(), index == 0) })
addMessage.visible = !forceDisableAddMessage && contactSelection.any { key -> key !is ContactSearchKey.RecipientSearchKey.Story } && getMultiShareArgs().isNotEmpty() addMessage.visible = !args.forceDisableAddMessage && contactSelection.any { key -> key !is ContactSearchKey.RecipientSearchKey.Story } && args.multiShareArgs.isNotEmpty()
if (contactSelection.isNotEmpty() && !bottomBar.isVisible) { if (contactSelection.isNotEmpty() && !bottomBar.isVisible) {
bottomBar.animation = AnimationUtils.loadAnimation(requireContext(), R.anim.slide_fade_from_bottom) bottomBar.animation = AnimationUtils.loadAnimation(requireContext(), R.anim.slide_fade_from_bottom)
@ -240,7 +233,7 @@ class MultiselectForwardFragment :
super.onResume() super.onResume()
val now = System.currentTimeMillis() val now = System.currentTimeMillis()
val expiringMessages = getMultiShareArgs().filter { it.expiresAt > 0L } val expiringMessages = args.multiShareArgs.filter { it.expiresAt > 0L }
val firstToExpire = expiringMessages.minByOrNull { it.expiresAt } val firstToExpire = expiringMessages.minByOrNull { it.expiresAt }
val earliestExpiration = firstToExpire?.expiresAt ?: -1L val earliestExpiration = firstToExpire?.expiresAt ?: -1L
@ -314,12 +307,12 @@ class MultiselectForwardFragment :
callback.exitFlow() callback.exitFlow()
} }
private fun getMessageCount(): Int = getMultiShareArgs().size + if (addMessage.text.isNotEmpty()) 1 else 0 private fun getMessageCount(): Int = args.multiShareArgs.size + if (addMessage.text.isNotEmpty()) 1 else 0
private fun handleMessageExpired() { private fun handleMessageExpired() {
callback.onFinishForwardAction() callback.onFinishForwardAction()
dismissibleDialog?.dismiss() dismissibleDialog?.dismiss()
Toast.makeText(requireContext(), resources.getQuantityString(R.plurals.MultiselectForwardFragment__couldnt_forward_messages, getMultiShareArgs().size), Toast.LENGTH_LONG).show() Toast.makeText(requireContext(), resources.getQuantityString(R.plurals.MultiselectForwardFragment__couldnt_forward_messages, args.multiShareArgs.size), Toast.LENGTH_LONG).show()
callback.exitFlow() callback.exitFlow()
} }
@ -435,19 +428,15 @@ class MultiselectForwardFragment :
} }
private fun includeSms(): Boolean { private fun includeSms(): Boolean {
return Util.isDefaultSmsProvider(requireContext()) && requireArguments().getBoolean(ARG_CAN_SEND_TO_NON_PUSH) return Util.isDefaultSmsProvider(requireContext()) && args.canSendToNonPush
}
private fun isSingleRecipientSelection(): Boolean {
return requireArguments().getBoolean(ARG_SELECT_SINGLE_RECIPIENT, false)
} }
private fun isSelectedMediaValidForStories(): Boolean { private fun isSelectedMediaValidForStories(): Boolean {
return getMultiShareArgs().all { it.isValidForStories } return args.multiShareArgs.all { it.isValidForStories }
} }
private fun isSelectedMediaValidForNonStories(): Boolean { private fun isSelectedMediaValidForNonStories(): Boolean {
return getMultiShareArgs().all { it.isValidForNonStories } return args.multiShareArgs.all { it.isValidForNonStories }
} }
override fun onGroupStoryClicked() { override fun onGroupStoryClicked() {
@ -478,13 +467,8 @@ class MultiselectForwardFragment :
} }
companion object { companion object {
const val ARG_MULTISHARE_ARGS = "multiselect.forward.fragment.arg.multishare.args" const val DIALOG_TITLE = "title"
const val ARG_CAN_SEND_TO_NON_PUSH = "multiselect.forward.fragment.arg.can.send.to.non.push" const val ARGS = "args"
const val ARG_TITLE = "multiselect.forward.fragment.title"
const val ARG_FORCE_DISABLE_ADD_MESSAGE = "multiselect.forward.fragment.force.disable.add.message"
const val ARG_FORCE_SELECTION_ONLY = "multiselect.forward.fragment.force.disable.add.message"
const val ARG_SELECT_SINGLE_RECIPIENT = "multiselect.forward.framgent.select.single.recipient"
const val ARG_SEND_BUTTON_TINT = "multiselect.forward.fragment.send.button.tint"
const val RESULT_KEY = "result_key" const val RESULT_KEY = "result_key"
const val RESULT_SELECTION = "result_selection_recipients" const val RESULT_SELECTION = "result_selection_recipients"
const val RESULT_SENT = "result_sent" const val RESULT_SENT = "result_sent"
@ -506,26 +490,14 @@ class MultiselectForwardFragment :
@JvmStatic @JvmStatic
fun create(multiselectForwardFragmentArgs: MultiselectForwardFragmentArgs): Fragment { fun create(multiselectForwardFragmentArgs: MultiselectForwardFragmentArgs): Fragment {
return MultiselectForwardFragment().apply { return MultiselectForwardFragment().apply {
arguments = createArgumentsBundle(multiselectForwardFragmentArgs) arguments = bundleOf(ARGS to multiselectForwardFragmentArgs)
} }
} }
private fun showDialogFragment(supportFragmentManager: FragmentManager, fragment: DialogFragment, multiselectForwardFragmentArgs: MultiselectForwardFragmentArgs) { private fun showDialogFragment(supportFragmentManager: FragmentManager, fragment: DialogFragment, multiselectForwardFragmentArgs: MultiselectForwardFragmentArgs) {
fragment.arguments = createArgumentsBundle(multiselectForwardFragmentArgs) fragment.arguments = bundleOf(ARGS to multiselectForwardFragmentArgs, DIALOG_TITLE to multiselectForwardFragmentArgs.title)
fragment.show(supportFragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG) fragment.show(supportFragmentManager, BottomSheetUtil.STANDARD_BOTTOM_SHEET_FRAGMENT_TAG)
} }
private fun createArgumentsBundle(multiselectForwardFragmentArgs: MultiselectForwardFragmentArgs): Bundle {
return Bundle().apply {
putParcelableArrayList(ARG_MULTISHARE_ARGS, ArrayList(multiselectForwardFragmentArgs.multiShareArgs))
putBoolean(ARG_CAN_SEND_TO_NON_PUSH, multiselectForwardFragmentArgs.canSendToNonPush)
putInt(ARG_TITLE, multiselectForwardFragmentArgs.title)
putBoolean(ARG_FORCE_DISABLE_ADD_MESSAGE, multiselectForwardFragmentArgs.forceDisableAddMessage)
putBoolean(ARG_FORCE_SELECTION_ONLY, multiselectForwardFragmentArgs.forceSelectionOnly)
putBoolean(ARG_SELECT_SINGLE_RECIPIENT, multiselectForwardFragmentArgs.selectSingleRecipient)
putInt(ARG_SEND_BUTTON_TINT, multiselectForwardFragmentArgs.sendButtonTint)
}
}
} }
} }

Wyświetl plik

@ -2,9 +2,11 @@ package org.thoughtcrime.securesms.conversation.mutiselect.forward
import android.content.Context import android.content.Context
import android.net.Uri import android.net.Uri
import android.os.Parcelable
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
import androidx.annotation.StringRes import androidx.annotation.StringRes
import androidx.annotation.WorkerThread import androidx.annotation.WorkerThread
import kotlinx.parcelize.Parcelize
import org.signal.core.util.StreamUtil import org.signal.core.util.StreamUtil
import org.signal.core.util.ThreadUtil import org.signal.core.util.ThreadUtil
import org.signal.core.util.concurrent.SignalExecutors import org.signal.core.util.concurrent.SignalExecutors
@ -17,6 +19,7 @@ import org.thoughtcrime.securesms.database.model.MmsMessageRecord
import org.thoughtcrime.securesms.mediasend.Media import org.thoughtcrime.securesms.mediasend.Media
import org.thoughtcrime.securesms.mms.PartAuthority import org.thoughtcrime.securesms.mms.PartAuthority
import org.thoughtcrime.securesms.sharing.MultiShareArgs import org.thoughtcrime.securesms.sharing.MultiShareArgs
import org.thoughtcrime.securesms.stories.Stories
import org.thoughtcrime.securesms.util.MediaUtil import org.thoughtcrime.securesms.util.MediaUtil
import java.util.Optional import java.util.Optional
import java.util.function.Consumer import java.util.function.Consumer
@ -31,6 +34,7 @@ import java.util.function.Consumer
* @param forceSelectionOnly Force the fragment to only select recipients, never actually performing the send. * @param forceSelectionOnly Force the fragment to only select recipients, never actually performing the send.
* @param selectSingleRecipient Only allow the selection of a single recipient. * @param selectSingleRecipient Only allow the selection of a single recipient.
*/ */
@Parcelize
data class MultiselectForwardFragmentArgs @JvmOverloads constructor( data class MultiselectForwardFragmentArgs @JvmOverloads constructor(
val canSendToNonPush: Boolean, val canSendToNonPush: Boolean,
val multiShareArgs: List<MultiShareArgs> = listOf(), val multiShareArgs: List<MultiShareArgs> = listOf(),
@ -38,8 +42,9 @@ data class MultiselectForwardFragmentArgs @JvmOverloads constructor(
val forceDisableAddMessage: Boolean = false, val forceDisableAddMessage: Boolean = false,
val forceSelectionOnly: Boolean = false, val forceSelectionOnly: Boolean = false,
val selectSingleRecipient: Boolean = false, val selectSingleRecipient: Boolean = false,
@ColorInt val sendButtonTint: Int = -1 @ColorInt val sendButtonTint: Int = -1,
) { val storySendRequirements: Stories.MediaTransform.SendRequirements = Stories.MediaTransform.SendRequirements.CAN_NOT_SEND
) : Parcelable {
fun withSendButtonTint(@ColorInt sendButtonTint: Int) = copy(sendButtonTint = sendButtonTint) fun withSendButtonTint(@ColorInt sendButtonTint: Int) = copy(sendButtonTint = sendButtonTint)
@ -58,7 +63,8 @@ data class MultiselectForwardFragmentArgs @JvmOverloads constructor(
consumer.accept( consumer.accept(
MultiselectForwardFragmentArgs( MultiselectForwardFragmentArgs(
isMmsSupported, isMmsSupported,
listOf(multiShareArgs) listOf(multiShareArgs),
storySendRequirements = Stories.MediaTransform.SendRequirements.CAN_NOT_SEND
) )
) )
} }
@ -79,7 +85,15 @@ data class MultiselectForwardFragmentArgs @JvmOverloads constructor(
val canSendToNonPush: Boolean = selectedParts.all { Multiselect.canSendToNonPush(context, it) } val canSendToNonPush: Boolean = selectedParts.all { Multiselect.canSendToNonPush(context, it) }
val multiShareArgs: List<MultiShareArgs> = conversationMessages.map { buildMultiShareArgs(context, it, selectedParts) } val multiShareArgs: List<MultiShareArgs> = conversationMessages.map { buildMultiShareArgs(context, it, selectedParts) }
ThreadUtil.runOnMain { consumer.accept(MultiselectForwardFragmentArgs(canSendToNonPush, multiShareArgs)) } ThreadUtil.runOnMain {
consumer.accept(
MultiselectForwardFragmentArgs(
canSendToNonPush,
multiShareArgs,
storySendRequirements = Stories.MediaTransform.SendRequirements.CAN_NOT_SEND
)
)
}
} }
} }

Wyświetl plik

@ -7,11 +7,12 @@ import androidx.core.content.ContextCompat
import androidx.fragment.app.setFragmentResult import androidx.fragment.app.setFragmentResult
import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.FullScreenDialogFragment import org.thoughtcrime.securesms.components.FullScreenDialogFragment
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragment.Companion.DIALOG_TITLE
import org.thoughtcrime.securesms.stories.Stories import org.thoughtcrime.securesms.stories.Stories
import org.thoughtcrime.securesms.util.fragments.findListener import org.thoughtcrime.securesms.util.fragments.findListener
class MultiselectForwardFullScreenDialogFragment : FullScreenDialogFragment(), MultiselectForwardFragment.Callback { class MultiselectForwardFullScreenDialogFragment : FullScreenDialogFragment(), MultiselectForwardFragment.Callback {
override fun getTitle(): Int = requireArguments().getInt(MultiselectForwardFragment.ARG_TITLE) override fun getTitle(): Int = requireArguments().getParcelable<MultiselectForwardFragmentArgs>(DIALOG_TITLE)!!.title
override fun getDialogLayoutResource(): Int = R.layout.fragment_container override fun getDialogLayoutResource(): Int = R.layout.fragment_container

Wyświetl plik

@ -10,6 +10,7 @@ import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.sharing.MultiShareArgs import org.thoughtcrime.securesms.sharing.MultiShareArgs
import org.thoughtcrime.securesms.sharing.MultiShareSender import org.thoughtcrime.securesms.sharing.MultiShareSender
import org.thoughtcrime.securesms.stories.Stories import org.thoughtcrime.securesms.stories.Stories
import org.whispersystems.signalservice.api.util.Preconditions
import java.util.Optional import java.util.Optional
class MultiselectForwardRepository { class MultiselectForwardRepository {
@ -21,7 +22,9 @@ class MultiselectForwardRepository {
) )
fun checkAllSelectedMediaCanBeSentToStories(records: List<MultiShareArgs>): Single<Stories.MediaTransform.SendRequirements> { fun checkAllSelectedMediaCanBeSentToStories(records: List<MultiShareArgs>): Single<Stories.MediaTransform.SendRequirements> {
if (!Stories.isFeatureEnabled() || records.isEmpty()) { Preconditions.checkArgument(records.isNotEmpty())
if (!Stories.isFeatureEnabled()) {
return Single.just(Stories.MediaTransform.SendRequirements.CAN_NOT_SEND) return Single.just(Stories.MediaTransform.SendRequirements.CAN_NOT_SEND)
} }

Wyświetl plik

@ -9,15 +9,21 @@ import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
import org.thoughtcrime.securesms.keyvalue.SignalStore import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.mediasend.v2.UntrustedRecords import org.thoughtcrime.securesms.mediasend.v2.UntrustedRecords
import org.thoughtcrime.securesms.sharing.MultiShareArgs import org.thoughtcrime.securesms.sharing.MultiShareArgs
import org.thoughtcrime.securesms.stories.Stories
import org.thoughtcrime.securesms.util.livedata.Store import org.thoughtcrime.securesms.util.livedata.Store
class MultiselectForwardViewModel( class MultiselectForwardViewModel(
private val storySendRequirements: Stories.MediaTransform.SendRequirements,
private val records: List<MultiShareArgs>, private val records: List<MultiShareArgs>,
private val isSelectionOnly: Boolean, private val isSelectionOnly: Boolean,
private val repository: MultiselectForwardRepository private val repository: MultiselectForwardRepository
) : ViewModel() { ) : ViewModel() {
private val store = Store(MultiselectForwardState()) private val store = Store(
MultiselectForwardState(
storySendRequirements = storySendRequirements
)
)
val state: LiveData<MultiselectForwardState> = store.stateLiveData val state: LiveData<MultiselectForwardState> = store.stateLiveData
val snapshot: MultiselectForwardState get() = store.state val snapshot: MultiselectForwardState get() = store.state
@ -25,8 +31,10 @@ class MultiselectForwardViewModel(
private val disposables = CompositeDisposable() private val disposables = CompositeDisposable()
init { init {
disposables += repository.checkAllSelectedMediaCanBeSentToStories(records).subscribe { sendRequirements -> if (records.isNotEmpty()) {
store.update { it.copy(storySendRequirements = sendRequirements) } disposables += repository.checkAllSelectedMediaCanBeSentToStories(records).subscribe { sendRequirements ->
store.update { it.copy(storySendRequirements = sendRequirements) }
}
} }
} }
@ -88,12 +96,13 @@ class MultiselectForwardViewModel(
} }
class Factory( class Factory(
private val storySendRequirements: Stories.MediaTransform.SendRequirements,
private val records: List<MultiShareArgs>, private val records: List<MultiShareArgs>,
private val isSelectionOnly: Boolean, private val isSelectionOnly: Boolean,
private val repository: MultiselectForwardRepository, private val repository: MultiselectForwardRepository,
) : ViewModelProvider.Factory { ) : ViewModelProvider.Factory {
override fun <T : ViewModel> create(modelClass: Class<T>): T { override fun <T : ViewModel> create(modelClass: Class<T>): T {
return requireNotNull(modelClass.cast(MultiselectForwardViewModel(records, isSelectionOnly, repository))) return requireNotNull(modelClass.cast(MultiselectForwardViewModel(storySendRequirements, records, isSelectionOnly, repository)))
} }
} }
} }

Wyświetl plik

@ -29,7 +29,6 @@ import org.thoughtcrime.securesms.contacts.paged.ContactSearchConfiguration
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
import org.thoughtcrime.securesms.contacts.paged.ContactSearchState import org.thoughtcrime.securesms.contacts.paged.ContactSearchState
import org.thoughtcrime.securesms.conversation.MessageSendType import org.thoughtcrime.securesms.conversation.MessageSendType
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFullScreenDialogFragment
import org.thoughtcrime.securesms.conversation.mutiselect.forward.SearchConfigurationProvider import org.thoughtcrime.securesms.conversation.mutiselect.forward.SearchConfigurationProvider
import org.thoughtcrime.securesms.keyboard.emoji.EmojiKeyboardPageFragment import org.thoughtcrime.securesms.keyboard.emoji.EmojiKeyboardPageFragment
import org.thoughtcrime.securesms.keyboard.emoji.search.EmojiSearchFragment import org.thoughtcrime.securesms.keyboard.emoji.search.EmojiSearchFragment
@ -52,8 +51,7 @@ class MediaSelectionActivity :
EmojiKeyboardPageFragment.Callback, EmojiKeyboardPageFragment.Callback,
EmojiEventListener, EmojiEventListener,
EmojiSearchFragment.Callback, EmojiSearchFragment.Callback,
SearchConfigurationProvider, SearchConfigurationProvider {
MultiselectForwardFullScreenDialogFragment.Callback {
private var animateInShadowLayerValueAnimator: ValueAnimator? = null private var animateInShadowLayerValueAnimator: ValueAnimator? = null
private var animateInTextColorValueAnimator: ValueAnimator? = null private var animateInTextColorValueAnimator: ValueAnimator? = null
@ -334,10 +332,6 @@ class MediaSelectionActivity :
} }
} }
override fun getStorySendRequirements(): Stories.MediaTransform.SendRequirements {
return viewModel.getStorySendRequirements()
}
private inner class OnBackPressed : OnBackPressedCallback(true) { private inner class OnBackPressed : OnBackPressedCallback(true) {
override fun handleOnBackPressed() { override fun handleOnBackPressed() {
val navController = Navigation.findNavController(this@MediaSelectionActivity, R.id.fragment_container) val navController = Navigation.findNavController(this@MediaSelectionActivity, R.id.fragment_container)

Wyświetl plik

@ -17,7 +17,6 @@ import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.DrawableCompat import androidx.core.graphics.drawable.DrawableCompat
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.setFragmentResultListener
import androidx.fragment.app.viewModels import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.ItemTouchHelper import androidx.recyclerview.widget.ItemTouchHelper
@ -28,7 +27,7 @@ import io.reactivex.rxjava3.disposables.CompositeDisposable
import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.R
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.conversation.mutiselect.forward.MultiselectForwardFragment import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardActivity
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs
import org.thoughtcrime.securesms.mediasend.MediaSendActivityResult import org.thoughtcrime.securesms.mediasend.MediaSendActivityResult
import org.thoughtcrime.securesms.mediasend.v2.HudCommand import org.thoughtcrime.securesms.mediasend.v2.HudCommand
@ -138,16 +137,20 @@ class MediaReviewFragment : Fragment(R.layout.v2_media_review_fragment) {
sharedViewModel.sendCommand(HudCommand.SaveMedia) sharedViewModel.sendCommand(HudCommand.SaveMedia)
} }
setFragmentResultListener(MultiselectForwardFragment.RESULT_KEY) { _, bundle -> val recipientSelectionLauncher = registerForActivityResult(MultiselectForwardActivity.SelectionContract()) { keys ->
val parcelizedKeys: List<ContactSearchKey.ParcelableRecipientSearchKey> = bundle.getParcelableArrayList(MultiselectForwardFragment.RESULT_SELECTION)!! if (keys.isNotEmpty()) {
val contactSearchKeys = parcelizedKeys.map { it.asRecipientSearchKey() } performSend(keys)
performSend(contactSearchKeys) }
} }
sendButton.setOnClickListener { sendButton.setOnClickListener {
if (sharedViewModel.isContactSelectionRequired) { if (sharedViewModel.isContactSelectionRequired) {
val args = MultiselectForwardFragmentArgs(false, title = R.string.MediaReviewFragment__send_to) val args = MultiselectForwardFragmentArgs(
MultiselectForwardFragment.showFullScreen(parentFragmentManager, args) false,
title = R.string.MediaReviewFragment__send_to,
storySendRequirements = sharedViewModel.getStorySendRequirements()
)
recipientSelectionLauncher.launch(args)
} else { } else {
performSend() performSend()
} }

Wyświetl plik

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/fragment_container_wrapper"
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragment_container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>