Disable interactions while user is unregistered or expired.

This commit is contained in:
Clark
2023-05-05 13:24:00 -04:00
committed by Cody Henthorne
parent 65d5f4c426
commit c2c1537858
37 changed files with 527 additions and 44 deletions

View File

@@ -2,6 +2,8 @@ package org.thoughtcrime.securesms.components.reminder;
import android.content.Context;
import androidx.annotation.NonNull;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.registration.RegistrationNavigationActivity;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
@@ -9,12 +11,14 @@ import org.thoughtcrime.securesms.util.TextSecurePreferences;
public class UnauthorizedReminder extends Reminder {
public UnauthorizedReminder(final Context context) {
super(context.getString(R.string.UnauthorizedReminder_device_no_longer_registered),
super(null,
context.getString(R.string.UnauthorizedReminder_this_is_likely_because_you_registered_your_phone_number_with_Signal_on_a_different_device));
setOkListener(v -> {
context.startActivity(RegistrationNavigationActivity.newIntentForReRegistration(context));
});
addAction(new Action(context.getString(R.string.UnauthorizedReminder_reregister_action), R.id.reminder_action_re_register));
}
@Override
@@ -22,6 +26,11 @@ public class UnauthorizedReminder extends Reminder {
return false;
}
@Override
public @NonNull Importance getImportance() {
return Importance.ERROR;
}
public static boolean isEligible(Context context) {
return TextSecurePreferences.isUnauthorizedReceived(context);
}

View File

@@ -64,6 +64,7 @@ abstract class PreferenceViewHolder<T : PreferenceModel<T>>(itemView: View) : Ma
val icon = model.icon?.resolve(context)
iconView.setImageDrawable(icon)
iconView.visible = icon != null
iconView.alpha = if (model.isEnabled) 1f else 0.5f
val iconEnd = model.iconEnd?.resolve(context)
iconEndView?.setImageDrawable(iconEnd)

View File

@@ -1,13 +1,22 @@
package org.thoughtcrime.securesms.components.settings.app
import android.os.Bundle
import android.view.View
import android.widget.TextView
import android.widget.Toast
import androidx.annotation.IdRes
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.badges.BadgeImageView
import org.thoughtcrime.securesms.components.AvatarImageView
import org.thoughtcrime.securesms.components.reminder.ExpiredBuildReminder
import org.thoughtcrime.securesms.components.reminder.Reminder
import org.thoughtcrime.securesms.components.reminder.ReminderView
import org.thoughtcrime.securesms.components.reminder.UnauthorizedReminder
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsIcon
@@ -15,20 +24,37 @@ import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.PreferenceModel
import org.thoughtcrime.securesms.components.settings.PreferenceViewHolder
import org.thoughtcrime.securesms.components.settings.configure
import org.thoughtcrime.securesms.events.ReminderUpdateEvent
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.phonenumbers.PhoneNumberFormatter
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.registration.RegistrationNavigationActivity
import org.thoughtcrime.securesms.util.FeatureFlags
import org.thoughtcrime.securesms.util.PlayStoreUtil
import org.thoughtcrime.securesms.util.Util
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.adapter.mapping.MappingViewHolder
import org.thoughtcrime.securesms.util.navigation.safeNavigate
import org.thoughtcrime.securesms.util.views.Stub
class AppSettingsFragment : DSLSettingsFragment(R.string.text_secure_normal__menu_settings) {
class AppSettingsFragment : DSLSettingsFragment(
titleId = R.string.text_secure_normal__menu_settings,
layoutId = R.layout.dsl_settings_fragment_with_reminder
) {
private val viewModel: AppSettingsViewModel by viewModels()
private lateinit var reminderView: Stub<ReminderView>
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
reminderView = ViewUtil.findStubById(view, R.id.reminder_stub)
updateReminders()
}
override fun bindAdapter(adapter: MappingAdapter) {
adapter.registerFactory(BioPreference::class.java, LayoutFactory(::BioPreferenceViewHolder, R.layout.bio_preference_item))
adapter.registerFactory(PaymentsPreference::class.java, LayoutFactory(::PaymentsPreferenceViewHolder, R.layout.dsl_payments_preference))
@@ -39,9 +65,60 @@ class AppSettingsFragment : DSLSettingsFragment(R.string.text_secure_normal__men
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEvent(event: ReminderUpdateEvent?) {
updateReminders()
}
private fun updateReminders() {
if (ExpiredBuildReminder.isEligible()) {
showReminder(ExpiredBuildReminder(context))
} else if (UnauthorizedReminder.isEligible(context)) {
showReminder(UnauthorizedReminder(context))
} else {
hideReminders()
}
viewModel.refreshDeprecatedOrUnregistered()
}
private fun showReminder(reminder: Reminder) {
if (!reminderView.resolved()) {
reminderView.get().addOnLayoutChangeListener { _, _, top, _, bottom, _, _, _, _ ->
recyclerView?.setPadding(0, bottom - top, 0, 0)
}
recyclerView?.clipToPadding = false
}
reminderView.get().showReminder(reminder)
reminderView.get().setOnActionClickListener { reminderActionId: Int -> this.handleReminderAction(reminderActionId) }
}
private fun hideReminders() {
if (reminderView.resolved()) {
reminderView.get().hide()
recyclerView?.clipToPadding = true
}
}
private fun handleReminderAction(@IdRes reminderActionId: Int) {
when (reminderActionId) {
R.id.reminder_action_update_now -> {
PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext())
}
R.id.reminder_action_re_register -> {
startActivity(RegistrationNavigationActivity.newIntentForReRegistration(requireContext()))
}
}
}
override fun onResume() {
super.onResume()
viewModel.refreshExpiredGiftBadge()
EventBus.getDefault().register(this)
}
override fun onPause() {
super.onPause()
EventBus.getDefault().unregister(this)
}
private fun getConfiguration(state: AppSettingsState): DSLConfiguration {
@@ -75,7 +152,8 @@ class AppSettingsFragment : DSLSettingsFragment(R.string.text_secure_normal__men
icon = DSLSettingsIcon.from(R.drawable.symbol_devices_24),
onClick = {
findNavController().safeNavigate(R.id.action_appSettingsFragment_to_deviceActivity)
}
},
isEnabled = state.isDeprecatedOrUnregistered()
)
if (state.allowUserToGoToDonationManagementScreen) {
@@ -111,7 +189,8 @@ class AppSettingsFragment : DSLSettingsFragment(R.string.text_secure_normal__men
icon = DSLSettingsIcon.from(R.drawable.symbol_chat_24),
onClick = {
findNavController().safeNavigate(R.id.action_appSettingsFragment_to_chatsSettingsFragment)
}
},
isEnabled = state.isDeprecatedOrUnregistered()
)
clickPref(
@@ -119,7 +198,8 @@ class AppSettingsFragment : DSLSettingsFragment(R.string.text_secure_normal__men
icon = DSLSettingsIcon.from(R.drawable.symbol_stories_24),
onClick = {
findNavController().safeNavigate(AppSettingsFragmentDirections.actionAppSettingsFragmentToStoryPrivacySettings(R.string.preferences__stories))
}
},
isEnabled = state.isDeprecatedOrUnregistered()
)
clickPref(
@@ -127,7 +207,8 @@ class AppSettingsFragment : DSLSettingsFragment(R.string.text_secure_normal__men
icon = DSLSettingsIcon.from(R.drawable.symbol_bell_24),
onClick = {
findNavController().safeNavigate(R.id.action_appSettingsFragment_to_notificationsSettingsFragment)
}
},
isEnabled = state.isDeprecatedOrUnregistered()
)
clickPref(
@@ -135,7 +216,8 @@ class AppSettingsFragment : DSLSettingsFragment(R.string.text_secure_normal__men
icon = DSLSettingsIcon.from(R.drawable.symbol_lock_24),
onClick = {
findNavController().safeNavigate(R.id.action_appSettingsFragment_to_privacySettingsFragment)
}
},
isEnabled = state.isDeprecatedOrUnregistered()
)
clickPref(

View File

@@ -6,5 +6,11 @@ data class AppSettingsState(
val self: Recipient,
val unreadPaymentsCount: Int,
val hasExpiredGiftBadge: Boolean,
val allowUserToGoToDonationManagementScreen: Boolean
)
val allowUserToGoToDonationManagementScreen: Boolean,
val userUnregistered: Boolean,
val clientDeprecated: Boolean
) {
fun isDeprecatedOrUnregistered(): Boolean {
return !(userUnregistered || clientDeprecated)
}
}

View File

@@ -11,6 +11,7 @@ import org.thoughtcrime.securesms.conversationlist.model.UnreadPaymentsLiveData
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.livedata.Store
class AppSettingsViewModel(
@@ -22,7 +23,9 @@ class AppSettingsViewModel(
Recipient.self(),
0,
SignalStore.donationsValues().getExpiredGiftBadge() != null,
SignalStore.donationsValues().isLikelyASustainer() || InAppDonations.hasAtLeastOnePaymentMethodAvailable()
SignalStore.donationsValues().isLikelyASustainer() || InAppDonations.hasAtLeastOnePaymentMethodAvailable(),
TextSecurePreferences.isUnauthorizedReceived(ApplicationDependencies.getApplication()),
SignalStore.misc().isClientDeprecated
)
)
@@ -50,6 +53,10 @@ class AppSettingsViewModel(
disposables.clear()
}
fun refreshDeprecatedOrUnregistered() {
store.update { it.copy(clientDeprecated = SignalStore.misc().isClientDeprecated, userUnregistered = TextSecurePreferences.isUnauthorizedReceived(ApplicationDependencies.getApplication())) }
}
fun refreshExpiredGiftBadge() {
store.update { it.copy(hasExpiredGiftBadge = SignalStore.donationsValues().getExpiredGiftBadge() != null) }
}

View File

@@ -1,6 +1,7 @@
package org.thoughtcrime.securesms.components.settings.app.account
import android.content.Context
import android.content.DialogInterface
import android.content.Intent
import android.graphics.Typeface
import android.text.InputType
@@ -9,6 +10,7 @@ import android.view.ViewGroup
import android.widget.Button
import android.widget.EditText
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AlertDialog
import androidx.autofill.HintConstants
import androidx.core.app.DialogCompat
@@ -24,12 +26,16 @@ import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
import org.thoughtcrime.securesms.components.settings.configure
import org.thoughtcrime.securesms.contactshare.SimpleTextWatcher
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.lock.PinHashing
import org.thoughtcrime.securesms.lock.v2.CreateKbsPinActivity
import org.thoughtcrime.securesms.lock.v2.KbsConstants
import org.thoughtcrime.securesms.lock.v2.PinKeyboardType
import org.thoughtcrime.securesms.pin.RegistrationLockV2Dialog
import org.thoughtcrime.securesms.registration.RegistrationNavigationActivity
import org.thoughtcrime.securesms.util.PlayStoreUtil
import org.thoughtcrime.securesms.util.ServiceUtil
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.navigation.safeNavigate
@@ -64,6 +70,7 @@ class AccountSettingsFragment : DSLSettingsFragment(R.string.AccountSettingsFrag
@Suppress("DEPRECATION")
clickPref(
title = DSLSettingsText.from(if (state.hasPin) R.string.preferences_app_protection__change_your_pin else R.string.preferences_app_protection__create_a_pin),
isEnabled = state.isDeprecatedOrUnregistered(),
onClick = {
if (state.hasPin) {
startActivityForResult(CreateKbsPinActivity.getIntentForPinChangeFromSettings(requireContext()), CreateKbsPinActivity.REQUEST_NEW_PIN)
@@ -77,7 +84,7 @@ class AccountSettingsFragment : DSLSettingsFragment(R.string.AccountSettingsFrag
title = DSLSettingsText.from(R.string.preferences_app_protection__pin_reminders),
summary = DSLSettingsText.from(R.string.AccountSettingsFragment__youll_be_asked_less_frequently),
isChecked = state.hasPin && state.pinRemindersEnabled,
isEnabled = state.hasPin,
isEnabled = state.hasPin && state.isDeprecatedOrUnregistered(),
onClick = {
setPinRemindersEnabled(!state.pinRemindersEnabled)
}
@@ -87,7 +94,7 @@ class AccountSettingsFragment : DSLSettingsFragment(R.string.AccountSettingsFrag
title = DSLSettingsText.from(R.string.preferences_app_protection__registration_lock),
summary = DSLSettingsText.from(R.string.AccountSettingsFragment__require_your_signal_pin),
isChecked = state.registrationLockEnabled,
isEnabled = state.hasPin,
isEnabled = state.hasPin && state.isDeprecatedOrUnregistered(),
onClick = {
setRegistrationLockEnabled(!state.registrationLockEnabled)
}
@@ -95,6 +102,7 @@ class AccountSettingsFragment : DSLSettingsFragment(R.string.AccountSettingsFrag
clickPref(
title = DSLSettingsText.from(R.string.preferences__advanced_pin_settings),
isEnabled = state.isDeprecatedOrUnregistered(),
onClick = {
Navigation.findNavController(requireView()).safeNavigate(R.id.action_accountSettingsFragment_to_advancedPinSettingsActivity)
}
@@ -107,6 +115,7 @@ class AccountSettingsFragment : DSLSettingsFragment(R.string.AccountSettingsFrag
if (SignalStore.account().isRegistered) {
clickPref(
title = DSLSettingsText.from(R.string.AccountSettingsFragment__change_phone_number),
isEnabled = state.isDeprecatedOrUnregistered(),
onClick = {
Navigation.findNavController(requireView()).safeNavigate(R.id.action_accountSettingsFragment_to_changePhoneNumberFragment)
}
@@ -116,6 +125,7 @@ class AccountSettingsFragment : DSLSettingsFragment(R.string.AccountSettingsFrag
clickPref(
title = DSLSettingsText.from(R.string.preferences_chats__transfer_account),
summary = DSLSettingsText.from(R.string.preferences_chats__transfer_account_to_a_new_android_device),
isEnabled = state.isDeprecatedOrUnregistered(),
onClick = {
Navigation.findNavController(requireView()).safeNavigate(R.id.action_accountSettingsFragment_to_oldDeviceTransferActivity)
}
@@ -123,13 +133,49 @@ class AccountSettingsFragment : DSLSettingsFragment(R.string.AccountSettingsFrag
clickPref(
title = DSLSettingsText.from(R.string.AccountSettingsFragment__request_account_data),
isEnabled = state.isDeprecatedOrUnregistered(),
onClick = {
Navigation.findNavController(requireView()).safeNavigate(R.id.action_accountSettingsFragment_to_exportAccountFragment)
}
)
if (!state.isDeprecatedOrUnregistered()) {
if (state.clientDeprecated) {
clickPref(
title = DSLSettingsText.from(R.string.preferences_account_update_signal),
onClick = {
PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext())
}
)
} else if (state.userUnregistered) {
clickPref(
title = DSLSettingsText.from(R.string.preferences_account_reregister),
onClick = {
startActivity(RegistrationNavigationActivity.newIntentForReRegistration(requireContext()))
}
)
}
clickPref(
title = DSLSettingsText.from(R.string.preferences_account_delete_all_data, ContextCompat.getColor(requireContext(), R.color.signal_alert_primary)),
onClick = {
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.preferences_account_delete_all_data_confirmation_title)
.setMessage(R.string.preferences_account_delete_all_data_confirmation_message)
.setPositiveButton(R.string.preferences_account_delete_all_data_confirmation_proceed) { _: DialogInterface, _: Int ->
if (!ServiceUtil.getActivityManager(ApplicationDependencies.getApplication()).clearApplicationUserData()) {
Toast.makeText(requireContext(), R.string.preferences_account_delete_all_data_failed, Toast.LENGTH_LONG).show()
}
}
.setNegativeButton(R.string.preferences_account_delete_all_data_confirmation_cancel, null)
.show()
}
)
}
clickPref(
title = DSLSettingsText.from(R.string.preferences__delete_account, ContextCompat.getColor(requireContext(), R.color.signal_alert_primary)),
title = DSLSettingsText.from(R.string.preferences__delete_account, ContextCompat.getColor(requireContext(), if (state.isDeprecatedOrUnregistered()) R.color.signal_alert_primary else R.color.signal_alert_primary_50)),
isEnabled = state.isDeprecatedOrUnregistered(),
onClick = {
Navigation.findNavController(requireView()).safeNavigate(R.id.action_accountSettingsFragment_to_deleteAccountFragment)
}

View File

@@ -3,5 +3,11 @@ package org.thoughtcrime.securesms.components.settings.app.account
data class AccountSettingsState(
val hasPin: Boolean,
val pinRemindersEnabled: Boolean,
val registrationLockEnabled: Boolean
)
val registrationLockEnabled: Boolean,
val userUnregistered: Boolean,
val clientDeprecated: Boolean
) {
fun isDeprecatedOrUnregistered(): Boolean {
return !(userUnregistered || clientDeprecated)
}
}

View File

@@ -2,7 +2,9 @@ package org.thoughtcrime.securesms.components.settings.app.account
import androidx.lifecycle.LiveData
import androidx.lifecycle.ViewModel
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.keyvalue.SignalStore
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.livedata.Store
class AccountSettingsViewModel : ViewModel() {
@@ -18,7 +20,9 @@ class AccountSettingsViewModel : ViewModel() {
return AccountSettingsState(
hasPin = SignalStore.kbsValues().hasPin() && !SignalStore.kbsValues().hasOptedOut(),
pinRemindersEnabled = SignalStore.pinValues().arePinRemindersEnabled(),
registrationLockEnabled = SignalStore.kbsValues().isV2RegistrationLockEnabled
registrationLockEnabled = SignalStore.kbsValues().isV2RegistrationLockEnabled,
userUnregistered = TextSecurePreferences.isUnauthorizedReceived(ApplicationDependencies.getApplication()),
clientDeprecated = SignalStore.misc().isClientDeprecated
)
}
}

View File

@@ -109,6 +109,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
private val args: ConversationSettingsFragmentArgs by navArgs()
private val alertTint by lazy { ContextCompat.getColor(requireContext(), R.color.signal_alert_primary) }
private val alertDisabledTint by lazy { ContextCompat.getColor(requireContext(), R.color.signal_alert_primary_50) }
private val blockIcon by lazy {
ContextUtil.requireDrawable(requireContext(), R.drawable.ic_block_tinted_24).apply {
colorFilter = PorterDuffColorFilter(alertTint, PorterDuff.Mode.SRC_IN)
@@ -383,6 +384,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
customPref(
ButtonStripPreference.Model(
state = state.buttonStripState,
enabled = !state.isDeprecatedOrUnregistered,
onMessageClick = {
val intent = ConversationIntents
.createBuilder(requireContext(), state.recipient.id, state.threadId)
@@ -470,7 +472,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
title = DSLSettingsText.from(R.string.ConversationSettingsFragment__disappearing_messages),
summary = summary,
icon = DSLSettingsIcon.from(icon),
isEnabled = enabled,
isEnabled = enabled && !state.isDeprecatedOrUnregistered,
onClick = {
val action = ConversationSettingsFragmentDirections.actionConversationSettingsFragmentToAppSettingsExpireTimer()
.setInitialValue(state.disappearingMessagesLifespan)
@@ -496,6 +498,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
clickPref(
title = DSLSettingsText.from(R.string.ConversationSettingsFragment__sounds_and_notifications),
icon = DSLSettingsIcon.from(R.drawable.ic_speaker_24),
isEnabled = !state.isDeprecatedOrUnregistered,
onClick = {
val action = ConversationSettingsFragmentDirections.actionConversationSettingsFragmentToSoundsAndNotificationsSettingsFragment(state.recipient.id)
@@ -540,6 +543,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
clickPref(
title = DSLSettingsText.from(R.string.ConversationSettingsFragment__view_safety_number),
icon = DSLSettingsIcon.from(R.drawable.ic_safety_number_24),
isEnabled = !state.isDeprecatedOrUnregistered,
onClick = {
startActivity(VerifyIdentityActivity.newIntent(requireActivity(), recipientState.identityRecord))
}
@@ -615,6 +619,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
LargeIconClickPreference.Model(
title = DSLSettingsText.from(R.string.ConversationSettingsFragment__add_to_a_group),
icon = DSLSettingsIcon.from(R.drawable.add_to_a_group, NO_TINT),
isEnabled = !state.isDeprecatedOrUnregistered,
onClick = {
viewModel.onAddToGroup()
}
@@ -657,7 +662,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
sectionHeaderPref(DSLSettingsText.from(resources.getQuantityString(R.plurals.ContactSelectionListFragment_d_members, memberCount, memberCount)))
}
if (groupState.canAddToGroup) {
if (groupState.canAddToGroup && !state.isDeprecatedOrUnregistered) {
customPref(
LargeIconClickPreference.Model(
title = DSLSettingsText.from(R.string.ConversationSettingsFragment__add_members),
@@ -700,6 +705,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
title = DSLSettingsText.from(R.string.ConversationSettingsFragment__group_link),
summary = DSLSettingsText.from(if (groupState.groupLinkEnabled) R.string.preferences_on else R.string.preferences_off),
icon = DSLSettingsIcon.from(R.drawable.ic_link_16),
isEnabled = !state.isDeprecatedOrUnregistered,
onClick = {
navController.safeNavigate(ConversationSettingsFragmentDirections.actionConversationSettingsFragmentToShareableGroupLinkFragment(groupState.groupId.requireV2().toString()))
}
@@ -708,6 +714,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
clickPref(
title = DSLSettingsText.from(R.string.ConversationSettingsFragment__requests_and_invites),
icon = DSLSettingsIcon.from(R.drawable.ic_update_group_add_16),
isEnabled = !state.isDeprecatedOrUnregistered,
onClick = {
startActivity(ManagePendingAndRequestingMembersActivity.newIntent(requireContext(), groupState.groupId.requireV2()))
}
@@ -717,6 +724,7 @@ class ConversationSettingsFragment : DSLSettingsFragment(
clickPref(
title = DSLSettingsText.from(R.string.ConversationSettingsFragment__permissions),
icon = DSLSettingsIcon.from(R.drawable.ic_lock_24),
isEnabled = !state.isDeprecatedOrUnregistered,
onClick = {
val action = ConversationSettingsFragmentDirections.actionConversationSettingsFragmentToPermissionsSettingsFragment(ParcelableGroupId.from(groupState.groupId))
navController.safeNavigate(action)
@@ -729,8 +737,9 @@ class ConversationSettingsFragment : DSLSettingsFragment(
dividerPref()
clickPref(
title = DSLSettingsText.from(R.string.conversation__menu_leave_group, alertTint),
title = DSLSettingsText.from(R.string.conversation__menu_leave_group, if (state.isDeprecatedOrUnregistered) alertDisabledTint else alertTint),
icon = DSLSettingsIcon.from(leaveIcon),
isEnabled = !state.isDeprecatedOrUnregistered,
onClick = {
LeaveGroupDialog.handleLeavePushGroup(requireActivity(), groupState.groupId.requirePush(), null)
}
@@ -759,12 +768,13 @@ class ConversationSettingsFragment : DSLSettingsFragment(
else -> R.string.ConversationSettingsFragment__block
}
val titleTint = if (isBlocked) null else alertTint
val titleTint = if (isBlocked) null else if (state.isDeprecatedOrUnregistered) alertDisabledTint else alertTint
val blockUnblockIcon = if (isBlocked) unblockIcon else blockIcon
clickPref(
title = if (titleTint != null) DSLSettingsText.from(title, titleTint) else DSLSettingsText.from(title),
icon = DSLSettingsIcon.from(blockUnblockIcon),
isEnabled = !state.isDeprecatedOrUnregistered,
onClick = {
if (state.recipient.isBlocked) {
BlockUnblockDialog.showUnblockFor(requireContext(), viewLifecycleOwner.lifecycle, state.recipient) {

View File

@@ -14,6 +14,7 @@ data class ConversationSettingsState(
val threadId: Long = -1,
val storyViewState: StoryViewState = StoryViewState.NONE,
val recipient: Recipient = Recipient.UNKNOWN,
val isDeprecatedOrUnregistered: Boolean = false,
val buttonStripState: ButtonStripPreference.State = ButtonStripPreference.State(),
val disappearingMessagesLifespan: Int = 0,
val canModifyBlockedState: Boolean = false,

View File

@@ -21,6 +21,7 @@ import org.thoughtcrime.securesms.components.settings.conversation.preferences.L
import org.thoughtcrime.securesms.database.AttachmentTable
import org.thoughtcrime.securesms.database.RecipientTable
import org.thoughtcrime.securesms.database.model.StoryViewState
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.groups.GroupId
import org.thoughtcrime.securesms.groups.LiveGroup
import org.thoughtcrime.securesms.groups.v2.GroupAddMembersResult
@@ -29,6 +30,7 @@ import org.thoughtcrime.securesms.recipients.Recipient
import org.thoughtcrime.securesms.recipients.RecipientId
import org.thoughtcrime.securesms.recipients.RecipientUtil
import org.thoughtcrime.securesms.util.FeatureFlags
import org.thoughtcrime.securesms.util.TextSecurePreferences
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil
import org.thoughtcrime.securesms.util.livedata.Store
import java.util.Optional
@@ -46,7 +48,8 @@ sealed class ConversationSettingsViewModel(
protected val store = Store(
ConversationSettingsState(
specificSettingsState = specificSettingsState
specificSettingsState = specificSettingsState,
isDeprecatedOrUnregistered = SignalStore.misc().isClientDeprecated || TextSecurePreferences.isUnauthorizedReceived(ApplicationDependencies.getApplication())
)
)
protected val internalEvents: Subject<ConversationSettingsEvent> = PublishSubject.create()

View File

@@ -7,6 +7,7 @@ import androidx.appcompat.content.res.AppCompatResources
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.settings.DSLSettingsIcon
import org.thoughtcrime.securesms.components.settings.PreferenceModel
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.adapter.mapping.LayoutFactory
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.adapter.mapping.MappingViewHolder
@@ -24,6 +25,7 @@ object ButtonStripPreference {
class Model(
val state: State,
val background: DSLSettingsIcon? = null,
val enabled: Boolean = true,
val onAddToStoryClick: () -> Unit = {},
val onMessageClick: () -> Unit = {},
val onVideoClick: () -> Unit = {},
@@ -87,6 +89,11 @@ object ButtonStripPreference {
}
}
listOf(messageContainer, videoContainer, audioContainer, muteContainer, addToStoryContainer, searchContainer).forEach {
it.alpha = if (model.enabled) 1.0f else 0.5f
ViewUtil.setEnabledRecursive(it, model.enabled)
}
message.setOnClickListener { model.onMessageClick() }
videoCall.setOnClickListener { model.onVideoClick() }
audioCall.setOnClickListener { model.onAudioClick() }

View File

@@ -22,6 +22,7 @@ object LargeIconClickPreference {
override val title: DSLSettingsText?,
override val icon: DSLSettingsIcon,
override val summary: DSLSettingsText? = null,
override val isEnabled: Boolean = true,
val onClick: () -> Unit
) : PreferenceModel<Model>()

View File

@@ -399,6 +399,7 @@ public class ConversationParentFragment extends Fragment
private ConversationFragment fragment;
private Button unblockButton;
private Stub<View> smsExportStub;
private Stub<View> loggedOutStub;
private Button registerButton;
private InputAwareLayout container;
protected Stub<ReminderView> reminderView;
@@ -1728,11 +1729,12 @@ public class ConversationParentFragment extends Fragment
Integer actionableRequestingMembers = groupViewModel.getActionableRequestingMembers().getValue();
List<RecipientId> gv1MigrationSuggestions = groupViewModel.getGroupV1MigrationSuggestions().getValue();
if (UnauthorizedReminder.isEligible(context)) {
reminderView.get().showReminder(new UnauthorizedReminder(context));
} else if (ExpiredBuildReminder.isEligible()) {
if (ExpiredBuildReminder.isEligible()) {
reminderView.get().showReminder(new ExpiredBuildReminder(context));
reminderView.get().setOnActionClickListener(this::handleReminderAction);
} else if (UnauthorizedReminder.isEligible(context)) {
reminderView.get().showReminder(new UnauthorizedReminder(context));
reminderView.get().setOnActionClickListener(this::handleReminderAction);
} else if (ServiceOutageReminder.isEligible(context)) {
ApplicationDependencies.getJobManager().add(new ServiceOutageDetectionJob());
reminderView.get().showReminder(new ServiceOutageReminder(context));
@@ -1788,6 +1790,8 @@ public class ConversationParentFragment extends Fragment
InsightsLauncher.showInsightsDashboard(getChildFragmentManager());
} else if (reminderActionId == R.id.reminder_action_update_now) {
PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext());
} else if (reminderActionId == R.id.reminder_action_re_register) {
startActivity(RegistrationNavigationActivity.newIntentForReRegistration(requireContext()));
} else {
throw new IllegalArgumentException("Unknown ID: " + reminderActionId);
}
@@ -1872,6 +1876,7 @@ public class ConversationParentFragment extends Fragment
attachmentKeyboardStub = ViewUtil.findStubById(view, R.id.attachment_keyboard_stub);
unblockButton = view.findViewById(R.id.unblock_button);
smsExportStub = ViewUtil.findStubById(view, R.id.sms_export_stub);
loggedOutStub = ViewUtil.findStubById(view, R.id.logged_out_stub);
registerButton = view.findViewById(R.id.register_button);
container = view.findViewById(R.id.layout_container);
reminderView = ViewUtil.findStubById(view, R.id.reminder_stub);
@@ -2608,16 +2613,46 @@ public class ConversationParentFragment extends Fragment
return;
}
if (!conversationSecurityInfo.isPushAvailable() && isPushGroupConversation()) {
if (conversationSecurityInfo.isClientExpired() || conversationSecurityInfo.isUnauthorized()) {
unblockButton.setVisibility(View.GONE);
inputPanel.setHideForBlockedState(true);
smsExportStub.setVisibility(View.GONE);
registerButton.setVisibility(View.GONE);
loggedOutStub.setVisibility(View.VISIBLE);
messageRequestBottomView.setVisibility(View.GONE);
int color = ContextCompat.getColor(requireContext(), recipient.hasWallpaper() ? R.color.wallpaper_bubble_color : R.color.signal_colorBackground);
loggedOutStub.get().setBackgroundColor(color);
WindowUtil.setNavigationBarColor(requireActivity(), color);
TextView message = loggedOutStub.get().findViewById(R.id.logged_out_message);
MaterialButton actionButton = loggedOutStub.get().findViewById(R.id.logged_out_button);
if (conversationSecurityInfo.isClientExpired()) {
message.setText(R.string.ExpiredBuildReminder_this_version_of_signal_has_expired);
actionButton.setText(R.string.ConversationFragment__update_build);
actionButton.setOnClickListener(v -> {
PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext());
});
} else if (conversationSecurityInfo.isUnauthorized()) {
message.setText(R.string.UnauthorizedReminder_this_is_likely_because_you_registered_your_phone_number_with_Signal_on_a_different_device);
actionButton.setText(R.string.ConversationFragment__reregister_signal);
actionButton.setOnClickListener(v -> {
startActivity(RegistrationNavigationActivity.newIntentForReRegistration(requireContext()));
});
}
} else if (!conversationSecurityInfo.isPushAvailable() && isPushGroupConversation()) {
unblockButton.setVisibility(View.GONE);
inputPanel.setHideForBlockedState(true);
smsExportStub.setVisibility(View.GONE);
loggedOutStub.setVisibility(View.GONE);
registerButton.setVisibility(View.VISIBLE);
} else if (!conversationSecurityInfo.isPushAvailable() && !(SignalStore.misc().getSmsExportPhase().isSmsSupported() && conversationSecurityInfo.isDefaultSmsApplication()) && (recipient.hasSmsAddress() || recipient.isMmsGroup())) {
unblockButton.setVisibility(View.GONE);
inputPanel.setHideForBlockedState(true);
smsExportStub.setVisibility(View.VISIBLE);
registerButton.setVisibility(View.GONE);
loggedOutStub.setVisibility(View.GONE);
int color = ContextCompat.getColor(requireContext(), recipient.hasWallpaper() ? R.color.wallpaper_bubble_color : R.color.signal_colorBackground);
smsExportStub.get().setBackgroundColor(color);

View File

@@ -28,6 +28,7 @@ import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.util.BubbleUtil;
import org.thoughtcrime.securesms.util.ConversationUtil;
import org.thoughtcrime.securesms.util.MessageRecordUtil;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.Util;
import java.io.IOException;
@@ -187,7 +188,9 @@ public class ConversationRepository {
registeredState == RecipientTable.RegisteredState.REGISTERED && signalEnabled,
Util.isDefaultSmsProvider(context),
true,
hasUnexportedInsecureMessages);
hasUnexportedInsecureMessages,
SignalStore.misc().isClientDeprecated(),
TextSecurePreferences.isUnauthorizedReceived(context));
}).subscribeOn(Schedulers.io());
}

View File

@@ -7,5 +7,7 @@ data class ConversationSecurityInfo(
val isPushAvailable: Boolean = false,
val isDefaultSmsApplication: Boolean = false,
val isInitialized: Boolean = false,
val hasUnexportedInsecureMessages: Boolean = false
val hasUnexportedInsecureMessages: Boolean = false,
val isClientExpired: Boolean = false,
val isUnauthorized: Boolean = false
)

View File

@@ -158,6 +158,7 @@ import org.thoughtcrime.securesms.profiles.manage.ManageProfileActivity;
import org.thoughtcrime.securesms.ratelimit.RecaptchaProofBottomSheetFragment;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.registration.RegistrationNavigationActivity;
import org.thoughtcrime.securesms.search.MessageResult;
import org.thoughtcrime.securesms.service.KeyCachingService;
import org.thoughtcrime.securesms.sms.MessageSender;
@@ -803,6 +804,8 @@ public class ConversationListFragment extends MainFragment implements ActionMode
CdsPermanentErrorBottomSheet.show(getChildFragmentManager());
} else if (reminderActionId == R.id.reminder_action_fix_username) {
startActivity(ManageProfileActivity.getIntentForUsernameEdit(requireContext()));
} else if (reminderActionId == R.id.reminder_action_re_register) {
startActivity(RegistrationNavigationActivity.newIntentForReRegistration(requireContext()));
}
}
@@ -1042,10 +1045,10 @@ public class ConversationListFragment extends MainFragment implements ActionMode
Context context = requireContext();
SimpleTask.run(getViewLifecycleOwner().getLifecycle(), () -> {
if (UnauthorizedReminder.isEligible(context)) {
return Optional.of(new UnauthorizedReminder(context));
} else if (ExpiredBuildReminder.isEligible()) {
if (ExpiredBuildReminder.isEligible()) {
return Optional.of(new ExpiredBuildReminder(context));
} else if (UnauthorizedReminder.isEligible(context)) {
return Optional.of(new UnauthorizedReminder(context));
} else if (ServiceOutageReminder.isEligible(context)) {
ApplicationDependencies.getJobManager().add(new ServiceOutageDetectionJob());
return Optional.of(new ServiceOutageReminder(context));

View File

@@ -176,7 +176,7 @@ final class GroupManagerV1 {
OutgoingMessage outgoingMessage = OutgoingMessage.groupUpdateMessage(groupRecipient,
new MessageGroupContext(groupContext),
Collections.singletonList(avatarAttachment),
avatarAttachment != null ? Collections.singletonList(avatarAttachment) : Collections.emptyList(),
System.currentTimeMillis(),
0,
false,

View File

@@ -38,6 +38,7 @@ import org.thoughtcrime.securesms.payments.backup.RecoveryPhraseStates;
import org.thoughtcrime.securesms.payments.backup.confirm.PaymentsRecoveryPhraseConfirmFragment;
import org.thoughtcrime.securesms.payments.preferences.model.InfoCard;
import org.thoughtcrime.securesms.payments.preferences.model.PaymentItem;
import org.thoughtcrime.securesms.registration.RegistrationNavigationActivity;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.PlayStoreUtil;
import org.thoughtcrime.securesms.util.SpanUtil;
@@ -261,6 +262,8 @@ public class PaymentsHomeFragment extends LoggingFragment {
reminderView.get().setOnActionClickListener(actionId -> {
if (actionId == R.id.reminder_action_update_now) {
PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext());
} else if (actionId == R.id.reminder_action_re_register) {
startActivity(RegistrationNavigationActivity.newIntentForReRegistration(requireContext()));
}
});
} else {

View File

@@ -49,6 +49,8 @@ import org.thoughtcrime.securesms.util.ThemeUtil;
import org.thoughtcrime.securesms.util.Util;
import org.thoughtcrime.securesms.util.WindowUtil;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import kotlin.Unit;
@@ -87,6 +89,8 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
private BadgeImageView badgeImageView;
private Callback callback;
private ButtonStripPreference.ViewHolder buttonStripViewHolder;
public static BottomSheetDialogFragment create(@NonNull RecipientId recipientId,
@Nullable GroupId groupId)
{
@@ -135,6 +139,7 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
interactionsContainer = view.findViewById(R.id.interactions_container);
badgeImageView = view.findViewById(R.id.rbs_badge);
buttonStripViewHolder = new ButtonStripPreference.ViewHolder(buttonStrip);
return view;
}
@@ -245,6 +250,7 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
ButtonStripPreference.Model buttonStripModel = new ButtonStripPreference.Model(
buttonStripState,
DSLSettingsIcon.from(ContextUtil.requireDrawable(requireContext(), R.drawable.selectable_recipient_bottom_sheet_icon_button)),
!viewModel.isDeprecatedOrUnregistered(),
() -> Unit.INSTANCE,
() -> {
dismiss();
@@ -267,7 +273,7 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
() -> Unit.INSTANCE
);
new ButtonStripPreference.ViewHolder(buttonStrip).bind(buttonStripModel);
buttonStripViewHolder.bind(buttonStripModel);
if (recipient.isReleaseNotes()) {
buttonStrip.setVisibility(View.GONE);
@@ -342,12 +348,21 @@ public final class RecipientBottomSheetDialogFragment extends BottomSheetDialogF
viewModel.getAdminActionBusy().observe(getViewLifecycleOwner(), busy -> {
adminActionBusy.setVisibility(busy ? View.VISIBLE : View.GONE);
makeGroupAdminButton.setEnabled(!busy);
removeAdminButton.setEnabled(!busy);
removeFromGroupButton.setEnabled(!busy);
boolean userLoggedOut = viewModel.isDeprecatedOrUnregistered();
makeGroupAdminButton.setEnabled(!busy && !userLoggedOut);
removeAdminButton.setEnabled(!busy && !userLoggedOut);
removeFromGroupButton.setEnabled(!busy && !userLoggedOut);
});
callback = getParentFragment() != null && getParentFragment() instanceof Callback ? (Callback) getParentFragment() : null;
if (viewModel.isDeprecatedOrUnregistered()) {
List<TextView> viewsToDisable = Arrays.asList(blockButton, unblockButton, removeFromGroupButton, makeGroupAdminButton, removeAdminButton, addToGroupButton, viewSafetyNumberButton);
for (TextView view : viewsToDisable) {
view.setEnabled(false);
view.setAlpha(0.5f);
}
}
}
@Override

View File

@@ -29,12 +29,14 @@ import org.thoughtcrime.securesms.groups.LiveGroup;
import org.thoughtcrime.securesms.groups.ui.GroupChangeFailureReason;
import org.thoughtcrime.securesms.groups.ui.GroupErrors;
import org.thoughtcrime.securesms.groups.ui.addtogroup.AddToGroupsActivity;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.recipients.Recipient;
import org.thoughtcrime.securesms.recipients.RecipientId;
import org.thoughtcrime.securesms.recipients.RecipientUtil;
import org.thoughtcrime.securesms.stories.StoryViewerArgs;
import org.thoughtcrime.securesms.stories.viewer.StoryViewerActivity;
import org.thoughtcrime.securesms.util.CommunicationActions;
import org.thoughtcrime.securesms.util.TextSecurePreferences;
import org.thoughtcrime.securesms.util.livedata.LiveDataUtil;
import org.thoughtcrime.securesms.verify.VerifyIdentityActivity;
@@ -54,16 +56,17 @@ final class RecipientDialogViewModel extends ViewModel {
private final MutableLiveData<Boolean> adminActionBusy;
private final MutableLiveData<StoryViewState> storyViewState;
private final CompositeDisposable disposables;
private final boolean isDeprecatedOrUnregistered;
private RecipientDialogViewModel(@NonNull Context context,
@NonNull RecipientDialogRepository recipientDialogRepository)
{
this.context = context;
this.recipientDialogRepository = recipientDialogRepository;
this.identity = new MutableLiveData<>();
this.adminActionBusy = new MutableLiveData<>(false);
this.storyViewState = new MutableLiveData<>();
this.disposables = new CompositeDisposable();
this.context = context;
this.recipientDialogRepository = recipientDialogRepository;
this.identity = new MutableLiveData<>();
this.adminActionBusy = new MutableLiveData<>(false);
this.storyViewState = new MutableLiveData<>();
this.disposables = new CompositeDisposable();
this.isDeprecatedOrUnregistered = SignalStore.misc().isClientDeprecated() || TextSecurePreferences.isUnauthorizedReceived(context);
boolean recipientIsSelf = recipientDialogRepository.getRecipientId().equals(Recipient.self().getId());
@@ -113,6 +116,10 @@ final class RecipientDialogViewModel extends ViewModel {
disposables.clear();
}
boolean isDeprecatedOrUnregistered() {
return isDeprecatedOrUnregistered;
}
LiveData<StoryViewState> getStoryViewState() {
return storyViewState;
}

View File

@@ -10,6 +10,7 @@ import android.view.MenuItem
import android.view.View
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.annotation.IdRes
import androidx.core.app.ActivityOptionsCompat
import androidx.core.app.SharedElementCallback
import androidx.core.view.ViewCompat
@@ -21,9 +22,16 @@ import com.google.android.material.snackbar.Snackbar
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.kotlin.subscribeBy
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import org.signal.core.util.concurrent.LifecycleDisposable
import org.thoughtcrime.securesms.R
import org.thoughtcrime.securesms.components.Material3SearchToolbar
import org.thoughtcrime.securesms.components.reminder.ExpiredBuildReminder
import org.thoughtcrime.securesms.components.reminder.Reminder
import org.thoughtcrime.securesms.components.reminder.ReminderView
import org.thoughtcrime.securesms.components.reminder.UnauthorizedReminder
import org.thoughtcrime.securesms.components.settings.DSLConfiguration
import org.thoughtcrime.securesms.components.settings.DSLSettingsFragment
import org.thoughtcrime.securesms.components.settings.DSLSettingsText
@@ -35,10 +43,12 @@ import org.thoughtcrime.securesms.database.model.MediaMmsMessageRecord
import org.thoughtcrime.securesms.database.model.MmsMessageRecord
import org.thoughtcrime.securesms.database.model.StoryViewState
import org.thoughtcrime.securesms.dependencies.ApplicationDependencies
import org.thoughtcrime.securesms.events.ReminderUpdateEvent
import org.thoughtcrime.securesms.main.Material3OnScrollHelperBinder
import org.thoughtcrime.securesms.main.SearchBinder
import org.thoughtcrime.securesms.mediasend.v2.MediaSelectionActivity
import org.thoughtcrime.securesms.permissions.Permissions
import org.thoughtcrime.securesms.registration.RegistrationNavigationActivity
import org.thoughtcrime.securesms.safety.SafetyNumberBottomSheet
import org.thoughtcrime.securesms.stories.StoryTextPostModel
import org.thoughtcrime.securesms.stories.StoryViewerArgs
@@ -49,8 +59,11 @@ import org.thoughtcrime.securesms.stories.settings.StorySettingsActivity
import org.thoughtcrime.securesms.stories.tabs.ConversationListTab
import org.thoughtcrime.securesms.stories.tabs.ConversationListTabsViewModel
import org.thoughtcrime.securesms.stories.viewer.StoryViewerActivity
import org.thoughtcrime.securesms.util.PlayStoreUtil
import org.thoughtcrime.securesms.util.ViewUtil
import org.thoughtcrime.securesms.util.adapter.mapping.MappingAdapter
import org.thoughtcrime.securesms.util.fragments.requireListener
import org.thoughtcrime.securesms.util.views.Stub
import org.thoughtcrime.securesms.util.visible
import java.util.concurrent.TimeUnit
@@ -66,6 +79,8 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l
private lateinit var emptyNotice: View
private lateinit var cameraFab: FloatingActionButton
private lateinit var reminderView: Stub<ReminderView>
private val lifecycleDisposable = LifecycleDisposable()
private val viewModel: StoriesLandingViewModel by viewModels(
@@ -95,11 +110,13 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l
viewModel.markStoriesRead()
ApplicationDependencies.getExpireStoriesManager().scheduleIfNecessary()
EventBus.getDefault().register(this)
}
override fun onPause() {
super.onPause()
requireListener<SearchBinder>().getSearchAction().setOnClickListener(null)
EventBus.getDefault().unregister(this)
}
private fun initializeSearchAction() {
@@ -121,6 +138,57 @@ class StoriesLandingFragment : DSLSettingsFragment(layoutId = R.layout.stories_l
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
reminderView = ViewUtil.findStubById(view, R.id.reminder)
updateReminders()
}
@Subscribe(threadMode = ThreadMode.MAIN)
fun onEvent(event: ReminderUpdateEvent?) {
updateReminders()
}
private fun updateReminders() {
if (ExpiredBuildReminder.isEligible()) {
showReminder(ExpiredBuildReminder(context))
} else if (UnauthorizedReminder.isEligible(context)) {
showReminder(UnauthorizedReminder(context))
} else {
hideReminders()
}
}
private fun showReminder(reminder: Reminder) {
if (!reminderView.resolved()) {
reminderView.get().addOnLayoutChangeListener { _, _, top, _, bottom, _, _, _, _ ->
recyclerView?.setPadding(0, bottom - top, 0, 0)
}
recyclerView?.clipToPadding = false
}
reminderView.get().showReminder(reminder)
reminderView.get().setOnActionClickListener { reminderActionId: Int -> this.handleReminderAction(reminderActionId) }
}
private fun hideReminders() {
if (reminderView.resolved()) {
reminderView.get().hide()
recyclerView?.clipToPadding = true
}
}
private fun handleReminderAction(@IdRes reminderActionId: Int) {
when (reminderActionId) {
R.id.reminder_action_update_now -> {
PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(requireContext())
}
R.id.reminder_action_re_register -> {
startActivity(RegistrationNavigationActivity.newIntentForReRegistration(requireContext()))
}
}
}
override fun bindAdapter(adapter: MappingAdapter) {
this.adapter = adapter

View File

@@ -24,6 +24,7 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder;
import org.thoughtcrime.securesms.R;
import org.thoughtcrime.securesms.keyvalue.SignalStore;
import org.thoughtcrime.securesms.registration.RegistrationNavigationActivity;
public class Dialogs {
public static void showAlertDialog(Context context, String title, String message) {
@@ -54,4 +55,26 @@ public class Dialogs {
})
.show();
}
public static void showUpgradeSignalDialog(@NonNull Context context) {
new MaterialAlertDialogBuilder(context)
.setTitle(R.string.UpdateSignalExpiredDialog__title)
.setMessage(R.string.UpdateSignalExpiredDialog__message)
.setNegativeButton(R.string.UpdateSignalExpiredDialog__cancel_action, null)
.setPositiveButton(R.string.UpdateSignalExpiredDialog__update_action, (d, w) -> {
PlayStoreUtil.openPlayStoreOrOurApkDownloadPage(context);
})
.show();
}
public static void showReregisterSignalDialog(@NonNull Context context) {
new MaterialAlertDialogBuilder(context)
.setTitle(R.string.ReregisterSignalDialog__title)
.setMessage(R.string.ReregisterSignalDialog__message)
.setNegativeButton(R.string.ReregisterSignalDialog__cancel_action, null)
.setPositiveButton(R.string.ReregisterSignalDialog__reregister_action, (d, w) -> {
context.startActivity(RegistrationNavigationActivity.newIntentForReRegistration(context));
})
.show();
}
}