From 85bbbd3349952b2495d51a750e58b17659f64347 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Mon, 31 Aug 2026 16:37:25 -0700 Subject: [PATCH 01/15] DonationReminderV3: end-of-experiment screens --- .../DonationReminderCardView.kt | 14 ++++- .../DonationReminderHelper.kt | 25 +++++--- .../page/leadimages/PageHeaderView.kt | 57 +++++++++++++++---- .../main/java/org/wikipedia/settings/Prefs.kt | 4 ++ .../dev/DeveloperSettingsPreferenceLoader.kt | 8 +++ .../drawable/ic_open_in_new_black_16px.xml | 9 +++ .../layout/view_donation_reminder_card.xml | 48 ++++++++++++++++ app/src/main/res/values/preference_keys.xml | 1 + .../main/res/xml/developer_preferences.xml | 4 ++ 9 files changed, 151 insertions(+), 19 deletions(-) create mode 100644 app/src/main/res/drawable/ic_open_in_new_black_16px.xml diff --git a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderCardView.kt b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderCardView.kt index cffbdd40f54..9c1b3595c7b 100644 --- a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderCardView.kt +++ b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderCardView.kt @@ -3,8 +3,13 @@ package org.wikipedia.donate.donationreminder import android.content.Context import android.util.AttributeSet import android.view.LayoutInflater +import androidx.core.net.toUri +import androidx.core.view.isVisible +import org.wikipedia.R import org.wikipedia.databinding.ViewDonationReminderCardBinding import org.wikipedia.util.DimenUtil +import org.wikipedia.util.StringUtil +import org.wikipedia.util.UriUtil import org.wikipedia.views.WikiCardView class DonationReminderCardView(context: Context, attrs: AttributeSet? = null) : WikiCardView(context, attrs) { @@ -21,7 +26,7 @@ class DonationReminderCardView(context: Context, attrs: AttributeSet? = null) : } fun setMessage(text: String) { - binding.messageTextView.text = text + binding.messageTextView.text = StringUtil.fromHtml(text) } fun setPositiveButton(text: String, listener: OnClickListener) { @@ -33,4 +38,11 @@ class DonationReminderCardView(context: Context, attrs: AttributeSet? = null) : binding.negativeButton.text = text binding.negativeButton.setOnClickListener(listener) } + + fun showWrapUpContainer() { + binding.wrapUpContainer.isVisible = true + binding.learnMoreButton.setOnClickListener { + UriUtil.visitInExternalBrowser(context, context.getString(R.string.donation_reminders_experiment_url).toUri()) + } + } } diff --git a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt index 23f15881fc5..3b6440bea8c 100644 --- a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt +++ b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt @@ -22,7 +22,9 @@ object DonationReminderHelper { private val enabledCountries = listOf( "NL" ) - private val isInDateRange get() = LocalDate.now() <= LocalDate.of(2026, 11, 9) // TODO: confirm with PM + private val isInDateRange get() = LocalDate.now() <= LocalDate.of(2026, 11, 9) + private val isInWrapUpDateRange get() = LocalDate.now() <= LocalDate.of(2026, 11, 15) + && LocalDate.now() >= LocalDate.of(2026, 11, 10) val isInEligibleCountry get() = ReleaseUtil.isDevRelease || enabledCountries.contains(GeoUtil.geoIPCountry.orEmpty()) val defaultReadFrequencyOptions = listOf(5, 10, 20) val presetsToRemoveFromConfig = listOf(2f, 10f, 15f) // V3 only. @@ -30,18 +32,20 @@ object DonationReminderHelper { val isEnabled get() = (ReleaseUtil.isDevRelease || isInEligibleCountry && isInDateRange) && isTestGroupUser + val isWrapUpEnabled + get() = (ReleaseUtil.isDevRelease && Prefs.donationReminderDevWrapUp || isInEligibleCountry && isInWrapUpDateRange) && isTestGroupUser && Prefs.donationReminderConfig.wrapUpEnabled val hasActiveReminder get() = Prefs.donationReminderConfig.userEnabled && Prefs.donationReminderConfig.isReminderReady && isInEligibleCountry var shouldShowSettingSnackbar = false fun getCampaignId(campaignIdOriginal: String = "appmenu"): String { - return if (isInEligibleCountry && isInDateRange) { + return if (isInEligibleCountry && isWrapUpEnabled) { campaignIdOriginal + when (DonationReminderAbTest().group) { GROUP_3 -> "_reminderC" GROUP_2 -> "_reminderB" else -> "_reminderA" - } // TODO: confirm with Shay + } } else { campaignIdOriginal } @@ -114,9 +118,15 @@ object DonationReminderHelper { fun dismissReminder() { val config = Prefs.donationReminderConfig - Prefs.donationReminderConfig = config.copy( - isReminderReady = false - ) + if (isWrapUpEnabled) { + Prefs.donationReminderConfig = config.copy( + wrapUpEnabled = false + ) + } else { + Prefs.donationReminderConfig = config.copy( + isReminderReady = false + ) + } } } @@ -130,7 +140,8 @@ data class DonationReminderConfig( val donateAmount: Float = 0f, val isReminderReady: Boolean = false, val timesReminderShown: Int = 0, - val goalReachedCount: Int = 0 + val goalReachedCount: Int = 0, + val wrapUpEnabled: Boolean = true ) { val isSetup: Boolean get() = userEnabled && setupTimestamp != 0L && articleFrequency > 0 diff --git a/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt b/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt index 1350f06cd7b..b908238cf59 100644 --- a/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt +++ b/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt @@ -12,6 +12,7 @@ import org.wikipedia.R import org.wikipedia.analytics.eventplatform.DonorExperienceEvent import org.wikipedia.databinding.ViewPageHeaderBinding import org.wikipedia.donate.DonateUtil +import org.wikipedia.donate.donationreminder.DonationReminderAbTest import org.wikipedia.donate.donationreminder.DonationReminderConfig import org.wikipedia.donate.donationreminder.DonationReminderHelper import org.wikipedia.settings.Prefs @@ -139,20 +140,52 @@ class PageHeaderView(context: Context, attrs: AttributeSet? = null) : LinearLayo private fun updateDonationReminderCardContent(config: DonationReminderConfig?) { config?.let { config -> + val isWrapUpEnabled = DonationReminderHelper.isWrapUpEnabled val articleText = context.resources.getQuantityString( R.plurals.donation_reminders_text_articles, config.articleFrequency, config.articleFrequency ) val donationAmount = DonateUtil.currencyFormat.format(Prefs.donationReminderConfig.donateAmount) - val titleText = if (config.goalReachedCount == 1) { - context.getString(R.string.donation_reminders_first_milestone_reached_prompt_title, articleText, donationAmount) + val titleText = if (isWrapUpEnabled) { + if (DonationReminderAbTest().group == 1) { + context.getString(R.string.donation_reminders_wrap_up_title) + } else { + context.getString(R.string.donation_reminders_eoe_title) + } } else { - context.getString(R.string.donation_reminders_subsequent_milestone_reached_prompt_title, articleText) + if (config.goalReachedCount == 1) { + context.getString(R.string.donation_reminders_first_milestone_reached_prompt_title, articleText, donationAmount) + } else { + context.getString(R.string.donation_reminders_subsequent_milestone_reached_prompt_title, articleText) + } } val dateText = DateUtil.getMMMMdYYYY(Date(config.setupTimestamp)) - val messageText = context.getString(R.string.donation_reminders_prompt_message_v2, dateText, articleText, donationAmount) - val positiveButtonText = context.getString(R.string.donation_reminders_prompt_positive_button_v2) - val negativeButtonText = context.getString(R.string.donation_reminders_prompt_negative_button) + val messageText = if (isWrapUpEnabled) { + if (DonationReminderAbTest().group == 1) { + context.getString(R.string.donation_reminders_wrap_up_message) + } else { + context.getString(R.string.donation_reminders_eoe_message, donationAmount) + } + } else { + context.getString(R.string.donation_reminders_prompt_message_v2, dateText, articleText, donationAmount) + } + val positiveButtonText = if (isWrapUpEnabled) { + if (DonationReminderAbTest().group == 1) { + context.getString(R.string.donation_reminders_wrap_up_share_feedback_button) + } else { + context.getString(R.string.donation_reminders_eoe_give_monthly_button) + } + } else { + context.getString(R.string.donation_reminders_prompt_positive_button_v2) + } + val negativeButtonText = if (isWrapUpEnabled) { + context.getString(R.string.donation_reminders_settings_no_thanks_btn_label) + } else { + context.getString(R.string.donation_reminders_prompt_negative_button) + } + if (isWrapUpEnabled) { + binding.donationReminderCardView.showWrapUpContainer() + } binding.donationReminderCardView.setTitle(titleText) binding.donationReminderCardView.setMessage(messageText) binding.donationReminderCardView.setPositiveButton(positiveButtonText) { @@ -168,11 +201,13 @@ class PageHeaderView(context: Context, attrs: AttributeSet? = null) : LinearLayo } fun maybeShowDonationReminderCard() { - if (DonationReminderHelper.shouldShowReminderNow()) { - DonorExperienceEvent.logDonationReminderAction( - activeInterface = "reminder_milestone", - action = "impression" - ) + if (DonationReminderHelper.shouldShowReminderNow() || DonationReminderHelper.isWrapUpEnabled) { + if (!DonationReminderHelper.isWrapUpEnabled) { + DonorExperienceEvent.logDonationReminderAction( + activeInterface = "reminder_milestone", + action = "impression" + ) + } updateDonationReminderCardContent(Prefs.donationReminderConfig) binding.donationReminderCardView.isVisible = true } else { diff --git a/app/src/main/java/org/wikipedia/settings/Prefs.kt b/app/src/main/java/org/wikipedia/settings/Prefs.kt index b570937b702..687f9fe5974 100644 --- a/app/src/main/java/org/wikipedia/settings/Prefs.kt +++ b/app/src/main/java/org/wikipedia/settings/Prefs.kt @@ -908,6 +908,10 @@ object Prefs { ) ?: DonationReminderConfig() set(types) = PrefsIoUtil.setString(R.string.preference_key_donation_reminder_config, JsonUtil.encodeToString(types)) + var donationReminderDevWrapUp + get() = PrefsIoUtil.getBoolean(R.string.preference_key_donation_reminders_dev_wrap_up_enabled, false) + set(value) = PrefsIoUtil.setBoolean(R.string.preference_key_donation_reminders_dev_wrap_up_enabled, value) + var activityTabModules: ActivityTabModules get() = JsonUtil.decodeFromString(PrefsIoUtil.getString(R.string.preference_key_activity_tab_modules, null)) ?: ActivityTabModules() diff --git a/app/src/main/java/org/wikipedia/settings/dev/DeveloperSettingsPreferenceLoader.kt b/app/src/main/java/org/wikipedia/settings/dev/DeveloperSettingsPreferenceLoader.kt index f94c5232b1b..da3d0523cf5 100644 --- a/app/src/main/java/org/wikipedia/settings/dev/DeveloperSettingsPreferenceLoader.kt +++ b/app/src/main/java/org/wikipedia/settings/dev/DeveloperSettingsPreferenceLoader.kt @@ -244,6 +244,7 @@ internal class DeveloperSettingsPreferenceLoader(fragment: PreferenceFragmentCom } findPreference(R.string.preference_key_donation_reminders_dev_reset).onPreferenceClickListener = Preference.OnPreferenceClickListener { Prefs.donationReminderConfig = DonationReminderConfig() + Prefs.donationReminderDevWrapUp = false Toast.makeText(activity, "donationReminderConfig has been reset", Toast.LENGTH_SHORT).show() fragment.requireActivity().finish() true @@ -256,6 +257,13 @@ internal class DeveloperSettingsPreferenceLoader(fragment: PreferenceFragmentCom fragment.requireActivity().finish() true } + findPreference(R.string.preference_key_donation_reminders_dev_wrap_up_enabled).onPreferenceClickListener = Preference.OnPreferenceClickListener { + Prefs.donationReminderConfig = Prefs.donationReminderConfig.copy( + wrapUpEnabled = true + ) + fragment.requireActivity().finish() + true + } (findPreference(R.string.preference_key_yir_survey_state) as ListPreference).apply { val states = YearInReviewSurveyState.entries val names = states.map { it.name }.toTypedArray() diff --git a/app/src/main/res/drawable/ic_open_in_new_black_16px.xml b/app/src/main/res/drawable/ic_open_in_new_black_16px.xml new file mode 100644 index 00000000000..2348d071c6c --- /dev/null +++ b/app/src/main/res/drawable/ic_open_in_new_black_16px.xml @@ -0,0 +1,9 @@ + + + \ No newline at end of file diff --git a/app/src/main/res/layout/view_donation_reminder_card.xml b/app/src/main/res/layout/view_donation_reminder_card.xml index c3898bf0b19..f2060540aff 100644 --- a/app/src/main/res/layout/view_donation_reminder_card.xml +++ b/app/src/main/res/layout/view_donation_reminder_card.xml @@ -12,6 +12,54 @@ android:orientation="vertical" android:background="?attr/background_color"> + + + + + + + + + + donationReminder donationReminderDevReset donationReminderDevResetSeenDate + donationReminderDevWrapUpEnabled donations activityTabModules activityTabOnboardingShown diff --git a/app/src/main/res/xml/developer_preferences.xml b/app/src/main/res/xml/developer_preferences.xml index 583559530cf..35477b8bafb 100644 --- a/app/src/main/res/xml/developer_preferences.xml +++ b/app/src/main/res/xml/developer_preferences.xml @@ -531,6 +531,10 @@ android:key="@string/preference_key_donation_reminders_dev_reset_seen_date" android:title="Remove the last prompt seen date." /> + + Date: Mon, 31 Aug 2026 16:44:43 -0700 Subject: [PATCH 02/15] Survey dialog --- .../java/org/wikipedia/views/SurveyDialog.kt | 51 +++++++++++++++++++ app/src/main/res/values-qq/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 3 files changed, 53 insertions(+) diff --git a/app/src/main/java/org/wikipedia/views/SurveyDialog.kt b/app/src/main/java/org/wikipedia/views/SurveyDialog.kt index 4fa40b803e5..601ba63690c 100644 --- a/app/src/main/java/org/wikipedia/views/SurveyDialog.kt +++ b/app/src/main/java/org/wikipedia/views/SurveyDialog.kt @@ -66,6 +66,57 @@ object SurveyDialog { dialog = dialogBuilder.show() } + fun showDonationReminderFeedbackDialog( + activity: Activity, + onImpression: () -> Unit, + onCancel: () -> Unit, + onSubmit: (feedbackOption: Int?, feedbackText: String) -> Unit + ) { + val maxCharacter = 250 + var dialog: AlertDialog? = null + val binding = DialogFeedbackOptionsBinding.inflate(activity.layoutInflater) + binding.titleText.text = activity.getString(R.string.donation_reminders_wrap_up_survey_title) + binding.messageText.text = activity.getString(R.string.donation_reminders_wrap_up_survey_message) + binding.optionVerySatisfied.isVisible = true + binding.optionVeryUnsatisfied.isVisible = true + binding.optionSatisfied.text = activity.getString(R.string.donation_reminders_wrap_up_survey_option_keep_it) + binding.optionNeutral.text = activity.getString(R.string.donation_reminders_wrap_up_survey_option_remove_it) + binding.optionUnsatisfied.text = activity.getString(R.string.donation_reminders_wrap_up_survey_option_not_sure) + binding.feedbackInputContainer.isVisible = true + binding.feedbackInputContainer.isCounterEnabled = true + binding.feedbackInputContainer.counterMaxLength = maxCharacter + binding.feedbackInputContainer.hint = activity.getString(R.string.donation_reminders_wrap_up_survey_optional_hint) + binding.feedbackInput.filters = arrayOf(InputFilter.LengthFilter(maxCharacter)) + binding.feedbackInput.setOnFocusChangeListener { _, hasFocus -> + if (hasFocus) { + binding.dialogContainer.postDelayed({ + if (!activity.isDestroyed) { + binding.dialogContainer.fullScroll(ScrollView.FOCUS_DOWN) + } + }, 200) + } + } + + binding.cancelButton.setOnClickListener { + onCancel() + dialog?.dismiss() + } + binding.submitButton.setOnClickListener { + val feedbackOption = getSelectedOption(binding) + val feedbackText = binding.feedbackInput.text.toString() + onSubmit(feedbackOption, feedbackText) + FeedbackUtil.showMessage(activity, R.string.donation_reminders_wrap_up_survey_thank_you_message) + dialog?.dismiss() + } + + val dialogBuilder = MaterialAlertDialogBuilder(activity, R.style.AlertDialogTheme_AdjustResize) + .setCancelable(false) + .setView(binding.root) + + onImpression() + dialog = dialogBuilder.show() + } + private fun getSelectedOption(binding: DialogFeedbackOptionsBinding): Int? { val selectedId = binding.feedbackRadioGroup.checkedRadioButtonId return when (selectedId) { diff --git a/app/src/main/res/values-qq/strings.xml b/app/src/main/res/values-qq/strings.xml index 3e7b38f7395..1dae43e6fa5 100644 --- a/app/src/main/res/values-qq/strings.xml +++ b/app/src/main/res/values-qq/strings.xml @@ -2151,6 +2151,7 @@ Label for the option to remove the donation reminder. Label for the option indicating uncertainty about the donation reminder. Hint text indicating that users can provide optional feedback. + Snackbar message that indicates the feedback has been submitted. Title shown at the end of the experiment for the donation reminder. Message shown at the end of the experiment for the donation reminder. %s is replaced by the pledged amount. Label for the button that allows the user to give monthly. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 762bb4b5ae2..9122e7c9844 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -2395,6 +2395,7 @@ Remove it Not sure Anything else? (Optional) + Thank you for your feedback. Your answer helps us decide what to build next. This is the end of the experiment We will no longer show in-app reminders but you can still support by donating your pledged amount %s monthly. Give monthly From 5201dfd18ce069f14c5ea5b39107b62a23caa304 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Mon, 31 Aug 2026 17:23:38 -0700 Subject: [PATCH 03/15] Update survey dialog and donation flow --- .../org/wikipedia/donate/GooglePayActivity.kt | 9 ++- .../wikipedia/donate/GooglePayComponent.kt | 4 +- .../wikipedia/donate/GooglePayViewModel.kt | 1 + .../java/org/wikipedia/donate/DonateDialog.kt | 42 ++++++++++--- .../page/leadimages/LeadImagesHandler.kt | 60 +++++++++++++------ .../page/leadimages/PageHeaderView.kt | 13 ++-- .../java/org/wikipedia/views/SurveyDialog.kt | 2 - 7 files changed, 97 insertions(+), 34 deletions(-) diff --git a/app/src/extra/java/org/wikipedia/donate/GooglePayActivity.kt b/app/src/extra/java/org/wikipedia/donate/GooglePayActivity.kt index cf38dd1aa5b..ca4150456d9 100644 --- a/app/src/extra/java/org/wikipedia/donate/GooglePayActivity.kt +++ b/app/src/extra/java/org/wikipedia/donate/GooglePayActivity.kt @@ -278,6 +278,7 @@ class GooglePayActivity : BaseActivity() { } binding.amountPresetsFlow.referencedIds = viewIds.toIntArray() setFilledAmountToText() + setCheckRecurringDonation() setButtonHighlighted(filledAmountButton) } @@ -287,6 +288,10 @@ class GooglePayActivity : BaseActivity() { } } + private fun setCheckRecurringDonation() { + binding.checkBoxRecurring.isChecked = viewModel.checkedRecurringDonation + } + private fun setButtonHighlighted(button: View? = null) { binding.amountPresetsContainer.children.forEach { child -> if (child is MaterialButton) { @@ -315,12 +320,14 @@ class GooglePayActivity : BaseActivity() { companion object { private const val CAMPAIGN_ID_APP_MENU = "appmenu" const val FILLED_AMOUNT = "filledAmount" + const val CHECKED_RECURRING_DONATION = "checkedRecurringDonation" - fun newIntent(context: Context, campaignId: String? = null, donateUrl: String? = null, filledAmount: Float = 0f): Intent { + fun newIntent(context: Context, campaignId: String? = null, donateUrl: String? = null, filledAmount: Float = 0f, checkedRecurringDonation: Boolean = false): Intent { return Intent(context, GooglePayActivity::class.java) .putExtra(DonateDialog.ARG_CAMPAIGN_ID, campaignId) .putExtra(DonateDialog.ARG_DONATE_URL, donateUrl) .putExtra(FILLED_AMOUNT, filledAmount) + .putExtra(CHECKED_RECURRING_DONATION, checkedRecurringDonation) } } } diff --git a/app/src/extra/java/org/wikipedia/donate/GooglePayComponent.kt b/app/src/extra/java/org/wikipedia/donate/GooglePayComponent.kt index 8a2229da2b3..75ec9741cde 100644 --- a/app/src/extra/java/org/wikipedia/donate/GooglePayComponent.kt +++ b/app/src/extra/java/org/wikipedia/donate/GooglePayComponent.kt @@ -78,8 +78,8 @@ internal object GooglePayComponent { return available } - fun getDonateActivityIntent(activity: Activity, campaignId: String? = null, donateUrl: String? = null, filledAmount: Float = 0f): Intent { - return GooglePayActivity.newIntent(activity, campaignId, donateUrl, filledAmount) + fun getDonateActivityIntent(activity: Activity, campaignId: String? = null, donateUrl: String? = null, filledAmount: Float = 0f, checkedRecurringDonation: Boolean = false): Intent { + return GooglePayActivity.newIntent(activity, campaignId, donateUrl, filledAmount, checkedRecurringDonation) } fun getPaymentDataRequestJson( diff --git a/app/src/extra/java/org/wikipedia/donate/GooglePayViewModel.kt b/app/src/extra/java/org/wikipedia/donate/GooglePayViewModel.kt index 07927a8065f..34d3b067c3d 100644 --- a/app/src/extra/java/org/wikipedia/donate/GooglePayViewModel.kt +++ b/app/src/extra/java/org/wikipedia/donate/GooglePayViewModel.kt @@ -32,6 +32,7 @@ import kotlin.math.abs class GooglePayViewModel(savedStateHandle: SavedStateHandle) : ViewModel() { val filledAmount = savedStateHandle.get(GooglePayActivity.FILLED_AMOUNT) ?: 0f + val checkedRecurringDonation = savedStateHandle.get(GooglePayActivity.CHECKED_RECURRING_DONATION) ?: false val uiState = MutableStateFlow(Resource()) private var donationConfig: DonationConfig? = null diff --git a/app/src/main/java/org/wikipedia/donate/DonateDialog.kt b/app/src/main/java/org/wikipedia/donate/DonateDialog.kt index 08b4f525fc7..87c84f14376 100644 --- a/app/src/main/java/org/wikipedia/donate/DonateDialog.kt +++ b/app/src/main/java/org/wikipedia/donate/DonateDialog.kt @@ -22,6 +22,7 @@ import org.wikipedia.donate.donationreminder.DonationReminderHelper import org.wikipedia.page.ExtendedBottomSheetDialogFragment import org.wikipedia.settings.Prefs import org.wikipedia.util.CustomTabsUtil +import org.wikipedia.util.DimenUtil import org.wikipedia.util.FeedbackUtil import org.wikipedia.util.Resource @@ -87,7 +88,7 @@ class DonateDialog : ExtendedBottomSheetDialogFragment() { } } if (arguments?.getBoolean(ARG_FROM_DONATION_REMINDER) == true) { - setupDirectGooglePayButton() + setupDirectGooglePayButton(arguments?.getBoolean(ARG_FROM_DONATION_REMINDER) ?: false) } } } @@ -114,10 +115,14 @@ class DonateDialog : ExtendedBottomSheetDialogFragment() { } } - private fun setupDirectGooglePayButton() { - val donateAmount = Prefs.donationReminderConfig.donateAmount + private fun setupDirectGooglePayButton(fromDonationReminderWrapUp: Boolean) { + val donateAmount = if (Prefs.donationReminderConfig.donateAmount <= 0) { + DonationReminderHelper.defaultDonateAmountOptions.first() + } else { + Prefs.donationReminderConfig.donateAmount + } val donateAmountText = - DonateUtil.currencyFormat.format(Prefs.donationReminderConfig.donateAmount) + DonateUtil.currencyFormat.format(donateAmount) val donateButtonText = getString(R.string.donation_reminders_gpay_text, donateAmountText) binding.donateGooglePayButton.text = donateButtonText binding.donateGooglePayButton.setOnClickListener { @@ -127,7 +132,13 @@ class DonateDialog : ExtendedBottomSheetDialogFragment() { campaignId = DonationReminderHelper.getCampaignId() ) (requireActivity() as? BaseActivity)?.launchDonateActivity( - GooglePayComponent.getDonateActivityIntent(requireActivity(), filledAmount = donateAmount, campaignId = DonationReminderHelper.getCampaignId())) + GooglePayComponent.getDonateActivityIntent( + activity = requireActivity(), + filledAmount = donateAmount, + checkedRecurringDonation = fromDonationReminderWrapUp, + campaignId = DonationReminderHelper.getCampaignId() + ) + ) } binding.donateGooglePayDifferentAmountButton.isVisible = true binding.donateGooglePayDifferentAmountButton.setOnClickListener { @@ -147,21 +158,38 @@ class DonateDialog : ExtendedBottomSheetDialogFragment() { ) onDonateClicked() } - binding.gPayHeaderContainer.isVisible = false + if (fromDonationReminderWrapUp) { + binding.gPayTitle.text = getString(R.string.donation_reminders_eoe_donate_dialog_title) + (binding.gPayTitle.layoutParams as? ViewGroup.MarginLayoutParams)?.let { params -> + params.bottomMargin = DimenUtil.roundedDpToPx(16.0f) + binding.gPayTitle.layoutParams = params + } + binding.gPayDescription.isVisible = false + } else { + binding.gPayHeaderContainer.isVisible = false + } } companion object { const val ARG_CAMPAIGN_ID = "campaignId" const val ARG_DONATE_URL = "donateUrl" const val ARG_FROM_DONATION_REMINDER = "fromDonationReminder" + const val ARG_FROM_DONATION_REMINDER_WRAP_UP = "fromDonationReminderWrapUp" const val ARG_FROM_YIR = "fromYiR" - fun newInstance(campaignId: String? = null, donateUrl: String? = null, fromDonationReminder: Boolean = false, fromYiR: Boolean = false): DonateDialog { + fun newInstance( + campaignId: String? = null, + donateUrl: String? = null, + fromDonationReminder: Boolean = false, + fromYiR: Boolean = false, + fromDonationReminderWrapUp: Boolean = false + ): DonateDialog { return DonateDialog().apply { arguments = Bundle().apply { putString(ARG_CAMPAIGN_ID, campaignId) putString(ARG_DONATE_URL, donateUrl) putBoolean(ARG_FROM_DONATION_REMINDER, fromDonationReminder) + putBoolean(ARG_FROM_DONATION_REMINDER_WRAP_UP, fromDonationReminderWrapUp) putBoolean(ARG_FROM_YIR, fromYiR) } } diff --git a/app/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.kt b/app/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.kt index bbaf963da2d..52e68771b62 100644 --- a/app/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.kt +++ b/app/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.kt @@ -23,6 +23,7 @@ import org.wikipedia.dataclient.WikiSite import org.wikipedia.dataclient.mwapi.MwQueryPage import org.wikipedia.descriptions.DescriptionEditActivity import org.wikipedia.donate.DonateDialog +import org.wikipedia.donate.donationreminder.DonationReminderAbTest import org.wikipedia.donate.donationreminder.DonationReminderActivity import org.wikipedia.donate.donationreminder.DonationReminderHelper import org.wikipedia.gallery.GalleryActivity @@ -36,6 +37,7 @@ import org.wikipedia.util.FeedbackUtil import org.wikipedia.util.StringUtil import org.wikipedia.util.log.L import org.wikipedia.views.ObservableWebView +import org.wikipedia.views.SurveyDialog class LeadImagesHandler(private val parentFragment: PageFragment, webView: ObservableWebView, @@ -208,28 +210,50 @@ class LeadImagesHandler(private val parentFragment: PageFragment, override fun donationReminderCardPositiveClicked() { hideDonationReminderCard() - DonorExperienceEvent.logDonationReminderAction( - activeInterface = "reminder_milestone", - action = "donate_start_click", - campaignId = DonationReminderHelper.getCampaignId() - ) - ExclusiveBottomSheetPresenter.show(parentFragment.parentFragmentManager, DonateDialog.newInstance(fromDonationReminder = true)) + if (DonationReminderHelper.isWrapUpEnabled) { + if (DonationReminderAbTest().group == 1) { + SurveyDialog.showDonationReminderFeedbackDialog( + activity = parentFragment.requireActivity(), + onImpression = { + // TODO: instrumentation + }, + onCancel = { + // TODO: instrumentation + }, + onSubmit = { feedbackOption, feedbackText -> + // TODO: instrumentation + } + ) + } else { + ExclusiveBottomSheetPresenter.show(parentFragment.parentFragmentManager, DonateDialog.newInstance(fromDonationReminder = true, fromDonationReminderWrapUp = true)) + } + } else { + DonorExperienceEvent.logDonationReminderAction( + activeInterface = "reminder_milestone", + action = "donate_start_click", + campaignId = DonationReminderHelper.getCampaignId() + ) + ExclusiveBottomSheetPresenter.show(parentFragment.parentFragmentManager, DonateDialog.newInstance(fromDonationReminder = true)) + } } override fun donationReminderCardNegativeClicked() { hideDonationReminderCard() - DonorExperienceEvent.logDonationReminderAction( - activeInterface = "reminder_milestone", - action = "notnow_click" - ) - FeedbackUtil.makeSnackbar(activity, activity.getString(R.string.donation_reminders_prompt_dismiss_snackbar)) - .setAction(R.string.donation_reminders_snackbar_modify_button_label) { - DonorExperienceEvent.logDonationReminderAction( - activeInterface = "reminder_milestone", - action = "setting_click" - ) - activity.startActivity(DonationReminderActivity.newIntent(activity, isFromSettings = true)) - }.show() + if (DonationReminderHelper.isWrapUpEnabled) { + // TODO: instrumentation + } else { + DonorExperienceEvent.logDonationReminderAction( + activeInterface = "reminder_milestone", + action = "notnow_click" + ) + FeedbackUtil.makeSnackbar(activity, activity.getString(R.string.donation_reminders_prompt_dismiss_snackbar)) + .setAction(R.string.donation_reminders_snackbar_modify_button_label) { + DonorExperienceEvent.logDonationReminderAction(activeInterface = "reminder_milestone", + action = "setting_click" + ) + activity.startActivity(DonationReminderActivity.newIntent(activity, isFromSettings = true)) + }.show() + } } } } diff --git a/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt b/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt index b908238cf59..d69af7a41fb 100644 --- a/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt +++ b/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt @@ -144,7 +144,12 @@ class PageHeaderView(context: Context, attrs: AttributeSet? = null) : LinearLayo val articleText = context.resources.getQuantityString( R.plurals.donation_reminders_text_articles, config.articleFrequency, config.articleFrequency ) - val donationAmount = DonateUtil.currencyFormat.format(Prefs.donationReminderConfig.donateAmount) + val donateAmount = if (Prefs.donationReminderConfig.donateAmount <= 0) { + DonationReminderHelper.defaultDonateAmountOptions.first() + } else { + Prefs.donationReminderConfig.donateAmount + } + val donationAmountText = DonateUtil.currencyFormat.format(donateAmount) val titleText = if (isWrapUpEnabled) { if (DonationReminderAbTest().group == 1) { context.getString(R.string.donation_reminders_wrap_up_title) @@ -153,7 +158,7 @@ class PageHeaderView(context: Context, attrs: AttributeSet? = null) : LinearLayo } } else { if (config.goalReachedCount == 1) { - context.getString(R.string.donation_reminders_first_milestone_reached_prompt_title, articleText, donationAmount) + context.getString(R.string.donation_reminders_first_milestone_reached_prompt_title, articleText, donationAmountText) } else { context.getString(R.string.donation_reminders_subsequent_milestone_reached_prompt_title, articleText) } @@ -164,10 +169,10 @@ class PageHeaderView(context: Context, attrs: AttributeSet? = null) : LinearLayo if (DonationReminderAbTest().group == 1) { context.getString(R.string.donation_reminders_wrap_up_message) } else { - context.getString(R.string.donation_reminders_eoe_message, donationAmount) + context.getString(R.string.donation_reminders_eoe_message, donationAmountText) } } else { - context.getString(R.string.donation_reminders_prompt_message_v2, dateText, articleText, donationAmount) + context.getString(R.string.donation_reminders_prompt_message_v2, dateText, articleText, donationAmountText) } val positiveButtonText = if (isWrapUpEnabled) { if (DonationReminderAbTest().group == 1) { diff --git a/app/src/main/java/org/wikipedia/views/SurveyDialog.kt b/app/src/main/java/org/wikipedia/views/SurveyDialog.kt index 601ba63690c..fd833352128 100644 --- a/app/src/main/java/org/wikipedia/views/SurveyDialog.kt +++ b/app/src/main/java/org/wikipedia/views/SurveyDialog.kt @@ -77,8 +77,6 @@ object SurveyDialog { val binding = DialogFeedbackOptionsBinding.inflate(activity.layoutInflater) binding.titleText.text = activity.getString(R.string.donation_reminders_wrap_up_survey_title) binding.messageText.text = activity.getString(R.string.donation_reminders_wrap_up_survey_message) - binding.optionVerySatisfied.isVisible = true - binding.optionVeryUnsatisfied.isVisible = true binding.optionSatisfied.text = activity.getString(R.string.donation_reminders_wrap_up_survey_option_keep_it) binding.optionNeutral.text = activity.getString(R.string.donation_reminders_wrap_up_survey_option_remove_it) binding.optionUnsatisfied.text = activity.getString(R.string.donation_reminders_wrap_up_survey_option_not_sure) From 1884350b14e1c27f5812705b1dc687d82bac0d99 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Mon, 31 Aug 2026 17:24:27 -0700 Subject: [PATCH 04/15] Lint --- .../donate/donationreminder/DonationReminderHelper.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt index 3b6440bea8c..c9e839137b3 100644 --- a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt +++ b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt @@ -23,8 +23,8 @@ object DonationReminderHelper { "NL" ) private val isInDateRange get() = LocalDate.now() <= LocalDate.of(2026, 11, 9) - private val isInWrapUpDateRange get() = LocalDate.now() <= LocalDate.of(2026, 11, 15) - && LocalDate.now() >= LocalDate.of(2026, 11, 10) + private val isInWrapUpDateRange get() = LocalDate.now() <= LocalDate.of(2026, 11, 15) && + LocalDate.now() >= LocalDate.of(2026, 11, 10) val isInEligibleCountry get() = ReleaseUtil.isDevRelease || enabledCountries.contains(GeoUtil.geoIPCountry.orEmpty()) val defaultReadFrequencyOptions = listOf(5, 10, 20) val presetsToRemoveFromConfig = listOf(2f, 10f, 15f) // V3 only. From b0e4f010d048252817073574206fec4a9bba4f33 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Mon, 31 Aug 2026 17:26:17 -0700 Subject: [PATCH 05/15] Naming --- app/src/extra/java/org/wikipedia/donate/GooglePayActivity.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/extra/java/org/wikipedia/donate/GooglePayActivity.kt b/app/src/extra/java/org/wikipedia/donate/GooglePayActivity.kt index ca4150456d9..055ee2b5871 100644 --- a/app/src/extra/java/org/wikipedia/donate/GooglePayActivity.kt +++ b/app/src/extra/java/org/wikipedia/donate/GooglePayActivity.kt @@ -278,7 +278,7 @@ class GooglePayActivity : BaseActivity() { } binding.amountPresetsFlow.referencedIds = viewIds.toIntArray() setFilledAmountToText() - setCheckRecurringDonation() + setCheckedRecurringDonation() setButtonHighlighted(filledAmountButton) } @@ -288,7 +288,7 @@ class GooglePayActivity : BaseActivity() { } } - private fun setCheckRecurringDonation() { + private fun setCheckedRecurringDonation() { binding.checkBoxRecurring.isChecked = viewModel.checkedRecurringDonation } From 152eaaa22f0622daba00c7aa7ec4f8471db85084 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Mon, 31 Aug 2026 21:29:31 -0700 Subject: [PATCH 06/15] Fix logic --- app/src/main/java/org/wikipedia/donate/DonateDialog.kt | 2 +- .../donationreminder/DonationReminderCardView.kt | 4 ++++ .../donate/donationreminder/DonationReminderHelper.kt | 3 ++- .../org/wikipedia/page/leadimages/LeadImagesHandler.kt | 9 +++++---- .../org/wikipedia/page/leadimages/PageHeaderView.kt | 10 ++++++---- 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/wikipedia/donate/DonateDialog.kt b/app/src/main/java/org/wikipedia/donate/DonateDialog.kt index 87c84f14376..4b0c3de5985 100644 --- a/app/src/main/java/org/wikipedia/donate/DonateDialog.kt +++ b/app/src/main/java/org/wikipedia/donate/DonateDialog.kt @@ -88,7 +88,7 @@ class DonateDialog : ExtendedBottomSheetDialogFragment() { } } if (arguments?.getBoolean(ARG_FROM_DONATION_REMINDER) == true) { - setupDirectGooglePayButton(arguments?.getBoolean(ARG_FROM_DONATION_REMINDER) ?: false) + setupDirectGooglePayButton(arguments?.getBoolean(ARG_FROM_DONATION_REMINDER_WRAP_UP) ?: false) } } } diff --git a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderCardView.kt b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderCardView.kt index 9c1b3595c7b..b6a5e13c465 100644 --- a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderCardView.kt +++ b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderCardView.kt @@ -46,3 +46,7 @@ class DonationReminderCardView(context: Context, attrs: AttributeSet? = null) : } } } + +enum class DonationReminderType { + GENERAL, WRAP_UP +} diff --git a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt index c9e839137b3..a374c411241 100644 --- a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt +++ b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt @@ -33,7 +33,8 @@ object DonationReminderHelper { val isEnabled get() = (ReleaseUtil.isDevRelease || isInEligibleCountry && isInDateRange) && isTestGroupUser val isWrapUpEnabled - get() = (ReleaseUtil.isDevRelease && Prefs.donationReminderDevWrapUp || isInEligibleCountry && isInWrapUpDateRange) && isTestGroupUser && Prefs.donationReminderConfig.wrapUpEnabled + get() = (ReleaseUtil.isDevRelease && Prefs.donationReminderDevWrapUp || isInEligibleCountry && isInWrapUpDateRange) && isTestGroupUser && + (Prefs.donationReminderConfig.wrapUpEnabled || ReleaseUtil.isDevRelease && Prefs.donationReminderDevWrapUp) val hasActiveReminder get() = Prefs.donationReminderConfig.userEnabled && Prefs.donationReminderConfig.isReminderReady && isInEligibleCountry diff --git a/app/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.kt b/app/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.kt index 52e68771b62..8b8c74f9555 100644 --- a/app/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.kt +++ b/app/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.kt @@ -26,6 +26,7 @@ import org.wikipedia.donate.DonateDialog import org.wikipedia.donate.donationreminder.DonationReminderAbTest import org.wikipedia.donate.donationreminder.DonationReminderActivity import org.wikipedia.donate.donationreminder.DonationReminderHelper +import org.wikipedia.donate.donationreminder.DonationReminderType import org.wikipedia.gallery.GalleryActivity import org.wikipedia.page.ExclusiveBottomSheetPresenter import org.wikipedia.page.PageFragment @@ -208,9 +209,9 @@ class LeadImagesHandler(private val parentFragment: PageFragment, } } - override fun donationReminderCardPositiveClicked() { + override fun donationReminderCardPositiveClicked(type: DonationReminderType) { hideDonationReminderCard() - if (DonationReminderHelper.isWrapUpEnabled) { + if (type == DonationReminderType.WRAP_UP) { if (DonationReminderAbTest().group == 1) { SurveyDialog.showDonationReminderFeedbackDialog( activity = parentFragment.requireActivity(), @@ -237,9 +238,9 @@ class LeadImagesHandler(private val parentFragment: PageFragment, } } - override fun donationReminderCardNegativeClicked() { + override fun donationReminderCardNegativeClicked(type: DonationReminderType) { hideDonationReminderCard() - if (DonationReminderHelper.isWrapUpEnabled) { + if (type == DonationReminderType.WRAP_UP) { // TODO: instrumentation } else { DonorExperienceEvent.logDonationReminderAction( diff --git a/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt b/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt index d69af7a41fb..e7aaa07be24 100644 --- a/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt +++ b/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt @@ -15,6 +15,7 @@ import org.wikipedia.donate.DonateUtil import org.wikipedia.donate.donationreminder.DonationReminderAbTest import org.wikipedia.donate.donationreminder.DonationReminderConfig import org.wikipedia.donate.donationreminder.DonationReminderHelper +import org.wikipedia.donate.donationreminder.DonationReminderType import org.wikipedia.settings.Prefs import org.wikipedia.util.DateUtil import org.wikipedia.util.DimenUtil @@ -28,8 +29,8 @@ class PageHeaderView(context: Context, attrs: AttributeSet? = null) : LinearLayo interface Callback { fun onImageClicked() fun onCallToActionClicked() - fun donationReminderCardPositiveClicked() - fun donationReminderCardNegativeClicked() + fun donationReminderCardPositiveClicked(type: DonationReminderType) + fun donationReminderCardNegativeClicked(type: DonationReminderType) } private val binding = ViewPageHeaderBinding.inflate(LayoutInflater.from(context), this) @@ -141,6 +142,7 @@ class PageHeaderView(context: Context, attrs: AttributeSet? = null) : LinearLayo private fun updateDonationReminderCardContent(config: DonationReminderConfig?) { config?.let { config -> val isWrapUpEnabled = DonationReminderHelper.isWrapUpEnabled + val reminderCardType = if (isWrapUpEnabled) DonationReminderType.WRAP_UP else DonationReminderType.GENERAL val articleText = context.resources.getQuantityString( R.plurals.donation_reminders_text_articles, config.articleFrequency, config.articleFrequency ) @@ -195,12 +197,12 @@ class PageHeaderView(context: Context, attrs: AttributeSet? = null) : LinearLayo binding.donationReminderCardView.setMessage(messageText) binding.donationReminderCardView.setPositiveButton(positiveButtonText) { DonationReminderHelper.dismissReminder() - callback?.donationReminderCardPositiveClicked() + callback?.donationReminderCardPositiveClicked(reminderCardType) } binding.donationReminderCardView.setNegativeButton(negativeButtonText) { binding.donationReminderCardView.isVisible = false DonationReminderHelper.dismissReminder() - callback?.donationReminderCardNegativeClicked() + callback?.donationReminderCardNegativeClicked(reminderCardType) } } } From 04ceb558f8e523733395ff7ce8d6618cb12e4f1a Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Mon, 31 Aug 2026 22:11:25 -0700 Subject: [PATCH 07/15] Code review comments --- .../fdroid/java/org/wikipedia/donate/GooglePayComponent.kt | 2 +- app/src/main/java/org/wikipedia/donate/DonateDialog.kt | 7 ++++++- .../donate/donationreminder/DonationReminderHelper.kt | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/fdroid/java/org/wikipedia/donate/GooglePayComponent.kt b/app/src/fdroid/java/org/wikipedia/donate/GooglePayComponent.kt index 16d2a28b8a1..a126fa92cf4 100644 --- a/app/src/fdroid/java/org/wikipedia/donate/GooglePayComponent.kt +++ b/app/src/fdroid/java/org/wikipedia/donate/GooglePayComponent.kt @@ -10,7 +10,7 @@ object GooglePayComponent { return false } - fun getDonateActivityIntent(activity: Activity, campaignId: String? = null, donateUrl: String? = null, filledAmount: Float = 0f): Intent { + fun getDonateActivityIntent(activity: Activity, campaignId: String? = null, donateUrl: String? = null, filledAmount: Float = 0f, checkedRecurringDonation: Boolean = false): Intent { return Intent() } } diff --git a/app/src/main/java/org/wikipedia/donate/DonateDialog.kt b/app/src/main/java/org/wikipedia/donate/DonateDialog.kt index 4b0c3de5985..4a126280403 100644 --- a/app/src/main/java/org/wikipedia/donate/DonateDialog.kt +++ b/app/src/main/java/org/wikipedia/donate/DonateDialog.kt @@ -148,7 +148,12 @@ class DonateDialog : ExtendedBottomSheetDialogFragment() { campaignId = DonationReminderHelper.getCampaignId() ) (requireActivity() as? BaseActivity)?.launchDonateActivity( - GooglePayComponent.getDonateActivityIntent(requireActivity(), campaignId = DonationReminderHelper.getCampaignId())) + GooglePayComponent.getDonateActivityIntent( + activity = requireActivity(), + campaignId = DonationReminderHelper.getCampaignId(), + checkedRecurringDonation = fromDonationReminderWrapUp + ) + ) } binding.donateOtherButton.setOnClickListener { DonorExperienceEvent.logDonationReminderAction( diff --git a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt index a374c411241..d906928b167 100644 --- a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt +++ b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt @@ -41,7 +41,7 @@ object DonationReminderHelper { var shouldShowSettingSnackbar = false fun getCampaignId(campaignIdOriginal: String = "appmenu"): String { - return if (isInEligibleCountry && isWrapUpEnabled) { + return if (isInEligibleCountry && (isInDateRange || isInWrapUpDateRange)) { campaignIdOriginal + when (DonationReminderAbTest().group) { GROUP_3 -> "_reminderC" GROUP_2 -> "_reminderB" From a77cb048e309b8696edbbfa5f217d1bb836f2723 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Tue, 1 Sep 2026 14:06:42 -0700 Subject: [PATCH 08/15] Enable wrap up only if user sees the campaign or modifiy donation reminder from settings --- .../donationreminder/DonationReminderActivity.kt | 10 ++++++++++ .../donate/donationreminder/DonationReminderHelper.kt | 2 +- .../java/org/wikipedia/page/campaign/CampaignDialog.kt | 4 ++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderActivity.kt b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderActivity.kt index 707fefff1ba..a38b42f4c42 100644 --- a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderActivity.kt +++ b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderActivity.kt @@ -12,6 +12,7 @@ import org.wikipedia.analytics.eventplatform.DonorExperienceEvent import org.wikipedia.compose.components.error.WikiErrorClickEvents import org.wikipedia.compose.theme.BaseTheme import org.wikipedia.readinglist.recommended.RecommendedReadingListOnboardingActivity.Companion.EXTRA_FROM_SETTINGS +import org.wikipedia.settings.Prefs import org.wikipedia.util.DeviceUtil import org.wikipedia.util.FeedbackUtil import org.wikipedia.util.UriUtil @@ -74,6 +75,7 @@ class DonationReminderActivity : BaseActivity() { } } sendAnalysis() + enableWrapUp() } private fun sendAnalysis() { @@ -86,6 +88,14 @@ class DonationReminderActivity : BaseActivity() { } } + private fun enableWrapUp() { + if (!DonationReminderHelper.isWrapUpEnabled) { + Prefs.donationReminderConfig = Prefs.donationReminderConfig.copy( + wrapUpEnabled = true + ) + } + } + companion object { const val RESULT_OK_FROM_DONATION_REMINDER = 100 fun newIntent(context: Context, isFromSettings: Boolean = false): Intent { diff --git a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt index d906928b167..b2ff911984a 100644 --- a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt +++ b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt @@ -142,7 +142,7 @@ data class DonationReminderConfig( val isReminderReady: Boolean = false, val timesReminderShown: Int = 0, val goalReachedCount: Int = 0, - val wrapUpEnabled: Boolean = true + val wrapUpEnabled: Boolean = false ) { val isSetup: Boolean get() = userEnabled && setupTimestamp != 0L && articleFrequency > 0 diff --git a/app/src/main/java/org/wikipedia/page/campaign/CampaignDialog.kt b/app/src/main/java/org/wikipedia/page/campaign/CampaignDialog.kt index d4b9ae44aaa..5ebea369364 100644 --- a/app/src/main/java/org/wikipedia/page/campaign/CampaignDialog.kt +++ b/app/src/main/java/org/wikipedia/page/campaign/CampaignDialog.kt @@ -87,6 +87,10 @@ class CampaignDialog internal constructor(private val context: Context, val camp campaignId = campaignId ) DonationReminderAbTest().maybeSendExposureEvent() + // Enable wrap up for the user if they are in the eligible country and have seen the campaign. + Prefs.donationReminderConfig = Prefs.donationReminderConfig.copy( + wrapUpEnabled = true + ) } if (!DonationReminderHelper.isEnabled) { Prefs.announcementPauseTime = Date().time From a8092d87bc0781db114d61adac643a0f264fb131 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Tue, 1 Sep 2026 15:10:59 -0700 Subject: [PATCH 09/15] Don't exit --- .../settings/dev/DeveloperSettingsPreferenceLoader.kt | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/wikipedia/settings/dev/DeveloperSettingsPreferenceLoader.kt b/app/src/main/java/org/wikipedia/settings/dev/DeveloperSettingsPreferenceLoader.kt index da3d0523cf5..e232f2ff04a 100644 --- a/app/src/main/java/org/wikipedia/settings/dev/DeveloperSettingsPreferenceLoader.kt +++ b/app/src/main/java/org/wikipedia/settings/dev/DeveloperSettingsPreferenceLoader.kt @@ -257,11 +257,12 @@ internal class DeveloperSettingsPreferenceLoader(fragment: PreferenceFragmentCom fragment.requireActivity().finish() true } - findPreference(R.string.preference_key_donation_reminders_dev_wrap_up_enabled).onPreferenceClickListener = Preference.OnPreferenceClickListener { + findPreference(R.string.preference_key_donation_reminders_dev_wrap_up_enabled).onPreferenceChangeListener = Preference.OnPreferenceChangeListener { _, newValue -> + val isWrapUpEnabled = newValue as Boolean + Prefs.donationReminderDevWrapUp = isWrapUpEnabled Prefs.donationReminderConfig = Prefs.donationReminderConfig.copy( - wrapUpEnabled = true + wrapUpEnabled = isWrapUpEnabled ) - fragment.requireActivity().finish() true } (findPreference(R.string.preference_key_yir_survey_state) as ListPreference).apply { From 1cf70a36ca683a473873317a707a6a3c9cb87da8 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Tue, 1 Sep 2026 15:22:54 -0700 Subject: [PATCH 10/15] Simplify isWrapUpEnabled --- .../donate/donationreminder/DonationReminderHelper.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt index b2ff911984a..e2f9f996a6d 100644 --- a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt +++ b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt @@ -33,8 +33,8 @@ object DonationReminderHelper { val isEnabled get() = (ReleaseUtil.isDevRelease || isInEligibleCountry && isInDateRange) && isTestGroupUser val isWrapUpEnabled - get() = (ReleaseUtil.isDevRelease && Prefs.donationReminderDevWrapUp || isInEligibleCountry && isInWrapUpDateRange) && isTestGroupUser && - (Prefs.donationReminderConfig.wrapUpEnabled || ReleaseUtil.isDevRelease && Prefs.donationReminderDevWrapUp) + get() = (Prefs.donationReminderDevWrapUp && Prefs.donationReminderConfig.wrapUpEnabled || isInEligibleCountry && isInWrapUpDateRange) && + isTestGroupUser && Prefs.donationReminderConfig.wrapUpEnabled val hasActiveReminder get() = Prefs.donationReminderConfig.userEnabled && Prefs.donationReminderConfig.isReminderReady && isInEligibleCountry @@ -123,6 +123,7 @@ object DonationReminderHelper { Prefs.donationReminderConfig = config.copy( wrapUpEnabled = false ) + Prefs.donationReminderDevWrapUp = false } else { Prefs.donationReminderConfig = config.copy( isReminderReady = false From 6f6b621c72839e492e2de38f4c1674a2a870c949 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Tue, 1 Sep 2026 15:44:44 -0700 Subject: [PATCH 11/15] Use GROUP_2 --- .../org/wikipedia/page/leadimages/LeadImagesHandler.kt | 3 ++- .../java/org/wikipedia/page/leadimages/PageHeaderView.kt | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.kt b/app/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.kt index 8b8c74f9555..90d8c7b85dd 100644 --- a/app/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.kt +++ b/app/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.kt @@ -13,6 +13,7 @@ import org.wikipedia.Constants.ImageEditType import org.wikipedia.Constants.InvokeSource import org.wikipedia.R import org.wikipedia.WikipediaApp +import org.wikipedia.analytics.ABTest.Companion.GROUP_2 import org.wikipedia.analytics.eventplatform.DonorExperienceEvent import org.wikipedia.auth.AccountUtil import org.wikipedia.bridge.JavaScriptActionHandler @@ -212,7 +213,7 @@ class LeadImagesHandler(private val parentFragment: PageFragment, override fun donationReminderCardPositiveClicked(type: DonationReminderType) { hideDonationReminderCard() if (type == DonationReminderType.WRAP_UP) { - if (DonationReminderAbTest().group == 1) { + if (DonationReminderAbTest().group == GROUP_2) { SurveyDialog.showDonationReminderFeedbackDialog( activity = parentFragment.requireActivity(), onImpression = { diff --git a/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt b/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt index e7aaa07be24..df235ee792e 100644 --- a/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt +++ b/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt @@ -9,6 +9,7 @@ import androidx.core.net.toUri import androidx.core.view.isVisible import androidx.core.view.updateLayoutParams import org.wikipedia.R +import org.wikipedia.analytics.ABTest.Companion.GROUP_2 import org.wikipedia.analytics.eventplatform.DonorExperienceEvent import org.wikipedia.databinding.ViewPageHeaderBinding import org.wikipedia.donate.DonateUtil @@ -153,13 +154,13 @@ class PageHeaderView(context: Context, attrs: AttributeSet? = null) : LinearLayo } val donationAmountText = DonateUtil.currencyFormat.format(donateAmount) val titleText = if (isWrapUpEnabled) { - if (DonationReminderAbTest().group == 1) { + if (DonationReminderAbTest().group == GROUP_2) { context.getString(R.string.donation_reminders_wrap_up_title) } else { context.getString(R.string.donation_reminders_eoe_title) } } else { - if (config.goalReachedCount == 1) { + if (config.goalReachedCount == GROUP_2) { context.getString(R.string.donation_reminders_first_milestone_reached_prompt_title, articleText, donationAmountText) } else { context.getString(R.string.donation_reminders_subsequent_milestone_reached_prompt_title, articleText) @@ -168,7 +169,7 @@ class PageHeaderView(context: Context, attrs: AttributeSet? = null) : LinearLayo val dateText = DateUtil.getMMMMdYYYY(Date(config.setupTimestamp)) val messageText = if (isWrapUpEnabled) { - if (DonationReminderAbTest().group == 1) { + if (DonationReminderAbTest().group == GROUP_2) { context.getString(R.string.donation_reminders_wrap_up_message) } else { context.getString(R.string.donation_reminders_eoe_message, donationAmountText) @@ -177,7 +178,7 @@ class PageHeaderView(context: Context, attrs: AttributeSet? = null) : LinearLayo context.getString(R.string.donation_reminders_prompt_message_v2, dateText, articleText, donationAmountText) } val positiveButtonText = if (isWrapUpEnabled) { - if (DonationReminderAbTest().group == 1) { + if (DonationReminderAbTest().group == GROUP_2) { context.getString(R.string.donation_reminders_wrap_up_share_feedback_button) } else { context.getString(R.string.donation_reminders_eoe_give_monthly_button) From b0df60ae55c5cd5517c73a6ea812ed83ad4ee8d3 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Wed, 2 Sep 2026 13:45:32 -0700 Subject: [PATCH 12/15] Logic change --- .../donationreminder/DonationReminderHelper.kt | 15 ++++++++++++--- .../wikipedia/page/leadimages/PageHeaderView.kt | 2 +- 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt index e2f9f996a6d..d74c9fb918e 100644 --- a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt +++ b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt @@ -32,9 +32,18 @@ object DonationReminderHelper { val isEnabled get() = (ReleaseUtil.isDevRelease || isInEligibleCountry && isInDateRange) && isTestGroupUser - val isWrapUpEnabled - get() = (Prefs.donationReminderDevWrapUp && Prefs.donationReminderConfig.wrapUpEnabled || isInEligibleCountry && isInWrapUpDateRange) && - isTestGroupUser && Prefs.donationReminderConfig.wrapUpEnabled + val isWrapUpEnabled: Boolean + get() { + val config = Prefs.donationReminderConfig + val group = DonationReminderAbTest().group + + val isWrapUpWindow = (Prefs.donationReminderDevWrapUp && config.wrapUpEnabled) || + (isInEligibleCountry && isInWrapUpDateRange) + val isEligibleGroup = (group == GROUP_2 && config.wrapUpEnabled) || + (group == GROUP_3 && config.wrapUpEnabled && config.userEnabled) + + return isWrapUpWindow && isEligibleGroup + } val hasActiveReminder get() = Prefs.donationReminderConfig.userEnabled && Prefs.donationReminderConfig.isReminderReady && isInEligibleCountry diff --git a/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt b/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt index df235ee792e..07eab75c11b 100644 --- a/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt +++ b/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt @@ -160,7 +160,7 @@ class PageHeaderView(context: Context, attrs: AttributeSet? = null) : LinearLayo context.getString(R.string.donation_reminders_eoe_title) } } else { - if (config.goalReachedCount == GROUP_2) { + if (config.goalReachedCount == 1) { context.getString(R.string.donation_reminders_first_milestone_reached_prompt_title, articleText, donationAmountText) } else { context.getString(R.string.donation_reminders_subsequent_milestone_reached_prompt_title, articleText) From 4752a9d95c4c19e5e0b33777068bda175aa4f15d Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Wed, 2 Sep 2026 14:00:48 -0700 Subject: [PATCH 13/15] Add monthly option to web donation URL --- .../main/java/org/wikipedia/donate/DonateDialog.kt | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/wikipedia/donate/DonateDialog.kt b/app/src/main/java/org/wikipedia/donate/DonateDialog.kt index 4a126280403..d58f3382063 100644 --- a/app/src/main/java/org/wikipedia/donate/DonateDialog.kt +++ b/app/src/main/java/org/wikipedia/donate/DonateDialog.kt @@ -103,8 +103,8 @@ class DonateDialog : ExtendedBottomSheetDialogFragment() { super.onDestroyView() } - private fun onDonateClicked() { - launchDonateLink(requireContext(), url = arguments?.getString(ARG_DONATE_URL), campaignId = campaignId) + private fun onDonateClicked(checkMonthly: Boolean = false) { + launchDonateLink(requireContext(), url = arguments?.getString(ARG_DONATE_URL), campaignId = campaignId, checkMonthly = checkMonthly) invalidateCampaign() dismiss() } @@ -161,7 +161,7 @@ class DonateDialog : ExtendedBottomSheetDialogFragment() { action = "other_method_click", campaignId = DonationReminderHelper.getCampaignId() ) - onDonateClicked() + onDonateClicked(fromDonationReminderWrapUp) } if (fromDonationReminderWrapUp) { binding.gPayTitle.text = getString(R.string.donation_reminders_eoe_donate_dialog_title) @@ -200,12 +200,15 @@ class DonateDialog : ExtendedBottomSheetDialogFragment() { } } - fun launchDonateLink(context: Context, url: String? = null, campaignId: String? = "appmenu") { + fun launchDonateLink(context: Context, url: String? = null, campaignId: String? = "appmenu", checkMonthly: Boolean = false) { val formattedCampaignId = campaignId?.let { return@let CampaignCollection.getFormattedCampaignId(it) }.orEmpty() - val donateUrl = url ?: context.getString(R.string.donate_url, formattedCampaignId, + var donateUrl = url ?: context.getString(R.string.donate_url, formattedCampaignId, WikipediaApp.instance.languageState.systemLanguageCode, BuildConfig.VERSION_NAME, Prefs.appInstallId) + if (checkMonthly) { + donateUrl += "&frequency=monthly" + } CustomTabsUtil.openInCustomTab(context, donateUrl) } } From 1b93fd6c1e05bdc553979701fd422907f5c5c7f8 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Wed, 2 Sep 2026 14:51:06 -0700 Subject: [PATCH 14/15] Add instrumentation, too --- .../org/wikipedia/donate/GooglePayActivity.kt | 15 +++++++-- .../eventplatform/DonorExperienceEvent.kt | 12 +++++-- .../java/org/wikipedia/donate/DonateDialog.kt | 11 +++++-- .../DonationReminderHelper.kt | 2 +- .../page/leadimages/LeadImagesHandler.kt | 33 +++++++++++++++---- .../page/leadimages/PageHeaderView.kt | 17 ++++++---- .../java/org/wikipedia/views/SurveyDialog.kt | 2 +- 7 files changed, 70 insertions(+), 22 deletions(-) diff --git a/app/src/extra/java/org/wikipedia/donate/GooglePayActivity.kt b/app/src/extra/java/org/wikipedia/donate/GooglePayActivity.kt index 055ee2b5871..b49960887d8 100644 --- a/app/src/extra/java/org/wikipedia/donate/GooglePayActivity.kt +++ b/app/src/extra/java/org/wikipedia/donate/GooglePayActivity.kt @@ -101,7 +101,11 @@ class GooglePayActivity : BaseActivity() { } is GooglePayViewModel.NoPaymentMethod -> { DonorExperienceEvent.logAction("no_payment_method", "gpay", campaignId = campaignId) - DonateDialog.launchDonateLink(this@GooglePayActivity, url = intent.getStringExtra(DonateDialog.ARG_DONATE_URL)) + DonateDialog.launchDonateLink( + context = this@GooglePayActivity, + url = intent.getStringExtra(DonateDialog.ARG_DONATE_URL), + checkMonthly = viewModel.checkedRecurringDonation + ) finish() } is Resource.Success -> { @@ -111,7 +115,11 @@ class GooglePayActivity : BaseActivity() { } catch (_: IllegalStateException) { // An IllegalStateException could happen on certain devices if Google Pay is not fully set up or supported. // In this case, fall back to an external link for donation. - DonateDialog.launchDonateLink(this@GooglePayActivity, url = intent.getStringExtra(DonateDialog.ARG_DONATE_URL)) + DonateDialog.launchDonateLink( + context = this@GooglePayActivity, + url = intent.getStringExtra(DonateDialog.ARG_DONATE_URL), + checkMonthly = viewModel.checkedRecurringDonation + ) finish() } } @@ -122,6 +130,9 @@ class GooglePayActivity : BaseActivity() { currency = DonateUtil.currencyCode, recurring = binding.checkBoxRecurring.isChecked ) + if (viewModel.checkedRecurringDonation && DonationReminderHelper.isInWrapUpDateRange) { + DonorExperienceEvent.logDonationReminderAction("impression", "reminder_recur_confirmed") + } setResult(RESULT_OK) finish() } diff --git a/app/src/main/java/org/wikipedia/analytics/eventplatform/DonorExperienceEvent.kt b/app/src/main/java/org/wikipedia/analytics/eventplatform/DonorExperienceEvent.kt index 85213f7e5f2..dc922f45c64 100644 --- a/app/src/main/java/org/wikipedia/analytics/eventplatform/DonorExperienceEvent.kt +++ b/app/src/main/java/org/wikipedia/analytics/eventplatform/DonorExperienceEvent.kt @@ -33,14 +33,18 @@ open class DonorExperienceEvent { campaignId: String? = null, articleFrequency: Int? = null, donateAmount: Float? = null, - groupAssigned: String? = null + groupAssigned: String? = null, + feedbackSelect: Int? = null, + feedbackText: String? = null ) { val actionData = DonationRemindersActionData( defaultMilestone = defaultMilestone, campaignId = campaignId?.let { CampaignCollection.getFormattedCampaignId(campaignId) }, articleFrequency = articleFrequency, donateAmount = donateAmount, - groupAssigned = groupAssigned + groupAssigned = groupAssigned, + feedbackSelect = feedbackSelect, + feedbackText = feedbackText ) submit( action, @@ -75,6 +79,8 @@ open class DonorExperienceEvent { @SerialName("campaign_id") val campaignId: String? = null, @SerialName("read_freq") val articleFrequency: Int? = null, @SerialName("donate_amount") val donateAmount: Float? = null, - @SerialName("group") val groupAssigned: String? = null + @SerialName("group") val groupAssigned: String? = null, + @SerialName("score") val feedbackSelect: Int? = null, + @SerialName("text") val feedbackText: String? = null ) } diff --git a/app/src/main/java/org/wikipedia/donate/DonateDialog.kt b/app/src/main/java/org/wikipedia/donate/DonateDialog.kt index d58f3382063..26bce3f01ae 100644 --- a/app/src/main/java/org/wikipedia/donate/DonateDialog.kt +++ b/app/src/main/java/org/wikipedia/donate/DonateDialog.kt @@ -116,6 +116,11 @@ class DonateDialog : ExtendedBottomSheetDialogFragment() { } private fun setupDirectGooglePayButton(fromDonationReminderWrapUp: Boolean) { + val activeInterface = if (fromDonationReminderWrapUp) { + "reminder_recur_end" + } else { + "reminder_milestone" + } val donateAmount = if (Prefs.donationReminderConfig.donateAmount <= 0) { DonationReminderHelper.defaultDonateAmountOptions.first() } else { @@ -127,7 +132,7 @@ class DonateDialog : ExtendedBottomSheetDialogFragment() { binding.donateGooglePayButton.text = donateButtonText binding.donateGooglePayButton.setOnClickListener { DonorExperienceEvent.logDonationReminderAction( - activeInterface = "reminder_milestone", + activeInterface = activeInterface, action = "gpay_click", campaignId = DonationReminderHelper.getCampaignId() ) @@ -143,7 +148,7 @@ class DonateDialog : ExtendedBottomSheetDialogFragment() { binding.donateGooglePayDifferentAmountButton.isVisible = true binding.donateGooglePayDifferentAmountButton.setOnClickListener { DonorExperienceEvent.logDonationReminderAction( - activeInterface = "reminder_milestone", + activeInterface = activeInterface, action = "other_gpay_click", campaignId = DonationReminderHelper.getCampaignId() ) @@ -157,7 +162,7 @@ class DonateDialog : ExtendedBottomSheetDialogFragment() { } binding.donateOtherButton.setOnClickListener { DonorExperienceEvent.logDonationReminderAction( - activeInterface = "reminder_milestone", + activeInterface = activeInterface, action = "other_method_click", campaignId = DonationReminderHelper.getCampaignId() ) diff --git a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt index d74c9fb918e..61c3bcb5895 100644 --- a/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt +++ b/app/src/main/java/org/wikipedia/donate/donationreminder/DonationReminderHelper.kt @@ -23,7 +23,7 @@ object DonationReminderHelper { "NL" ) private val isInDateRange get() = LocalDate.now() <= LocalDate.of(2026, 11, 9) - private val isInWrapUpDateRange get() = LocalDate.now() <= LocalDate.of(2026, 11, 15) && + val isInWrapUpDateRange get() = LocalDate.now() <= LocalDate.of(2026, 11, 15) && LocalDate.now() >= LocalDate.of(2026, 11, 10) val isInEligibleCountry get() = ReleaseUtil.isDevRelease || enabledCountries.contains(GeoUtil.geoIPCountry.orEmpty()) val defaultReadFrequencyOptions = listOf(5, 10, 20) diff --git a/app/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.kt b/app/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.kt index 90d8c7b85dd..04348c2927f 100644 --- a/app/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.kt +++ b/app/src/main/java/org/wikipedia/page/leadimages/LeadImagesHandler.kt @@ -214,19 +214,33 @@ class LeadImagesHandler(private val parentFragment: PageFragment, hideDonationReminderCard() if (type == DonationReminderType.WRAP_UP) { if (DonationReminderAbTest().group == GROUP_2) { + DonorExperienceEvent.logDonationReminderAction( + activeInterface = "reminder_end", + action = "feedback_start_click", + ) SurveyDialog.showDonationReminderFeedbackDialog( activity = parentFragment.requireActivity(), - onImpression = { - // TODO: instrumentation - }, + onImpression = { }, onCancel = { - // TODO: instrumentation + DonorExperienceEvent.logDonationReminderAction( + activeInterface = "reminder_feedback", + action = "cancel_click", + ) }, onSubmit = { feedbackOption, feedbackText -> - // TODO: instrumentation + DonorExperienceEvent.logDonationReminderAction( + activeInterface = "reminder_feedback", + action = "feedback_submit_click", + feedbackSelect = feedbackOption, + feedbackText = feedbackText + ) } ) } else { + DonorExperienceEvent.logDonationReminderAction( + activeInterface = "reminder_recur_end", + action = "recurring_start_click", + ) ExclusiveBottomSheetPresenter.show(parentFragment.parentFragmentManager, DonateDialog.newInstance(fromDonationReminder = true, fromDonationReminderWrapUp = true)) } } else { @@ -242,7 +256,14 @@ class LeadImagesHandler(private val parentFragment: PageFragment, override fun donationReminderCardNegativeClicked(type: DonationReminderType) { hideDonationReminderCard() if (type == DonationReminderType.WRAP_UP) { - // TODO: instrumentation + DonorExperienceEvent.logDonationReminderAction( + activeInterface = if (DonationReminderAbTest().group == GROUP_2) { + "reminder_end" + } else { + "reminder_recur_end" + }, + action = "nothanks_click", + ) } else { DonorExperienceEvent.logDonationReminderAction( activeInterface = "reminder_milestone", diff --git a/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt b/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt index 07eab75c11b..bb42af1bacc 100644 --- a/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt +++ b/app/src/main/java/org/wikipedia/page/leadimages/PageHeaderView.kt @@ -210,12 +210,17 @@ class PageHeaderView(context: Context, attrs: AttributeSet? = null) : LinearLayo fun maybeShowDonationReminderCard() { if (DonationReminderHelper.shouldShowReminderNow() || DonationReminderHelper.isWrapUpEnabled) { - if (!DonationReminderHelper.isWrapUpEnabled) { - DonorExperienceEvent.logDonationReminderAction( - activeInterface = "reminder_milestone", - action = "impression" - ) - } + DonorExperienceEvent.logDonationReminderAction( + activeInterface = if (DonationReminderHelper.isWrapUpEnabled) { + if (DonationReminderAbTest().group == GROUP_2) { + "reminder_end" + } else { + "reminder_recur_end" + } + } else "reminder_milestone", + action = "impression", + campaignId = DonationReminderHelper.getCampaignId(), + ) updateDonationReminderCardContent(Prefs.donationReminderConfig) binding.donationReminderCardView.isVisible = true } else { diff --git a/app/src/main/java/org/wikipedia/views/SurveyDialog.kt b/app/src/main/java/org/wikipedia/views/SurveyDialog.kt index fd833352128..64955a64bfd 100644 --- a/app/src/main/java/org/wikipedia/views/SurveyDialog.kt +++ b/app/src/main/java/org/wikipedia/views/SurveyDialog.kt @@ -100,7 +100,7 @@ object SurveyDialog { dialog?.dismiss() } binding.submitButton.setOnClickListener { - val feedbackOption = getSelectedOption(binding) + val feedbackOption = (getSelectedOption(binding) ?: 2) - 1 // score is from 2 to 4, since we hide 1 and 5, we need to subtract 1 to make it from 1 to 3 val feedbackText = binding.feedbackInput.text.toString() onSubmit(feedbackOption, feedbackText) FeedbackUtil.showMessage(activity, R.string.donation_reminders_wrap_up_survey_thank_you_message) From 272e16357753c6508d19a4b38c7a90e78fcca3ae Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Wed, 2 Sep 2026 15:01:19 -0700 Subject: [PATCH 15/15] Simplify feedback option calculation Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- app/src/main/java/org/wikipedia/views/SurveyDialog.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/wikipedia/views/SurveyDialog.kt b/app/src/main/java/org/wikipedia/views/SurveyDialog.kt index 64955a64bfd..5ffecc5aad9 100644 --- a/app/src/main/java/org/wikipedia/views/SurveyDialog.kt +++ b/app/src/main/java/org/wikipedia/views/SurveyDialog.kt @@ -100,7 +100,7 @@ object SurveyDialog { dialog?.dismiss() } binding.submitButton.setOnClickListener { - val feedbackOption = (getSelectedOption(binding) ?: 2) - 1 // score is from 2 to 4, since we hide 1 and 5, we need to subtract 1 to make it from 1 to 3 + val feedbackOption = getSelectedOption(binding)?.minus(1) val feedbackText = binding.feedbackInput.text.toString() onSubmit(feedbackOption, feedbackText) FeedbackUtil.showMessage(activity, R.string.donation_reminders_wrap_up_survey_thank_you_message)