Remove deprecated SMS fields from recipient table.
This commit is contained in:
parent
e7972d4903
commit
e3ec53c2d0
52 changed files with 34 additions and 2044 deletions
|
@ -17,7 +17,6 @@ object MmsHelper {
|
|||
recipient: Recipient = Recipient.UNKNOWN,
|
||||
body: String = "body",
|
||||
sentTimeMillis: Long = System.currentTimeMillis(),
|
||||
subscriptionId: Int = -1,
|
||||
expiresIn: Long = 0,
|
||||
viewOnce: Boolean = false,
|
||||
distributionType: Int = ThreadTable.DistributionTypes.DEFAULT,
|
||||
|
@ -32,7 +31,6 @@ object MmsHelper {
|
|||
recipient = recipient,
|
||||
body = body,
|
||||
timestamp = sentTimeMillis,
|
||||
subscriptionId = subscriptionId,
|
||||
expiresIn = expiresIn,
|
||||
viewOnce = viewOnce,
|
||||
distributionType = distributionType,
|
||||
|
|
|
@ -6,7 +6,6 @@ import androidx.annotation.NonNull;
|
|||
|
||||
import org.signal.core.util.logging.Log;
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
||||
import org.thoughtcrime.securesms.insights.InsightsOptOut;
|
||||
import org.thoughtcrime.securesms.jobmanager.JobManager;
|
||||
import org.thoughtcrime.securesms.jobs.EmojiSearchIndexDownloadJob;
|
||||
import org.thoughtcrime.securesms.jobs.StickerPackDownloadJob;
|
||||
|
@ -30,7 +29,6 @@ public final class AppInitialization {
|
|||
public static void onFirstEverAppLaunch(@NonNull Context context) {
|
||||
Log.i(TAG, "onFirstEverAppLaunch()");
|
||||
|
||||
InsightsOptOut.userRequestedOptOut(context);
|
||||
TextSecurePreferences.setAppMigrationVersion(context, ApplicationMigrations.CURRENT_VERSION);
|
||||
TextSecurePreferences.setJobManagerVersion(context, JobManager.CURRENT_VERSION);
|
||||
TextSecurePreferences.setLastVersionCode(context, Util.getCanonicalVersionCode());
|
||||
|
@ -71,7 +69,6 @@ public final class AppInitialization {
|
|||
public static void onRepairFirstEverAppLaunch(@NonNull Context context) {
|
||||
Log.w(TAG, "onRepairFirstEverAppLaunch()");
|
||||
|
||||
InsightsOptOut.userRequestedOptOut(context);
|
||||
TextSecurePreferences.setAppMigrationVersion(context, ApplicationMigrations.CURRENT_VERSION);
|
||||
TextSecurePreferences.setJobManagerVersion(context, JobManager.CURRENT_VERSION);
|
||||
TextSecurePreferences.setLastVersionCode(context, Util.getCanonicalVersionCode());
|
||||
|
|
|
@ -254,13 +254,8 @@ public class InviteActivity extends PassphraseRequiredActivity implements Contac
|
|||
for (SelectedContact contact : contacts) {
|
||||
RecipientId recipientId = contact.getOrCreateRecipientId(context);
|
||||
Recipient recipient = Recipient.resolved(recipientId);
|
||||
int subscriptionId = recipient.getDefaultSubscriptionId().orElse(-1);
|
||||
|
||||
MessageSender.send(context, OutgoingMessage.sms(recipient, message, subscriptionId), -1L, MessageSender.SendType.SMS, null, null);
|
||||
|
||||
if (recipient.getContactUri() != null) {
|
||||
SignalDatabase.recipients().setHasSentInvite(recipient.getId());
|
||||
}
|
||||
MessageSender.send(context, OutgoingMessage.sms(recipient, message), -1L, MessageSender.SendType.SMS, null, null);
|
||||
}
|
||||
|
||||
return null;
|
||||
|
|
|
@ -11,7 +11,6 @@ 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;
|
||||
|
@ -78,10 +77,6 @@ public class MainNavigator {
|
|||
activity.startActivity(intent);
|
||||
}
|
||||
|
||||
public void goToInsights() {
|
||||
InsightsLauncher.showInsightsDashboard(activity.getSupportFragmentManager());
|
||||
}
|
||||
|
||||
private @NonNull FragmentManager getFragmentManager() {
|
||||
return activity.getSupportFragmentManager();
|
||||
}
|
||||
|
|
|
@ -1,25 +0,0 @@
|
|||
package org.thoughtcrime.securesms.components.reminder;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
|
||||
public final class FirstInviteReminder extends Reminder {
|
||||
|
||||
private final int percentIncrease;
|
||||
|
||||
public FirstInviteReminder(final int percentIncrease) {
|
||||
super(R.string.FirstInviteReminder__title, NO_RESOURCE);
|
||||
this.percentIncrease = percentIncrease;
|
||||
|
||||
addAction(new Action(R.string.InsightsReminder__invite, R.id.reminder_action_invite));
|
||||
addAction(new Action(R.string.InsightsReminder__view_insights, R.id.reminder_action_view_insights));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull CharSequence getText(@NonNull Context context) {
|
||||
return context.getString(R.string.FirstInviteReminder__description, percentIncrease);
|
||||
}
|
||||
}
|
|
@ -1,37 +0,0 @@
|
|||
package org.thoughtcrime.securesms.components.reminder;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
public final class SecondInviteReminder extends Reminder {
|
||||
|
||||
private final Recipient recipient;
|
||||
private final int progress;
|
||||
|
||||
public SecondInviteReminder(final @NonNull Context context,
|
||||
final @NonNull Recipient recipient,
|
||||
final int percent)
|
||||
{
|
||||
super(R.string.SecondInviteReminder__title, NO_RESOURCE);
|
||||
this.recipient = recipient;
|
||||
|
||||
this.progress = percent;
|
||||
|
||||
addAction(new Action(R.string.InsightsReminder__invite, R.id.reminder_action_invite));
|
||||
addAction(new Action(R.string.InsightsReminder__view_insights, R.id.reminder_action_view_insights));
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull CharSequence getText(@NonNull Context context) {
|
||||
return context.getString(R.string.SecondInviteReminder__description, recipient.getDisplayName(context));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getProgress() {
|
||||
return progress;
|
||||
}
|
||||
}
|
|
@ -573,7 +573,7 @@ open class ContactSearchAdapter(
|
|||
}
|
||||
|
||||
private fun isSmsContact(model: T): Boolean {
|
||||
return (getRecipient(model).isForceSmsSelection || getRecipient(model).isUnregistered) && !getRecipient(model).isDistributionList
|
||||
return getRecipient(model).isUnregistered && !getRecipient(model).isDistributionList
|
||||
}
|
||||
|
||||
private fun isNotRegistered(model: T): Boolean {
|
||||
|
|
|
@ -184,10 +184,7 @@ import org.thoughtcrime.securesms.groups.ui.LeaveGroupDialog;
|
|||
import org.thoughtcrime.securesms.groups.ui.invitesandrequests.ManagePendingAndRequestingMembersActivity;
|
||||
import org.thoughtcrime.securesms.groups.ui.migration.GroupsV1MigrationInitiationBottomSheetDialogFragment;
|
||||
import org.thoughtcrime.securesms.groups.ui.migration.GroupsV1MigrationSuggestionsDialog;
|
||||
import org.thoughtcrime.securesms.insights.InsightsLauncher;
|
||||
import org.thoughtcrime.securesms.invites.InviteActions;
|
||||
import org.thoughtcrime.securesms.invites.InviteReminderModel;
|
||||
import org.thoughtcrime.securesms.invites.InviteReminderRepository;
|
||||
import org.thoughtcrime.securesms.jobs.ForceUpdateGroupV2Job;
|
||||
import org.thoughtcrime.securesms.jobs.GroupV1MigrationJob;
|
||||
import org.thoughtcrime.securesms.jobs.GroupV2UpdateSelfProfileKeyJob;
|
||||
|
@ -437,7 +434,6 @@ public class ConversationParentFragment extends Fragment
|
|||
private ConversationSearchViewModel searchViewModel;
|
||||
private ConversationStickerViewModel stickerViewModel;
|
||||
private ConversationViewModel viewModel;
|
||||
private InviteReminderModel inviteReminderModel;
|
||||
private ConversationGroupViewModel groupViewModel;
|
||||
private MentionsPickerViewModel mentionsViewModel;
|
||||
private InlineQueryViewModel inlineQueryViewModel;
|
||||
|
@ -1364,8 +1360,7 @@ public class ConversationParentFragment extends Fragment
|
|||
if (paymentsValues.getPaymentsAvailability().isSendAllowed() &&
|
||||
!recipient.get().isSelf() &&
|
||||
!recipient.get().isGroup() &&
|
||||
recipient.get().isRegistered() &&
|
||||
!recipient.get().isForceSmsSelection())
|
||||
recipient.get().isRegistered())
|
||||
{
|
||||
attachmentKeyboardStub.get().filterAttachmentKeyboardButtons(null);
|
||||
} else {
|
||||
|
@ -1425,16 +1420,11 @@ public class ConversationParentFragment extends Fragment
|
|||
sendButton.disableTransportType(MessageSendType.TransportType.SIGNAL);
|
||||
}
|
||||
|
||||
if (!recipient.get().isPushGroup() && recipient.get().isForceSmsSelection() && smsEnabled) {
|
||||
if (isPushAvailable || isPushGroupConversation() || recipient.get().isServiceIdOnly() || recipient.get().isReleaseNotes() || !smsEnabled) {
|
||||
sendButton.setDefaultTransport(MessageSendType.TransportType.SIGNAL);
|
||||
} else {
|
||||
sendButton.setDefaultTransport(MessageSendType.TransportType.SMS);
|
||||
viewModel.insertSmsExportUpdateEvent(recipient.get());
|
||||
} else {
|
||||
if (isPushAvailable || isPushGroupConversation() || recipient.get().isServiceIdOnly() || recipient.get().isReleaseNotes() || !smsEnabled) {
|
||||
sendButton.setDefaultTransport(MessageSendType.TransportType.SIGNAL);
|
||||
} else {
|
||||
sendButton.setDefaultTransport(MessageSendType.TransportType.SMS);
|
||||
viewModel.insertSmsExportUpdateEvent(recipient.get());
|
||||
}
|
||||
}
|
||||
|
||||
calculateCharactersRemaining();
|
||||
|
@ -1710,12 +1700,9 @@ public class ConversationParentFragment extends Fragment
|
|||
private void onSecurityUpdated() {
|
||||
Log.i(TAG, "onSecurityUpdated()");
|
||||
updateReminders();
|
||||
updateDefaultSubscriptionId(recipient.get().getDefaultSubscriptionId());
|
||||
}
|
||||
|
||||
private void initializeInsightObserver() {
|
||||
inviteReminderModel = new InviteReminderModel(requireContext(), new InviteReminderRepository(requireContext()));
|
||||
inviteReminderModel.loadReminder(recipient, this::updateReminders);
|
||||
}
|
||||
|
||||
protected void updateReminders() {
|
||||
|
@ -1724,7 +1711,6 @@ public class ConversationParentFragment extends Fragment
|
|||
return;
|
||||
}
|
||||
|
||||
Optional<Reminder> inviteReminder = inviteReminderModel.getReminder();
|
||||
Integer actionableRequestingMembers = groupViewModel.getActionableRequestingMembers().getValue();
|
||||
List<RecipientId> gv1MigrationSuggestions = groupViewModel.getGroupV1MigrationSuggestions().getValue();
|
||||
|
||||
|
@ -1740,11 +1726,8 @@ public class ConversationParentFragment extends Fragment
|
|||
} else if (SignalStore.account().isRegistered() &&
|
||||
TextSecurePreferences.isShowInviteReminders(context) &&
|
||||
!viewModel.isPushAvailable() &&
|
||||
inviteReminder.isPresent() &&
|
||||
!recipient.get().isGroup()) {
|
||||
reminderView.get().setOnActionClickListener(this::handleReminderAction);
|
||||
reminderView.get().setOnDismissListener(() -> inviteReminderModel.dismissReminder());
|
||||
reminderView.get().showReminder(inviteReminder.get());
|
||||
} else if (actionableRequestingMembers != null && actionableRequestingMembers > 0) {
|
||||
reminderView.get().showReminder(new PendingGroupJoinRequestsReminder(actionableRequestingMembers));
|
||||
reminderView.get().setOnActionClickListener(id -> {
|
||||
|
@ -1785,8 +1768,6 @@ public class ConversationParentFragment extends Fragment
|
|||
if (reminderActionId == R.id.reminder_action_invite) {
|
||||
handleInviteLink();
|
||||
reminderView.get().requestDismiss();
|
||||
} else if (reminderActionId == R.id.reminder_action_view_insights) {
|
||||
InsightsLauncher.showInsightsDashboard(getChildFragmentManager());
|
||||
} else if (reminderActionId == R.id.reminder_action_update_now) {
|
||||
PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext());
|
||||
} else if (reminderActionId == R.id.reminder_action_re_register) {
|
||||
|
@ -1958,8 +1939,6 @@ public class ConversationParentFragment extends Fragment
|
|||
composeText.setMessageSendType(newMessageSendType);
|
||||
|
||||
updateSendButtonColor(newMessageSendType);
|
||||
|
||||
if (manuallySelected) recordTransportPreference(newMessageSendType);
|
||||
});
|
||||
|
||||
titleView.setOnStoryRingClickListener(v -> handleStoryRingClick());
|
||||
|
@ -2461,7 +2440,6 @@ public class ConversationParentFragment extends Fragment
|
|||
titleView.setVerified(identityRecords.isVerified() && !recipient.isSelf());
|
||||
setBlockedUserState(recipient, viewModel.getConversationStateSnapshot().getSecurityInfo());
|
||||
updateReminders();
|
||||
updateDefaultSubscriptionId(recipient.getDefaultSubscriptionId());
|
||||
updatePaymentsAvailable();
|
||||
updateSendButtonColor(sendButton.getSelectedSendType());
|
||||
|
||||
|
@ -2904,7 +2882,6 @@ public class ConversationParentFragment extends Fragment
|
|||
result.getBody(),
|
||||
Collections.emptyList(),
|
||||
System.currentTimeMillis(),
|
||||
-1,
|
||||
expiresIn,
|
||||
result.isViewOnce(),
|
||||
distributionType,
|
||||
|
@ -3033,7 +3010,6 @@ public class ConversationParentFragment extends Fragment
|
|||
OutgoingMessage.buildMessage(slideDeck, body),
|
||||
slideDeck.asAttachments(),
|
||||
System.currentTimeMillis(),
|
||||
sendType.getSimSubscriptionIdOr(-1),
|
||||
expiresIn,
|
||||
viewOnce,
|
||||
distributionType,
|
||||
|
@ -3126,7 +3102,7 @@ public class ConversationParentFragment extends Fragment
|
|||
}
|
||||
ApplicationDependencies.getTypingStatusSender().onTypingStopped(thread);
|
||||
} else {
|
||||
message = OutgoingMessage.sms(recipient.get(), messageBody, sendType.getSimSubscriptionIdOr(-1));
|
||||
message = OutgoingMessage.sms(recipient.get(), messageBody);
|
||||
}
|
||||
|
||||
Permissions.with(this)
|
||||
|
@ -3246,23 +3222,6 @@ public class ConversationParentFragment extends Fragment
|
|||
}
|
||||
}
|
||||
|
||||
private void recordTransportPreference(MessageSendType sendType) {
|
||||
new AsyncTask<Void, Void, Void>() {
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
RecipientTable recipientTable = SignalDatabase.recipients();
|
||||
|
||||
recipientTable.setDefaultSubscriptionId(recipient.getId(), sendType.getSimSubscriptionIdOr(-1));
|
||||
|
||||
if (!recipient.resolve().isPushGroup()) {
|
||||
recipientTable.setForceSmsSelection(recipient.getId(), recipient.get().getRegistered() == RegisteredState.REGISTERED && sendType.usesSmsTransport());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRecorderPermissionRequired() {
|
||||
Permissions.with(this)
|
||||
|
|
|
@ -104,8 +104,7 @@ class AttachmentKeyboardFragment : LoggingFragment(R.layout.attachment_keyboard_
|
|||
if (paymentsValues.paymentsAvailability.isSendAllowed &&
|
||||
!recipient.isSelf &&
|
||||
!recipient.isGroup &&
|
||||
recipient.isRegistered &&
|
||||
!recipient.isForceSmsSelection
|
||||
recipient.isRegistered
|
||||
) {
|
||||
attachmentKeyboardView.filterAttachmentKeyboardButtons(null)
|
||||
} else {
|
||||
|
|
|
@ -138,7 +138,6 @@ import org.thoughtcrime.securesms.dependencies.ApplicationDependencies;
|
|||
import org.thoughtcrime.securesms.events.ReminderUpdateEvent;
|
||||
import org.thoughtcrime.securesms.exporter.flow.SmsExportDialogs;
|
||||
import org.thoughtcrime.securesms.groups.SelectionLimits;
|
||||
import org.thoughtcrime.securesms.insights.InsightsLauncher;
|
||||
import org.thoughtcrime.securesms.jobs.ServiceOutageDetectionJob;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.lock.v2.CreateSvrPinActivity;
|
||||
|
@ -472,10 +471,6 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
itemAnimator.disable();
|
||||
SpoilerAnnotation.resetRevealedSpoilers();
|
||||
|
||||
if (Util.isDefaultSmsProvider(requireContext())) {
|
||||
InsightsLauncher.showInsightsModal(requireContext(), requireFragmentManager());
|
||||
}
|
||||
|
||||
if ((!requireCallback().getSearchToolbar().resolved() || !(requireCallback().getSearchToolbar().get().getVisibility() == View.VISIBLE)) && list.getAdapter() != defaultAdapter) {
|
||||
setAdapter(defaultAdapter);
|
||||
}
|
||||
|
@ -561,7 +556,6 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
menu.findItem(R.id.menu_insights).setVisible(Util.isDefaultSmsProvider(requireContext()));
|
||||
menu.findItem(R.id.menu_clear_passphrase).setVisible(!TextSecurePreferences.isPasswordDisabled(requireContext()));
|
||||
|
||||
ConversationFilterRequest request = viewModel.getConversationFilterRequest();
|
||||
|
@ -592,9 +586,6 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
} else if (itemId == R.id.menu_invite) {
|
||||
handleInvite();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_insights) {
|
||||
handleInsights();
|
||||
return true;
|
||||
} else if (itemId == R.id.menu_notification_profile) {
|
||||
handleNotificationProfile();
|
||||
return true;
|
||||
|
@ -1143,10 +1134,6 @@ public class ConversationListFragment extends MainFragment implements ActionMode
|
|||
getNavigator().goToInvite();
|
||||
}
|
||||
|
||||
private void handleInsights() {
|
||||
getNavigator().goToInsights();
|
||||
}
|
||||
|
||||
private void handleNotificationProfile() {
|
||||
NotificationProfileSelectionFragment.show(getParentFragmentManager());
|
||||
}
|
||||
|
|
|
@ -112,7 +112,6 @@ import org.thoughtcrime.securesms.database.model.databaseprotos.SessionSwitchove
|
|||
import org.thoughtcrime.securesms.database.model.databaseprotos.ThreadMergeEvent
|
||||
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
|
||||
import org.thoughtcrime.securesms.groups.GroupMigrationMembershipChange
|
||||
import org.thoughtcrime.securesms.insights.InsightsConstants
|
||||
import org.thoughtcrime.securesms.jobs.OptimizeMessageSearchIndexJob
|
||||
import org.thoughtcrime.securesms.jobs.ThreadUpdateJob
|
||||
import org.thoughtcrime.securesms.jobs.TrimThreadJob
|
||||
|
@ -1084,10 +1083,6 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
|||
if (unread && editedMessage == null) {
|
||||
threads.incrementUnread(threadId, 1, 0)
|
||||
}
|
||||
|
||||
if (message.subscriptionId != -1) {
|
||||
recipients.setDefaultSubscriptionId(message.authorId, message.subscriptionId)
|
||||
}
|
||||
}
|
||||
|
||||
id
|
||||
|
@ -2507,7 +2502,6 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
|||
body = body,
|
||||
attachments = attachments,
|
||||
timestamp = timestamp,
|
||||
subscriptionId = subscriptionId,
|
||||
expiresIn = expiresIn,
|
||||
viewOnce = viewOnce,
|
||||
distributionType = distributionType,
|
||||
|
@ -3712,15 +3706,6 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
|||
.readToSingleInt()
|
||||
}
|
||||
|
||||
fun getInsecureMessageSentCount(threadId: Long): Int {
|
||||
return readableDatabase
|
||||
.select("COUNT(*)")
|
||||
.from(TABLE_NAME)
|
||||
.where("$THREAD_ID = ? AND $outgoingInsecureMessageClause AND $DATE_SENT > ?", threadId, (System.currentTimeMillis() - InsightsConstants.PERIOD_IN_MILLIS))
|
||||
.run()
|
||||
.readToSingleInt()
|
||||
}
|
||||
|
||||
fun getSecureMessageCount(threadId: Long): Int {
|
||||
return readableDatabase
|
||||
.select("COUNT(*)")
|
||||
|
@ -3739,14 +3724,6 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
|||
.readToSingleInt()
|
||||
}
|
||||
|
||||
fun getInsecureMessageCountForInsights(): Int {
|
||||
return getMessageCountForRecipientsAndType(outgoingInsecureMessageClause)
|
||||
}
|
||||
|
||||
fun getSecureMessageCountForInsights(): Int {
|
||||
return getMessageCountForRecipientsAndType(outgoingSecureMessageClause)
|
||||
}
|
||||
|
||||
private fun hasSmsExportMessage(threadId: Long): Boolean {
|
||||
return readableDatabase
|
||||
.exists(TABLE_NAME)
|
||||
|
@ -3754,15 +3731,6 @@ open class MessageTable(context: Context?, databaseHelper: SignalDatabase) : Dat
|
|||
.run()
|
||||
}
|
||||
|
||||
private fun getMessageCountForRecipientsAndType(typeClause: String): Int {
|
||||
return readableDatabase
|
||||
.select("COUNT(*)")
|
||||
.from(TABLE_NAME)
|
||||
.where("$typeClause AND $DATE_SENT > ?", (System.currentTimeMillis() - InsightsConstants.PERIOD_IN_MILLIS))
|
||||
.run()
|
||||
.readToSingleInt()
|
||||
}
|
||||
|
||||
private val outgoingInsecureMessageClause = "($TYPE & ${MessageTypes.BASE_TYPE_MASK}) = ${MessageTypes.BASE_SENT_TYPE} AND NOT ($TYPE & ${MessageTypes.SECURE_MESSAGE_BIT})"
|
||||
private val outgoingSecureMessageClause = "($TYPE & ${MessageTypes.BASE_TYPE_MASK}) = ${MessageTypes.BASE_SENT_TYPE} AND ($TYPE & ${MessageTypes.SECURE_MESSAGE_BIT or MessageTypes.PUSH_MESSAGE_BIT})"
|
||||
|
||||
|
|
|
@ -285,8 +285,6 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
|
|||
CALL_VIBRATE,
|
||||
MUTE_UNTIL,
|
||||
AVATAR_COLOR,
|
||||
SEEN_INVITE_REMINDER,
|
||||
DEFAULT_SUBSCRIPTION_ID,
|
||||
MESSAGE_EXPIRATION_TIME,
|
||||
REGISTERED,
|
||||
PROFILE_KEY,
|
||||
|
@ -305,7 +303,6 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
|
|||
LAST_PROFILE_FETCH,
|
||||
NOTIFICATION_CHANNEL,
|
||||
UNIDENTIFIED_ACCESS_MODE,
|
||||
FORCE_SMS_SELECTION,
|
||||
CAPABILITIES,
|
||||
STORAGE_SERVICE_ID,
|
||||
MENTION_SETTING,
|
||||
|
@ -396,21 +393,6 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
|
|||
"""
|
||||
)
|
||||
|
||||
private val INSIGHTS_INVITEE_LIST =
|
||||
"""
|
||||
SELECT $TABLE_NAME.$ID
|
||||
FROM $TABLE_NAME INNER JOIN ${ThreadTable.TABLE_NAME} ON $TABLE_NAME.$ID = ${ThreadTable.TABLE_NAME}.${ThreadTable.RECIPIENT_ID}
|
||||
WHERE
|
||||
$TABLE_NAME.$GROUP_ID IS NULL AND
|
||||
$TABLE_NAME.$REGISTERED = ${RegisteredState.NOT_REGISTERED.id} AND
|
||||
$TABLE_NAME.$SEEN_INVITE_REMINDER < ${InsightsBannerTier.TIER_TWO.id} AND
|
||||
${ThreadTable.TABLE_NAME}.${ThreadTable.HAS_SENT} AND
|
||||
${ThreadTable.TABLE_NAME}.${ThreadTable.DATE} > ? AND
|
||||
${ThreadTable.TABLE_NAME}.${ThreadTable.ACTIVE} = 1 AND
|
||||
$TABLE_NAME.$HIDDEN = 0
|
||||
ORDER BY ${ThreadTable.TABLE_NAME}.${ThreadTable.DATE} DESC LIMIT 50
|
||||
"""
|
||||
|
||||
/** Used as a placeholder recipient for self during migrations when self isn't yet available. */
|
||||
private val PLACEHOLDER_SELF_ID = -2L
|
||||
}
|
||||
|
@ -1348,24 +1330,6 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
|
|||
}
|
||||
}
|
||||
|
||||
fun setDefaultSubscriptionId(id: RecipientId, defaultSubscriptionId: Int) {
|
||||
val values = ContentValues().apply {
|
||||
put(DEFAULT_SUBSCRIPTION_ID, defaultSubscriptionId)
|
||||
}
|
||||
if (update(id, values)) {
|
||||
ApplicationDependencies.getDatabaseObserver().notifyRecipientChanged(id)
|
||||
}
|
||||
}
|
||||
|
||||
fun setForceSmsSelection(id: RecipientId, forceSmsSelection: Boolean) {
|
||||
val contentValues = ContentValues(1).apply {
|
||||
put(FORCE_SMS_SELECTION, if (forceSmsSelection) 1 else 0)
|
||||
}
|
||||
if (update(id, contentValues)) {
|
||||
ApplicationDependencies.getDatabaseObserver().notifyRecipientChanged(id)
|
||||
}
|
||||
}
|
||||
|
||||
fun setBlocked(id: RecipientId, blocked: Boolean) {
|
||||
val values = ContentValues().apply {
|
||||
put(BLOCKED, if (blocked) 1 else 0)
|
||||
|
@ -1452,29 +1416,6 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
|
|||
StorageSyncHelper.scheduleSyncForDataChange()
|
||||
}
|
||||
|
||||
fun setSeenFirstInviteReminder(id: RecipientId) {
|
||||
setInsightsBannerTier(id, InsightsBannerTier.TIER_ONE)
|
||||
}
|
||||
|
||||
fun setSeenSecondInviteReminder(id: RecipientId) {
|
||||
setInsightsBannerTier(id, InsightsBannerTier.TIER_TWO)
|
||||
}
|
||||
|
||||
fun setHasSentInvite(id: RecipientId) {
|
||||
setSeenSecondInviteReminder(id)
|
||||
}
|
||||
|
||||
private fun setInsightsBannerTier(id: RecipientId, insightsBannerTier: InsightsBannerTier) {
|
||||
val query = "$ID = ? AND $SEEN_INVITE_REMINDER < ?"
|
||||
val args = arrayOf(id.serialize(), insightsBannerTier.toString())
|
||||
val values = ContentValues(1).apply {
|
||||
put(SEEN_INVITE_REMINDER, insightsBannerTier.id)
|
||||
}
|
||||
|
||||
writableDatabase.update(TABLE_NAME, values, query, args)
|
||||
ApplicationDependencies.getDatabaseObserver().notifyRecipientChanged(id)
|
||||
}
|
||||
|
||||
fun setExpireMessages(id: RecipientId, expiration: Int) {
|
||||
val values = ContentValues(1).apply {
|
||||
put(MESSAGE_EXPIRATION_TIME, expiration)
|
||||
|
@ -3096,19 +3037,6 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
|
|||
return operations
|
||||
}
|
||||
|
||||
fun getUninvitedRecipientsForInsights(): List<RecipientId> {
|
||||
val results: MutableList<RecipientId> = LinkedList()
|
||||
val args = arrayOf((System.currentTimeMillis() - TimeUnit.DAYS.toMillis(31)).toString())
|
||||
|
||||
readableDatabase.rawQuery(INSIGHTS_INVITEE_LIST, args).use { cursor ->
|
||||
while (cursor != null && cursor.moveToNext()) {
|
||||
results.add(RecipientId.from(cursor.getLong(cursor.getColumnIndexOrThrow(ID))))
|
||||
}
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
fun getRegistered(): List<RecipientId> {
|
||||
val results: MutableList<RecipientId> = LinkedList()
|
||||
|
||||
|
@ -3899,8 +3827,6 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
|
|||
CHAT_COLORS to Optional.ofNullable(primaryRecord.chatColors).or(Optional.ofNullable(secondaryRecord.chatColors)).map { colors: ChatColors? -> colors!!.serialize().toByteArray() }.orElse(null),
|
||||
AVATAR_COLOR to primaryRecord.avatarColor.serialize(),
|
||||
CUSTOM_CHAT_COLORS_ID to Optional.ofNullable(primaryRecord.chatColors).or(Optional.ofNullable(secondaryRecord.chatColors)).map { colors: ChatColors? -> colors!!.id.longValue }.orElse(null),
|
||||
SEEN_INVITE_REMINDER to secondaryRecord.insightsBannerTier.id,
|
||||
DEFAULT_SUBSCRIPTION_ID to secondaryRecord.getDefaultSubscriptionId().orElse(-1),
|
||||
MESSAGE_EXPIRATION_TIME to if (primaryRecord.expireMessages > 0) primaryRecord.expireMessages else secondaryRecord.expireMessages,
|
||||
REGISTERED to RegisteredState.REGISTERED.id,
|
||||
SYSTEM_GIVEN_NAME to secondaryRecord.systemProfileName.givenName,
|
||||
|
@ -4246,7 +4172,6 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
|
|||
callVibrateState = VibrateState.fromId(cursor.requireInt(CALL_VIBRATE)),
|
||||
messageRingtone = Util.uri(cursor.requireString(MESSAGE_RINGTONE)),
|
||||
callRingtone = Util.uri(cursor.requireString(CALL_RINGTONE)),
|
||||
defaultSubscriptionId = cursor.requireInt(DEFAULT_SUBSCRIPTION_ID),
|
||||
expireMessages = cursor.requireInt(MESSAGE_EXPIRATION_TIME),
|
||||
registered = RegisteredState.fromId(cursor.requireInt(REGISTERED)),
|
||||
profileKey = profileKey,
|
||||
|
@ -4263,9 +4188,7 @@ open class RecipientTable(context: Context, databaseHelper: SignalDatabase) : Da
|
|||
lastProfileFetch = cursor.requireLong(LAST_PROFILE_FETCH),
|
||||
notificationChannel = cursor.requireString(NOTIFICATION_CHANNEL),
|
||||
unidentifiedAccessMode = UnidentifiedAccessMode.fromMode(cursor.requireInt(UNIDENTIFIED_ACCESS_MODE)),
|
||||
forceSmsSelection = cursor.requireBoolean(FORCE_SMS_SELECTION),
|
||||
capabilities = readCapabilities(cursor),
|
||||
insightsBannerTier = InsightsBannerTier.fromId(cursor.requireInt(SEEN_INVITE_REMINDER)),
|
||||
storageId = Base64.decodeNullableOrThrow(cursor.requireString(STORAGE_SERVICE_ID)),
|
||||
mentionSetting = MentionSetting.fromId(cursor.requireInt(MENTION_SETTING)),
|
||||
wallpaper = chatWallpaper,
|
||||
|
|
|
@ -8,7 +8,6 @@ import org.thoughtcrime.securesms.conversation.colors.AvatarColor
|
|||
import org.thoughtcrime.securesms.conversation.colors.ChatColors
|
||||
import org.thoughtcrime.securesms.database.IdentityTable.VerifiedStatus
|
||||
import org.thoughtcrime.securesms.database.RecipientTable
|
||||
import org.thoughtcrime.securesms.database.RecipientTable.InsightsBannerTier
|
||||
import org.thoughtcrime.securesms.database.RecipientTable.MentionSetting
|
||||
import org.thoughtcrime.securesms.database.RecipientTable.RegisteredState
|
||||
import org.thoughtcrime.securesms.database.RecipientTable.UnidentifiedAccessMode
|
||||
|
@ -22,7 +21,6 @@ import org.thoughtcrime.securesms.wallpaper.ChatWallpaper
|
|||
import org.whispersystems.signalservice.api.push.ServiceId
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.ACI
|
||||
import org.whispersystems.signalservice.api.push.ServiceId.PNI
|
||||
import java.util.Optional
|
||||
|
||||
/**
|
||||
* Database model for [RecipientTable].
|
||||
|
@ -43,7 +41,6 @@ data class RecipientRecord(
|
|||
val callVibrateState: VibrateState,
|
||||
val messageRingtone: Uri?,
|
||||
val callRingtone: Uri?,
|
||||
private val defaultSubscriptionId: Int,
|
||||
val expireMessages: Int,
|
||||
val registered: RegisteredState,
|
||||
val profileKey: ByteArray?,
|
||||
|
@ -63,10 +60,7 @@ data class RecipientRecord(
|
|||
val lastProfileFetch: Long,
|
||||
val notificationChannel: String?,
|
||||
val unidentifiedAccessMode: UnidentifiedAccessMode,
|
||||
@get:JvmName("isForceSmsSelection")
|
||||
val forceSmsSelection: Boolean,
|
||||
val capabilities: Capabilities,
|
||||
val insightsBannerTier: InsightsBannerTier,
|
||||
val storageId: ByteArray?,
|
||||
val mentionSetting: MentionSetting,
|
||||
val wallpaper: ChatWallpaper?,
|
||||
|
@ -85,10 +79,6 @@ data class RecipientRecord(
|
|||
val callLinkRoomId: CallLinkRoomId?
|
||||
) {
|
||||
|
||||
fun getDefaultSubscriptionId(): Optional<Int> {
|
||||
return if (defaultSubscriptionId != -1) Optional.of(defaultSubscriptionId) else Optional.empty()
|
||||
}
|
||||
|
||||
fun e164Only(): Boolean {
|
||||
return this.e164 != null && this.aci == null
|
||||
}
|
||||
|
|
|
@ -1,94 +0,0 @@
|
|||
package org.thoughtcrime.securesms.insights;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
final class InsightsAnimatorSetFactory {
|
||||
private static final int PROGRESS_ANIMATION_DURATION = 800;
|
||||
private static final int DETAILS_ANIMATION_DURATION = 200;
|
||||
private static final int PERCENT_SECURE_ANIMATION_DURATION = 400;
|
||||
private static final int LOTTIE_ANIMATION_DURATION = 1500;
|
||||
private static final int ANIMATION_START_DELAY = PROGRESS_ANIMATION_DURATION - DETAILS_ANIMATION_DURATION;
|
||||
private static final float PERCENT_SECURE_MAX_SCALE = 1.3f;
|
||||
|
||||
private InsightsAnimatorSetFactory() {
|
||||
}
|
||||
|
||||
static AnimatorSet create(int insecurePercent,
|
||||
@Nullable final UpdateListener progressUpdateListener,
|
||||
@Nullable final UpdateListener detailsUpdateListener,
|
||||
@Nullable final UpdateListener percentSecureListener,
|
||||
@Nullable final UpdateListener lottieListener)
|
||||
{
|
||||
final int securePercent = 100 - insecurePercent;
|
||||
final AnimatorSet animatorSet = new AnimatorSet();
|
||||
final ValueAnimator[] animators = Stream.of(createProgressAnimator(securePercent, progressUpdateListener),
|
||||
createDetailsAnimator(detailsUpdateListener),
|
||||
createPercentSecureAnimator(percentSecureListener),
|
||||
createLottieAnimator(lottieListener))
|
||||
.filter(a -> a != null)
|
||||
.toArray(ValueAnimator[]::new);
|
||||
|
||||
animatorSet.setInterpolator(new DecelerateInterpolator());
|
||||
animatorSet.playTogether(animators);
|
||||
|
||||
return animatorSet;
|
||||
}
|
||||
|
||||
private static @Nullable Animator createProgressAnimator(int securePercent, @Nullable UpdateListener updateListener) {
|
||||
if (updateListener == null) return null;
|
||||
|
||||
final ValueAnimator progressAnimator = ValueAnimator.ofFloat(0, securePercent / 100f);
|
||||
|
||||
progressAnimator.setDuration(PROGRESS_ANIMATION_DURATION);
|
||||
progressAnimator.addUpdateListener(animation -> updateListener.onUpdate((float) animation.getAnimatedValue()));
|
||||
|
||||
return progressAnimator;
|
||||
}
|
||||
|
||||
private static @Nullable Animator createDetailsAnimator(@Nullable UpdateListener updateListener) {
|
||||
if (updateListener == null) return null;
|
||||
|
||||
final ValueAnimator detailsAnimator = ValueAnimator.ofFloat(0, 1f);
|
||||
|
||||
detailsAnimator.setDuration(DETAILS_ANIMATION_DURATION);
|
||||
detailsAnimator.setStartDelay(ANIMATION_START_DELAY);
|
||||
detailsAnimator.addUpdateListener(animation -> updateListener.onUpdate((float) animation.getAnimatedValue()));
|
||||
|
||||
return detailsAnimator;
|
||||
}
|
||||
|
||||
private static @Nullable Animator createPercentSecureAnimator(@Nullable UpdateListener updateListener) {
|
||||
if (updateListener == null) return null;
|
||||
|
||||
final ValueAnimator percentSecureAnimator = ValueAnimator.ofFloat(1f, PERCENT_SECURE_MAX_SCALE, 1f);
|
||||
|
||||
percentSecureAnimator.setStartDelay(ANIMATION_START_DELAY);
|
||||
percentSecureAnimator.setDuration(PERCENT_SECURE_ANIMATION_DURATION);
|
||||
percentSecureAnimator.addUpdateListener(animation -> updateListener.onUpdate((float) animation.getAnimatedValue()));
|
||||
|
||||
return percentSecureAnimator;
|
||||
}
|
||||
|
||||
private static @Nullable Animator createLottieAnimator(@Nullable UpdateListener updateListener) {
|
||||
if (updateListener == null) return null;
|
||||
|
||||
final ValueAnimator lottieAnimator = ValueAnimator.ofFloat(0, 1f);
|
||||
|
||||
lottieAnimator.setStartDelay(ANIMATION_START_DELAY);
|
||||
lottieAnimator.setDuration(LOTTIE_ANIMATION_DURATION);
|
||||
lottieAnimator.addUpdateListener(animation -> updateListener.onUpdate((float) animation.getAnimatedValue()));
|
||||
|
||||
return lottieAnimator;
|
||||
}
|
||||
|
||||
interface UpdateListener {
|
||||
void onUpdate(float value);
|
||||
}
|
||||
}
|
|
@ -1,13 +0,0 @@
|
|||
package org.thoughtcrime.securesms.insights;
|
||||
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public final class InsightsConstants {
|
||||
|
||||
public static final long PERIOD_IN_DAYS = 7L;
|
||||
public static final long PERIOD_IN_MILLIS = TimeUnit.DAYS.toMillis(PERIOD_IN_DAYS);
|
||||
|
||||
private InsightsConstants() {
|
||||
}
|
||||
|
||||
}
|
|
@ -1,271 +0,0 @@
|
|||
package org.thoughtcrime.securesms.insights;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.appcompat.widget.Toolbar;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import com.airbnb.lottie.LottieAnimationView;
|
||||
import com.google.android.material.dialog.MaterialAlertDialogBuilder;
|
||||
|
||||
import org.thoughtcrime.securesms.NewConversationActivity;
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.ArcProgressBar;
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.util.ThemeUtil;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public final class InsightsDashboardDialogFragment extends DialogFragment {
|
||||
|
||||
private TextView securePercentage;
|
||||
private ArcProgressBar progress;
|
||||
private View progressContainer;
|
||||
private TextView tagline;
|
||||
private TextView encryptedMessages;
|
||||
private TextView title;
|
||||
private TextView description;
|
||||
private RecyclerView insecureRecipients;
|
||||
private TextView locallyGenerated;
|
||||
private AvatarImageView avatarImageView;
|
||||
private InsightsInsecureRecipientsAdapter adapter;
|
||||
private LottieAnimationView lottieAnimationView;
|
||||
private AnimatorSet animatorSet;
|
||||
private Button startAConversation;
|
||||
private Toolbar toolbar;
|
||||
private InsightsDashboardViewModel viewModel;
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(@NonNull Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
|
||||
requireFragmentManager().beginTransaction()
|
||||
.detach(this)
|
||||
.attach(this)
|
||||
.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
if (ThemeUtil.isDarkTheme(requireActivity())) {
|
||||
setStyle(STYLE_NO_FRAME, R.style.TextSecure_DarkTheme);
|
||||
} else {
|
||||
setStyle(STYLE_NO_FRAME, R.style.TextSecure_LightTheme);
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.insights_dashboard, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
securePercentage = view.findViewById(R.id.insights_dashboard_percent_secure);
|
||||
progress = view.findViewById(R.id.insights_dashboard_progress);
|
||||
progressContainer = view.findViewById(R.id.insights_dashboard_percent_container);
|
||||
encryptedMessages = view.findViewById(R.id.insights_dashboard_encrypted_messages);
|
||||
tagline = view.findViewById(R.id.insights_dashboard_tagline);
|
||||
title = view.findViewById(R.id.insights_dashboard_make_signal_secure);
|
||||
description = view.findViewById(R.id.insights_dashboard_invite_your_contacts);
|
||||
insecureRecipients = view.findViewById(R.id.insights_dashboard_recycler);
|
||||
locallyGenerated = view.findViewById(R.id.insights_dashboard_this_stat_was_generated_locally);
|
||||
avatarImageView = view.findViewById(R.id.insights_dashboard_avatar);
|
||||
startAConversation = view.findViewById(R.id.insights_dashboard_start_a_conversation);
|
||||
lottieAnimationView = view.findViewById(R.id.insights_dashboard_lottie_animation);
|
||||
toolbar = view.findViewById(R.id.insights_dashboard_toolbar);
|
||||
|
||||
setupStartAConversation();
|
||||
setDashboardDetailsAlpha(0f);
|
||||
setNotEnoughDataAlpha(0f);
|
||||
setupToolbar();
|
||||
setupRecycler();
|
||||
initializeViewModel();
|
||||
}
|
||||
|
||||
private void setupStartAConversation() {
|
||||
startAConversation.setOnClickListener(v -> startActivity(new Intent(requireActivity(), NewConversationActivity.class)));
|
||||
}
|
||||
|
||||
private void setDashboardDetailsAlpha(float alpha) {
|
||||
tagline.setAlpha(alpha);
|
||||
title.setAlpha(alpha);
|
||||
description.setAlpha(alpha);
|
||||
insecureRecipients.setAlpha(alpha);
|
||||
locallyGenerated.setAlpha(alpha);
|
||||
encryptedMessages.setAlpha(alpha);
|
||||
}
|
||||
|
||||
private void setupToolbar() {
|
||||
toolbar.setNavigationOnClickListener(v -> dismiss());
|
||||
}
|
||||
|
||||
private void setupRecycler() {
|
||||
adapter = new InsightsInsecureRecipientsAdapter(this::handleInviteRecipient);
|
||||
insecureRecipients.setAdapter(adapter);
|
||||
}
|
||||
|
||||
private void initializeViewModel() {
|
||||
final InsightsDashboardViewModel.Repository repository = new InsightsRepository(requireContext());
|
||||
final InsightsDashboardViewModel.Factory factory = new InsightsDashboardViewModel.Factory(repository);
|
||||
|
||||
viewModel = new ViewModelProvider(this, factory).get(InsightsDashboardViewModel.class);
|
||||
|
||||
viewModel.getState().observe(getViewLifecycleOwner(), state -> {
|
||||
updateInsecurePercent(state.getData());
|
||||
updateInsecureRecipients(state.getInsecureRecipients());
|
||||
updateUserAvatar(state.getUserAvatar());
|
||||
});
|
||||
}
|
||||
|
||||
private void updateInsecurePercent(@Nullable InsightsData insightsData) {
|
||||
if (insightsData == null) return;
|
||||
|
||||
if (insightsData.hasEnoughData()) {
|
||||
setTitleAndDescriptionText(insightsData.getPercentInsecure());
|
||||
animateProgress(insightsData.getPercentInsecure());
|
||||
} else {
|
||||
setNotEnoughDataText();
|
||||
animateNotEnoughData();
|
||||
}
|
||||
}
|
||||
|
||||
private void animateProgress(int insecurePercent) {
|
||||
startAConversation.setVisibility(View.GONE);
|
||||
if (animatorSet == null) {
|
||||
animatorSet = InsightsAnimatorSetFactory.create(insecurePercent,
|
||||
this::setProgressPercentage,
|
||||
this::setDashboardDetailsAlpha,
|
||||
this::setPercentSecureScale,
|
||||
insecurePercent == 0 ? this::setLottieProgress : null);
|
||||
|
||||
if (insecurePercent == 0) {
|
||||
animatorSet.addListener(new ToolbarBackgroundColorAnimationListener());
|
||||
}
|
||||
|
||||
animatorSet.start();
|
||||
}
|
||||
}
|
||||
|
||||
private void setProgressPercentage(float percent) {
|
||||
securePercentage.setText(String.valueOf(Math.round(percent * 100)));
|
||||
progress.setProgress(percent);
|
||||
}
|
||||
|
||||
private void setPercentSecureScale(float scale) {
|
||||
progressContainer.setScaleX(scale);
|
||||
progressContainer.setScaleY(scale);
|
||||
}
|
||||
|
||||
private void setLottieProgress(float progress) {
|
||||
lottieAnimationView.setProgress(progress);
|
||||
}
|
||||
|
||||
private void setTitleAndDescriptionText(int insecurePercent) {
|
||||
startAConversation.setVisibility(View.GONE);
|
||||
progressContainer.setVisibility(View.VISIBLE);
|
||||
insecureRecipients.setVisibility(View.VISIBLE);
|
||||
encryptedMessages.setText(R.string.InsightsDashboardFragment__encrypted_messages);
|
||||
tagline.setText(getString(R.string.InsightsDashboardFragment__signal_protocol_automatically_protected, 100 - insecurePercent, InsightsConstants.PERIOD_IN_DAYS));
|
||||
|
||||
if (insecurePercent == 0) {
|
||||
lottieAnimationView.setVisibility(View.VISIBLE);
|
||||
title.setVisibility(View.GONE);
|
||||
description.setVisibility(View.GONE);
|
||||
} else {
|
||||
lottieAnimationView.setVisibility(View.GONE);
|
||||
title.setText(R.string.InsightsDashboardFragment__spread_the_word);
|
||||
description.setText(R.string.InsightsDashboardFragment__invite_your_contacts);
|
||||
title.setVisibility(View.VISIBLE);
|
||||
description.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private void setNotEnoughDataText() {
|
||||
startAConversation.setVisibility(View.VISIBLE);
|
||||
progressContainer.setVisibility(View.INVISIBLE);
|
||||
insecureRecipients.setVisibility(View.GONE);
|
||||
encryptedMessages.setText(R.string.InsightsDashboardFragment__not_enough_data);
|
||||
tagline.setText(getString(R.string.InsightsDashboardFragment__your_insights_percentage_is_calculated_based_on, InsightsConstants.PERIOD_IN_DAYS));
|
||||
}
|
||||
|
||||
private void animateNotEnoughData() {
|
||||
if (animatorSet == null) {
|
||||
animatorSet = InsightsAnimatorSetFactory.create(0, null, this::setNotEnoughDataAlpha, null, null);
|
||||
animatorSet.start();
|
||||
}
|
||||
}
|
||||
|
||||
private void setNotEnoughDataAlpha(float alpha) {
|
||||
encryptedMessages.setAlpha(alpha);
|
||||
tagline.setAlpha(alpha);
|
||||
startAConversation.setAlpha(alpha);
|
||||
}
|
||||
|
||||
private void updateInsecureRecipients(@NonNull List<Recipient> recipients) {
|
||||
adapter.updateData(recipients);
|
||||
}
|
||||
|
||||
private void updateUserAvatar(@Nullable InsightsUserAvatar userAvatar) {
|
||||
if (userAvatar == null) avatarImageView.setImageDrawable(null);
|
||||
else userAvatar.load(avatarImageView);
|
||||
}
|
||||
|
||||
private void handleInviteRecipient(final @NonNull Recipient recipient) {
|
||||
new MaterialAlertDialogBuilder(requireContext())
|
||||
.setTitle(getResources().getQuantityString(R.plurals.InviteActivity_send_sms_invites, 1, 1))
|
||||
.setMessage(getString(R.string.InviteActivity_lets_switch_to_signal, getString(R.string.install_url)))
|
||||
.setPositiveButton(R.string.InsightsDashboardFragment__send, (dialog, which) -> viewModel.sendSmsInvite(recipient))
|
||||
.setNegativeButton(R.string.InsightsDashboardFragment__cancel, (dialog, which) -> dialog.dismiss())
|
||||
.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
if (animatorSet != null) {
|
||||
animatorSet.cancel();
|
||||
animatorSet = null;
|
||||
}
|
||||
|
||||
super.onDestroyView();
|
||||
}
|
||||
|
||||
private final class ToolbarBackgroundColorAnimationListener implements Animator.AnimatorListener {
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
toolbar.setBackgroundResource(R.color.transparent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
toolbar.setBackgroundColor(ThemeUtil.getThemedColor(requireContext(), android.R.attr.windowBackground));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
toolbar.setBackgroundColor(ThemeUtil.getThemedColor(requireContext(), android.R.attr.windowBackground));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,70 +0,0 @@
|
|||
package org.thoughtcrime.securesms.insights;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
final class InsightsDashboardState {
|
||||
|
||||
private final List<Recipient> insecureRecipients;
|
||||
private final InsightsData insightsData;
|
||||
private final InsightsUserAvatar userAvatar;
|
||||
|
||||
private InsightsDashboardState(@NonNull Builder builder) {
|
||||
this.insecureRecipients = builder.insecureRecipients;
|
||||
this.insightsData = builder.insightsData;
|
||||
this.userAvatar = builder.userAvatar;
|
||||
}
|
||||
|
||||
static @NonNull InsightsDashboardState.Builder builder() {
|
||||
return new InsightsDashboardState.Builder();
|
||||
}
|
||||
|
||||
@NonNull InsightsDashboardState.Builder buildUpon() {
|
||||
return builder().withData(insightsData).withUserAvatar(userAvatar).withInsecureRecipients(insecureRecipients);
|
||||
}
|
||||
|
||||
@NonNull List<Recipient> getInsecureRecipients() {
|
||||
return insecureRecipients;
|
||||
}
|
||||
|
||||
@Nullable InsightsUserAvatar getUserAvatar() {
|
||||
return userAvatar;
|
||||
}
|
||||
|
||||
@Nullable InsightsData getData() {
|
||||
return insightsData;
|
||||
}
|
||||
|
||||
static final class Builder {
|
||||
private List<Recipient> insecureRecipients = Collections.emptyList();
|
||||
private InsightsUserAvatar userAvatar;
|
||||
private InsightsData insightsData;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
||||
@NonNull Builder withInsecureRecipients(@NonNull List<Recipient> insecureRecipients) {
|
||||
this.insecureRecipients = insecureRecipients;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull Builder withData(@NonNull InsightsData insightsData) {
|
||||
this.insightsData = insightsData;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull Builder withUserAvatar(@NonNull InsightsUserAvatar userAvatar) {
|
||||
this.userAvatar = userAvatar;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull InsightsDashboardState build() {
|
||||
return new InsightsDashboardState(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
package org.thoughtcrime.securesms.insights;
|
||||
|
||||
import androidx.annotation.MainThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.util.Consumer;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
final class InsightsDashboardViewModel extends ViewModel {
|
||||
|
||||
private final MutableLiveData<InsightsDashboardState> internalState = new MutableLiveData<>(InsightsDashboardState.builder().build());
|
||||
private final Repository repository;
|
||||
|
||||
private InsightsDashboardViewModel(@NonNull Repository repository) {
|
||||
this.repository = repository;
|
||||
|
||||
repository.getInsightsData(data -> internalState.setValue(getNewState(b -> b.withData(data))));
|
||||
repository.getUserAvatar(avatar -> internalState.setValue(getNewState(b -> b.withUserAvatar(avatar))));
|
||||
updateInsecureRecipients();
|
||||
}
|
||||
|
||||
private void updateInsecureRecipients() {
|
||||
repository.getInsecureRecipients(recipients -> internalState.setValue(getNewState(b -> b.withInsecureRecipients(recipients))));
|
||||
}
|
||||
|
||||
@MainThread
|
||||
private InsightsDashboardState getNewState(Consumer<InsightsDashboardState.Builder> builderConsumer) {
|
||||
InsightsDashboardState.Builder builder = internalState.getValue().buildUpon();
|
||||
builderConsumer.accept(builder);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull LiveData<InsightsDashboardState> getState() {
|
||||
return internalState;
|
||||
}
|
||||
|
||||
public void sendSmsInvite(@NonNull Recipient recipient) {
|
||||
repository.sendSmsInvite(recipient, this::updateInsecureRecipients);
|
||||
}
|
||||
|
||||
interface Repository {
|
||||
void getInsightsData(@NonNull Consumer<InsightsData> insightsDataConsumer);
|
||||
void getInsecureRecipients(@NonNull Consumer<List<Recipient>> insecureRecipientsConsumer);
|
||||
void getUserAvatar(@NonNull Consumer<InsightsUserAvatar> userAvatarConsumer);
|
||||
void sendSmsInvite(@NonNull Recipient recipient, Runnable onSmsMessageSent);
|
||||
}
|
||||
|
||||
final static class Factory implements ViewModelProvider.Factory {
|
||||
|
||||
private final Repository repository;
|
||||
|
||||
Factory(@NonNull Repository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
|
||||
return (T) new InsightsDashboardViewModel(repository);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,19 +0,0 @@
|
|||
package org.thoughtcrime.securesms.insights;
|
||||
|
||||
final class InsightsData {
|
||||
private final boolean hasEnoughData;
|
||||
private final int percentInsecure;
|
||||
|
||||
InsightsData(boolean hasEnoughData, int percentInsecure) {
|
||||
this.hasEnoughData = hasEnoughData;
|
||||
this.percentInsecure = percentInsecure;
|
||||
}
|
||||
|
||||
public boolean hasEnoughData() {
|
||||
return hasEnoughData;
|
||||
}
|
||||
|
||||
public int getPercentInsecure() {
|
||||
return percentInsecure;
|
||||
}
|
||||
}
|
|
@ -1,118 +0,0 @@
|
|||
package org.thoughtcrime.securesms.insights;
|
||||
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.util.Consumer;
|
||||
import androidx.recyclerview.widget.DiffUtil;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
final class InsightsInsecureRecipientsAdapter extends RecyclerView.Adapter<InsightsInsecureRecipientsAdapter.ViewHolder> {
|
||||
|
||||
private List<Recipient> data = Collections.emptyList();
|
||||
|
||||
private final Consumer<Recipient> onInviteClickedConsumer;
|
||||
|
||||
InsightsInsecureRecipientsAdapter(Consumer<Recipient> onInviteClickedConsumer) {
|
||||
this.onInviteClickedConsumer = onInviteClickedConsumer;
|
||||
}
|
||||
|
||||
public void updateData(List<Recipient> recipients) {
|
||||
List<Recipient> oldData = data;
|
||||
data = recipients;
|
||||
|
||||
DiffUtil.calculateDiff(new DiffCallback(oldData, data)).dispatchUpdatesTo(this);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
return new ViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.insights_dashboard_adapter_item, parent, false), this::handleInviteClicked);
|
||||
}
|
||||
|
||||
private void handleInviteClicked(@NonNull Integer position) {
|
||||
onInviteClickedConsumer.accept(data.get(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
holder.bind(data.get(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return data.size();
|
||||
}
|
||||
|
||||
static final class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
private AvatarImageView avatarImageView;
|
||||
private TextView displayName;
|
||||
|
||||
private ViewHolder(@NonNull View itemView, Consumer<Integer> onInviteClicked) {
|
||||
super(itemView);
|
||||
|
||||
avatarImageView = itemView.findViewById(R.id.recipient_avatar);
|
||||
displayName = itemView.findViewById(R.id.recipient_display_name);
|
||||
|
||||
Button invite = itemView.findViewById(R.id.recipient_invite);
|
||||
invite.setOnClickListener(v -> {
|
||||
int adapterPosition = getAdapterPosition();
|
||||
|
||||
if (adapterPosition == RecyclerView.NO_POSITION) return;
|
||||
|
||||
onInviteClicked.accept(adapterPosition);
|
||||
});
|
||||
}
|
||||
|
||||
private void bind(@NonNull Recipient recipient) {
|
||||
displayName.setText(recipient.getDisplayName(itemView.getContext()));
|
||||
avatarImageView.setAvatar(GlideApp.with(itemView), recipient, false);
|
||||
}
|
||||
}
|
||||
|
||||
private static class DiffCallback extends DiffUtil.Callback {
|
||||
|
||||
private final List<Recipient> oldData;
|
||||
private final List<Recipient> newData;
|
||||
|
||||
private DiffCallback(@NonNull List<Recipient> oldData,
|
||||
@NonNull List<Recipient> newData)
|
||||
{
|
||||
this.oldData = oldData;
|
||||
this.newData = newData;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOldListSize() {
|
||||
return oldData.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNewListSize() {
|
||||
return newData.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {
|
||||
return oldData.get(oldItemPosition).getId() == newData.get(newItemPosition).getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {
|
||||
return oldData.get(oldItemPosition).equals(newData.get(newItemPosition));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,25 +0,0 @@
|
|||
package org.thoughtcrime.securesms.insights;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
public final class InsightsLauncher {
|
||||
|
||||
private static final String MODAL_TAG = "modal.fragment";
|
||||
|
||||
public static void showInsightsModal(@NonNull Context context, @NonNull FragmentManager fragmentManager) {
|
||||
if (InsightsOptOut.userHasOptedOut(context)) return;
|
||||
|
||||
final Fragment fragment = fragmentManager.findFragmentByTag(MODAL_TAG);
|
||||
|
||||
if (fragment == null) new InsightsModalDialogFragment().show(fragmentManager, MODAL_TAG);
|
||||
}
|
||||
|
||||
public static void showInsightsDashboard(@NonNull FragmentManager fragmentManager) {
|
||||
new InsightsDashboardDialogFragment().show(fragmentManager, null);
|
||||
}
|
||||
|
||||
}
|
|
@ -1,132 +0,0 @@
|
|||
package org.thoughtcrime.securesms.insights;
|
||||
|
||||
import android.animation.AnimatorSet;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.Button;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.components.ArcProgressBar;
|
||||
import org.thoughtcrime.securesms.components.AvatarImageView;
|
||||
|
||||
public final class InsightsModalDialogFragment extends DialogFragment {
|
||||
|
||||
private ArcProgressBar progress;
|
||||
private TextView securePercentage;
|
||||
private AvatarImageView avatarImageView;
|
||||
private AnimatorSet animatorSet;
|
||||
private View progressContainer;
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(@NonNull Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
|
||||
requireFragmentManager().beginTransaction()
|
||||
.detach(this)
|
||||
.attach(this)
|
||||
.commit();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setStyle(STYLE_NO_FRAME, R.style.Theme_Signal_Insights_Modal);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
|
||||
Dialog dialog = super.onCreateDialog(savedInstanceState);
|
||||
dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.insights_modal, container, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
View close = view.findViewById(R.id.insights_modal_close);
|
||||
Button viewInsights = view.findViewById(R.id.insights_modal_view_insights);
|
||||
|
||||
progress = view.findViewById(R.id.insights_modal_progress);
|
||||
securePercentage = view.findViewById(R.id.insights_modal_percent_secure);
|
||||
avatarImageView = view.findViewById(R.id.insights_modal_avatar);
|
||||
progressContainer = view.findViewById(R.id.insights_modal_percent_container);
|
||||
|
||||
close.setOnClickListener(v -> dismiss());
|
||||
viewInsights.setOnClickListener(v -> openInsightsAndDismiss());
|
||||
|
||||
initializeViewModel();
|
||||
}
|
||||
|
||||
private void initializeViewModel() {
|
||||
final InsightsModalViewModel.Repository repository = new InsightsRepository(requireContext());
|
||||
final InsightsModalViewModel.Factory factory = new InsightsModalViewModel.Factory(repository);
|
||||
final InsightsModalViewModel viewModel = new ViewModelProvider(this, factory).get(InsightsModalViewModel.class);
|
||||
|
||||
viewModel.getState().observe(getViewLifecycleOwner(), state -> {
|
||||
updateInsecurePercent(state.getData());
|
||||
updateUserAvatar(state.getUserAvatar());
|
||||
});
|
||||
}
|
||||
|
||||
private void updateInsecurePercent(@Nullable InsightsData insightsData) {
|
||||
if (insightsData == null) return;
|
||||
|
||||
if (animatorSet == null) {
|
||||
animatorSet = InsightsAnimatorSetFactory.create(insightsData.getPercentInsecure(), this::setProgressPercentage, null, this::setPercentSecureScale, null);
|
||||
animatorSet.start();
|
||||
}
|
||||
}
|
||||
|
||||
private void setProgressPercentage(float percent) {
|
||||
securePercentage.setText(String.valueOf(Math.round(percent * 100)));
|
||||
progress.setProgress(percent);
|
||||
}
|
||||
|
||||
private void setPercentSecureScale(float scale) {
|
||||
progressContainer.setScaleX(scale);
|
||||
progressContainer.setScaleY(scale);
|
||||
}
|
||||
|
||||
private void updateUserAvatar(@Nullable InsightsUserAvatar userAvatar) {
|
||||
if (userAvatar == null) avatarImageView.setImageDrawable(null);
|
||||
else userAvatar.load(avatarImageView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss(@NonNull DialogInterface dialog) {
|
||||
super.onDismiss(dialog);
|
||||
InsightsOptOut.userRequestedOptOut(requireContext());
|
||||
}
|
||||
|
||||
private void openInsightsAndDismiss() {
|
||||
InsightsLauncher.showInsightsDashboard(requireFragmentManager());
|
||||
dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyView() {
|
||||
if (animatorSet != null) {
|
||||
animatorSet.cancel();
|
||||
animatorSet = null;
|
||||
}
|
||||
|
||||
super.onDestroyView();
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
package org.thoughtcrime.securesms.insights;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
final class InsightsModalState {
|
||||
|
||||
private final InsightsData insightsData;
|
||||
private final InsightsUserAvatar userAvatar;
|
||||
|
||||
private InsightsModalState(@NonNull Builder builder) {
|
||||
this.insightsData = builder.insightsData;
|
||||
this.userAvatar = builder.userAvatar;
|
||||
}
|
||||
|
||||
static @NonNull InsightsModalState.Builder builder() {
|
||||
return new InsightsModalState.Builder();
|
||||
}
|
||||
|
||||
@NonNull InsightsModalState.Builder buildUpon() {
|
||||
return builder().withUserAvatar(userAvatar).withData(insightsData);
|
||||
}
|
||||
|
||||
@Nullable InsightsUserAvatar getUserAvatar() {
|
||||
return userAvatar;
|
||||
}
|
||||
|
||||
@Nullable InsightsData getData() {
|
||||
return insightsData;
|
||||
}
|
||||
|
||||
static final class Builder {
|
||||
private InsightsData insightsData;
|
||||
private InsightsUserAvatar userAvatar;
|
||||
|
||||
private Builder() {
|
||||
}
|
||||
|
||||
@NonNull Builder withData(@NonNull InsightsData insightsData) {
|
||||
this.insightsData = insightsData;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull Builder withUserAvatar(@NonNull InsightsUserAvatar userAvatar) {
|
||||
this.userAvatar = userAvatar;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NonNull InsightsModalState build() {
|
||||
return new InsightsModalState(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package org.thoughtcrime.securesms.insights;
|
||||
|
||||
import androidx.annotation.MainThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.util.Consumer;
|
||||
import androidx.lifecycle.LiveData;
|
||||
import androidx.lifecycle.MutableLiveData;
|
||||
import androidx.lifecycle.ViewModel;
|
||||
import androidx.lifecycle.ViewModelProvider;
|
||||
|
||||
final class InsightsModalViewModel extends ViewModel {
|
||||
|
||||
private final MutableLiveData<InsightsModalState> internalState = new MutableLiveData<>(InsightsModalState.builder().build());
|
||||
|
||||
private InsightsModalViewModel(@NonNull Repository repository) {
|
||||
repository.getInsightsData(data -> internalState.setValue(getNewState(b -> b.withData(data))));
|
||||
repository.getUserAvatar(avatar -> internalState.setValue(getNewState(b -> b.withUserAvatar(avatar))));
|
||||
}
|
||||
|
||||
@MainThread
|
||||
private InsightsModalState getNewState(Consumer<InsightsModalState.Builder> builderConsumer) {
|
||||
InsightsModalState.Builder builder = internalState.getValue().buildUpon();
|
||||
builderConsumer.accept(builder);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@NonNull LiveData<InsightsModalState> getState() {
|
||||
return internalState;
|
||||
}
|
||||
|
||||
interface Repository {
|
||||
void getInsightsData(Consumer<InsightsData> insecurePercentConsumer);
|
||||
void getUserAvatar(@NonNull Consumer<InsightsUserAvatar> userAvatarConsumer);
|
||||
}
|
||||
|
||||
final static class Factory implements ViewModelProvider.Factory {
|
||||
|
||||
private final Repository repository;
|
||||
|
||||
Factory(@NonNull Repository repository) {
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
|
||||
return (T) new InsightsModalViewModel(repository);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,22 +0,0 @@
|
|||
package org.thoughtcrime.securesms.insights;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.util.TextSecurePreferences;
|
||||
|
||||
public final class InsightsOptOut {
|
||||
private static final String INSIGHTS_OPT_OUT_PREFERENCE = "insights.opt.out";
|
||||
|
||||
private InsightsOptOut() {
|
||||
}
|
||||
|
||||
static boolean userHasOptedOut(@NonNull Context context) {
|
||||
return TextSecurePreferences.getBooleanPreference(context, INSIGHTS_OPT_OUT_PREFERENCE, false);
|
||||
}
|
||||
|
||||
public static void userRequestedOptOut(@NonNull Context context) {
|
||||
TextSecurePreferences.setBooleanPreference(context, INSIGHTS_OPT_OUT_PREFERENCE, true);
|
||||
}
|
||||
}
|
|
@ -1,89 +0,0 @@
|
|||
package org.thoughtcrime.securesms.insights;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.util.Consumer;
|
||||
|
||||
import com.annimon.stream.Stream;
|
||||
|
||||
import org.thoughtcrime.securesms.R;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.GeneratedContactPhoto;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
|
||||
import org.thoughtcrime.securesms.database.MessageTable;
|
||||
import org.thoughtcrime.securesms.database.RecipientTable;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.mms.OutgoingMessage;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.thoughtcrime.securesms.recipients.RecipientId;
|
||||
import org.thoughtcrime.securesms.sms.MessageSender;
|
||||
import org.thoughtcrime.securesms.util.Util;
|
||||
import org.signal.core.util.concurrent.SimpleTask;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class InsightsRepository implements InsightsDashboardViewModel.Repository, InsightsModalViewModel.Repository {
|
||||
|
||||
private final Context context;
|
||||
|
||||
public InsightsRepository(Context context) {
|
||||
this.context = context.getApplicationContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getInsightsData(@NonNull Consumer<InsightsData> insightsDataConsumer) {
|
||||
SimpleTask.run(() -> {
|
||||
MessageTable messageTable = SignalDatabase.messages();
|
||||
int insecure = messageTable.getInsecureMessageCountForInsights();
|
||||
int secure = messageTable.getSecureMessageCountForInsights();
|
||||
|
||||
if (insecure + secure == 0) {
|
||||
return new InsightsData(false, 0);
|
||||
} else {
|
||||
return new InsightsData(true, Util.clamp((int) Math.ceil((insecure * 100f) / (insecure + secure)), 0, 100));
|
||||
}
|
||||
}, insightsDataConsumer::accept);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getInsecureRecipients(@NonNull Consumer<List<Recipient>> insecureRecipientsConsumer) {
|
||||
SimpleTask.run(() -> {
|
||||
RecipientTable recipientTable = SignalDatabase.recipients();
|
||||
List<RecipientId> unregisteredRecipients = recipientTable.getUninvitedRecipientsForInsights();
|
||||
|
||||
return Stream.of(unregisteredRecipients)
|
||||
.map(Recipient::resolved)
|
||||
.toList();
|
||||
},
|
||||
insecureRecipientsConsumer::accept);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void getUserAvatar(@NonNull Consumer<InsightsUserAvatar> avatarConsumer) {
|
||||
SimpleTask.run(() -> {
|
||||
Recipient self = Recipient.self().resolve();
|
||||
String name = Optional.of(self.getDisplayName(context)).orElse("");
|
||||
|
||||
return new InsightsUserAvatar(new ProfileContactPhoto(self),
|
||||
self.getAvatarColor(),
|
||||
new GeneratedContactPhoto(name, R.drawable.ic_profile_outline_40));
|
||||
}, avatarConsumer::accept);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void sendSmsInvite(@NonNull Recipient recipient, Runnable onSmsMessageSent) {
|
||||
SimpleTask.run(() -> {
|
||||
Recipient resolved = recipient.resolve();
|
||||
int subscriptionId = resolved.getDefaultSubscriptionId().orElse(-1);
|
||||
String message = context.getString(R.string.InviteActivity_lets_switch_to_signal, context.getString(R.string.install_url));
|
||||
|
||||
MessageSender.send(context, OutgoingMessage.sms(resolved, message, subscriptionId), -1L, MessageSender.SendType.SMS, null, null);
|
||||
|
||||
RecipientTable database = SignalDatabase.recipients();
|
||||
database.setHasSentInvite(recipient.getId());
|
||||
|
||||
return null;
|
||||
}, v -> onSmsMessageSent.run());
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package org.thoughtcrime.securesms.insights;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.widget.ImageView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.bumptech.glide.load.engine.DiskCacheStrategy;
|
||||
|
||||
import org.thoughtcrime.securesms.contacts.avatars.FallbackContactPhoto;
|
||||
import org.thoughtcrime.securesms.contacts.avatars.ProfileContactPhoto;
|
||||
import org.thoughtcrime.securesms.conversation.colors.AvatarColor;
|
||||
import org.thoughtcrime.securesms.mms.GlideApp;
|
||||
|
||||
class InsightsUserAvatar {
|
||||
private final ProfileContactPhoto profileContactPhoto;
|
||||
private final AvatarColor fallbackColor;
|
||||
private final FallbackContactPhoto fallbackContactPhoto;
|
||||
|
||||
InsightsUserAvatar(@NonNull ProfileContactPhoto profileContactPhoto, @NonNull AvatarColor fallbackColor, @NonNull FallbackContactPhoto fallbackContactPhoto) {
|
||||
this.profileContactPhoto = profileContactPhoto;
|
||||
this.fallbackColor = fallbackColor;
|
||||
this.fallbackContactPhoto = fallbackContactPhoto;
|
||||
}
|
||||
|
||||
private Drawable fallbackDrawable(@NonNull Context context) {
|
||||
return fallbackContactPhoto.asDrawable(context, fallbackColor);
|
||||
}
|
||||
|
||||
void load(ImageView into) {
|
||||
GlideApp.with(into)
|
||||
.load(profileContactPhoto)
|
||||
.error(fallbackDrawable(into.getContext()))
|
||||
.circleCrop()
|
||||
.diskCacheStrategy(DiskCacheStrategy.ALL)
|
||||
.into(into);
|
||||
}
|
||||
}
|
|
@ -1,143 +0,0 @@
|
|||
package org.thoughtcrime.securesms.invites;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.MainThread;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.WorkerThread;
|
||||
|
||||
import org.thoughtcrime.securesms.components.reminder.FirstInviteReminder;
|
||||
import org.thoughtcrime.securesms.components.reminder.Reminder;
|
||||
import org.thoughtcrime.securesms.components.reminder.SecondInviteReminder;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.database.ThreadTable;
|
||||
import org.thoughtcrime.securesms.recipients.LiveRecipient;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
import org.signal.core.util.concurrent.SimpleTask;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
|
||||
public final class InviteReminderModel {
|
||||
|
||||
private static final int FIRST_INVITE_REMINDER_MESSAGE_THRESHOLD = 10;
|
||||
private static final int SECOND_INVITE_REMINDER_MESSAGE_THRESHOLD = 500;
|
||||
|
||||
private final Context context;
|
||||
private final Repository repository;
|
||||
private final AtomicReference<ReminderInfo> reminderInfo = new AtomicReference<>();
|
||||
|
||||
public InviteReminderModel(@NonNull Context context, @NonNull Repository repository) {
|
||||
this.context = context;
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@MainThread
|
||||
public void loadReminder(LiveRecipient liveRecipient, Runnable reminderCheckComplete) {
|
||||
SimpleTask.run(() -> createReminderInfo(liveRecipient.resolve()), result -> {
|
||||
reminderInfo.set(result);
|
||||
reminderCheckComplete.run();
|
||||
});
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
private @NonNull ReminderInfo createReminderInfo(Recipient recipient) {
|
||||
Recipient resolved = recipient.resolve();
|
||||
|
||||
if (resolved.isRegistered() || resolved.isGroup() || resolved.hasSeenSecondInviteReminder()) {
|
||||
return new NoReminderInfo();
|
||||
}
|
||||
|
||||
ThreadTable threadTable = SignalDatabase.threads();
|
||||
Long threadId = threadTable.getThreadIdFor(recipient.getId());
|
||||
|
||||
if (threadId != null) {
|
||||
int conversationCount = SignalDatabase.messages().getInsecureMessageSentCount(threadId);
|
||||
|
||||
if (conversationCount >= SECOND_INVITE_REMINDER_MESSAGE_THRESHOLD && !resolved.hasSeenSecondInviteReminder()) {
|
||||
return new SecondInviteReminderInfo(context, resolved, repository, repository.getPercentOfInsecureMessages(conversationCount));
|
||||
} else if (conversationCount >= FIRST_INVITE_REMINDER_MESSAGE_THRESHOLD && !resolved.hasSeenFirstInviteReminder()) {
|
||||
return new FirstInviteReminderInfo(resolved, repository, repository.getPercentOfInsecureMessages(conversationCount));
|
||||
}
|
||||
}
|
||||
return new NoReminderInfo();
|
||||
}
|
||||
|
||||
public @NonNull Optional<Reminder> getReminder() {
|
||||
ReminderInfo info = reminderInfo.get();
|
||||
if (info == null) return Optional.empty();
|
||||
else return Optional.ofNullable(info.reminder);
|
||||
}
|
||||
|
||||
public void dismissReminder() {
|
||||
final ReminderInfo info = reminderInfo.getAndSet(null);
|
||||
|
||||
SimpleTask.run(() -> {
|
||||
info.dismiss();
|
||||
return null;
|
||||
}, (v) -> {});
|
||||
}
|
||||
|
||||
interface Repository {
|
||||
void setHasSeenFirstInviteReminder(Recipient recipient);
|
||||
void setHasSeenSecondInviteReminder(Recipient recipient);
|
||||
int getPercentOfInsecureMessages(int insecureCount);
|
||||
}
|
||||
|
||||
private static abstract class ReminderInfo {
|
||||
|
||||
private final Reminder reminder;
|
||||
|
||||
ReminderInfo(Reminder reminder) {
|
||||
this.reminder = reminder;
|
||||
}
|
||||
|
||||
@WorkerThread
|
||||
void dismiss() {
|
||||
}
|
||||
}
|
||||
|
||||
private static class NoReminderInfo extends ReminderInfo {
|
||||
private NoReminderInfo() {
|
||||
super(null);
|
||||
}
|
||||
}
|
||||
|
||||
private class FirstInviteReminderInfo extends ReminderInfo {
|
||||
|
||||
private final Repository repository;
|
||||
private final Recipient recipient;
|
||||
|
||||
private FirstInviteReminderInfo(@NonNull Recipient recipient, @NonNull Repository repository, int percentInsecure) {
|
||||
super(new FirstInviteReminder(percentInsecure));
|
||||
|
||||
this.recipient = recipient;
|
||||
this.repository = repository;
|
||||
}
|
||||
|
||||
@Override
|
||||
@WorkerThread
|
||||
void dismiss() {
|
||||
repository.setHasSeenFirstInviteReminder(recipient);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SecondInviteReminderInfo extends ReminderInfo {
|
||||
|
||||
private final Repository repository;
|
||||
private final Recipient recipient;
|
||||
|
||||
private SecondInviteReminderInfo(@NonNull Context context, @NonNull Recipient recipient, @NonNull Repository repository, int percentInsecure) {
|
||||
super(new SecondInviteReminder(context, recipient, percentInsecure));
|
||||
|
||||
this.repository = repository;
|
||||
this.recipient = recipient;
|
||||
}
|
||||
|
||||
@Override
|
||||
@WorkerThread
|
||||
void dismiss() {
|
||||
repository.setHasSeenSecondInviteReminder(recipient);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
package org.thoughtcrime.securesms.invites;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import org.thoughtcrime.securesms.database.MessageTable;
|
||||
import org.thoughtcrime.securesms.database.RecipientTable;
|
||||
import org.thoughtcrime.securesms.database.SignalDatabase;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
public final class InviteReminderRepository implements InviteReminderModel.Repository {
|
||||
|
||||
private final Context context;
|
||||
|
||||
public InviteReminderRepository(Context context) {
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHasSeenFirstInviteReminder(Recipient recipient) {
|
||||
RecipientTable recipientTable = SignalDatabase.recipients();
|
||||
recipientTable.setSeenFirstInviteReminder(recipient.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setHasSeenSecondInviteReminder(Recipient recipient) {
|
||||
RecipientTable recipientTable = SignalDatabase.recipients();
|
||||
recipientTable.setSeenSecondInviteReminder(recipient.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPercentOfInsecureMessages(int insecureCount) {
|
||||
MessageTable messageTable = SignalDatabase.messages();
|
||||
int insecure = messageTable.getInsecureMessageCountForInsights();
|
||||
int secure = messageTable.getSecureMessageCountForInsights();
|
||||
|
||||
if (insecure + secure == 0) return 0;
|
||||
return Math.round(100f * (insecureCount / (float) (insecure + secure)));
|
||||
}
|
||||
}
|
|
@ -91,7 +91,7 @@ public final class MmsSendJob extends SendJob {
|
|||
}
|
||||
|
||||
List<Job> compressionJobs = Stream.of(message.getAttachments())
|
||||
.map(a -> (Job) AttachmentCompressionJob.fromAttachment((DatabaseAttachment) a, true, message.getSubscriptionId()))
|
||||
.map(a -> (Job) AttachmentCompressionJob.fromAttachment((DatabaseAttachment) a, true, -1))
|
||||
.toList();
|
||||
|
||||
MmsSendJob sendJob = new MmsSendJob(messageId);
|
||||
|
@ -139,7 +139,7 @@ public final class MmsSendJob extends SendJob {
|
|||
validateDestinations(message, pdu);
|
||||
|
||||
final byte[] pduBytes = getPduBytes(pdu);
|
||||
final SendConf sendConf = new CompatMmsConnection(context).send(pduBytes, message.getSubscriptionId());
|
||||
final SendConf sendConf = new CompatMmsConnection(context).send(pduBytes, -1);
|
||||
final MmsSendResult result = getSendResult(sendConf, pdu);
|
||||
|
||||
database.markAsSent(messageId, false);
|
||||
|
@ -231,7 +231,7 @@ public final class MmsSendJob extends SendJob {
|
|||
{
|
||||
SendReq req = new SendReq();
|
||||
String lineNumber = getMyNumber(context);
|
||||
MediaConstraints mediaConstraints = MediaConstraints.getMmsMediaConstraints(message.getSubscriptionId());
|
||||
MediaConstraints mediaConstraints = MediaConstraints.getMmsMediaConstraints(-1);
|
||||
List<Attachment> scaledAttachments = message.getAttachments();
|
||||
|
||||
if (!TextUtils.isEmpty(lineNumber)) {
|
||||
|
|
|
@ -108,7 +108,7 @@ public class TypingSendJob extends BaseJob {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!recipient.isRegistered() || recipient.isForceSmsSelection()) {
|
||||
if (!recipient.isRegistered()) {
|
||||
Log.w(TAG, "Not sending typing indicators to non-Signal recipients.");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -414,8 +414,6 @@ public class MessageContentProcessor {
|
|||
warn(String.valueOf(content.getTimestamp()), "Got unrecognized message!");
|
||||
}
|
||||
|
||||
resetRecipientToPush(senderRecipient);
|
||||
|
||||
if (pending != null) {
|
||||
warn(content.getTimestamp(), "Pending retry was processed. Deleting.");
|
||||
ApplicationDependencies.getPendingRetryReceiptCache().delete(pending);
|
||||
|
@ -2219,7 +2217,6 @@ public class MessageContentProcessor {
|
|||
body,
|
||||
Collections.emptyList(),
|
||||
message.getTimestamp(),
|
||||
-1,
|
||||
expiresInMillis,
|
||||
false,
|
||||
ThreadTable.DistributionTypes.DEFAULT,
|
||||
|
@ -2342,7 +2339,6 @@ public class MessageContentProcessor {
|
|||
textStoryBody,
|
||||
pendingAttachments,
|
||||
sentAtTimestamp,
|
||||
-1,
|
||||
0,
|
||||
false,
|
||||
ThreadTable.DistributionTypes.DEFAULT,
|
||||
|
@ -2442,7 +2438,6 @@ public class MessageContentProcessor {
|
|||
message.getDataMessage().get().getBody().orElse(null),
|
||||
syncAttachments,
|
||||
message.getTimestamp(),
|
||||
-1,
|
||||
TimeUnit.SECONDS.toMillis(message.getDataMessage().get().getExpiresInSeconds()),
|
||||
viewOnce,
|
||||
ThreadTable.DistributionTypes.DEFAULT,
|
||||
|
@ -2657,7 +2652,6 @@ public class MessageContentProcessor {
|
|||
new SlideDeck(),
|
||||
body,
|
||||
message.getTimestamp(),
|
||||
-1,
|
||||
expiresInMillis,
|
||||
false,
|
||||
StoryType.NONE,
|
||||
|
@ -3403,12 +3397,6 @@ public class MessageContentProcessor {
|
|||
return false;
|
||||
}
|
||||
|
||||
private void resetRecipientToPush(@NonNull Recipient recipient) {
|
||||
if (recipient.isForceSmsSelection()) {
|
||||
SignalDatabase.recipients().setForceSmsSelection(recipient.getId(), false);
|
||||
}
|
||||
}
|
||||
|
||||
private void forceStickerDownloadIfNecessary(long messageId, List<DatabaseAttachment> stickerAttachments) {
|
||||
if (stickerAttachments.isEmpty()) return;
|
||||
|
||||
|
|
|
@ -284,12 +284,6 @@ open class MessageContentProcessorV2(private val context: Context) {
|
|||
null
|
||||
}
|
||||
}
|
||||
|
||||
private fun resetRecipientToPush(recipient: Recipient) {
|
||||
if (recipient.isForceSmsSelection) {
|
||||
SignalDatabase.recipients.setForceSmsSelection(recipient.id, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -425,8 +419,6 @@ open class MessageContentProcessorV2(private val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
resetRecipientToPush(senderRecipient)
|
||||
|
||||
if (pending != null) {
|
||||
warn(envelope.timestamp, "Pending retry was processed. Deleting.")
|
||||
ApplicationDependencies.getPendingRetryReceiptCache().delete(pending)
|
||||
|
|
|
@ -23,7 +23,6 @@ data class OutgoingMessage(
|
|||
val sentTimeMillis: Long,
|
||||
val body: String = "",
|
||||
val distributionType: Int = ThreadTable.DistributionTypes.DEFAULT,
|
||||
val subscriptionId: Int = -1,
|
||||
val expiresIn: Long = 0L,
|
||||
val isViewOnce: Boolean = false,
|
||||
val outgoingQuote: QuoteModel? = null,
|
||||
|
@ -66,7 +65,6 @@ data class OutgoingMessage(
|
|||
body: String? = "",
|
||||
attachments: List<Attachment> = emptyList(),
|
||||
timestamp: Long,
|
||||
subscriptionId: Int = -1,
|
||||
expiresIn: Long = 0L,
|
||||
viewOnce: Boolean = false,
|
||||
distributionType: Int = ThreadTable.DistributionTypes.DEFAULT,
|
||||
|
@ -89,7 +87,6 @@ data class OutgoingMessage(
|
|||
body = body ?: "",
|
||||
attachments = attachments,
|
||||
sentTimeMillis = timestamp,
|
||||
subscriptionId = subscriptionId,
|
||||
expiresIn = expiresIn,
|
||||
isViewOnce = viewOnce,
|
||||
distributionType = distributionType,
|
||||
|
@ -117,7 +114,6 @@ data class OutgoingMessage(
|
|||
slideDeck: SlideDeck,
|
||||
body: String? = "",
|
||||
timestamp: Long,
|
||||
subscriptionId: Int = -1,
|
||||
expiresIn: Long = 0L,
|
||||
viewOnce: Boolean = false,
|
||||
storyType: StoryType = StoryType.NONE,
|
||||
|
@ -131,7 +127,6 @@ data class OutgoingMessage(
|
|||
body = buildMessage(slideDeck, body ?: ""),
|
||||
attachments = slideDeck.asAttachments(),
|
||||
sentTimeMillis = timestamp,
|
||||
subscriptionId = subscriptionId,
|
||||
expiresIn = expiresIn,
|
||||
isViewOnce = viewOnce,
|
||||
storyType = storyType,
|
||||
|
@ -142,6 +137,8 @@ data class OutgoingMessage(
|
|||
sharedContacts = contacts
|
||||
)
|
||||
|
||||
val subscriptionId = -1
|
||||
|
||||
fun withExpiry(expiresIn: Long): OutgoingMessage {
|
||||
return copy(expiresIn = expiresIn)
|
||||
}
|
||||
|
@ -172,12 +169,11 @@ data class OutgoingMessage(
|
|||
* A literal, insecure SMS message.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun sms(threadRecipient: Recipient, body: String, subscriptionId: Int): OutgoingMessage {
|
||||
fun sms(threadRecipient: Recipient, body: String): OutgoingMessage {
|
||||
return OutgoingMessage(
|
||||
threadRecipient = threadRecipient,
|
||||
sentTimeMillis = System.currentTimeMillis(),
|
||||
body = body,
|
||||
subscriptionId = subscriptionId,
|
||||
isSecure = false
|
||||
)
|
||||
}
|
||||
|
|
|
@ -76,7 +76,6 @@ public class RemoteReplyReceiver extends BroadcastReceiver {
|
|||
long threadId;
|
||||
|
||||
Recipient recipient = Recipient.resolved(recipientId);
|
||||
int subscriptionId = recipient.getDefaultSubscriptionId().orElse(-1);
|
||||
long expiresIn = TimeUnit.SECONDS.toMillis(recipient.getExpiresInSeconds());
|
||||
ParentStoryId parentStoryId = groupStoryId != Long.MIN_VALUE ? ParentStoryId.deserialize(groupStoryId) : null;
|
||||
|
||||
|
@ -86,7 +85,6 @@ public class RemoteReplyReceiver extends BroadcastReceiver {
|
|||
responseText.toString(),
|
||||
new LinkedList<>(),
|
||||
System.currentTimeMillis(),
|
||||
subscriptionId,
|
||||
expiresIn,
|
||||
false,
|
||||
0,
|
||||
|
@ -112,11 +110,6 @@ public class RemoteReplyReceiver extends BroadcastReceiver {
|
|||
threadId = MessageSender.send(context, reply, -1, MessageSender.SendType.SIGNAL, null, null);
|
||||
break;
|
||||
}
|
||||
case UnsecuredSmsMessage: {
|
||||
OutgoingMessage reply = OutgoingMessage.sms(recipient, responseText.toString(), subscriptionId);
|
||||
threadId = MessageSender.send(context, reply, -1, MessageSender.SendType.SMS, null, null);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new AssertionError("Unknown Reply method");
|
||||
}
|
||||
|
|
|
@ -1,26 +1,19 @@
|
|||
package org.thoughtcrime.securesms.notifications;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import org.thoughtcrime.securesms.database.RecipientTable;
|
||||
import org.thoughtcrime.securesms.keyvalue.SignalStore;
|
||||
import org.thoughtcrime.securesms.recipients.Recipient;
|
||||
|
||||
public enum ReplyMethod {
|
||||
|
||||
GroupMessage,
|
||||
SecureMessage,
|
||||
UnsecuredSmsMessage;
|
||||
SecureMessage;
|
||||
|
||||
public static @NonNull ReplyMethod forRecipient(Context context, Recipient recipient) {
|
||||
public static @NonNull ReplyMethod forRecipient(Recipient recipient) {
|
||||
if (recipient.isGroup()) {
|
||||
return ReplyMethod.GroupMessage;
|
||||
} else if (SignalStore.account().isRegistered() && recipient.getRegistered() == RecipientTable.RegisteredState.REGISTERED && !recipient.isForceSmsSelection()) {
|
||||
return ReplyMethod.SecureMessage;
|
||||
} else {
|
||||
return ReplyMethod.UnsecuredSmsMessage;
|
||||
return ReplyMethod.SecureMessage;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -123,7 +123,7 @@ sealed class NotificationBuilder(protected val context: Context) {
|
|||
}
|
||||
}
|
||||
|
||||
addActions(ReplyMethod.forRecipient(context, conversation.recipient), conversation)
|
||||
addActions(ReplyMethod.forRecipient(conversation.recipient), conversation)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -504,6 +504,5 @@ private fun ReplyMethod.toLongDescription(): Int {
|
|||
return when (this) {
|
||||
ReplyMethod.GroupMessage -> R.string.MessageNotifier_reply
|
||||
ReplyMethod.SecureMessage -> R.string.MessageNotifier_signal_message
|
||||
ReplyMethod.UnsecuredSmsMessage -> R.string.MessageNotifier_unsecured_sms
|
||||
}
|
||||
}
|
||||
|
|
|
@ -104,7 +104,6 @@ public class Recipient {
|
|||
private final VibrateState callVibrate;
|
||||
private final Uri messageRingtone;
|
||||
private final Uri callRingtone;
|
||||
private final Optional<Integer> defaultSubscriptionId;
|
||||
private final int expireMessages;
|
||||
private final RegisteredState registered;
|
||||
private final byte[] profileKey;
|
||||
|
@ -121,9 +120,7 @@ public class Recipient {
|
|||
private final long lastProfileFetch;
|
||||
private final String notificationChannel;
|
||||
private final UnidentifiedAccessMode unidentifiedAccessMode;
|
||||
private final boolean forceSmsSelection;
|
||||
private final RecipientRecord.Capabilities capabilities;
|
||||
private final InsightsBannerTier insightsBannerTier;
|
||||
private final byte[] storageId;
|
||||
private final MentionSetting mentionSetting;
|
||||
private final ChatWallpaper wallpaper;
|
||||
|
@ -392,8 +389,6 @@ public class Recipient {
|
|||
this.callVibrate = VibrateState.DEFAULT;
|
||||
this.messageRingtone = null;
|
||||
this.callRingtone = null;
|
||||
this.insightsBannerTier = InsightsBannerTier.TIER_TWO;
|
||||
this.defaultSubscriptionId = Optional.empty();
|
||||
this.expireMessages = 0;
|
||||
this.registered = RegisteredState.UNKNOWN;
|
||||
this.profileKey = null;
|
||||
|
@ -410,7 +405,6 @@ public class Recipient {
|
|||
this.lastProfileFetch = 0;
|
||||
this.notificationChannel = null;
|
||||
this.unidentifiedAccessMode = UnidentifiedAccessMode.DISABLED;
|
||||
this.forceSmsSelection = false;
|
||||
this.capabilities = RecipientRecord.Capabilities.UNKNOWN;
|
||||
this.storageId = null;
|
||||
this.mentionSetting = MentionSetting.ALWAYS_NOTIFY;
|
||||
|
@ -450,8 +444,6 @@ public class Recipient {
|
|||
this.callVibrate = details.callVibrateState;
|
||||
this.messageRingtone = details.messageRingtone;
|
||||
this.callRingtone = details.callRingtone;
|
||||
this.insightsBannerTier = details.insightsBannerTier;
|
||||
this.defaultSubscriptionId = details.defaultSubscriptionId;
|
||||
this.expireMessages = details.expireMessages;
|
||||
this.registered = details.registered;
|
||||
this.profileKey = details.profileKey;
|
||||
|
@ -468,7 +460,6 @@ public class Recipient {
|
|||
this.lastProfileFetch = details.lastProfileFetch;
|
||||
this.notificationChannel = details.notificationChannel;
|
||||
this.unidentifiedAccessMode = details.unidentifiedAccessMode;
|
||||
this.forceSmsSelection = details.forceSmsSelection;
|
||||
this.capabilities = details.capabilities;
|
||||
this.storageId = details.storageId;
|
||||
this.mentionSetting = details.mentionSetting;
|
||||
|
@ -840,10 +831,6 @@ public class Recipient {
|
|||
return requireSmsAddress();
|
||||
}
|
||||
|
||||
public Optional<Integer> getDefaultSubscriptionId() {
|
||||
return defaultSubscriptionId;
|
||||
}
|
||||
|
||||
public @NonNull ProfileName getProfileName() {
|
||||
return signalProfileName;
|
||||
}
|
||||
|
@ -1029,14 +1016,6 @@ public class Recipient {
|
|||
return expireMessages;
|
||||
}
|
||||
|
||||
public boolean hasSeenFirstInviteReminder() {
|
||||
return insightsBannerTier.seen(InsightsBannerTier.TIER_ONE);
|
||||
}
|
||||
|
||||
public boolean hasSeenSecondInviteReminder() {
|
||||
return insightsBannerTier.seen(InsightsBannerTier.TIER_TWO);
|
||||
}
|
||||
|
||||
public @NonNull RegisteredState getRegistered() {
|
||||
if (isPushGroup() || isDistributionList()) {
|
||||
return RegisteredState.REGISTERED;
|
||||
|
@ -1063,10 +1042,6 @@ public class Recipient {
|
|||
return !NotificationChannels.supported() ? null : notificationChannel;
|
||||
}
|
||||
|
||||
public boolean isForceSmsSelection() {
|
||||
return forceSmsSelection;
|
||||
}
|
||||
|
||||
public @NonNull Capability getStoriesCapability() {
|
||||
return capabilities.getStoriesCapability();
|
||||
}
|
||||
|
@ -1353,7 +1328,6 @@ public class Recipient {
|
|||
Objects.equals(profileAvatarFileDetails, other.profileAvatarFileDetails) &&
|
||||
profileSharing == other.profileSharing &&
|
||||
isHidden == other.isHidden &&
|
||||
forceSmsSelection == other.forceSmsSelection &&
|
||||
Objects.equals(aci, other.aci) &&
|
||||
Objects.equals(username, other.username) &&
|
||||
Objects.equals(e164, other.e164) &&
|
||||
|
@ -1365,7 +1339,6 @@ public class Recipient {
|
|||
callVibrate == other.callVibrate &&
|
||||
Objects.equals(messageRingtone, other.messageRingtone) &&
|
||||
Objects.equals(callRingtone, other.callRingtone) &&
|
||||
Objects.equals(defaultSubscriptionId, other.defaultSubscriptionId) &&
|
||||
registered == other.registered &&
|
||||
Arrays.equals(profileKey, other.profileKey) &&
|
||||
Objects.equals(expiringProfileKeyCredential, other.expiringProfileKeyCredential) &&
|
||||
|
@ -1378,7 +1351,6 @@ public class Recipient {
|
|||
Objects.equals(profileAvatar, other.profileAvatar) &&
|
||||
Objects.equals(notificationChannel, other.notificationChannel) &&
|
||||
unidentifiedAccessMode == other.unidentifiedAccessMode &&
|
||||
insightsBannerTier == other.insightsBannerTier &&
|
||||
Arrays.equals(storageId, other.storageId) &&
|
||||
mentionSetting == other.mentionSetting &&
|
||||
Objects.equals(wallpaper, other.wallpaper) &&
|
||||
|
|
|
@ -58,7 +58,6 @@ public class RecipientDetails {
|
|||
final int expireMessages;
|
||||
final List<RecipientId> participantIds;
|
||||
final ProfileName profileName;
|
||||
final Optional<Integer> defaultSubscriptionId;
|
||||
final RegisteredState registered;
|
||||
final byte[] profileKey;
|
||||
final ExpiringProfileKeyCredential expiringProfileKeyCredential;
|
||||
|
@ -72,9 +71,7 @@ public class RecipientDetails {
|
|||
final boolean isSelf;
|
||||
final String notificationChannel;
|
||||
final UnidentifiedAccessMode unidentifiedAccessMode;
|
||||
final boolean forceSmsSelection;
|
||||
final RecipientRecord.Capabilities capabilities;
|
||||
final InsightsBannerTier insightsBannerTier;
|
||||
final byte[] storageId;
|
||||
final MentionSetting mentionSetting;
|
||||
final ChatWallpaper wallpaper;
|
||||
|
@ -125,7 +122,6 @@ public class RecipientDetails {
|
|||
this.participantIds = participantIds == null ? new LinkedList<>() : participantIds;
|
||||
this.isActiveGroup = isActiveGroup;
|
||||
this.profileName = record.getProfileName();
|
||||
this.defaultSubscriptionId = record.getDefaultSubscriptionId();
|
||||
this.registered = registeredState;
|
||||
this.profileKey = record.getProfileKey();
|
||||
this.expiringProfileKeyCredential = record.getExpiringProfileKeyCredential();
|
||||
|
@ -138,9 +134,7 @@ public class RecipientDetails {
|
|||
this.isSelf = isSelf;
|
||||
this.notificationChannel = record.getNotificationChannel();
|
||||
this.unidentifiedAccessMode = record.getUnidentifiedAccessMode();
|
||||
this.forceSmsSelection = record.isForceSmsSelection();
|
||||
this.capabilities = record.getCapabilities();
|
||||
this.insightsBannerTier = record.getInsightsBannerTier();
|
||||
this.storageId = record.getStorageId();
|
||||
this.mentionSetting = record.getMentionSetting();
|
||||
this.wallpaper = record.getWallpaper();
|
||||
|
@ -181,8 +175,6 @@ public class RecipientDetails {
|
|||
this.expireMessages = 0;
|
||||
this.participantIds = new LinkedList<>();
|
||||
this.profileName = ProfileName.EMPTY;
|
||||
this.insightsBannerTier = InsightsBannerTier.TIER_TWO;
|
||||
this.defaultSubscriptionId = Optional.empty();
|
||||
this.registered = RegisteredState.UNKNOWN;
|
||||
this.profileKey = null;
|
||||
this.expiringProfileKeyCredential = null;
|
||||
|
@ -195,7 +187,6 @@ public class RecipientDetails {
|
|||
this.isSelf = false;
|
||||
this.notificationChannel = null;
|
||||
this.unidentifiedAccessMode = UnidentifiedAccessMode.UNKNOWN;
|
||||
this.forceSmsSelection = false;
|
||||
this.groupName = null;
|
||||
this.capabilities = RecipientRecord.Capabilities.UNKNOWN;
|
||||
this.storageId = null;
|
||||
|
|
|
@ -297,7 +297,6 @@ public class RecipientUtil {
|
|||
threadRecipient.isProfileSharing() ||
|
||||
threadRecipient.isSystemContact() ||
|
||||
!threadRecipient.isRegistered() ||
|
||||
threadRecipient.isForceSmsSelection() ||
|
||||
threadRecipient.isHidden();
|
||||
}
|
||||
|
||||
|
@ -346,7 +345,6 @@ public class RecipientUtil {
|
|||
threadRecipient.isSelf() ||
|
||||
threadRecipient.isProfileSharing() ||
|
||||
threadRecipient.isSystemContact() ||
|
||||
threadRecipient.isForceSmsSelection() ||
|
||||
!threadRecipient.isRegistered() ||
|
||||
(!threadRecipient.isHidden() && (
|
||||
hasSentMessageInThread(threadId) ||
|
||||
|
|
|
@ -46,11 +46,10 @@ public class QuickResponseService extends IntentService {
|
|||
number = URLDecoder.decode(number);
|
||||
}
|
||||
|
||||
Recipient recipient = Recipient.external(this, number);
|
||||
int subscriptionId = recipient.getDefaultSubscriptionId().orElse(-1);
|
||||
Recipient recipient = Recipient.external(this, number);
|
||||
|
||||
if (!TextUtils.isEmpty(content)) {
|
||||
MessageSender.send(this, OutgoingMessage.sms(recipient, content, subscriptionId), -1, MessageSender.SendType.SIGNAL, null, null);
|
||||
MessageSender.send(this, OutgoingMessage.sms(recipient, content), -1, MessageSender.SendType.SIGNAL, null, null);
|
||||
}
|
||||
} catch (URISyntaxException e) {
|
||||
Toast.makeText(this, R.string.QuickResponseService_problem_sending_message, Toast.LENGTH_LONG).show();
|
||||
|
|
|
@ -108,9 +108,7 @@ public final class MultiShareSender {
|
|||
|
||||
long threadId = SignalDatabase.threads().getOrCreateThreadIdFor(recipient);
|
||||
List<Mention> mentions = getValidMentionsForRecipient(recipient, multiShareArgs.getMentions());
|
||||
MessageSendType sendType = resolveTransportOption(context, recipient);
|
||||
boolean forceSms = recipient.isForceSmsSelection() && sendType.usesSmsTransport();
|
||||
int subscriptionId = sendType.getSimSubscriptionIdOr(-1);
|
||||
MessageSendType sendType = MessageSendType.SignalMessageSendType.INSTANCE;
|
||||
long expiresIn = TimeUnit.SECONDS.toMillis(recipient.getExpiresInSeconds());
|
||||
List<Contact> contacts = multiShareArgs.getSharedContacts();
|
||||
boolean needsSplit = !sendType.usesSmsTransport() &&
|
||||
|
@ -139,10 +137,8 @@ public final class MultiShareSender {
|
|||
slideDeck,
|
||||
sendType,
|
||||
threadId,
|
||||
forceSms,
|
||||
expiresIn,
|
||||
multiShareArgs.isViewOnce(),
|
||||
subscriptionId,
|
||||
mentions,
|
||||
recipientSearchKey.isStory(),
|
||||
sentTimestamp,
|
||||
|
@ -154,7 +150,7 @@ public final class MultiShareSender {
|
|||
} else if (recipientSearchKey.isStory()) {
|
||||
results.add(new MultiShareSendResult(recipientSearchKey, MultiShareSendResult.Type.INVALID_SHARE_TO_STORY));
|
||||
} else {
|
||||
sendTextMessage(context, multiShareArgs, recipient, threadId, forceSms, expiresIn, subscriptionId);
|
||||
sendTextMessage(context, multiShareArgs, recipient, threadId, expiresIn);
|
||||
results.add(new MultiShareSendResult(recipientSearchKey, MultiShareSendResult.Type.SUCCESS));
|
||||
}
|
||||
|
||||
|
@ -179,39 +175,14 @@ public final class MultiShareSender {
|
|||
return new MultiShareSendResultCollection(results);
|
||||
}
|
||||
|
||||
public static @NonNull MessageSendType getWorstTransportOption(@NonNull Context context, @NonNull Set<ContactSearchKey.RecipientSearchKey> recipientSearchKeys) {
|
||||
for (ContactSearchKey.RecipientSearchKey recipientSearchKey : recipientSearchKeys) {
|
||||
MessageSendType type = resolveTransportOption(context, Recipient.resolved(recipientSearchKey.getRecipientId()).isForceSmsSelection() && !recipientSearchKey.isStory());
|
||||
if (type.usesSmsTransport()) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
return MessageSendType.SignalMessageSendType.INSTANCE;
|
||||
}
|
||||
|
||||
private static @NonNull MessageSendType resolveTransportOption(@NonNull Context context, @NonNull Recipient recipient) {
|
||||
return resolveTransportOption(context, !recipient.isDistributionList() && (recipient.isForceSmsSelection() || !recipient.isRegistered()));
|
||||
}
|
||||
|
||||
public static @NonNull MessageSendType resolveTransportOption(@NonNull Context context, boolean forceSms) {
|
||||
if (forceSms && SignalStore.misc().getSmsExportPhase().allowSmsFeatures()) {
|
||||
return MessageSendType.getFirstForTransport(context, false, MessageSendType.TransportType.SMS);
|
||||
} else {
|
||||
return MessageSendType.SignalMessageSendType.INSTANCE;
|
||||
}
|
||||
}
|
||||
|
||||
private static void sendMediaMessageOrCollectStoryToBatch(@NonNull Context context,
|
||||
@NonNull MultiShareArgs multiShareArgs,
|
||||
@NonNull Recipient recipient,
|
||||
@NonNull SlideDeck slideDeck,
|
||||
@NonNull MessageSendType sendType,
|
||||
long threadId,
|
||||
boolean forceSms,
|
||||
long expiresIn,
|
||||
boolean isViewOnce,
|
||||
int subscriptionId,
|
||||
@NonNull List<Mention> validatedMentions,
|
||||
boolean isStory,
|
||||
@NonNull MultiShareTimestampProvider sentTimestamps,
|
||||
|
@ -221,7 +192,7 @@ public final class MultiShareSender {
|
|||
@NonNull List<Contact> contacts)
|
||||
{
|
||||
String body = multiShareArgs.getDraftText();
|
||||
if (sendType.usesSignalTransport() && !forceSms && body != null) {
|
||||
if (sendType.usesSignalTransport() && body != null) {
|
||||
MessageUtil.SplitResult splitMessage = MessageUtil.getSplitMessage(context, body, sendType.calculateCharacters(body).maxPrimaryMessageSize);
|
||||
body = splitMessage.getBody();
|
||||
|
||||
|
@ -249,7 +220,6 @@ public final class MultiShareSender {
|
|||
new SlideDeck(),
|
||||
body,
|
||||
sentTimestamps.getMillis(0),
|
||||
subscriptionId,
|
||||
0L,
|
||||
false,
|
||||
storyType.toTextStoryType(),
|
||||
|
@ -289,7 +259,6 @@ public final class MultiShareSender {
|
|||
singletonDeck,
|
||||
body,
|
||||
sentTimestamps.getMillis(i),
|
||||
subscriptionId,
|
||||
0L,
|
||||
false,
|
||||
storyType,
|
||||
|
@ -307,7 +276,6 @@ public final class MultiShareSender {
|
|||
slideDeck,
|
||||
body,
|
||||
sentTimestamps.getMillis(0),
|
||||
subscriptionId,
|
||||
expiresIn,
|
||||
isViewOnce,
|
||||
StoryType.NONE,
|
||||
|
@ -322,7 +290,7 @@ public final class MultiShareSender {
|
|||
|
||||
if (isStory) {
|
||||
storiesToBatchSend.addAll(outgoingMessages);
|
||||
} else if (shouldSendAsPush(recipient, forceSms)) {
|
||||
} else if (shouldSendAsPush(recipient)) {
|
||||
for (final OutgoingMessage outgoingMessage : outgoingMessages) {
|
||||
MessageSender.send(context, outgoingMessage.makeSecure(), threadId, SendType.SIGNAL, null, null);
|
||||
}
|
||||
|
@ -399,20 +367,18 @@ public final class MultiShareSender {
|
|||
@NonNull MultiShareArgs multiShareArgs,
|
||||
@NonNull Recipient recipient,
|
||||
long threadId,
|
||||
boolean forceSms,
|
||||
long expiresIn,
|
||||
int subscriptionId)
|
||||
long expiresIn)
|
||||
{
|
||||
String body = multiShareArgs.getDraftText() == null ? "" : multiShareArgs.getDraftText();
|
||||
|
||||
OutgoingMessage outgoingMessage;
|
||||
if (shouldSendAsPush(recipient, forceSms)) {
|
||||
if (shouldSendAsPush(recipient)) {
|
||||
outgoingMessage = OutgoingMessage.text(recipient, body, expiresIn, System.currentTimeMillis(), multiShareArgs.getBodyRanges());
|
||||
} else {
|
||||
outgoingMessage = OutgoingMessage.sms(recipient, body, subscriptionId);
|
||||
outgoingMessage = OutgoingMessage.sms(recipient, body);
|
||||
}
|
||||
|
||||
MessageSender.send(context, outgoingMessage, threadId, forceSms ? SendType.SMS : SendType.SIGNAL, null, null);
|
||||
MessageSender.send(context, outgoingMessage, threadId, SendType.SIGNAL, null, null);
|
||||
}
|
||||
|
||||
private static @NonNull OutgoingMessage generateTextStory(@NonNull Context context,
|
||||
|
@ -458,10 +424,10 @@ public final class MultiShareSender {
|
|||
return trimmed.replace(linkPreview.getUrl(), "").trim();
|
||||
}
|
||||
|
||||
private static boolean shouldSendAsPush(@NonNull Recipient recipient, boolean forceSms) {
|
||||
private static boolean shouldSendAsPush(@NonNull Recipient recipient) {
|
||||
return recipient.isDistributionList() ||
|
||||
recipient.isServiceIdOnly() ||
|
||||
(recipient.isRegistered() && !forceSms);
|
||||
recipient.isRegistered();
|
||||
}
|
||||
|
||||
private static @NonNull SlideDeck buildSlideDeck(@NonNull Context context, @NonNull MultiShareArgs multiShareArgs) throws SlideNotFoundException {
|
||||
|
|
|
@ -93,7 +93,7 @@ public class ShareInterstitialActivity extends PassphraseRequiredActivity {
|
|||
return false;
|
||||
}
|
||||
|
||||
return !recipient.isRegistered() || recipient.isForceSmsSelection();
|
||||
return !recipient.isRegistered();
|
||||
});
|
||||
|
||||
if (hasSms) {
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.thoughtcrime.securesms.PassphraseRequiredActivity
|
|||
import org.thoughtcrime.securesms.R
|
||||
import org.thoughtcrime.securesms.contacts.paged.ContactSearchKey
|
||||
import org.thoughtcrime.securesms.conversation.ConversationIntents
|
||||
import org.thoughtcrime.securesms.conversation.MessageSendType
|
||||
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragment
|
||||
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFragmentArgs
|
||||
import org.thoughtcrime.securesms.conversation.mutiselect.forward.MultiselectForwardFullScreenDialogFragment
|
||||
|
@ -271,7 +272,7 @@ class ShareActivity : PassphraseRequiredActivity(), MultiselectForwardFragment.C
|
|||
|
||||
val intent = share(
|
||||
this,
|
||||
MultiShareSender.getWorstTransportOption(this, multiShareArgs.recipientSearchKeys),
|
||||
MessageSendType.SignalMessageSendType,
|
||||
media,
|
||||
multiShareArgs.recipientSearchKeys.toList(),
|
||||
multiShareArgs.draftText,
|
||||
|
|
|
@ -1,200 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
tools:viewBindingIgnore="true"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<androidx.core.widget.NestedScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:fillViewport="true"
|
||||
app:layout_constraintBottom_toTopOf="@id/insights_dashboard_this_stat_was_generated_locally"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clipToPadding="false"
|
||||
android:paddingTop="?actionBarSize">
|
||||
|
||||
<com.airbnb.lottie.LottieAnimationView
|
||||
android:id="@+id/insights_dashboard_lottie_animation"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:visibility="gone"
|
||||
app:layout_constraintBottom_toBottomOf="@id/insights_dashboard_progress"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/insights_dashboard_progress"
|
||||
app:lottie_rawRes="@raw/lottie_insights_100" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.ArcProgressBar
|
||||
android:id="@+id/insights_dashboard_progress"
|
||||
style="@style/Widget.Signal.ArcProgressBar"
|
||||
android:layout_width="187dp"
|
||||
android:layout_height="187dp"
|
||||
android:layout_marginTop="8dp"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.AvatarImageView
|
||||
android:id="@+id/insights_dashboard_avatar"
|
||||
android:layout_width="140dp"
|
||||
android:layout_height="140dp"
|
||||
app:layout_constraintBottom_toBottomOf="@id/insights_dashboard_progress"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/insights_dashboard_progress" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/insights_dashboard_percent_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/insights_dashboard_avatar">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/insights_dashboard_percent_secure"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Headline.Insights"
|
||||
tools:text="100" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/insights_dashboard_percent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginBottom="1dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/Insights__percent"
|
||||
android:textAppearance="@style/TextAppearance.Signal.SubHead.Insights" />
|
||||
</LinearLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/insights_dashboard_encrypted_messages"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="2dp"
|
||||
android:text="@string/InsightsDashboardFragment__encrypted_messages"
|
||||
android:textAppearance="@style/TextAppearance.Signal.SubHead.Insights"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/insights_dashboard_percent_container" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/insights_dashboard_tagline"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:gravity="center"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Body.Insights"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/insights_dashboard_encrypted_messages"
|
||||
tools:text="100% of your outgoing messages in the past 7 days were end-to-end encrypted with Signal Protocol." />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/insights_dashboard_start_a_conversation"
|
||||
style="@style/Signal.Widget.Button.Large.Secondary"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="22dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:text="@string/InsightsDashboardFragment__start_a_conversation"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Caption.Insights"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/insights_dashboard_tagline" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/insights_dashboard_make_signal_secure"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="24dp"
|
||||
android:gravity="center"
|
||||
android:text="@string/InsightsDashboardFragment__spread_the_word"
|
||||
android:textAppearance="@style/TextAppearance.Signal.SubHead.Insights"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/insights_dashboard_tagline" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/insights_dashboard_invite_your_contacts"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:gravity="center"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:text="@string/InsightsDashboardFragment__invite_your_contacts"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Body.Insights"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/insights_dashboard_make_signal_secure" />
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/insights_dashboard_recycler"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="20dp"
|
||||
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
|
||||
app:layout_constrainedHeight="true"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/insights_dashboard_invite_your_contacts"
|
||||
tools:itemCount="10"
|
||||
tools:listitem="@layout/insights_dashboard_adapter_item" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
|
||||
<androidx.appcompat.widget.Toolbar
|
||||
android:id="@+id/insights_dashboard_toolbar"
|
||||
style="?actionBarStyle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="?attr/actionBarSize"
|
||||
android:background="?android:windowBackground"
|
||||
android:theme="?actionBarStyle"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:navigationIcon="@drawable/ic_x_tinted"
|
||||
app:title="@string/InsightsDashboardFragment__title" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/insights_dashboard_this_stat_was_generated_locally"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@color/signal_background_secondary"
|
||||
android:gravity="center"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingTop="24dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:paddingBottom="24dp"
|
||||
android:text="@string/InsightsDashboardFragment__this_stat_was_generated_locally"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Body2.Insights"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,47 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
tools:viewBindingIgnore="true"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="68dp">
|
||||
|
||||
<org.thoughtcrime.securesms.components.AvatarImageView
|
||||
android:id="@+id/recipient_avatar"
|
||||
android:layout_width="48dp"
|
||||
android:layout_height="48dp"
|
||||
android:layout_marginStart="8dp"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.emoji.EmojiTextView
|
||||
android:id="@+id/recipient_display_name"
|
||||
android:layout_width="0dip"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="9dp"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Title.Insights"
|
||||
app:layout_constraintEnd_toStartOf="@id/recipient_invite"
|
||||
app:layout_constraintStart_toEndOf="@id/recipient_avatar"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintVertical_chainStyle="packed"
|
||||
tools:text="Peter Parker (This is a long name to make sure we stick within our bounds)" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/recipient_invite"
|
||||
style="@style/Signal.Widget.Button.Large.Secondary"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="48dp"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/conversation_insecure__invite"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Caption.Insights"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -1,115 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
tools:viewBindingIgnore="true"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/insight_modal_background"
|
||||
android:orientation="vertical">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/insights_modal_close"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:tint="@color/signal_icon_tint_primary"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:srcCompat="@drawable/ic_x" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/insights_modal_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/insights_modal_title_margin_top"
|
||||
android:text="@string/InsightsModalFragment__title"
|
||||
android:textAppearance="@style/TextAppearance.Signal.SubHead.Insights"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/insights_modal_description"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="@dimen/insights_modal_description_margin_top"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:gravity="center"
|
||||
android:lineSpacingMultiplier="1.2"
|
||||
android:text="@string/InsightsModalFragment__description"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Title.Insights"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/insights_modal_title" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.ArcProgressBar
|
||||
android:id="@+id/insights_modal_progress"
|
||||
style="@style/Widget.Signal.ArcProgressBar"
|
||||
android:layout_width="@dimen/insights_modal_progress_size"
|
||||
android:layout_height="@dimen/insights_modal_progress_size"
|
||||
android:layout_marginTop="@dimen/insights_modal_progress_margin_top"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/insights_modal_description" />
|
||||
|
||||
<org.thoughtcrime.securesms.components.AvatarImageView
|
||||
android:id="@+id/insights_modal_avatar"
|
||||
android:layout_width="@dimen/insights_modal_avatar_size"
|
||||
android:layout_height="@dimen/insights_modal_avatar_size"
|
||||
app:layout_constraintBottom_toBottomOf="@id/insights_modal_progress"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="@id/insights_modal_progress" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/insights_modal_percent_container"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
app:layout_constrainedWidth="true"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintHorizontal_chainStyle="packed"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/insights_modal_avatar">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/insights_modal_percent_secure"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Headline.Insights.Modal.Percent"
|
||||
tools:text="100" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/insights_modal_percent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:gravity="center"
|
||||
android:text="@string/Insights__percent"
|
||||
android:textAppearance="@style/TextAppearance.Signal.SubHead.Insights.Modal.Percent" />
|
||||
</LinearLayout>
|
||||
|
||||
<Button
|
||||
android:id="@+id/insights_modal_view_insights"
|
||||
style="@style/Widget.AppCompat.Button.Borderless"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="16dp"
|
||||
android:layout_marginTop="@dimen/insights_modal_view_insights_margin_top"
|
||||
android:layout_marginEnd="16dp"
|
||||
android:layout_marginBottom="20dp"
|
||||
android:background="@drawable/insights_cta_button_background"
|
||||
android:text="@string/InsightsModalFragment__view_insights"
|
||||
android:textAppearance="@style/TextAppearance.Signal.Caption.Insights"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@id/insights_modal_progress" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
@ -26,8 +26,4 @@
|
|||
<item android:title="@string/ConversationListFragment__notification_profile"
|
||||
android:id="@+id/menu_notification_profile" />
|
||||
|
||||
<item android:title="@string/Insights__title"
|
||||
android:id="@+id/menu_insights"
|
||||
android:visible="false" />
|
||||
|
||||
</menu>
|
||||
|
|
|
@ -4,7 +4,6 @@
|
|||
<item type="id" name="contact_info_tag"/>
|
||||
<item type="id" name="motion_view_edittext"/>
|
||||
|
||||
<item name="reminder_action_view_insights" type="id" />
|
||||
<item name="reminder_action_invite" type="id" />
|
||||
<item name="reminder_action_update_now" type="id" />
|
||||
<item name="reminder_action_re_register" type="id" />
|
||||
|
|
|
@ -3445,33 +3445,6 @@
|
|||
<string name="new_conversation_activity__refresh">Refresh</string>
|
||||
<!-- redphone_audio_popup_menu -->
|
||||
|
||||
<!-- Insights -->
|
||||
<string name="Insights__percent">%</string>
|
||||
<string name="Insights__title">Insights</string>
|
||||
<string name="InsightsDashboardFragment__title">Insights</string>
|
||||
<!-- Body text for a page describing how many signal messages you\'ve sent. The first placeholder represents the number of signal messages sent, and the second placeholder represents how many days have passed. -->
|
||||
<string name="InsightsDashboardFragment__signal_protocol_automatically_protected">Signal Protocol automatically protected %1$d%% of your outgoing messages over the past %2$d days. Chats between Signal users are always end-to-end encrypted.</string>
|
||||
<string name="InsightsDashboardFragment__spread_the_word">Spread the word</string>
|
||||
<string name="InsightsDashboardFragment__not_enough_data">Not enough data</string>
|
||||
<string name="InsightsDashboardFragment__your_insights_percentage_is_calculated_based_on">Your Insights percentage is calculated based on outgoing messages within the past %1$d days that have not disappeared or been deleted.</string>
|
||||
<!-- Label for a button that, when pressed, will begin a chat with a person whose name is showed on the screen. -->
|
||||
<string name="InsightsDashboardFragment__start_a_conversation">Start a chat</string>
|
||||
<string name="InsightsDashboardFragment__invite_your_contacts">Start communicating securely and enable new features that go beyond the limitations of unencrypted SMS messages by inviting more contacts to join Signal.</string>
|
||||
<string name="InsightsDashboardFragment__this_stat_was_generated_locally">These statistics were locally generated on your device and can only be seen by you. They are never transmitted anywhere.</string>
|
||||
<string name="InsightsDashboardFragment__encrypted_messages">Encrypted messages</string>
|
||||
<string name="InsightsDashboardFragment__cancel">Cancel</string>
|
||||
<string name="InsightsDashboardFragment__send">Send</string>
|
||||
<string name="InsightsModalFragment__title">Introducing Insights</string>
|
||||
<string name="InsightsModalFragment__description">Find out how many of your outgoing messages were sent securely, then quickly invite new contacts to boost your Signal percentage.</string>
|
||||
<string name="InsightsModalFragment__view_insights">View Insights</string>
|
||||
|
||||
<string name="FirstInviteReminder__title">Invite to Signal</string>
|
||||
<string name="FirstInviteReminder__description">You could increase the number of encrypted messages you send by %1$d%%</string>
|
||||
<string name="SecondInviteReminder__title">Boost your Signal</string>
|
||||
<string name="SecondInviteReminder__description">Invite %1$s</string>
|
||||
<string name="InsightsReminder__view_insights">View Insights</string>
|
||||
<string name="InsightsReminder__invite">Invite</string>
|
||||
|
||||
<!-- Edit KBS Pin -->
|
||||
|
||||
<!-- BaseKbsPinFragment -->
|
||||
|
|
|
@ -46,7 +46,6 @@ object RecipientDatabaseTestUtils {
|
|||
callVibrateState: RecipientTable.VibrateState = RecipientTable.VibrateState.DEFAULT,
|
||||
messageRingtone: Uri = Uri.EMPTY,
|
||||
callRingtone: Uri = Uri.EMPTY,
|
||||
defaultSubscriptionId: Int = 0,
|
||||
expireMessages: Int = 0,
|
||||
registered: RecipientTable.RegisteredState = RecipientTable.RegisteredState.REGISTERED,
|
||||
profileKey: ByteArray = Random.nextBytes(32),
|
||||
|
@ -63,9 +62,7 @@ object RecipientDatabaseTestUtils {
|
|||
lastProfileFetch: Long = 0L,
|
||||
notificationChannel: String? = null,
|
||||
unidentifiedAccessMode: RecipientTable.UnidentifiedAccessMode = RecipientTable.UnidentifiedAccessMode.UNKNOWN,
|
||||
forceSmsSelection: Boolean = false,
|
||||
capabilities: Long = 0L,
|
||||
insightBannerTier: RecipientTable.InsightsBannerTier = RecipientTable.InsightsBannerTier.NO_TIER,
|
||||
storageId: ByteArray? = null,
|
||||
mentionSetting: RecipientTable.MentionSetting = RecipientTable.MentionSetting.ALWAYS_NOTIFY,
|
||||
wallpaper: ChatWallpaper? = null,
|
||||
|
@ -114,7 +111,6 @@ object RecipientDatabaseTestUtils {
|
|||
callVibrateState,
|
||||
messageRingtone,
|
||||
callRingtone,
|
||||
defaultSubscriptionId,
|
||||
expireMessages,
|
||||
registered,
|
||||
profileKey,
|
||||
|
@ -131,7 +127,6 @@ object RecipientDatabaseTestUtils {
|
|||
lastProfileFetch,
|
||||
notificationChannel,
|
||||
unidentifiedAccessMode,
|
||||
forceSmsSelection,
|
||||
RecipientRecord.Capabilities(
|
||||
capabilities,
|
||||
Recipient.Capability.deserialize(Bitmask.read(capabilities, RecipientTable.Capabilities.GROUPS_V1_MIGRATION, RecipientTable.Capabilities.BIT_LENGTH).toInt()),
|
||||
|
@ -143,7 +138,6 @@ object RecipientDatabaseTestUtils {
|
|||
Recipient.Capability.deserialize(Bitmask.read(capabilities, RecipientTable.Capabilities.PNP, RecipientTable.Capabilities.BIT_LENGTH).toInt()),
|
||||
Recipient.Capability.deserialize(Bitmask.read(capabilities, RecipientTable.Capabilities.PAYMENT_ACTIVATION, RecipientTable.Capabilities.BIT_LENGTH).toInt())
|
||||
),
|
||||
insightBannerTier,
|
||||
storageId,
|
||||
mentionSetting,
|
||||
wallpaper,
|
||||
|
|
|
@ -20,7 +20,6 @@ object TestMms {
|
|||
body: String = "body",
|
||||
sentTimeMillis: Long = System.currentTimeMillis(),
|
||||
receivedTimestampMillis: Long = System.currentTimeMillis(),
|
||||
subscriptionId: Int = -1,
|
||||
expiresIn: Long = 0,
|
||||
viewOnce: Boolean = false,
|
||||
distributionType: Int = ThreadTable.DistributionTypes.DEFAULT,
|
||||
|
@ -35,7 +34,6 @@ object TestMms {
|
|||
body,
|
||||
emptyList(),
|
||||
sentTimeMillis,
|
||||
subscriptionId,
|
||||
expiresIn,
|
||||
viewOnce,
|
||||
distributionType,
|
||||
|
|
Loading…
Add table
Reference in a new issue