From 15b2ab22b0253d2c4c72f2b72ad36cb01d370351 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Wed, 29 Oct 2025 17:14:03 -0700 Subject: [PATCH 01/13] YiR: wire up instrumentation --- .../eventplatform/YearInReviewEvent.kt | 39 +++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 app/src/main/java/org/wikipedia/analytics/eventplatform/YearInReviewEvent.kt diff --git a/app/src/main/java/org/wikipedia/analytics/eventplatform/YearInReviewEvent.kt b/app/src/main/java/org/wikipedia/analytics/eventplatform/YearInReviewEvent.kt new file mode 100644 index 00000000000..346d1451146 --- /dev/null +++ b/app/src/main/java/org/wikipedia/analytics/eventplatform/YearInReviewEvent.kt @@ -0,0 +1,39 @@ +package org.wikipedia.analytics.eventplatform + +import kotlinx.serialization.SerialName +import kotlinx.serialization.Serializable +import org.wikipedia.WikipediaApp +import org.wikipedia.json.JsonUtil + +open class YearInReviewEvent { + + companion object { + fun submit( + action: String, + activeInterface: String = "wiki_yir", + slide: String, + wikiId: String = WikipediaApp.instance.appOrSystemLanguageCode + ) { + EventPlatformClient.submit( + AppInteractionEvent( + action = action, + active_interface = activeInterface, + action_data = JsonUtil.encodeToString(ActionData( + slide = slide + )).orEmpty(), + primary_language = WikipediaApp.instance.languageState.appLanguageCode, + wiki_id = wikiId, + streamName = "app_donor_experience" + ) + ) + } + } + + @Serializable + class ActionData( + val slide: String? = null, + @SerialName("campaign_id") val campaignId: String? = null, + @SerialName("feedback_select") val feedbackSelect: Int? = null, + @SerialName("feedback_text") val feedbackText: String? = null + ) +} From b2a1599841fb665df120725a963bcfccfe6a885f Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Wed, 29 Oct 2025 22:14:44 -0700 Subject: [PATCH 02/13] Add events for slides --- .../java/org/wikipedia/navtab/MenuNavTabDialog.kt | 10 +++++++++- .../main/java/org/wikipedia/settings/AppIconDialog.kt | 3 +++ .../wikipedia/settings/SettingsPreferenceLoader.kt | 11 ++++++++++- .../yearinreview/YearInReviewOnboardingActivity.kt | 5 +++++ .../yearinreview/YearInReviewOnboardingScreen.kt | 7 ++++++- 5 files changed, 33 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/wikipedia/navtab/MenuNavTabDialog.kt b/app/src/main/java/org/wikipedia/navtab/MenuNavTabDialog.kt index 889cf8037f8..17134d6fe14 100644 --- a/app/src/main/java/org/wikipedia/navtab/MenuNavTabDialog.kt +++ b/app/src/main/java/org/wikipedia/navtab/MenuNavTabDialog.kt @@ -13,6 +13,7 @@ import org.wikipedia.analytics.eventplatform.ActivityTabEvent import org.wikipedia.analytics.eventplatform.BreadCrumbLogEvent import org.wikipedia.analytics.eventplatform.DonorExperienceEvent import org.wikipedia.analytics.eventplatform.PlacesEvent +import org.wikipedia.analytics.eventplatform.YearInReviewEvent import org.wikipedia.auth.AccountUtil import org.wikipedia.databinding.ViewMainDrawerBinding import org.wikipedia.page.ExtendedBottomSheetDialogFragment @@ -38,10 +39,16 @@ class MenuNavTabDialog : ExtendedBottomSheetDialogFragment() { private var _binding: ViewMainDrawerBinding? = null private val binding get() = _binding!! + private val yirEntrySlide get() = if (AccountUtil.isLoggedIn) "entry_b" else "entry_c" + private val yirEnabled get() = YearInReviewViewModel.isAccessible && Prefs.isYearInReviewEnabled + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { _binding = ViewMainDrawerBinding.inflate(inflater, container, false) - binding.mainDrawerYearInReviewContainer.isVisible = YearInReviewViewModel.isAccessible && Prefs.isYearInReviewEnabled + if (yirEnabled) { + YearInReviewEvent.submit(action = "impression", slide = yirEntrySlide) + } + binding.mainDrawerYearInReviewContainer.isVisible = yirEnabled binding.mainDrawerAccountContainer.setOnClickListener { BreadCrumbLogEvent.logClick(requireActivity(), binding.mainDrawerAccountContainer) @@ -91,6 +98,7 @@ class MenuNavTabDialog : ExtendedBottomSheetDialogFragment() { } binding.mainDrawerYearInReviewContainer.setOnClickListener { + YearInReviewEvent.submit(action = "start_click", slide = yirEntrySlide) callback()?.yearInReviewClick() dismiss() } diff --git a/app/src/main/java/org/wikipedia/settings/AppIconDialog.kt b/app/src/main/java/org/wikipedia/settings/AppIconDialog.kt index 39440460353..f5a951ee6a0 100644 --- a/app/src/main/java/org/wikipedia/settings/AppIconDialog.kt +++ b/app/src/main/java/org/wikipedia/settings/AppIconDialog.kt @@ -12,6 +12,7 @@ import com.google.android.flexbox.FlexDirection import com.google.android.flexbox.FlexboxLayoutManager import com.google.android.flexbox.JustifyContent import org.wikipedia.R +import org.wikipedia.analytics.eventplatform.YearInReviewEvent import org.wikipedia.appshortcuts.AppShortcuts import org.wikipedia.databinding.DialogAppIconBinding import org.wikipedia.databinding.ItemAppIconBinding @@ -33,6 +34,8 @@ class AppIconDialog : ExtendedBottomSheetDialogFragment() { } binding.appIconRecyclerView.adapter = AppIconAdapter(LauncherIcon.entries).apply { onItemClickListener = { icon -> + val eventAction = if (icon == LauncherIcon.DEFAULT) "icon_deactivate_click" else "icon_activate_click" + YearInReviewEvent.submit(action = eventAction, slide = "setting") Prefs.selectedAppIcon = icon.key LauncherController.setIcon(icon) AppShortcuts.setShortcuts(requireContext()) diff --git a/app/src/main/java/org/wikipedia/settings/SettingsPreferenceLoader.kt b/app/src/main/java/org/wikipedia/settings/SettingsPreferenceLoader.kt index 76ce08d606f..9d6dacd256b 100644 --- a/app/src/main/java/org/wikipedia/settings/SettingsPreferenceLoader.kt +++ b/app/src/main/java/org/wikipedia/settings/SettingsPreferenceLoader.kt @@ -12,6 +12,7 @@ import org.wikipedia.Constants import org.wikipedia.R import org.wikipedia.WikipediaApp import org.wikipedia.analytics.eventplatform.RecommendedReadingListEvent +import org.wikipedia.analytics.eventplatform.YearInReviewEvent import org.wikipedia.auth.AccountUtil import org.wikipedia.donate.DonateUtil import org.wikipedia.donate.donationreminder.DonationReminderActivity @@ -69,18 +70,26 @@ internal class SettingsPreferenceLoader(fragment: PreferenceFragmentCompat) : Ba findPreference(R.string.preference_key_year_in_review_is_enabled).let { it.isVisible = YearInReviewViewModel.isAccessible + if (it.isVisible) { + YearInReviewEvent.submit(action = "impression", slide = "setting") + } it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { preference, newValue -> if (newValue as Boolean) { + val eventAction = if (newValue) "yir_on_click" else "yir_off_click" + YearInReviewEvent.submit(action = eventAction, slide = "setting") return@OnPreferenceChangeListener true } MaterialAlertDialogBuilder(activity) .setTitle(R.string.year_in_review_disable_title) .setMessage(R.string.year_in_review_setting_subtitle) .setPositiveButton(R.string.year_in_review_disable_positive_button) { _, _ -> + YearInReviewEvent.submit(action = "yir_off_confirm_click", slide = "setting") Prefs.yearInReviewModelData = emptyMap() (preference as SwitchPreferenceCompat).isChecked = false } - .setNegativeButton(R.string.year_in_review_disable_negative_button, null) + .setNegativeButton(R.string.year_in_review_disable_negative_button) { _, _ -> + YearInReviewEvent.submit(action = "yir_off_cancel_click", slide = "setting") + } .show() false } diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewOnboardingActivity.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewOnboardingActivity.kt index 6c7ba829008..cef4180afdc 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewOnboardingActivity.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewOnboardingActivity.kt @@ -12,6 +12,7 @@ import androidx.compose.runtime.setValue import androidx.compose.ui.res.stringResource import org.wikipedia.R import org.wikipedia.activity.BaseActivity +import org.wikipedia.analytics.eventplatform.YearInReviewEvent import org.wikipedia.auth.AccountUtil import org.wikipedia.compose.components.WikipediaAlertDialog import org.wikipedia.compose.theme.BaseTheme @@ -29,6 +30,7 @@ class YearInReviewOnboardingActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + YearInReviewEvent.submit(action = "impression", slide = "entry_a") Prefs.yearInReviewVisited = true setContent { BaseTheme { @@ -43,9 +45,11 @@ class YearInReviewOnboardingActivity : BaseActivity() { showLoginDialog = false }, onConfirmButtonClick = { + YearInReviewEvent.submit(action = "login_click", slide = "entry_a") loginLauncher.launch(LoginActivity.newIntent(this, LoginActivity.SOURCE_YEAR_IN_REVIEW)) }, onDismissButtonClick = { + YearInReviewEvent.submit(action = "continue_click", slide = "entry_a") proceed() } ) @@ -53,6 +57,7 @@ class YearInReviewOnboardingActivity : BaseActivity() { YearInReviewOnboardingScreen( onBackButtonClick = { + YearInReviewEvent.submit(action = "close_click", slide = "entry_a") setResult(RESULT_CANCELED) finish() }, diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewOnboardingScreen.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewOnboardingScreen.kt index a0891c311a4..750c99f92ec 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewOnboardingScreen.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewOnboardingScreen.kt @@ -36,6 +36,7 @@ import coil3.compose.SubcomposeAsyncImageContent import coil3.request.ImageRequest import coil3.request.allowHardware import org.wikipedia.R +import org.wikipedia.analytics.eventplatform.YearInReviewEvent import org.wikipedia.compose.theme.BaseTheme import org.wikipedia.compose.theme.WikipediaTheme import org.wikipedia.theme.Theme @@ -159,6 +160,7 @@ fun YearInReviewOnboardingBottomBar( .weight(1f) .padding(end = 12.dp), onClick = { + YearInReviewEvent.submit(action = "learn_click", slide = "entry_a") UriUtil.handleExternalLink( context = context, uri = context.getString(R.string.year_in_review_media_wiki_url).toUri() @@ -178,7 +180,10 @@ fun YearInReviewOnboardingBottomBar( modifier = Modifier .weight(1f) .padding(start = 12.dp), - onClick = { onGetStartedClick() } + onClick = { + YearInReviewEvent.submit(action = "start_click", slide = "entry_a") + onGetStartedClick() + } ) { Text( text = stringResource(R.string.year_in_review_get_started), From 96d25fb52fe46691ce1860680bb621676666dfba Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Tue, 4 Nov 2025 14:31:55 -0800 Subject: [PATCH 03/13] Put slide names to screen data functions --- .../eventplatform/YearInReviewEvent.kt | 3 + .../createaccount/CreateAccountActivity.kt | 12 ++- .../yearinreview/YearInReviewScreenData.kt | 23 ++++-- .../yearinreview/YearInReviewSlides.kt | 74 ++++++++++++++----- 4 files changed, 86 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/org/wikipedia/analytics/eventplatform/YearInReviewEvent.kt b/app/src/main/java/org/wikipedia/analytics/eventplatform/YearInReviewEvent.kt index 346d1451146..efcf2d4b6b2 100644 --- a/app/src/main/java/org/wikipedia/analytics/eventplatform/YearInReviewEvent.kt +++ b/app/src/main/java/org/wikipedia/analytics/eventplatform/YearInReviewEvent.kt @@ -3,6 +3,7 @@ package org.wikipedia.analytics.eventplatform import kotlinx.serialization.SerialName import kotlinx.serialization.Serializable import org.wikipedia.WikipediaApp +import org.wikipedia.dataclient.donate.CampaignCollection import org.wikipedia.json.JsonUtil open class YearInReviewEvent { @@ -11,6 +12,7 @@ open class YearInReviewEvent { fun submit( action: String, activeInterface: String = "wiki_yir", + campaignId: String? = null, slide: String, wikiId: String = WikipediaApp.instance.appOrSystemLanguageCode ) { @@ -19,6 +21,7 @@ open class YearInReviewEvent { action = action, active_interface = activeInterface, action_data = JsonUtil.encodeToString(ActionData( + campaignId = campaignId?.let { "campaign_id: ${CampaignCollection.getFormattedCampaignId(it)}" }, slide = slide )).orEmpty(), primary_language = WikipediaApp.instance.languageState.appLanguageCode, diff --git a/app/src/main/java/org/wikipedia/createaccount/CreateAccountActivity.kt b/app/src/main/java/org/wikipedia/createaccount/CreateAccountActivity.kt index 5ec066c9d23..a0f93773a04 100644 --- a/app/src/main/java/org/wikipedia/createaccount/CreateAccountActivity.kt +++ b/app/src/main/java/org/wikipedia/createaccount/CreateAccountActivity.kt @@ -24,10 +24,12 @@ import org.wikipedia.R import org.wikipedia.WikipediaApp import org.wikipedia.activity.BaseActivity import org.wikipedia.analytics.eventplatform.CreateAccountEvent +import org.wikipedia.analytics.eventplatform.YearInReviewEvent import org.wikipedia.auth.AccountUtil import org.wikipedia.captcha.CaptchaHandler import org.wikipedia.captcha.CaptchaResult import org.wikipedia.databinding.ActivityCreateAccountBinding +import org.wikipedia.login.LoginActivity import org.wikipedia.util.DeviceUtil import org.wikipedia.util.FeedbackUtil import org.wikipedia.util.StringUtil @@ -46,6 +48,7 @@ class CreateAccountActivity : BaseActivity() { private lateinit var createAccountEvent: CreateAccountEvent private var wiki = WikipediaApp.instance.wikiSite private var userNameTextWatcher: TextWatcher? = null + private var requestSource: String = "" private val viewModel: CreateAccountActivityViewModel by viewModels() public override fun onCreate(savedInstanceState: Bundle?) { @@ -60,7 +63,8 @@ class CreateAccountActivity : BaseActivity() { // Don't allow user to continue when they're shown a captcha until they fill it in NonEmptyValidator(binding.captchaContainer.captchaSubmitButton, binding.captchaContainer.captchaText) setClickListeners() - createAccountEvent = CreateAccountEvent(intent.getStringExtra(LOGIN_REQUEST_SOURCE).orEmpty()) + requestSource = intent.getStringExtra(LOGIN_REQUEST_SOURCE).orEmpty() + createAccountEvent = CreateAccountEvent(requestSource) // Only send the editing start log event if the activity is created for the first time if (savedInstanceState == null) { createAccountEvent.logStart() @@ -151,12 +155,18 @@ class CreateAccountActivity : BaseActivity() { } binding.viewCreateAccountError.retryClickListener = View.OnClickListener { binding.viewCreateAccountError.visibility = View.GONE } binding.createAccountSubmitButton.setOnClickListener { + if (requestSource == LoginActivity.SOURCE_YEAR_IN_REVIEW) { + YearInReviewEvent.submit(action = "create_account_click", slide = "entry_a") + } validateThenCreateAccount() } binding.captchaContainer.captchaSubmitButton.setOnClickListener { validateThenCreateAccount() } binding.createAccountLoginButton.setOnClickListener { + if (requestSource == LoginActivity.SOURCE_YEAR_IN_REVIEW) { + YearInReviewEvent.submit(action = "login_click", slide = "entry_a") + } // This assumes that the CreateAccount activity was launched from the Login activity // (since there's currently no other mechanism to invoke CreateAccountActivity), // so finishing this activity will implicitly go back to Login. diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenData.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenData.kt index d7a3e2e0c24..80c2931f074 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenData.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenData.kt @@ -72,6 +72,7 @@ sealed class YearInReviewScreenData( val imageModifier: Modifier = Modifier.size(200.dp), val headlineText: Any? = null, val bodyText: Any? = null, + val slideName: String, showDonateInToolbar: Boolean = true ) : YearInReviewScreenData(allowDonate, showDonateInToolbar) { @@ -126,7 +127,8 @@ sealed class YearInReviewScreenData( ) data class HighlightsScreen( - val highlights: List + val highlights: List, + val slideName: String ) : YearInReviewScreenData() class GeoScreen( @@ -135,7 +137,8 @@ sealed class YearInReviewScreenData( val largestClusterBottomRight: Pair, val pagesWithCoordinates: List, val headlineText: String? = null, - val bodyText: String? = null + val bodyText: String? = null, + val slideName: String ) : YearInReviewScreenData(allowDonate) class ReadingPatterns( @@ -143,26 +146,30 @@ sealed class YearInReviewScreenData( imageResource: Int = 0, headlineText: Any? = null, bodyText: Any? = null, + slideName: String, val favoriteTimeText: String, val favoriteDayText: String, - val favoriteMonthText: String + val favoriteMonthText: String, ) : StandardScreen( allowDonate, imageResource = imageResource, headlineText = headlineText, bodyText = bodyText, + slideName = slideName ) class CustomIconScreen( allowDonate: Boolean = true, headlineText: Any? = null, bodyText: Any? = null, + slideName: String, val showDonateButton: Boolean = false ) : StandardScreen( allowDonate = allowDonate, imageResource = R.drawable.launcher_foreground_yir25, headlineText = headlineText, bodyText = bodyText, + slideName = slideName, showDonateInToolbar = !showDonateButton ) { @Composable @@ -201,7 +208,9 @@ private fun CustomIconScreenHeaderPreview() { Box( modifier = Modifier.size(400.dp, 300.dp) ) { - CustomIconScreen().Header( + CustomIconScreen( + slideName = "test" + ).Header( context = LocalContext.current, screenCaptureMode = false, aspectRatio = 1f @@ -217,7 +226,11 @@ private fun CustomIconScreenButtonPreview() { Box( modifier = Modifier.size(400.dp, 200.dp) ) { - CustomIconScreen(allowDonate = true, showDonateButton = true).BottomButton( + CustomIconScreen( + allowDonate = true, + showDonateButton = true, + slideName = "test" + ).BottomButton( context = LocalContext.current, onButtonClick = {} ) diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewSlides.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewSlides.kt index 03cbc733679..31b3e620bbb 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewSlides.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewSlides.kt @@ -41,7 +41,8 @@ class YearInReviewSlides( allowDonate = isFundraisingAllowed, imageResource = R.drawable.yir_puzzle_clock, headlineText = context.resources.getQuantityString(R.plurals.year_in_review_slide_english_reading_hours_headline, config.hoursReadEN.toInt(), config.hoursReadEN), - bodyText = bodyText + bodyText = bodyText, + slideName = "lo_en_collhours" ) } @@ -64,6 +65,7 @@ class YearInReviewSlides( yearInReviewModel.localReadingArticlesCount > it.min && yearInReviewModel.localReadingArticlesCount <= it.max }?.identifier + var slideName: String var bodyText = "" rankPercentage?.let { bodyText += context.resources.getQuantityString(R.plurals.year_in_review_slide_spent_minutes_reading_body_top, @@ -71,11 +73,13 @@ class YearInReviewSlides( } bodyText += if (isEnglishWiki) { + slideName = "li_en_readcount" context.resources.getQuantityString(R.plurals.year_in_review_slide_spent_minutes_reading_body_english_first, config.hoursReadEN.toInt(), config.hoursReadEN) + " " + context.resources.getQuantityString(R.plurals.year_in_review_slide_spent_minutes_reading_body_english_second, config.yearsReadEN, config.yearsReadEN, currentYear) } else { + slideName = "li_non_readcount" context.resources.getQuantityString(R.plurals.year_in_review_slide_spent_minutes_reading_body_global_first, config.articles.toInt(), config.articles) + " " + context.resources.getQuantityString(R.plurals.year_in_review_slide_spent_minutes_reading_body_global_second, @@ -87,7 +91,8 @@ class YearInReviewSlides( imageResource = R.drawable.yir_puzzle_walk, imageModifier = Modifier.fillMaxSize(), headlineText = headlineText, - bodyText = bodyText + bodyText = bodyText, + slideName = slideName ) } @@ -101,16 +106,23 @@ class YearInReviewSlides( imageResource = R.drawable.yir_puzzle_browser, headlineText = context.getString(R.string.year_in_review_slide_popular_english_articles_headline), bodyText = context.resources.getQuantityString(R.plurals.year_in_review_slide_popular_english_articles_body, - config.topReadEN.size, config.topReadEN.size, popularEnglishArticlesText, popularEnglishArticlesBlogUrl) + config.topReadEN.size, config.topReadEN.size, popularEnglishArticlesText, popularEnglishArticlesBlogUrl), + slideName = if (isLoggedIn) "li_en_popular" else "lo_en_popular" ) } private fun appSavedArticlesScreen(): StandardScreen { + val slideName = if (isEnglishWiki) { + if (isLoggedIn) "li_en_collrlists" else "lo_en_collrlists" + } else { + if (isLoggedIn) "li_non_collrlists" else "lo_non_collrlists" + } return StandardScreen( allowDonate = isFundraisingAllowed, imageResource = R.drawable.yir_puzzle_cloud, headlineText = context.resources.getQuantityString(R.plurals.year_in_review_slide_global_saved_articles_headline, config.savedArticlesApps.toInt(), config.savedArticlesApps), - bodyText = context.getString(R.string.year_in_review_slide_global_saved_articles_body) + bodyText = context.getString(R.string.year_in_review_slide_global_saved_articles_body), + slideName = slideName ) } @@ -123,7 +135,8 @@ class YearInReviewSlides( allowDonate = isFundraisingAllowed, imageResource = R.drawable.yir_puzzle_stone, headlineText = context.resources.getQuantityString(R.plurals.year_in_review_slide_available_languages_headline, config.languages, config.languages), - bodyText = bodyText + bodyText = bodyText, + slideName = if (isLoggedIn) "li_non_langs" else "lo_non_langs" ) } @@ -132,7 +145,8 @@ class YearInReviewSlides( allowDonate = isFundraisingAllowed, imageResource = R.drawable.yir_puzzle_browser, headlineText = context.resources.getQuantityString(R.plurals.year_in_review_slide_viewed_articles_times_headline, config.viewsApps.toInt(), config.viewsApps), - bodyText = context.getString(R.string.year_in_review_slide_viewed_articles_times_body) + bodyText = context.getString(R.string.year_in_review_slide_viewed_articles_times_body), + slideName = if (isLoggedIn) "li_non_collappread" else "lo_non_collappread" ) } @@ -156,6 +170,7 @@ class YearInReviewSlides( allowDonate = isFundraisingAllowed, imageResource = R.drawable.yir_puzzle_clock, headlineText = context.getString(R.string.year_in_review_slide_reading_patterns_headline), + slideName = if (isEnglishWiki) "li_en_readpattern" else "li_non_readpattern", favoriteTimeText = favoriteTimeText, favoriteDayText = favoriteDayText, favoriteMonthText = favoriteMonthText @@ -173,7 +188,8 @@ class YearInReviewSlides( allowDonate = isFundraisingAllowed, imageResource = R.drawable.yir_puzzle_farmer, headlineText = context.getString(R.string.year_in_review_slide_top_categories_headline), - bodyText = context.getString(R.string.year_in_review_slide_top_categories_body, currentYear, topCategoriesText) + bodyText = context.getString(R.string.year_in_review_slide_top_categories_body, currentYear, topCategoriesText), + slideName = if (isEnglishWiki) "li_en_readcategory" else "li_non_readcategory" ) } @@ -189,7 +205,8 @@ class YearInReviewSlides( allowDonate = isFundraisingAllowed, imageResource = R.drawable.yir_puzzle_sundial, headlineText = context.resources.getQuantityString(R.plurals.year_in_review_slide_top_articles_headline, quantity), - bodyText = context.resources.getQuantityString(R.plurals.year_in_review_slide_top_articles_body, quantity, currentYear, topArticlesText) + bodyText = context.resources.getQuantityString(R.plurals.year_in_review_slide_top_articles_body, quantity, currentYear, topArticlesText), + slideName = if (isEnglishWiki) "li_en_toparticles" else "li_non_toparticles" ) } @@ -203,7 +220,8 @@ class YearInReviewSlides( largestClusterBottomRight = yearInReviewModel.largestClusterBottomRight, pagesWithCoordinates = pagesWithCoordinates, headlineText = context.resources.getString(R.string.year_in_review_slide_geo_headline, yearInReviewModel.largestClusterCountryName), - bodyText = context.resources.getString(R.string.year_in_review_slide_geo_body, yearInReviewModel.largestClusterCountryName, yearInReviewModel.largestClusterArticles[0], yearInReviewModel.largestClusterArticles[1]) + bodyText = context.resources.getString(R.string.year_in_review_slide_geo_body, yearInReviewModel.largestClusterCountryName, yearInReviewModel.largestClusterArticles[0], yearInReviewModel.largestClusterArticles[1]), + slideName = if (isEnglishWiki) "li_en_readgeo" else "li_non_readgeo" ) } @@ -218,7 +236,8 @@ class YearInReviewSlides( headlineText = context.resources.getQuantityString(R.plurals.year_in_review_slide_saved_articles_headline, yearInReviewModel.localSavedArticlesCount, yearInReviewModel.localSavedArticlesCount), bodyText = context.resources.getQuantityString(R.plurals.year_in_review_slide_saved_articles_body, appSavedArticlesSize, yearInReviewModel.localSavedArticles[0], yearInReviewModel.localSavedArticles[1], - yearInReviewModel.localSavedArticles[2], config.savedArticlesApps) + yearInReviewModel.localSavedArticles[2], config.savedArticlesApps), + slideName = if (isEnglishWiki) "li_en_savedcount" else "li_non_savedcount" ) } @@ -232,7 +251,8 @@ class YearInReviewSlides( allowDonate = isFundraisingAllowed, imageResource = R.drawable.yir_puzzle_worker, headlineText = context.resources.getQuantityString(R.plurals.year_in_review_slide_edited_times_headline, userEditsCount, formattedUserEditsNumber), - bodyText = context.resources.getQuantityString(R.plurals.year_in_review_slide_edited_times_body, config.edits.toInt(), config.edits) + bodyText = context.resources.getQuantityString(R.plurals.year_in_review_slide_edited_times_body, config.edits.toInt(), config.edits), + slideName = if (isEnglishWiki) "li_en_editedcount" else "li_non_editedcount" ) } @@ -245,7 +265,8 @@ class YearInReviewSlides( allowDonate = isFundraisingAllowed, imageResource = R.drawable.yir_puzzle_pencil, headlineText = context.resources.getQuantityString(R.plurals.year_in_review_slide_edits_viewed_times_headline, quantity, yearInReviewModel.userEditsViewedTimes), - bodyText = context.resources.getQuantityString(R.plurals.year_in_review_slide_edits_viewed_times_body, quantity, yearInReviewModel.userEditsViewedTimes) + bodyText = context.resources.getQuantityString(R.plurals.year_in_review_slide_edits_viewed_times_body, quantity, yearInReviewModel.userEditsViewedTimes), + slideName = if (isEnglishWiki) "li_en_editviewcount" else "li_non_editviewcount" ) } @@ -254,7 +275,8 @@ class YearInReviewSlides( allowDonate = isFundraisingAllowed, imageResource = R.drawable.yir_puzzle_worker, headlineText = context.resources.getQuantityString(R.plurals.year_in_review_slide_app_edited_times_headline, config.edits.toInt(), config.edits), - bodyText = context.getString(R.string.year_in_review_slide_app_edited_times_body) + bodyText = context.getString(R.string.year_in_review_slide_app_edited_times_body), + slideName = if (isLoggedIn) "li_non_appcolledits" else "lo_non_appcolledits" ) } @@ -264,7 +286,8 @@ class YearInReviewSlides( imageResource = R.drawable.yir_puzzle_bytes, imageModifier = Modifier.fillMaxSize(), headlineText = context.resources.getQuantityString(R.plurals.year_in_review_slide_edited_per_minute_headline, config.editsPerMinute, config.editsPerMinute), - bodyText = context.getString(R.string.year_in_review_slide_edited_per_minute_body, context.getString(R.string.editing_learn_more_url)) + bodyText = context.getString(R.string.year_in_review_slide_edited_per_minute_body, context.getString(R.string.editing_learn_more_url)), + slideName = if (isLoggedIn) "li_non_colleditspm" else "lo_non_colleditspm" ) } @@ -278,7 +301,8 @@ class YearInReviewSlides( imageResource = R.drawable.yir_puzzle_worker, imageModifier = Modifier.fillMaxSize(), headlineText = context.resources.getQuantityString(R.plurals.year_in_review_slide_english_edited_times_headline, config.edits.toInt(), config.edits), - bodyText = bodyText + bodyText = bodyText, + slideName = if (isLoggedIn) "li_en_changes" else "lo_en_changes" ) } @@ -289,7 +313,8 @@ class YearInReviewSlides( imageModifier = Modifier.fillMaxSize(), headlineText = context.resources.getQuantityString(R.plurals.year_in_review_slide_bytes_added_headline, config.bytesAddedEN.toInt(), config.bytesAddedEN), bodyText = context.resources.getQuantityString(R.plurals.year_in_review_slide_bytes_added_body, - config.bytesAddedEN.toInt(), currentYear, config.bytesAddedEN, context.getString(R.string.editing_learn_more_url)) + config.bytesAddedEN.toInt(), currentYear, config.bytesAddedEN, context.getString(R.string.editing_learn_more_url)), + slideName = if (isLoggedIn) "li_en_bytes" else "lo_en_bytes" ) } @@ -340,7 +365,8 @@ class YearInReviewSlides( ) ) } - } + }, + slideName = if (isEnglishWiki) "li_en_summary" else "li_non_summary" ) } @@ -360,7 +386,8 @@ class YearInReviewSlides( title = context.resources.getQuantityString(R.plurals.year_in_review_highlights_logged_out_en_edits_title, config.editsEN.toInt()), singleValue = numberFormatter.format(config.editsEN) ) - ) + ), + slideName = "lo_en_summary" ) } @@ -379,7 +406,8 @@ class YearInReviewSlides( title = context.resources.getString(R.string.year_in_review_highlights_logged_out_non_en_wikipedia_edited_title), singleValue = context.resources.getQuantityString(R.plurals.year_in_review_highlights_logged_out_non_en_wikipedia_per_minute_label, config.editsPerMinute, config.editsPerMinute) ) - ) + ), + slideName = "lo_non_summary" ) } @@ -405,6 +433,10 @@ class YearInReviewSlides( } private fun unlockedIconRoute(): YearInReviewScreenData? { + val slideNamePrefix = if (isLoggedIn) "li" else "lo" + val slideNameLang = if (isEnglishWiki) "en" else "non" + val slideNameUnlock = if (isFundraisingAllowed) "nondonoricon" else "donoricon" + val slideName = slideNamePrefix + "_" + slideNameLang + "_" + slideNameUnlock return if (yearInReviewModel.isCustomIconUnlocked) { val contributorType = if (yearInReviewModel.userEditsCount > 0 && Prefs.donationResults.isNotEmpty()) { context.getString(R.string.year_in_review_slide_app_icon_donor_and_editor) @@ -416,7 +448,8 @@ class YearInReviewSlides( CustomIconScreen( isFundraisingAllowed, headlineText = R.string.year_in_review_slide_app_icon_title_unlocked, - bodyText = context.getString(R.string.year_in_review_slide_app_icon_body_unlocked, contributorType, YearInReviewViewModel.YIR_YEAR) + bodyText = context.getString(R.string.year_in_review_slide_app_icon_body_unlocked, contributorType, YearInReviewViewModel.YIR_YEAR), + slideName = slideName ) } else if (isFundraisingAllowed) { CustomIconScreen( @@ -424,6 +457,7 @@ class YearInReviewSlides( headlineText = R.string.year_in_review_slide_app_icon_title_unlock, bodyText = context.getString(R.string.year_in_review_slide_app_icon_body_unlock, YearInReviewViewModel.YIR_YEAR, YearInReviewViewModel.YIR_YEAR + 1, context.getString(R.string.editing_learn_more_url), context.getString(R.string.apps_about_wmf_url)), + slideName = slideName, showDonateButton = true ) } else null From 983a337f7c2b18ab32d52e354ab231cfc77b0ed2 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Tue, 4 Nov 2025 16:27:28 -0800 Subject: [PATCH 04/13] Fix --- .../yearinreview/YearInReviewHighlightsScreen.kt | 3 ++- .../org/wikipedia/yearinreview/YearInReviewScreenDeck.kt | 9 ++++++--- 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewHighlightsScreen.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewHighlightsScreen.kt index ba9f9065188..60595a34e83 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewHighlightsScreen.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewHighlightsScreen.kt @@ -269,7 +269,8 @@ private fun YearInReviewHighlightsScreenPreview() { ), highlightColor = ComposeColors.Blue600 ) - ) + ), + slideName = "test" ), onShareHighlightsBtnClick = {} ) diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt index 4a5af347098..6a1b30fa5a5 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt @@ -561,7 +561,8 @@ fun PreviewScreenShot() { allowDonate = true, imageResource = R.drawable.yir_puzzle_browser, headlineText = "Over 3 billion bytes added", - bodyText = "TBD" + bodyText = "TBD", + slideName = "test" ), requestScreenshotBitmap = null ) { /* No logic, preview only */ } @@ -578,7 +579,8 @@ fun PreviewStandardContent() { allowDonate = true, imageResource = R.drawable.yir_puzzle_bytes, headlineText = "Over 3 billion bytes added", - bodyText = "TBD" + bodyText = "TBD", + slideName = "test" ) )), requestScreenshotBitmap = null @@ -599,7 +601,8 @@ fun PreviewReadingPatternsContent() { bodyText = "", favoriteTimeText = "Afternoon", favoriteDayText = "Wednesday", - favoriteMonthText = "February" + favoriteMonthText = "February", + slideName = "test" ) )), requestScreenshotBitmap = null From 248710c68d04c14564844efde9905d302e36a216 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Tue, 4 Nov 2025 17:11:38 -0800 Subject: [PATCH 05/13] Wire up click actions --- .../eventplatform/YearInReviewEvent.kt | 4 ++- .../yearinreview/YearInReviewActivity.kt | 13 +++++---- .../yearinreview/YearInReviewScreenData.kt | 28 +++++++++++++------ .../yearinreview/YearInReviewScreenDeck.kt | 23 +++++++++++---- 4 files changed, 47 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/org/wikipedia/analytics/eventplatform/YearInReviewEvent.kt b/app/src/main/java/org/wikipedia/analytics/eventplatform/YearInReviewEvent.kt index efcf2d4b6b2..0d8eda669e0 100644 --- a/app/src/main/java/org/wikipedia/analytics/eventplatform/YearInReviewEvent.kt +++ b/app/src/main/java/org/wikipedia/analytics/eventplatform/YearInReviewEvent.kt @@ -21,7 +21,9 @@ open class YearInReviewEvent { action = action, active_interface = activeInterface, action_data = JsonUtil.encodeToString(ActionData( - campaignId = campaignId?.let { "campaign_id: ${CampaignCollection.getFormattedCampaignId(it)}" }, + campaignId = campaignId?.let { + CampaignCollection.getFormattedCampaignId(it) + }, slide = slide )).orEmpty(), primary_language = WikipediaApp.instance.languageState.appLanguageCode, diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewActivity.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewActivity.kt index 7d3e482d3e8..6ffc5ddd5f6 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewActivity.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewActivity.kt @@ -16,8 +16,8 @@ import androidx.navigation.compose.rememberNavController import kotlinx.coroutines.launch import org.wikipedia.activity.BaseActivity import org.wikipedia.analytics.eventplatform.BreadCrumbLogEvent -import org.wikipedia.analytics.eventplatform.DonorExperienceEvent import org.wikipedia.analytics.eventplatform.EventPlatformClient +import org.wikipedia.analytics.eventplatform.YearInReviewEvent import org.wikipedia.compose.theme.BaseTheme import org.wikipedia.settings.Prefs @@ -69,18 +69,19 @@ class YearInReviewActivity : BaseActivity() { finish() } }, - onDonateClick = { + onDonateClick = { currentSlide -> EventPlatformClient.submit( BreadCrumbLogEvent( screen_name = "year_in_review", action = "donate_click") ) - DonorExperienceEvent.logAction( + val campaignId = "appmenu_yir_$currentSlide" + YearInReviewEvent.submit( action = "donate_start_click_yir", - activeInterface = "wiki_yir", - campaignId = "yir" + slide = currentSlide, + campaignId = campaignId ) - launchDonateDialog("yir") + launchDonateDialog(campaignId) // TODO: confirm with Shay }, onRetryClick = { viewModel.fetchPersonalizedData() diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenData.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenData.kt index 80c2931f074..d1727d6135d 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenData.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenData.kt @@ -59,7 +59,8 @@ fun Modifier.yearInReviewHeaderBackground(): Modifier { sealed class YearInReviewScreenData( val allowDonate: Boolean = true, - val showDonateInToolbar: Boolean = true + val showDonateInToolbar: Boolean = true, + val slideName: String ) { @Composable @@ -72,9 +73,13 @@ sealed class YearInReviewScreenData( val imageModifier: Modifier = Modifier.size(200.dp), val headlineText: Any? = null, val bodyText: Any? = null, - val slideName: String, + slideName: String, showDonateInToolbar: Boolean = true - ) : YearInReviewScreenData(allowDonate, showDonateInToolbar) { + ) : YearInReviewScreenData( + allowDonate = allowDonate, + showDonateInToolbar = showDonateInToolbar, + slideName = slideName + ) { @Composable open fun Header(context: Context, @@ -126,20 +131,25 @@ sealed class YearInReviewScreenData( val highlightColor: Color = ComposeColors.Gray700 ) - data class HighlightsScreen( + open class HighlightsScreen( val highlights: List, - val slideName: String - ) : YearInReviewScreenData() + slideName: String + ) : YearInReviewScreenData( + slideName = slideName + ) - class GeoScreen( + open class GeoScreen( allowDonate: Boolean = true, val largestClusterTopLeft: Pair, val largestClusterBottomRight: Pair, val pagesWithCoordinates: List, val headlineText: String? = null, val bodyText: String? = null, - val slideName: String - ) : YearInReviewScreenData(allowDonate) + slideName: String + ) : YearInReviewScreenData( + allowDonate = allowDonate, + slideName = slideName + ) class ReadingPatterns( allowDonate: Boolean = true, diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt index 6a1b30fa5a5..8fa1c8ee78d 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt @@ -61,6 +61,7 @@ import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp import androidx.core.net.toUri import org.wikipedia.R +import org.wikipedia.analytics.eventplatform.YearInReviewEvent import org.wikipedia.compose.components.HtmlText import org.wikipedia.compose.components.error.WikiErrorClickEvents import org.wikipedia.compose.components.error.WikiErrorView @@ -77,7 +78,7 @@ fun YearInReviewScreenDeck( modifier: Modifier = Modifier, state: UiState>, requestScreenshotBitmap: ((Int, Int) -> Bitmap)?, - onDonateClick: () -> Unit = {}, + onDonateClick: (String) -> Unit = {}, onNextButtonClick: (PagerState, YearInReviewScreenData) -> Unit = { _, _ -> }, onCloseButtonClick: () -> Unit = {}, onRetryClick: () -> Unit = {} @@ -116,7 +117,10 @@ fun YearInReviewScreenDeck( ), title = { }, navigationIcon = { - IconButton(onClick = { onCloseButtonClick() }) { + IconButton(onClick = { + YearInReviewEvent.submit(action = "close_click", slide = pages[pagerState.currentPage].slideName) + onCloseButtonClick() + }) { Icon( painter = painterResource(R.drawable.ic_close_black_24dp), tint = WikipediaTheme.colors.primaryColor, @@ -128,7 +132,9 @@ fun YearInReviewScreenDeck( if (pages[pagerState.currentPage].allowDonate && pages[pagerState.currentPage].showDonateInToolbar) { Box( modifier = Modifier - .clickable(onClick = { onDonateClick() }) + .clickable(onClick = { + onDonateClick(pages[pagerState.currentPage].slideName) + }) ) { Row( modifier = Modifier @@ -157,17 +163,23 @@ fun YearInReviewScreenDeck( bottomBar = { MainBottomBar( pages, - onNavigationRightClick = { onNextButtonClick(pagerState, pages[pagerState.currentPage]) }, + onNavigationRightClick = { + YearInReviewEvent.submit(action = "next_click", slide = pages[pagerState.currentPage].slideName) + onNextButtonClick(pagerState, pages[pagerState.currentPage]) + }, pagerState = pagerState, totalPages = pages.size, onShareClick = { + YearInReviewEvent.submit(action = "share_click", slide = pages[pagerState.currentPage].slideName) when (pages[pagerState.currentPage]) { is YearInReviewScreenData.GeoScreen -> { captureRequest = YearInReviewCaptureRequest.GeoScreen(pages[pagerState.currentPage], requestScreenshotBitmap) } is YearInReviewScreenData.StandardScreen -> { captureRequest = YearInReviewCaptureRequest.StandardScreen(pages[pagerState.currentPage]) } is YearInReviewScreenData.HighlightsScreen -> {} } }, - onDonateClick = onDonateClick + onDonateClick = { + onDonateClick(pages[pagerState.currentPage].slideName) + } ) }, content = { paddingValues -> @@ -382,6 +394,7 @@ fun YearInReviewScreenContent( onShareHighlightsBtnClick: ((List) -> Unit)? = null, isImageResourceLoaded: ((Boolean) -> Unit)? = null ) { + YearInReviewEvent.submit(action = "impression", slide = screenData.slideName) when (screenData) { is YearInReviewScreenData.StandardScreen -> { StandardScreenContent( From e8e3a3b147c80e9fe4123f0c8325f8fd33dc15b3 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Tue, 4 Nov 2025 17:33:17 -0800 Subject: [PATCH 06/13] Only send impression for the current slide --- .../org/wikipedia/yearinreview/YearInReviewScreenDeck.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt index 8fa1c8ee78d..772e31a4fd4 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt @@ -188,6 +188,12 @@ fun YearInReviewScreenDeck( state = pagerState, contentPadding = PaddingValues(0.dp), ) { page -> + if (page == pagerState.currentPage) { + YearInReviewEvent.submit( + action = "impression", + slide = pages[page].slideName + ) + } YearInReviewScreenContent( modifier = Modifier .fillMaxSize() @@ -394,7 +400,6 @@ fun YearInReviewScreenContent( onShareHighlightsBtnClick: ((List) -> Unit)? = null, isImageResourceLoaded: ((Boolean) -> Unit)? = null ) { - YearInReviewEvent.submit(action = "impression", slide = screenData.slideName) when (screenData) { is YearInReviewScreenData.StandardScreen -> { StandardScreenContent( From b6c2531e745bb2f01aed99bf12f6bb045afeba3b Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Tue, 4 Nov 2025 17:34:49 -0800 Subject: [PATCH 07/13] Fix lint --- .../java/org/wikipedia/yearinreview/YearInReviewScreenData.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenData.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenData.kt index d1727d6135d..00e6fcff811 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenData.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenData.kt @@ -138,7 +138,7 @@ sealed class YearInReviewScreenData( slideName = slideName ) - open class GeoScreen( + open class GeoScreen( allowDonate: Boolean = true, val largestClusterTopLeft: Pair, val largestClusterBottomRight: Pair, From b859418b7eb90d40ac120d382521b3433ed9a075 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Wed, 5 Nov 2025 16:26:14 -0800 Subject: [PATCH 08/13] Update after discussion --- .../activity/SingleWebViewActivity.kt | 19 +++++++++++++++++-- .../createaccount/CreateAccountActivity.kt | 4 ++-- .../java/org/wikipedia/donate/DonateDialog.kt | 16 ++++++++++++---- .../java/org/wikipedia/page/PageActivity.kt | 3 +++ .../yearinreview/YearInReviewActivity.kt | 4 +++- .../YearInReviewOnboardingActivity.kt | 8 ++++---- 6 files changed, 41 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/org/wikipedia/activity/SingleWebViewActivity.kt b/app/src/main/java/org/wikipedia/activity/SingleWebViewActivity.kt index e0507fc85c2..749e00e1431 100644 --- a/app/src/main/java/org/wikipedia/activity/SingleWebViewActivity.kt +++ b/app/src/main/java/org/wikipedia/activity/SingleWebViewActivity.kt @@ -22,6 +22,7 @@ import org.wikipedia.Constants import org.wikipedia.R import org.wikipedia.WikipediaApp import org.wikipedia.analytics.eventplatform.DonorExperienceEvent +import org.wikipedia.analytics.eventplatform.YearInReviewEvent import org.wikipedia.bridge.JavaScriptActionHandler import org.wikipedia.databinding.ActivitySingleWebViewBinding import org.wikipedia.dataclient.SharedPreferenceCookieManager @@ -177,8 +178,21 @@ class SingleWebViewActivity : BaseActivity() { } private fun goBack() { - if (intent.getStringExtra(EXTRA_PAGE_CONTENT_INFO).orEmpty() == PAGE_CONTENT_SOURCE_DONOR_EXPERIENCE) { - DonorExperienceEvent.logAction("article_return_click", "webpay_processed") + if (!intent.getStringExtra(EXTRA_PAGE_CONTENT_INFO).isNullOrEmpty()) { + val extraPageContentInfo = intent.getStringExtra(EXTRA_PAGE_CONTENT_INFO) + when (extraPageContentInfo) { + PAGE_CONTENT_SOURCE_DONOR_EXPERIENCE -> { + DonorExperienceEvent.logAction("article_return_click", "webpay_processed") + } + PAGE_CONTENT_SOURCE_YIR -> { + YearInReviewEvent.submit( + action = "article_return_click", + slide = "webpay_processed", + campaignId = "" // TODO: tbd + ) + } + else -> { } + } } pageTitleToLoadOnBackPress?.let { val entry = HistoryEntry(it, HistoryEntry.SOURCE_SINGLE_WEBVIEW) @@ -208,6 +222,7 @@ class SingleWebViewActivity : BaseActivity() { const val EXTRA_SHOW_BACK_BUTTON = "goBack" const val EXTRA_PAGE_CONTENT_INFO = "pageContentInfo" const val PAGE_CONTENT_SOURCE_DONOR_EXPERIENCE = "donorExperience" + const val PAGE_CONTENT_SOURCE_YIR = "yearInReview" const val EXTRA_IS_WEB_FORM = "isWebForm" fun newIntent(context: Context, url: String, showBackButton: Boolean = false, pageTitleToLoadOnBackPress: PageTitle? = null, diff --git a/app/src/main/java/org/wikipedia/createaccount/CreateAccountActivity.kt b/app/src/main/java/org/wikipedia/createaccount/CreateAccountActivity.kt index a0f93773a04..287db2f6b0f 100644 --- a/app/src/main/java/org/wikipedia/createaccount/CreateAccountActivity.kt +++ b/app/src/main/java/org/wikipedia/createaccount/CreateAccountActivity.kt @@ -156,7 +156,7 @@ class CreateAccountActivity : BaseActivity() { binding.viewCreateAccountError.retryClickListener = View.OnClickListener { binding.viewCreateAccountError.visibility = View.GONE } binding.createAccountSubmitButton.setOnClickListener { if (requestSource == LoginActivity.SOURCE_YEAR_IN_REVIEW) { - YearInReviewEvent.submit(action = "create_account_click", slide = "entry_a") + YearInReviewEvent.submit(action = "create_account_click", slide = "explore_prompt") } validateThenCreateAccount() } @@ -165,7 +165,7 @@ class CreateAccountActivity : BaseActivity() { } binding.createAccountLoginButton.setOnClickListener { if (requestSource == LoginActivity.SOURCE_YEAR_IN_REVIEW) { - YearInReviewEvent.submit(action = "login_click", slide = "entry_a") + YearInReviewEvent.submit(action = "login_click", slide = "explore_prompt") } // This assumes that the CreateAccount activity was launched from the Login activity // (since there's currently no other mechanism to invoke CreateAccountActivity), diff --git a/app/src/main/java/org/wikipedia/donate/DonateDialog.kt b/app/src/main/java/org/wikipedia/donate/DonateDialog.kt index 8a3c6fba186..5aab211b3b5 100644 --- a/app/src/main/java/org/wikipedia/donate/DonateDialog.kt +++ b/app/src/main/java/org/wikipedia/donate/DonateDialog.kt @@ -36,14 +36,20 @@ class DonateDialog : ExtendedBottomSheetDialogFragment() { _binding = DialogDonateBinding.inflate(inflater, container, false) campaignId = arguments?.getString(ARG_CAMPAIGN_ID) + val activeInterface = if (arguments?.getBoolean(ARG_FROM_YIR) == true) { + "wiki_yir" + } else { + if (campaignId.isNullOrEmpty()) "setting" else "article_banner" + } + binding.donateOtherButton.setOnClickListener { - DonorExperienceEvent.logAction("webpay_click", if (campaignId.isNullOrEmpty()) "setting" else "article_banner", campaignId = campaignId) + DonorExperienceEvent.logAction("webpay_click", activeInterface, campaignId = campaignId) onDonateClicked() } binding.donateGooglePayButton.setOnClickListener { invalidateCampaign() - DonorExperienceEvent.logAction("gpay_click", if (campaignId.isNullOrEmpty()) "setting" else "article_banner", campaignId = campaignId) + DonorExperienceEvent.logAction("gpay_click", activeInterface, campaignId = campaignId) (requireActivity() as? BaseActivity)?.launchDonateActivity( GooglePayComponent.getDonateActivityIntent(requireActivity(), campaignId, arguments?.getString(ARG_DONATE_URL))) } @@ -146,13 +152,15 @@ class DonateDialog : ExtendedBottomSheetDialogFragment() { const val ARG_CAMPAIGN_ID = "campaignId" const val ARG_DONATE_URL = "donateUrl" const val ARG_FROM_DONATION_REMINDER = "fromDonationReminder" + const val ARG_FROM_YIR = "fromYiR" - fun newInstance(campaignId: String? = null, donateUrl: String? = null, fromDonationReminder: Boolean = false): DonateDialog { + fun newInstance(campaignId: String? = null, donateUrl: String? = null, fromDonationReminder: Boolean = false, fromYiR: Boolean = false): DonateDialog { return DonateDialog().apply { arguments = bundleOf( ARG_CAMPAIGN_ID to campaignId, ARG_DONATE_URL to donateUrl, - ARG_FROM_DONATION_REMINDER to fromDonationReminder + ARG_FROM_DONATION_REMINDER to fromDonationReminder, + ARG_FROM_YIR to fromYiR, ) } } diff --git a/app/src/main/java/org/wikipedia/page/PageActivity.kt b/app/src/main/java/org/wikipedia/page/PageActivity.kt index 8d30d7563a9..0bb9f4e3302 100644 --- a/app/src/main/java/org/wikipedia/page/PageActivity.kt +++ b/app/src/main/java/org/wikipedia/page/PageActivity.kt @@ -549,6 +549,9 @@ class PageActivity : BaseActivity(), PageFragment.Callback, LinkPreviewDialog.Lo // Check if the donation started from the app, but completed via web, in which case // show it in a SingleWebViewActivity. val campaign = uri.getQueryParameter("wmf_campaign") + + // TODO: check if we want to keep the campaignId in memory. + if (campaign != null && campaign == "Android") { DonorExperienceEvent.logAction("impression", "webpay_processed", wiki.languageCode) startActivity(SingleWebViewActivity.newIntent(this@PageActivity, uri.toString(), diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewActivity.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewActivity.kt index 6ffc5ddd5f6..9f513c4c26d 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewActivity.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewActivity.kt @@ -19,6 +19,8 @@ import org.wikipedia.analytics.eventplatform.BreadCrumbLogEvent import org.wikipedia.analytics.eventplatform.EventPlatformClient import org.wikipedia.analytics.eventplatform.YearInReviewEvent import org.wikipedia.compose.theme.BaseTheme +import org.wikipedia.donate.DonateDialog +import org.wikipedia.page.ExclusiveBottomSheetPresenter import org.wikipedia.settings.Prefs class YearInReviewActivity : BaseActivity() { @@ -81,7 +83,7 @@ class YearInReviewActivity : BaseActivity() { slide = currentSlide, campaignId = campaignId ) - launchDonateDialog(campaignId) // TODO: confirm with Shay + ExclusiveBottomSheetPresenter.show(supportFragmentManager, DonateDialog.newInstance(campaignId = campaignId, fromYiR = true)) }, onRetryClick = { viewModel.fetchPersonalizedData() diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewOnboardingActivity.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewOnboardingActivity.kt index cef4180afdc..df6db382bbe 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewOnboardingActivity.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewOnboardingActivity.kt @@ -30,7 +30,7 @@ class YearInReviewOnboardingActivity : BaseActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - YearInReviewEvent.submit(action = "impression", slide = "entry_a") + YearInReviewEvent.submit(action = "impression", slide = "explore_prompt") Prefs.yearInReviewVisited = true setContent { BaseTheme { @@ -45,11 +45,11 @@ class YearInReviewOnboardingActivity : BaseActivity() { showLoginDialog = false }, onConfirmButtonClick = { - YearInReviewEvent.submit(action = "login_click", slide = "entry_a") + YearInReviewEvent.submit(action = "login_click", slide = "explore_prompt") loginLauncher.launch(LoginActivity.newIntent(this, LoginActivity.SOURCE_YEAR_IN_REVIEW)) }, onDismissButtonClick = { - YearInReviewEvent.submit(action = "continue_click", slide = "entry_a") + YearInReviewEvent.submit(action = "continue_click", slide = "explore_prompt") proceed() } ) @@ -57,7 +57,7 @@ class YearInReviewOnboardingActivity : BaseActivity() { YearInReviewOnboardingScreen( onBackButtonClick = { - YearInReviewEvent.submit(action = "close_click", slide = "entry_a") + YearInReviewEvent.submit(action = "close_click", slide = "explore_prompt") setResult(RESULT_CANCELED) finish() }, From eb9d96a16c3468e99381e05da13205391a284add Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Wed, 5 Nov 2025 16:49:59 -0800 Subject: [PATCH 09/13] Wire up survey --- .../eventplatform/YearInReviewEvent.kt | 11 +++++-- .../readinglist/ReadingListFragment.kt | 2 ++ .../yearinreview/YearInReviewDialog.kt | 33 ++++++++++++++++--- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/wikipedia/analytics/eventplatform/YearInReviewEvent.kt b/app/src/main/java/org/wikipedia/analytics/eventplatform/YearInReviewEvent.kt index 0d8eda669e0..9e31d2d4669 100644 --- a/app/src/main/java/org/wikipedia/analytics/eventplatform/YearInReviewEvent.kt +++ b/app/src/main/java/org/wikipedia/analytics/eventplatform/YearInReviewEvent.kt @@ -12,8 +12,11 @@ open class YearInReviewEvent { fun submit( action: String, activeInterface: String = "wiki_yir", + groupAssigned: String? = null, campaignId: String? = null, - slide: String, + slide: String? = null, + feedbackSelect: Int? = null, + feedbackText: String? = null, wikiId: String = WikipediaApp.instance.appOrSystemLanguageCode ) { EventPlatformClient.submit( @@ -24,7 +27,10 @@ open class YearInReviewEvent { campaignId = campaignId?.let { CampaignCollection.getFormattedCampaignId(it) }, - slide = slide + groupAssigned = groupAssigned, + slide = slide, + feedbackSelect = feedbackSelect, + feedbackText = feedbackText )).orEmpty(), primary_language = WikipediaApp.instance.languageState.appLanguageCode, wiki_id = wikiId, @@ -38,6 +44,7 @@ open class YearInReviewEvent { class ActionData( val slide: String? = null, @SerialName("campaign_id") val campaignId: String? = null, + @SerialName("group_assigned") val groupAssigned: String? = null, @SerialName("feedback_select") val feedbackSelect: Int? = null, @SerialName("feedback_text") val feedbackText: String? = null ) diff --git a/app/src/main/java/org/wikipedia/readinglist/ReadingListFragment.kt b/app/src/main/java/org/wikipedia/readinglist/ReadingListFragment.kt index a7dd3b2a104..2e4ca16b853 100644 --- a/app/src/main/java/org/wikipedia/readinglist/ReadingListFragment.kt +++ b/app/src/main/java/org/wikipedia/readinglist/ReadingListFragment.kt @@ -43,6 +43,7 @@ import org.wikipedia.R import org.wikipedia.activity.BaseActivity import org.wikipedia.analytics.eventplatform.ReadingListsAnalyticsHelper import org.wikipedia.analytics.eventplatform.RecommendedReadingListEvent +import org.wikipedia.analytics.eventplatform.YearInReviewEvent import org.wikipedia.auth.AccountUtil import org.wikipedia.concurrency.FlowEventBus import org.wikipedia.databinding.FragmentReadingListBinding @@ -530,6 +531,7 @@ class ReadingListFragment : Fragment(), MenuProvider, ReadingListItemActionsDial ReadingListMode.YEAR_IN_REVIEW -> { if (readingList == null) { + YearInReviewEvent.submit(action = "impression", slide = "reading_list_create") viewModel.generateYearInReviewReadingList(AccountUtil.userName) } else { update() diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewDialog.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewDialog.kt index 3446f4eb92c..243fa45acb2 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewDialog.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewDialog.kt @@ -7,6 +7,7 @@ import android.widget.TextView import androidx.core.view.isVisible import com.google.android.material.dialog.MaterialAlertDialogBuilder import org.wikipedia.R +import org.wikipedia.analytics.eventplatform.YearInReviewEvent import org.wikipedia.auth.AccountUtil import org.wikipedia.database.AppDatabase import org.wikipedia.databinding.DialogFeedbackOptionsBinding @@ -28,6 +29,11 @@ object YearInReviewDialog { return } + YearInReviewEvent.submit( + action = "group_assigned", + groupAssigned = if (isTestGroupUser) "android_yir_2025_b" else "android_yir_2025_a" + ) + val cutoffDate = Instant.parse(YearInReviewViewModel.CUT_OFF_DATE_FOR_SHOWING_YIR_READING_LIST_DIALOG).toEpochMilli() if (System.currentTimeMillis() > cutoffDate) { return @@ -50,21 +56,27 @@ object YearInReviewDialog { .setTitle(title) .setMessage(StringUtil.fromHtml(message)) .setPositiveButton(resource.getString(R.string.year_in_review_reading_list_dialog_positive_button_label)) { dialog, _ -> + YearInReviewEvent.submit(action = "create_click", slide = "reading_list_prompt") YearInReviewViewModel.updateYearInReviewModel { it.copy(isReadingListDialogShown = true) } activity.startActivity(ReadingListActivity.newIntent(activity, readingListMode = ReadingListMode.YEAR_IN_REVIEW)) dialog.dismiss() } .setCancelable(false) - .setNegativeButton(resource.getString(R.string.year_in_review_reading_list_dialog_negative_button_label)) { _, _ -> YearInReviewViewModel.updateYearInReviewModel { it.copy(isReadingListDialogShown = true) } } + .setNegativeButton(resource.getString(R.string.year_in_review_reading_list_dialog_negative_button_label)) { _, _ -> + YearInReviewEvent.submit(action = "nothanks_click", slide = "reading_list_prompt") + YearInReviewViewModel.updateYearInReviewModel { it.copy(isReadingListDialogShown = true) } + } .show() .findViewById(android.R.id.message)?.movementMethod = LinkMovementMethod.getInstance() + + YearInReviewEvent.submit(action = "impression", slide = "reading_list_prompt") } fun maybeShowYirReadingListSurveyDialog(activity: Activity) { if (Prefs.yearInReviewReadingListSurveyShown || Prefs.yearInReviewReadingListVisitCount < 2 || !isTestGroupUser) { return } - + YearInReviewEvent.submit(action = "impression", slide = "feedback_choice_rltest") val binding = DialogFeedbackOptionsBinding.inflate(activity.layoutInflater) binding.titleText.text = activity.getString(R.string.year_in_review_reading_list_survey_title, YearInReviewViewModel.YIR_YEAR) @@ -79,13 +91,19 @@ object YearInReviewDialog { .create() binding.cancelButton.setOnClickListener { + YearInReviewEvent.submit(action = "close_click", slide = "feedback_choice_rltest") dialog.dismiss() } binding.submitButton.setOnClickListener { val selectedOption = getSelectedOption(binding) val feedbackText = binding.feedbackInput.text.toString() - // @TODO: instrumentation FeedbackUtil.showMessage(activity, R.string.survey_dialog_submitted_snackbar) + YearInReviewEvent.submit( + action = "feedback_submit_click", + slide = "feedback_choice_rltest", + feedbackSelect = selectedOption, + feedbackText = feedbackText + ) dialog.dismiss() } @@ -107,6 +125,7 @@ object YearInReviewDialog { if (Prefs.yearInReviewSurveyState != YearInReviewSurveyState.SHOULD_SHOW) { return } + YearInReviewEvent.submit(action = "impression", slide = "feedback_choice") val binding = DialogFeedbackOptionsBinding.inflate(activity.layoutInflater) binding.titleText.text = activity.getString(R.string.year_in_review_survey_title) binding.messageText.text = activity.getString(R.string.year_in_review_survey_subtitle) @@ -122,12 +141,18 @@ object YearInReviewDialog { .create() binding.cancelButton.setOnClickListener { + YearInReviewEvent.submit(action = "close_click", slide = "feedback_choice") dialog.dismiss() } binding.submitButton.setOnClickListener { val selectedOption = getSelectedOption(binding) val feedbackText = binding.feedbackInput.text.toString() - // @TODO: instrumentation + YearInReviewEvent.submit( + action = "feedback_submit_click", + slide = "feedback_choice", + feedbackSelect = selectedOption, + feedbackText = feedbackText + ) FeedbackUtil.showMessage(activity, R.string.survey_dialog_submitted_snackbar) dialog.dismiss() } From 4cb9ecdae2caba10017340d450ea48775d21f044 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Wed, 5 Nov 2025 16:55:39 -0800 Subject: [PATCH 10/13] highlight share --- .../java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt index b1d07db2bc0..ca3fac33789 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt @@ -202,6 +202,7 @@ fun YearInReviewScreenDeck( requestScreenshotBitmap = requestScreenshotBitmap, screenData = pages[page], onShareHighlightsBtnClick = { highlights -> + YearInReviewEvent.submit(action = "share_click", slide = pages[pagerState.currentPage].slideName) captureRequest = YearInReviewCaptureRequest.HighlightsScreen(highlights) } From 2c6ca8ab54dde275712bcd8ea6f15e591c0b9cc4 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Fri, 7 Nov 2025 14:19:28 -0800 Subject: [PATCH 11/13] Code review comment --- .../main/java/org/wikipedia/navtab/MenuNavTabDialog.kt | 2 +- .../org/wikipedia/settings/SettingsPreferenceLoader.kt | 8 +++++--- .../yearinreview/YearInReviewOnboardingScreen.kt | 4 ++-- .../java/org/wikipedia/yearinreview/YearInReviewSlides.kt | 2 +- 4 files changed, 9 insertions(+), 7 deletions(-) diff --git a/app/src/main/java/org/wikipedia/navtab/MenuNavTabDialog.kt b/app/src/main/java/org/wikipedia/navtab/MenuNavTabDialog.kt index 17134d6fe14..7912f776f18 100644 --- a/app/src/main/java/org/wikipedia/navtab/MenuNavTabDialog.kt +++ b/app/src/main/java/org/wikipedia/navtab/MenuNavTabDialog.kt @@ -39,7 +39,7 @@ class MenuNavTabDialog : ExtendedBottomSheetDialogFragment() { private var _binding: ViewMainDrawerBinding? = null private val binding get() = _binding!! - private val yirEntrySlide get() = if (AccountUtil.isLoggedIn) "entry_b" else "entry_c" + private val yirEntrySlide get() = if (AccountUtil.isLoggedIn) "li_profile" else "lo_profile" private val yirEnabled get() = YearInReviewViewModel.isAccessible && Prefs.isYearInReviewEnabled override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View { diff --git a/app/src/main/java/org/wikipedia/settings/SettingsPreferenceLoader.kt b/app/src/main/java/org/wikipedia/settings/SettingsPreferenceLoader.kt index e03d3a64544..8583e01f72e 100644 --- a/app/src/main/java/org/wikipedia/settings/SettingsPreferenceLoader.kt +++ b/app/src/main/java/org/wikipedia/settings/SettingsPreferenceLoader.kt @@ -75,17 +75,19 @@ internal class SettingsPreferenceLoader(fragment: PreferenceFragmentCompat) : Ba } it.onPreferenceChangeListener = Preference.OnPreferenceChangeListener { preference, newValue -> if (newValue as Boolean) { - val eventAction = if (newValue) "yir_on_click" else "yir_off_click" - YearInReviewEvent.submit(action = eventAction, slide = "setting") + YearInReviewEvent.submit(action = "yir_on_click", slide = "setting") return@OnPreferenceChangeListener true } + YearInReviewEvent.submit(action = "yir_off_click", slide = "setting") MaterialAlertDialogBuilder(activity) .setTitle(R.string.year_in_review_disable_title) .setMessage(R.string.year_in_review_setting_subtitle) .setPositiveButton(R.string.year_in_review_disable_positive_button) { _, _ -> YearInReviewEvent.submit(action = "yir_off_confirm_click", slide = "setting") Prefs.yearInReviewModelData = emptyMap() - YearInReviewViewModel.updateYearInReviewModel { it.copy(slideViewedCount = 0) } + YearInReviewViewModel.updateYearInReviewModel { model -> + model.copy(slideViewedCount = 0) + } Prefs.yearInReviewReadingListSurveyShown = false Prefs.yearInReviewReadingListVisitCount = 0 (preference as SwitchPreferenceCompat).isChecked = false diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewOnboardingScreen.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewOnboardingScreen.kt index 6de58ccdac4..4f86c193f5c 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewOnboardingScreen.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewOnboardingScreen.kt @@ -165,7 +165,7 @@ fun YearInReviewOnboardingBottomBar( .weight(1f) .padding(end = 12.dp), onClick = { - YearInReviewEvent.submit(action = "learn_click", slide = "entry_a") + YearInReviewEvent.submit(action = "learn_click", slide = "explore_prompt") UriUtil.handleExternalLink( context = context, uri = context.getString(R.string.year_in_review_media_wiki_url).toUri() @@ -186,7 +186,7 @@ fun YearInReviewOnboardingBottomBar( .weight(1f) .padding(start = 12.dp), onClick = { - YearInReviewEvent.submit(action = "start_click", slide = "entry_a") + YearInReviewEvent.submit(action = "start_click", slide = "explore_prompt") onGetStartedClick() } ) { diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewSlides.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewSlides.kt index bf4b26284d8..fb319f41f04 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewSlides.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewSlides.kt @@ -42,7 +42,7 @@ class YearInReviewSlides( imageResource = R.drawable.yir_puzzle_clock, headlineText = context.resources.getQuantityString(R.plurals.year_in_review_slide_english_reading_hours_headline, config.hoursReadEN.toInt(), config.hoursReadEN), bodyText = bodyText, - slideName = "lo_en_collhours" + slideName = if (isLoggedIn) "li_en_collhours" else "lo_en_collhours" ) } From 572745ded0c38a7b8dea876d9748da647d1bdf33 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Fri, 7 Nov 2025 14:24:51 -0800 Subject: [PATCH 12/13] Avoid sending multiple events --- .../yearinreview/YearInReviewScreenDeck.kt | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt index 3ba0f13190a..30f2ad74e26 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewScreenDeck.kt @@ -184,17 +184,19 @@ fun YearInReviewScreenDeck( ) }, content = { paddingValues -> + + LaunchedEffect(pagerState.currentPage) { + YearInReviewEvent.submit( + action = "impression", + slide = pages[pagerState.currentPage].slideName + ) + } + HorizontalPager( verticalAlignment = Alignment.Top, state = pagerState, contentPadding = PaddingValues(0.dp), ) { page -> - if (page == pagerState.currentPage) { - YearInReviewEvent.submit( - action = "impression", - slide = pages[page].slideName - ) - } YearInReviewScreenContent( modifier = Modifier .fillMaxSize() From e504fe3d9c7d34bb4a65fca091c5960288a0ad93 Mon Sep 17 00:00:00 2001 From: Cooltey Feng Date: Fri, 7 Nov 2025 16:49:21 -0800 Subject: [PATCH 13/13] Finalized instrumentation --- .../wikipedia/activity/SingleWebViewActivity.kt | 13 ++++++++----- .../main/java/org/wikipedia/donate/DonateDialog.kt | 2 +- .../main/java/org/wikipedia/page/PageActivity.kt | 14 ++++++++++---- .../wikipedia/yearinreview/YearInReviewActivity.kt | 6 +++--- .../yearinreview/YearInReviewViewModel.kt | 2 ++ 5 files changed, 24 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/org/wikipedia/activity/SingleWebViewActivity.kt b/app/src/main/java/org/wikipedia/activity/SingleWebViewActivity.kt index 749e00e1431..7eb97a3b7e9 100644 --- a/app/src/main/java/org/wikipedia/activity/SingleWebViewActivity.kt +++ b/app/src/main/java/org/wikipedia/activity/SingleWebViewActivity.kt @@ -37,6 +37,7 @@ import org.wikipedia.page.PageViewModel import org.wikipedia.staticdata.MainPageNameData import org.wikipedia.util.StringUtil import org.wikipedia.util.UriUtil +import org.wikipedia.yearinreview.YearInReviewViewModel class SingleWebViewActivity : BaseActivity() { private lateinit var binding: ActivitySingleWebViewBinding @@ -185,11 +186,13 @@ class SingleWebViewActivity : BaseActivity() { DonorExperienceEvent.logAction("article_return_click", "webpay_processed") } PAGE_CONTENT_SOURCE_YIR -> { - YearInReviewEvent.submit( - action = "article_return_click", - slide = "webpay_processed", - campaignId = "" // TODO: tbd - ) + YearInReviewViewModel.currentCampaignId?.let { campaignId -> + YearInReviewEvent.submit( + action = "article_return_click", + slide = "webpay_processed", + campaignId = campaignId + ) + } } else -> { } } diff --git a/app/src/main/java/org/wikipedia/donate/DonateDialog.kt b/app/src/main/java/org/wikipedia/donate/DonateDialog.kt index cac09e02174..f03cf0aa975 100644 --- a/app/src/main/java/org/wikipedia/donate/DonateDialog.kt +++ b/app/src/main/java/org/wikipedia/donate/DonateDialog.kt @@ -102,7 +102,7 @@ class DonateDialog : ExtendedBottomSheetDialogFragment() { } private fun onDonateClicked() { - launchDonateLink(requireContext(), url = arguments?.getString(ARG_DONATE_URL)) + launchDonateLink(requireContext(), url = arguments?.getString(ARG_DONATE_URL), campaignId = campaignId) invalidateCampaign() dismiss() } diff --git a/app/src/main/java/org/wikipedia/page/PageActivity.kt b/app/src/main/java/org/wikipedia/page/PageActivity.kt index 0bb9f4e3302..34dd95e1801 100644 --- a/app/src/main/java/org/wikipedia/page/PageActivity.kt +++ b/app/src/main/java/org/wikipedia/page/PageActivity.kt @@ -40,6 +40,7 @@ import org.wikipedia.activity.BaseActivity import org.wikipedia.activity.SingleWebViewActivity import org.wikipedia.analytics.eventplatform.BreadCrumbLogEvent import org.wikipedia.analytics.eventplatform.DonorExperienceEvent +import org.wikipedia.analytics.eventplatform.YearInReviewEvent import org.wikipedia.auth.AccountUtil import org.wikipedia.commons.FilePageActivity import org.wikipedia.concurrency.FlowEventBus @@ -87,6 +88,7 @@ import org.wikipedia.views.ObservableWebView import org.wikipedia.views.ViewUtil import org.wikipedia.watchlist.WatchlistExpiry import org.wikipedia.yearinreview.YearInReviewDialog +import org.wikipedia.yearinreview.YearInReviewViewModel import java.util.Locale class PageActivity : BaseActivity(), PageFragment.Callback, LinkPreviewDialog.LoadPageCallback, FrameLayoutNavMenuTriggerer.Callback { @@ -550,12 +552,16 @@ class PageActivity : BaseActivity(), PageFragment.Callback, LinkPreviewDialog.Lo // show it in a SingleWebViewActivity. val campaign = uri.getQueryParameter("wmf_campaign") - // TODO: check if we want to keep the campaignId in memory. - if (campaign != null && campaign == "Android") { - DonorExperienceEvent.logAction("impression", "webpay_processed", wiki.languageCode) + var pageContentInfo = SingleWebViewActivity.PAGE_CONTENT_SOURCE_DONOR_EXPERIENCE + YearInReviewViewModel.currentCampaignId?.let { campaignId -> + YearInReviewEvent.submit(action = "impression", slide = "webpay_processed", campaignId = campaignId) + pageContentInfo = SingleWebViewActivity.PAGE_CONTENT_SOURCE_YIR + } ?: run { + DonorExperienceEvent.logAction("impression", "webpay_processed", wiki.languageCode) + } startActivity(SingleWebViewActivity.newIntent(this@PageActivity, uri.toString(), - true, pageFragment.title, SingleWebViewActivity.PAGE_CONTENT_SOURCE_DONOR_EXPERIENCE)) + true, pageFragment.title, pageContentInfo)) finish() return } diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewActivity.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewActivity.kt index 9f513c4c26d..e898a067590 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewActivity.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewActivity.kt @@ -77,13 +77,13 @@ class YearInReviewActivity : BaseActivity() { screen_name = "year_in_review", action = "donate_click") ) - val campaignId = "appmenu_yir_$currentSlide" + YearInReviewViewModel.currentCampaignId = "appmenu_yir_$currentSlide" YearInReviewEvent.submit( action = "donate_start_click_yir", slide = currentSlide, - campaignId = campaignId + campaignId = YearInReviewViewModel.currentCampaignId ) - ExclusiveBottomSheetPresenter.show(supportFragmentManager, DonateDialog.newInstance(campaignId = campaignId, fromYiR = true)) + ExclusiveBottomSheetPresenter.show(supportFragmentManager, DonateDialog.newInstance(campaignId = YearInReviewViewModel.currentCampaignId, fromYiR = true)) }, onRetryClick = { viewModel.fetchPersonalizedData() diff --git a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewViewModel.kt b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewViewModel.kt index 2e0ea55a504..a42c5a71ce2 100644 --- a/app/src/main/java/org/wikipedia/yearinreview/YearInReviewViewModel.kt +++ b/app/src/main/java/org/wikipedia/yearinreview/YearInReviewViewModel.kt @@ -314,6 +314,8 @@ class YearInReviewViewModel() : ViewModel() { now.isBefore(config.activeEndDate)) } + var currentCampaignId: String? = null + val isCustomIconAllowed get(): Boolean { return Prefs.yearInReviewModelData[YIR_YEAR]?.isCustomIconUnlocked == true }