Guard first time on add to my story.

fork-5.53.8
Alex Hart 2022-03-17 15:26:47 -03:00 zatwierdzone przez Cody Henthorne
rodzic 945c308cf5
commit 7edef20f4f
7 zmienionych plików z 97 dodań i 45 usunięć

Wyświetl plik

@ -35,8 +35,10 @@ 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
import org.thoughtcrime.securesms.stories.Stories.getHeaderAction import org.thoughtcrime.securesms.stories.Stories.getHeaderAction
import org.thoughtcrime.securesms.stories.dialogs.StoryDialogs
import org.thoughtcrime.securesms.stories.settings.create.CreateStoryFlowDialogFragment import org.thoughtcrime.securesms.stories.settings.create.CreateStoryFlowDialogFragment
import org.thoughtcrime.securesms.stories.settings.create.CreateStoryWithViewersFragment import org.thoughtcrime.securesms.stories.settings.create.CreateStoryWithViewersFragment
import org.thoughtcrime.securesms.stories.settings.hide.HideStoryFromDialogFragment
import org.thoughtcrime.securesms.util.BottomSheetUtil import org.thoughtcrime.securesms.util.BottomSheetUtil
import org.thoughtcrime.securesms.util.FeatureFlags import org.thoughtcrime.securesms.util.FeatureFlags
import org.thoughtcrime.securesms.util.LifecycleDisposable import org.thoughtcrime.securesms.util.LifecycleDisposable
@ -105,7 +107,21 @@ class MultiselectForwardFragment :
sendButton.setOnClickListener { sendButton.setOnClickListener {
sendButton.isEnabled = false sendButton.isEnabled = false
viewModel.send(addMessage.text.toString(), contactSearchMediator.getSelectedContacts())
StoryDialogs.guardWithAddToYourStoryDialog(
requireContext(),
contactSearchMediator.getSelectedContacts(),
onAddToStory = {
performSend()
},
onEditViewers = {
sendButton.isEnabled = true
HideStoryFromDialogFragment().show(childFragmentManager, null)
},
onCancel = {
sendButton.isEnabled = true
}
)
} }
shareSelectionRecycler.adapter = shareSelectionAdapter shareSelectionRecycler.adapter = shareSelectionAdapter
@ -211,6 +227,10 @@ class MultiselectForwardFragment :
.show() .show()
} }
private fun performSend() {
viewModel.send(addMessage.text.toString(), contactSearchMediator.getSelectedContacts())
}
private fun displaySafetyNumberConfirmation(identityRecords: List<IdentityRecord>) { private fun displaySafetyNumberConfirmation(identityRecords: List<IdentityRecord>) {
SafetyNumberChangeDialog.show(childFragmentManager, identityRecords) SafetyNumberChangeDialog.show(childFragmentManager, identityRecords)
} }

Wyświetl plik

@ -24,5 +24,5 @@ internal class StoryValues(store: KeyValueStore) : SignalStoreValues(store) {
var lastFontVersionCheck: Long by longValue(LAST_FONT_VERSION_CHECK, 0) var lastFontVersionCheck: Long by longValue(LAST_FONT_VERSION_CHECK, 0)
var userHasAddedToAStory: Boolean by booleanValue(USER_HAS_ADDED_TO_A_STORY, false) var userHasBeenNotifiedAboutStories: Boolean by booleanValue(USER_HAS_ADDED_TO_A_STORY, false)
} }

Wyświetl plik

@ -46,7 +46,7 @@ class TextStoryPostSendFragment : Fragment(R.layout.stories_send_text_post_fragm
private val viewModel: TextStoryPostSendViewModel by viewModels( private val viewModel: TextStoryPostSendViewModel by viewModels(
factoryProducer = { factoryProducer = {
TextStoryPostSendViewModel.Factory(TextStoryPostSendRepository(requireContext())) TextStoryPostSendViewModel.Factory(TextStoryPostSendRepository())
} }
) )
@ -83,8 +83,9 @@ class TextStoryPostSendFragment : Fragment(R.layout.stories_send_text_post_fragm
} }
shareConfirmButton.setOnClickListener { shareConfirmButton.setOnClickListener {
if (viewModel.isFirstSendToAStory(contactSearchMediator.getSelectedContacts())) { viewModel.onSending()
StoryDialogs.guardWithAddToYourStoryDialog( StoryDialogs.guardWithAddToYourStoryDialog(
contacts = contactSearchMediator.getSelectedContacts(),
context = requireContext(), context = requireContext(),
onAddToStory = { send() }, onAddToStory = { send() },
onEditViewers = { onEditViewers = {
@ -95,9 +96,6 @@ class TextStoryPostSendFragment : Fragment(R.layout.stories_send_text_post_fragm
viewModel.onSendCancelled() viewModel.onSendCancelled()
} }
) )
} else {
send()
}
} }
disposables += viewModel.untrustedIdentities.subscribe { disposables += viewModel.untrustedIdentities.subscribe {

Wyświetl plik

@ -1,6 +1,5 @@
package org.thoughtcrime.securesms.mediasend.v2.text.send package org.thoughtcrime.securesms.mediasend.v2.text.send
import android.content.Context
import io.reactivex.rxjava3.core.Completable import io.reactivex.rxjava3.core.Completable
import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.core.Single
import org.signal.core.util.ThreadUtil import org.signal.core.util.ThreadUtil
@ -11,7 +10,6 @@ import org.thoughtcrime.securesms.database.ThreadDatabase
import org.thoughtcrime.securesms.database.model.StoryType import org.thoughtcrime.securesms.database.model.StoryType
import org.thoughtcrime.securesms.database.model.databaseprotos.StoryTextPost import org.thoughtcrime.securesms.database.model.databaseprotos.StoryTextPost
import org.thoughtcrime.securesms.fonts.TextFont import org.thoughtcrime.securesms.fonts.TextFont
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.linkpreview.LinkPreview import org.thoughtcrime.securesms.linkpreview.LinkPreview
import org.thoughtcrime.securesms.mediasend.v2.UntrustedRecords import org.thoughtcrime.securesms.mediasend.v2.UntrustedRecords
import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryPostCreationState import org.thoughtcrime.securesms.mediasend.v2.text.TextStoryPostCreationState
@ -21,17 +19,7 @@ import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.stories.Stories import org.thoughtcrime.securesms.stories.Stories
import org.thoughtcrime.securesms.util.Base64 import org.thoughtcrime.securesms.util.Base64
class TextStoryPostSendRepository(context: Context) { class TextStoryPostSendRepository {
private val context = context.applicationContext
fun isFirstSendToStory(shareContacts: Set<ContactSearchKey>): Boolean {
if (SignalStore.storyValues().userHasAddedToAStory) {
return false
}
return shareContacts.any { it is ContactSearchKey.Story }
}
fun send(contactSearchKey: Set<ContactSearchKey>, textStoryPostCreationState: TextStoryPostCreationState, linkPreview: LinkPreview?): Single<TextStoryPostSendResult> { fun send(contactSearchKey: Set<ContactSearchKey>, textStoryPostCreationState: TextStoryPostCreationState, linkPreview: LinkPreview?): Single<TextStoryPostSendResult> {
return UntrustedRecords return UntrustedRecords

Wyświetl plik

@ -27,12 +27,10 @@ class TextStoryPostSendViewModel(private val repository: TextStoryPostSendReposi
disposables.clear() disposables.clear()
} }
fun isFirstSendToAStory(contactSearchKeys: Set<ContactSearchKey>): Boolean { fun onSending() {
store.update { store.update {
TextStoryPostSendState.SENDING TextStoryPostSendState.SENDING
} }
return repository.isFirstSendToStory(contactSearchKeys)
} }
fun onSendCancelled() { fun onSendCancelled() {

Wyświetl plik

@ -47,6 +47,7 @@ import org.thoughtcrime.securesms.PassphraseRequiredActivity;
import org.thoughtcrime.securesms.R; import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.components.SearchToolbar; import org.thoughtcrime.securesms.components.SearchToolbar;
import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode; import org.thoughtcrime.securesms.contacts.ContactsCursorLoader.DisplayMode;
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey;
import org.thoughtcrime.securesms.conversation.ConversationIntents; import org.thoughtcrime.securesms.conversation.ConversationIntents;
import org.thoughtcrime.securesms.database.SignalDatabase; import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.database.ThreadDatabase; import org.thoughtcrime.securesms.database.ThreadDatabase;
@ -56,6 +57,8 @@ import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId; import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.sharing.interstitial.ShareInterstitialActivity; import org.thoughtcrime.securesms.sharing.interstitial.ShareInterstitialActivity;
import org.thoughtcrime.securesms.stories.Stories; import org.thoughtcrime.securesms.stories.Stories;
import org.thoughtcrime.securesms.stories.dialogs.StoryDialogs;
import org.thoughtcrime.securesms.stories.settings.hide.HideStoryFromDialogFragment;
import org.thoughtcrime.securesms.util.ConversationUtil; import org.thoughtcrime.securesms.util.ConversationUtil;
import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicLanguage;
import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme; import org.thoughtcrime.securesms.util.DynamicNoActionBarTheme;
@ -78,6 +81,7 @@ import java.util.concurrent.atomic.AtomicReference;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers; import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.schedulers.Schedulers; import io.reactivex.rxjava3.schedulers.Schedulers;
import kotlin.Unit;
/** /**
* Entry point for sharing content into the app. * Entry point for sharing content into the app.
@ -380,11 +384,30 @@ public class ShareActivity extends PassphraseRequiredActivity
.commit(); .commit();
shareConfirm.setOnClickListener(unused -> { shareConfirm.setOnClickListener(unused -> {
shareConfirm.setEnabled(false);
Set<ShareContact> shareContacts = viewModel.getShareContacts(); Set<ShareContact> shareContacts = viewModel.getShareContacts();
if (shareContacts.isEmpty()) throw new AssertionError(); StoryDialogs.INSTANCE.guardWithAddToYourStoryDialog(this,
else if (shareContacts.size() == 1) onConfirmSingleDestination(shareContacts.iterator().next()); shareContacts.stream()
else onConfirmMultipleDestinations(shareContacts); .filter(contact -> contact.getRecipientId().isPresent())
.map(contact -> Recipient.resolved(contact.getRecipientId().get()))
.filter(Recipient::isMyStory)
.map(myStory -> new ContactSearchKey.Story(myStory.getId()))
.collect(java.util.stream.Collectors.toList()),
() -> {
performSend(shareContacts);
return Unit.INSTANCE;
},
() -> {
shareConfirm.setEnabled(true);
new HideStoryFromDialogFragment().show(getSupportFragmentManager(), null);
return Unit.INSTANCE;
},
() -> {
shareConfirm.setEnabled(true);
return Unit.INSTANCE;
});
}); });
viewModel.getSelectedContactModels().observe(this, models -> { viewModel.getSelectedContactModels().observe(this, models -> {
@ -438,6 +461,12 @@ public class ShareActivity extends PassphraseRequiredActivity
}); });
} }
private void performSend(Set<ShareContact> shareContacts) {
if (shareContacts.isEmpty()) throw new AssertionError();
else if (shareContacts.size() == 1) onConfirmSingleDestination(shareContacts.iterator().next());
else onConfirmMultipleDestinations(shareContacts);
}
private void initializeArgs() { private void initializeArgs() {
this.args = ShareIntents.Args.from(getIntent()); this.args = ShareIntents.Args.from(getIntent());
} }

Wyświetl plik

@ -3,6 +3,9 @@ package org.thoughtcrime.securesms.stories.dialogs
import android.content.Context import android.content.Context
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.thoughtcrime.securesms.R import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
object StoryDialogs { object StoryDialogs {
@ -11,17 +14,33 @@ object StoryDialogs {
*/ */
fun guardWithAddToYourStoryDialog( fun guardWithAddToYourStoryDialog(
context: Context, context: Context,
contacts: Collection<ContactSearchKey>,
onAddToStory: () -> Unit, onAddToStory: () -> Unit,
onEditViewers: () -> Unit, onEditViewers: () -> Unit,
onCancel: () -> Unit = {} onCancel: () -> Unit = {}
) { ) {
if (!isFirstSendToMyStory(contacts)) {
onAddToStory()
} else {
SignalStore.storyValues().userHasBeenNotifiedAboutStories = true
MaterialAlertDialogBuilder(context, R.style.Signal_ThemeOverlay_Dialog_Rounded) MaterialAlertDialogBuilder(context, R.style.Signal_ThemeOverlay_Dialog_Rounded)
.setTitle(R.string.StoryDialogs__add_to_story_q) .setTitle(R.string.StoryDialogs__add_to_story_q)
.setMessage(R.string.StoryDialogs__adding_content) .setMessage(R.string.StoryDialogs__adding_content)
.setPositiveButton(R.string.StoryDialogs__add_to_story) { _, _ -> onAddToStory.invoke() } .setPositiveButton(R.string.StoryDialogs__add_to_story) { _, _ ->
onAddToStory.invoke()
}
.setNeutralButton(R.string.StoryDialogs__edit_viewers) { _, _ -> onEditViewers.invoke() } .setNeutralButton(R.string.StoryDialogs__edit_viewers) { _, _ -> onEditViewers.invoke() }
.setNegativeButton(android.R.string.cancel) { _, _ -> onCancel.invoke() } .setNegativeButton(android.R.string.cancel) { _, _ -> onCancel.invoke() }
.setCancelable(false) .setCancelable(false)
.show() .show()
} }
}
private fun isFirstSendToMyStory(shareContacts: Collection<ContactSearchKey>): Boolean {
if (SignalStore.storyValues().userHasBeenNotifiedAboutStories) {
return false
}
return shareContacts.any { it is ContactSearchKey.Story && Recipient.resolved(it.recipientId).isMyStory }
}
} }