Add lazy thread creation throughout in preparation for CFV2.

This commit is contained in:
Alex Hart
2023-07-12 15:33:34 -03:00
committed by Clark Chen
parent 6ca9cb6da1
commit 8f253ffc43
24 changed files with 176 additions and 82 deletions

View File

@@ -7,20 +7,27 @@ import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import org.signal.core.util.concurrent.LifecycleDisposable;
import org.thoughtcrime.securesms.components.settings.app.AppSettingsActivity;
import org.thoughtcrime.securesms.conversation.ConversationIntents;
import org.thoughtcrime.securesms.groups.ui.creategroup.CreateGroupActivity;
import org.thoughtcrime.securesms.insights.InsightsLauncher;
import org.thoughtcrime.securesms.recipients.RecipientId;
import io.reactivex.rxjava3.disposables.Disposable;
public class MainNavigator {
public static final int REQUEST_CONFIG_CHANGES = 901;
private final MainActivity activity;
private final MainActivity activity;
private final LifecycleDisposable lifecycleDisposable;
public MainNavigator(@NonNull MainActivity activity) {
this.activity = activity;
this.activity = activity;
this.lifecycleDisposable = new LifecycleDisposable();
lifecycleDisposable.bindTo(activity);
}
public static MainNavigator get(@NonNull Activity activity) {
@@ -33,7 +40,7 @@ public class MainNavigator {
/**
* @return True if the back pressed was handled in our own custom way, false if it should be given
* to the system to do the default behavior.
* to the system to do the default behavior.
*/
public boolean onBackPressed() {
Fragment fragment = getFragmentManager().findFragmentById(R.id.fragment_container);
@@ -46,13 +53,16 @@ public class MainNavigator {
}
public void goToConversation(@NonNull RecipientId recipientId, long threadId, int distributionType, int startingPosition) {
Intent intent = ConversationIntents.createBuilder(activity, recipientId, threadId)
.withDistributionType(distributionType)
.withStartingPosition(startingPosition)
.build();
Disposable disposable = ConversationIntents.createBuilder(activity, recipientId, threadId)
.map(builder -> builder.withDistributionType(distributionType)
.withStartingPosition(startingPosition)
.build())
.subscribe(intent -> {
activity.startActivity(intent);
activity.overridePendingTransition(R.anim.slide_from_end, R.anim.fade_scale_out);
});
activity.startActivity(intent);
activity.overridePendingTransition(R.anim.slide_from_end, R.anim.fade_scale_out);
lifecycleDisposable.add(disposable);
}
public void goToAppSettings() {
@@ -79,7 +89,7 @@ public class MainNavigator {
public interface BackHandler {
/**
* @return True if the back pressed was handled in our own custom way, false if it should be given
* to the system to do the default behavior.
* to the system to do the default behavior.
*/
boolean onBackPressed();
}

View File

@@ -36,6 +36,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import com.google.android.material.snackbar.Snackbar;
import org.signal.core.util.DimensionUnit;
import org.signal.core.util.concurrent.LifecycleDisposable;
import org.signal.core.util.concurrent.SimpleTask;
import org.signal.core.util.logging.Log;
import org.thoughtcrime.securesms.components.menu.ActionItem;
@@ -45,14 +46,12 @@ import org.thoughtcrime.securesms.contacts.management.ContactsManagementViewMode
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey;
import org.thoughtcrime.securesms.contacts.sync.ContactDiscovery;
import org.thoughtcrime.securesms.conversation.ConversationIntents;
import org.thoughtcrime.securesms.database.SignalDatabase;
import org.thoughtcrime.securesms.groups.ui.creategroup.CreateGroupActivity;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.FeatureFlags;
import org.signal.core.util.concurrent.LifecycleDisposable;
import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
import java.io.IOException;
@@ -64,6 +63,8 @@ import java.util.function.Consumer;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import io.reactivex.rxjava3.disposables.Disposable;
/**
* Activity container for starting a new conversation.
*
@@ -163,15 +164,18 @@ public class NewConversationActivity extends ContactSelectionActivity
}
private void launch(Recipient recipient) {
long existingThread = SignalDatabase.threads().getThreadIdIfExistsFor(recipient.getId());
Intent intent = ConversationIntents.createBuilder(this, recipient.getId(), existingThread)
.withDraftText(getIntent().getStringExtra(Intent.EXTRA_TEXT))
.withDataUri(getIntent().getData())
.withDataType(getIntent().getType())
.build();
Disposable disposable = ConversationIntents.createBuilder(this, recipient.getId(), -1L)
.map(builder -> builder
.withDraftText(getIntent().getStringExtra(Intent.EXTRA_TEXT))
.withDataUri(getIntent().getData())
.withDataType(getIntent().getType())
.build())
.subscribe(intent -> {
startActivity(intent);
finish();
});
startActivity(intent);
finish();
disposables.add(disposable);
}
@Override
@@ -233,8 +237,8 @@ public class NewConversationActivity extends ContactSelectionActivity
@Override
public boolean onLongClick(View anchorView, ContactSearchKey contactSearchKey, RecyclerView recyclerView) {
RecipientId recipientId = contactSearchKey.requireRecipientSearchKey().getRecipientId();
List<ActionItem> actions = generateContextualActionsForRecipient(recipientId);
RecipientId recipientId = contactSearchKey.requireRecipientSearchKey().getRecipientId();
List<ActionItem> actions = generateContextualActionsForRecipient(recipientId);
if (actions.isEmpty()) {
return false;
}
@@ -269,7 +273,12 @@ public class NewConversationActivity extends ContactSelectionActivity
R.drawable.ic_chat_message_24,
getString(R.string.NewConversationActivity__message),
R.color.signal_colorOnSurface,
() -> startActivity(ConversationIntents.createBuilder(this, recipient.getId(), -1L).build())
() -> {
Disposable disposable = ConversationIntents.createBuilder(this, recipient.getId(), -1L)
.subscribe(builder -> startActivity(builder.build()));
disposables.add(disposable);
}
);
}
@@ -370,7 +379,7 @@ public class NewConversationActivity extends ContactSelectionActivity
.show();
}
private void displaySnackbar(@StringRes int message, Object ... formatArgs) {
private void displaySnackbar(@StringRes int message, Object... formatArgs) {
Snackbar.make(findViewById(android.R.id.content), getString(message, formatArgs), Snackbar.LENGTH_SHORT).show();
}
}

View File

@@ -48,9 +48,9 @@ public class SmsSendtoActivity extends Activity {
Toast.makeText(this, R.string.ConversationActivity_specify_recipient, Toast.LENGTH_LONG).show();
} else {
Recipient recipient = Recipient.external(this, destination.getDestination());
long threadId = SignalDatabase.threads().getThreadIdIfExistsFor(recipient.getId());
long threadId = SignalDatabase.threads().getOrCreateThreadIdFor(recipient);
nextIntent = ConversationIntents.createBuilder(this, recipient.getId(), threadId)
nextIntent = ConversationIntents.createBuilderSync(this, recipient.getId(), threadId)
.withDraftText(destination.getBody())
.build();
}

View File

@@ -264,12 +264,14 @@ class GiftFlowConfirmationFragment :
override fun onPaymentComplete(gatewayRequest: GatewayRequest) {
val mainActivityIntent = MainActivity.clearTop(requireContext())
val conversationIntent = ConversationIntents
.createBuilder(requireContext(), viewModel.snapshot.recipient!!.id, -1L)
.withGiftBadge(viewModel.snapshot.giftBadge!!)
.build()
requireActivity().startActivities(arrayOf(mainActivityIntent, conversationIntent))
lifecycleDisposable += ConversationIntents
.createBuilder(requireContext(), viewModel.snapshot.recipient!!.id, -1L)
.subscribe { conversationIntent ->
requireActivity().startActivities(
arrayOf(mainActivityIntent, conversationIntent.withGiftBadge(viewModel.snapshot.giftBadge!!).build())
)
}
}
override fun onProcessorActionProcessed() = Unit

View File

@@ -4,6 +4,8 @@ import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.RecyclerView
import io.reactivex.rxjava3.kotlin.subscribeBy
import org.signal.core.util.concurrent.LifecycleDisposable
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.calls.links.details.CallLinkDetailsActivity
import org.thoughtcrime.securesms.components.menu.ActionItem
@@ -21,6 +23,9 @@ class CallLogContextMenu(
private val fragment: Fragment,
private val callbacks: Callbacks
) {
private val lifecycleDisposable by lazy { LifecycleDisposable().bindTo(fragment.viewLifecycleOwner) }
fun show(recyclerView: RecyclerView, anchor: View, call: CallLogRow.Call) {
recyclerView.suppressLayout(true)
anchor.isSelected = true
@@ -91,7 +96,10 @@ class CallLogContextMenu(
iconRes = R.drawable.symbol_open_24,
title = fragment.getString(R.string.CallContextMenu__go_to_chat)
) {
fragment.startActivity(ConversationIntents.createBuilder(fragment.requireContext(), call.peer.id, -1L).build())
lifecycleDisposable += ConversationIntents.createBuilder(fragment.requireContext(), call.peer.id, -1L)
.subscribeBy {
fragment.startActivity(it.build())
}
}
}
}

View File

@@ -26,6 +26,7 @@ import app.cash.exhaustive.Exhaustive
import com.google.android.flexbox.FlexboxLayoutManager
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.snackbar.Snackbar
import io.reactivex.rxjava3.kotlin.subscribeBy
import org.signal.core.util.DimensionUnit
import org.signal.core.util.concurrent.LifecycleDisposable
import org.signal.core.util.getParcelableArrayListExtraCompat
@@ -387,7 +388,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
enabled = !state.isDeprecatedOrUnregistered,
onMessageClick = {
val intent = ConversationIntents
.createBuilder(requireContext(), state.recipient.id, state.threadId)
.createBuilderSync(requireContext(), state.recipient.id, state.threadId)
.build()
startActivity(intent)
@@ -432,12 +433,15 @@ class ConversationSettingsFragment : DSLSettingsFragment(
}
},
onSearchClick = {
val intent = ConversationIntents.createBuilder(requireContext(), state.recipient.id, state.threadId)
.withSearchOpen(true)
.build()
lifecycleDisposable += ConversationIntents.createBuilder(requireContext(), state.recipient.id, state.threadId)
.subscribeBy { builder ->
val intent = builder
.withSearchOpen(true)
.build()
startActivity(intent)
requireActivity().finish()
startActivity(intent)
requireActivity().finish()
}
}
)
)

View File

@@ -99,7 +99,7 @@ class VoiceNoteNotificationManager {
notificationManager.setColor(color);
Intent conversationActivity = ConversationIntents.createBuilder(context, recipientId, threadId)
Intent conversationActivity = ConversationIntents.createBuilderSync(context, recipientId, threadId)
.withStartingPosition(startingPosition)
.build();

View File

@@ -2050,7 +2050,7 @@ public class ConversationFragment extends LoggingFragment implements Multiselect
@Override
public void goToMediaPreview(ConversationItem parent, View sharedElement, MediaIntentFactory.MediaPreviewArgs args) {
if (listener.isInBubble()) {
Intent intent = ConversationIntents.createBuilder(requireActivity(), recipient.getId(), threadId)
Intent intent = ConversationIntents.createBuilderSync(requireActivity(), recipient.getId(), threadId)
.withStartingPosition(list.getChildAdapterPosition(parent))
.build();

View File

@@ -6,6 +6,7 @@ import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -28,6 +29,10 @@ import java.util.Collection;
import java.util.List;
import java.util.Objects;
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.schedulers.Schedulers;
public class ConversationIntents {
private static final String TAG = Log.tag(ConversationIntents.class);
@@ -52,8 +57,26 @@ public class ConversationIntents {
private ConversationIntents() {
}
public static @NonNull Builder createBuilder(@NonNull Context context, @NonNull RecipientId recipientId, long threadId) {
return new Builder(context, recipientId, threadId);
/**
* Create a conversation builder for the given recipientId / threadId. Thread ids are required for CFV2,
* so we will resolve the Recipient into a ThreadId if the threadId is invalid (below 0)
*
* @param context Context for Intent creation
* @param recipientId The RecipientId to query the thread ID for if the passed one is invalid.
* @param threadId The threadId, or -1L
*
* @return A Single that will return a builder to create the conversation intent.
*/
@MainThread
public static @NonNull Single<Builder> createBuilder(@NonNull Context context, @NonNull RecipientId recipientId, long threadId) {
if (threadId > 0L) {
return Single.just(createBuilderSync(context, recipientId, threadId));
} else {
return Single.fromCallable(() -> {
long newThreadId = SignalDatabase.threads().getOrCreateThreadIdFor(Recipient.resolved(recipientId));
return createBuilderSync(context, recipientId, newThreadId);
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread());
}
}
public static @NonNull Builder createPopUpBuilder(@NonNull Context context, @NonNull RecipientId recipientId, long threadId) {
@@ -64,6 +87,20 @@ public class ConversationIntents {
return new Builder(context, BubbleConversationActivity.class, recipientId, threadId).build();
}
/**
* Create a Builder for a Conversation Intent. Does not perform a lookup for the thread id if the thread id is < 1. For CFV2, this is
* considered an invalid state and will be met with an IllegalArgumentException.
*
* @param context Context for Intent creation
* @param recipientId The recipientId, only used if the threadId is not valid
* @param threadId The threadId, required for CFV2.
*
* @return A builder that can be used to create a conversation intent.
*/
public static @NonNull Builder createBuilderSync(@NonNull Context context, @NonNull RecipientId recipientId, long threadId) {
return new Builder(context, recipientId, threadId);
}
static boolean isInvalid(@NonNull Bundle arguments) {
Uri uri = getIntentData(arguments);
if (isBubbleIntentUri(uri)) {
@@ -308,7 +345,7 @@ public class ConversationIntents {
this.context = context;
this.conversationActivityClass = conversationActivityClass;
this.recipientId = recipientId;
this.threadId = resolveThreadId(recipientId, threadId);
this.threadId = checkThreadId(threadId);
this.conversationScreenType = ConversationScreenType.fromActivityClass(conversationActivityClass);
}
@@ -475,11 +512,9 @@ public class ConversationIntents {
}
}
private static long resolveThreadId(@NonNull RecipientId recipientId, long threadId) {
private static long checkThreadId(long threadId) {
if (threadId < 0 && SignalStore.internalValues().useConversationFragmentV2()) {
Log.w(TAG, "Getting thread id from database...");
// TODO [alex] -- Yes, this hits the database. No, we shouldn't be doing this.
return SignalDatabase.threads().getOrCreateThreadIdFor(Recipient.resolved(recipientId));
throw new IllegalArgumentException("ThreadId is a required field in CFV2");
} else {
return threadId;
}

View File

@@ -4451,7 +4451,7 @@ public class ConversationParentFragment extends Fragment
@Override
public void onNavigateToMessage(long threadId, @NonNull RecipientId threadRecipientId, @NonNull RecipientId senderId, long messageTimestamp, long messagePositionInThread) {
if (threadId != ConversationParentFragment.this.threadId) {
startActivity(ConversationIntents.createBuilder(requireActivity(), threadRecipientId, threadId)
startActivity(ConversationIntents.createBuilderSync(requireActivity(), threadRecipientId, threadId)
.withStartingPosition((int) messagePositionInThread)
.build());
} else {

View File

@@ -73,7 +73,7 @@ public class AddGroupDetailsActivity extends PassphraseRequiredActivity implemen
}
void goToConversation(@NonNull RecipientId recipientId, long threadId) {
Intent intent = ConversationIntents.createBuilder(this, recipientId, threadId)
Intent intent = ConversationIntents.createBuilderSync(this, recipientId, threadId)
.firstTimeInSelfCreatedGroup()
.build();

View File

@@ -132,7 +132,7 @@ public final class GroupJoinBottomSheetDialogFragment extends BottomSheetDialogF
viewModel.getJoinSuccess().observe(getViewLifecycleOwner(), joinGroupSuccess -> {
Log.i(TAG, "Group joined, navigating to group");
Intent intent = ConversationIntents.createBuilder(requireContext(), joinGroupSuccess.getGroupRecipient().getId(), joinGroupSuccess.getGroupThreadId())
Intent intent = ConversationIntents.createBuilderSync(requireContext(), joinGroupSuccess.getGroupRecipient().getId(), joinGroupSuccess.getGroupThreadId())
.build();
requireActivity().startActivity(intent);

View File

@@ -110,7 +110,7 @@ class MediaPreviewRepository {
stopwatch.split("get recipient ID")
stopwatch.stop(TAG)
ConversationIntents.createBuilder(context, recipientId, threadId)
ConversationIntents.createBuilderSync(context, recipientId, threadId)
.withStartingPosition(messagePosition)
.build()
}

View File

@@ -128,7 +128,7 @@ data class NotificationConversation(
)
)
} else {
ConversationIntents.createBuilder(context, recipient.id, thread.threadId)
ConversationIntents.createBuilderSync(context, recipient.id, thread.threadId)
.withStartingPosition(mostRecentNotification.getStartingPosition(context))
.build()
}.makeUniqueToPreventMerging()

View File

@@ -349,7 +349,7 @@ object NotificationFactory {
val intent: Intent = if (recipient.isDistributionList || thread.groupStoryId != null) {
Intent(context, MyStoriesActivity::class.java)
} else {
ConversationIntents.createBuilder(context, recipient.id, thread.threadId)
ConversationIntents.createBuilderSync(context, recipient.id, thread.threadId)
.build()
}.makeUniqueToPreventMerging()
@@ -419,7 +419,7 @@ object NotificationFactory {
val intent: Intent = if (recipient.isDistributionList || thread.groupStoryId != null) {
Intent(context, MyStoriesActivity::class.java)
} else {
ConversationIntents.createBuilder(context, recipient.id, thread.threadId)
ConversationIntents.createBuilderSync(context, recipient.id, thread.threadId)
.build()
}.makeUniqueToPreventMerging()

View File

@@ -118,7 +118,7 @@ public class PaymentRecipientSelectionFragment extends LoggingFragment implement
private void openConversation(@NonNull RecipientId recipientId) {
SimpleTask.run(getViewLifecycleOwner().getLifecycle(),
() -> SignalDatabase.threads().getThreadIdIfExistsFor(recipientId),
threadId -> startActivity(ConversationIntents.createBuilder(requireContext(), recipientId, threadId).build()));
() -> SignalDatabase.threads().getOrCreateThreadIdFor(Recipient.resolved(recipientId)),
threadId -> startActivity(ConversationIntents.createBuilderSync(requireContext(), recipientId, threadId).build()));
}
}

View File

@@ -72,7 +72,7 @@ class ScheduledMessageManager(
@WorkerThread
override fun scheduleAlarm(application: Application, event: Event, delay: Long) {
val conversationIntent = ConversationIntents.createBuilder(application, event.recipientId, event.threadId).build()
val conversationIntent = ConversationIntents.createBuilderSync(application, event.recipientId, event.threadId).build()
trySetExactAlarm(
application,

View File

@@ -13,6 +13,7 @@ import androidx.activity.viewModels
import androidx.core.content.ContextCompat
import androidx.core.content.pm.ShortcutManagerCompat
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.kotlin.subscribeBy
import org.signal.core.util.Result
import org.signal.core.util.concurrent.LifecycleDisposable
import org.signal.core.util.getParcelableArrayListCompat
@@ -164,11 +165,13 @@ class ShareActivity : PassphraseRequiredActivity(), MultiselectForwardFragment.C
Result.success(UnresolvedShareData.ExternalPrimitiveShare(stringBuilder))
} ?: Result.failure(IntentError.SEND_MULTIPLE_TEXT)
}
intent.action == Intent.ACTION_SEND_MULTIPLE && intent.hasExtra(Intent.EXTRA_STREAM) -> {
intent.getParcelableArrayListExtraCompat(Intent.EXTRA_STREAM, Uri::class.java)?.let {
Result.success(UnresolvedShareData.ExternalMultiShare(it))
} ?: Result.failure(IntentError.SEND_MULTIPLE_STREAM)
}
intent.action == Intent.ACTION_SEND && intent.hasExtra(Intent.EXTRA_STREAM) -> {
val uri: Uri? = intent.getParcelableExtraCompat(Intent.EXTRA_STREAM, Uri::class.java)
if (uri == null) {
@@ -178,9 +181,11 @@ class ShareActivity : PassphraseRequiredActivity(), MultiselectForwardFragment.C
Result.success(UnresolvedShareData.ExternalSingleShare(uri, intent.type, text))
}
}
intent.action == Intent.ACTION_SEND && intent.hasExtra(Intent.EXTRA_TEXT) -> {
extractSingleExtraTextFromIntent()
}
else -> null
} ?: Result.failure(IntentError.UNKNOWN)
}
@@ -221,18 +226,21 @@ class ShareActivity : PassphraseRequiredActivity(), MultiselectForwardFragment.C
Log.d(TAG, "Opening conversation...")
val multiShareArgs = shareEvent.getMultiShareArgs()
val conversationIntentBuilder = ConversationIntents.createBuilder(this, shareEvent.contact.recipientId, -1L)
.withDataUri(multiShareArgs.dataUri)
.withDataType(multiShareArgs.dataType)
.withMedia(multiShareArgs.media)
.withDraftText(multiShareArgs.draftText)
.withStickerLocator(multiShareArgs.stickerLocator)
.asBorderless(multiShareArgs.isBorderless)
.withShareDataTimestamp(System.currentTimeMillis())
lifecycleDisposable += ConversationIntents.createBuilder(this, shareEvent.contact.recipientId, -1L)
.subscribeBy { conversationIntentBuilder ->
conversationIntentBuilder
.withDataUri(multiShareArgs.dataUri)
.withDataType(multiShareArgs.dataType)
.withMedia(multiShareArgs.media)
.withDraftText(multiShareArgs.draftText)
.withStickerLocator(multiShareArgs.stickerLocator)
.asBorderless(multiShareArgs.isBorderless)
.withShareDataTimestamp(System.currentTimeMillis())
val mainActivityIntent = MainActivity.clearTop(this)
finish()
startActivities(arrayOf(mainActivityIntent, conversationIntentBuilder.build()))
val mainActivityIntent = MainActivity.clearTop(this)
finish()
startActivities(arrayOf(mainActivityIntent, conversationIntentBuilder.build()))
}
}
private fun openMediaInterstitial(shareEvent: ShareEvent.OpenMediaInterstitial) {

View File

@@ -183,6 +183,7 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l
R.id.reminder_action_update_now -> {
PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext())
}
R.id.reminder_action_re_register -> {
startActivity(RegistrationNavigationActivity.newIntentForReRegistration(requireContext()))
}
@@ -324,8 +325,11 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l
MultiselectForwardFragment.showBottomSheet(childFragmentManager, args)
}
},
onGoToChat = {
startActivityIfAble(ConversationIntents.createBuilder(requireContext(), it.data.storyRecipient.id, -1L).build())
onGoToChat = { model ->
lifecycleDisposable += ConversationIntents.createBuilder(requireContext(), model.data.storyRecipient.id, -1L)
.subscribeBy {
startActivityIfAble(it.build())
}
},
onHideStory = {
if (!it.data.isHidden) {

View File

@@ -6,6 +6,7 @@ import androidx.appcompat.widget.Toolbar
import androidx.core.content.ContextCompat
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import io.reactivex.rxjava3.kotlin.subscribeBy
import org.signal.core.util.concurrent.LifecycleDisposable
import org.signal.core.util.dp
import org.thoughtcrime.securesms.R
@@ -45,8 +46,10 @@ class GroupStorySettingsFragment : DSLSettingsFragment(menuId = R.menu.story_gro
iconRes = R.drawable.ic_open_24_tinted,
title = getString(R.string.StoriesLandingItem__go_to_chat),
action = {
lifecycleDisposable += viewModel.getConversationData().subscribe { data ->
startActivity(ConversationIntents.createBuilder(requireContext(), data.groupRecipientId, data.groupThreadId).build())
lifecycleDisposable += viewModel.getConversationData().flatMap { data ->
ConversationIntents.createBuilder(requireContext(), data.groupRecipientId, data.groupThreadId)
}.subscribeBy {
startActivity(it.build())
}
}
)

View File

@@ -34,6 +34,7 @@ import com.google.android.material.progressindicator.CircularProgressIndicatorSp
import com.google.android.material.progressindicator.IndeterminateDrawable
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Observable
import io.reactivex.rxjava3.kotlin.subscribeBy
import org.signal.core.util.DimensionUnit
import org.signal.core.util.concurrent.LifecycleDisposable
import org.signal.core.util.dp
@@ -1064,7 +1065,9 @@ class StoryViewerPageFragment :
}
},
onGoToChat = {
startActivity(ConversationIntents.createBuilder(requireContext(), storyViewerPageArgs.recipientId, -1L).build())
lifecycleDisposable += ConversationIntents.createBuilder(requireContext(), storyViewerPageArgs.recipientId, -1L).subscribeBy {
startActivity(it.build())
}
},
onHide = {
viewModel.setIsDisplayingHideDialog(true)

View File

@@ -5,6 +5,8 @@ import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import io.reactivex.rxjava3.kotlin.subscribeBy
import org.signal.core.util.concurrent.LifecycleDisposable
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
@@ -37,9 +39,13 @@ class StoryViewsFragment :
private val storyId: Long
get() = requireArguments().getLong(ARG_STORY_ID)
private val lifecycleDisposable = LifecycleDisposable()
override fun bindAdapter(adapter: MappingAdapter) {
StoryViewItem.register(adapter)
lifecycleDisposable.bindTo(viewLifecycleOwner)
val emptyNotice: View = requireView().findViewById(R.id.empty_notice)
val disabledNotice: View = requireView().findViewById(R.id.disabled_notice)
val disabledButton: View = requireView().findViewById(R.id.disabled_button)
@@ -74,9 +80,11 @@ class StoryViewsFragment :
StoryViewItem.Model(
storyViewItemData = storyViewItemData,
canRemoveMember = state.storyRecipient?.isDistributionList ?: false,
goToChat = {
val chatIntent = ConversationIntents.createBuilder(requireContext(), it.storyViewItemData.recipient.id, -1L).build()
startActivity(chatIntent)
goToChat = { model ->
lifecycleDisposable += ConversationIntents.createBuilder(requireContext(), model.storyViewItemData.recipient.id, -1L).subscribeBy {
val chatIntent = it.build()
startActivity(chatIntent)
}
},
removeFromStory = {
if (state.storyRecipient?.isDistributionList == true) {

View File

@@ -48,6 +48,7 @@ import org.thoughtcrime.securesms.util.views.SimpleProgressDialog;
import org.whispersystems.signalservice.api.push.ServiceId;
import java.io.IOException;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.TimeUnit;
@@ -142,13 +143,12 @@ public class CommunicationActions {
new AsyncTask<Void, Void, Long>() {
@Override
protected Long doInBackground(Void... voids) {
return SignalDatabase.threads().getThreadIdFor(recipient.getId());
return SignalDatabase.threads().getOrCreateThreadIdFor(recipient);
}
@Override
protected void onPostExecute(@Nullable Long threadId) {
// TODO [alex] -- ThreadID should *always* exist
ConversationIntents.Builder builder = ConversationIntents.createBuilder(context, recipient.getId(), threadId != null ? threadId : -1);
protected void onPostExecute(@NonNull Long threadId) {
ConversationIntents.Builder builder = ConversationIntents.createBuilderSync(context, recipient.getId(), Objects.requireNonNull(threadId));
if (!TextUtils.isEmpty(text)) {
builder.withDraftText(text);
}

View File

@@ -216,14 +216,14 @@ public final class ConversationUtil {
{
Recipient resolved = recipient.resolve();
Person[] persons = buildPersons(context, resolved);
Long threadId = SignalDatabase.threads().getThreadIdFor(resolved.getId());
long threadId = SignalDatabase.threads().getOrCreateThreadIdFor(resolved);
String shortName = resolved.isSelf() ? context.getString(R.string.note_to_self) : resolved.getShortDisplayName(context);
String longName = resolved.isSelf() ? context.getString(R.string.note_to_self) : resolved.getDisplayName(context);
String shortcutId = getShortcutId(resolved);
ShortcutInfoCompat.Builder builder = new ShortcutInfoCompat.Builder(context, shortcutId)
.setLongLived(true)
.setIntent(ConversationIntents.createBuilder(context, resolved.getId(), threadId != null ? threadId : -1).build())
.setIntent(ConversationIntents.createBuilderSync(context, resolved.getId(), threadId).build())
.setShortLabel(shortName)
.setLongLabel(longName)
.setIcon(AvatarUtil.getIconCompatForShortcut(context, resolved))