Skip to content

Commit

Permalink
Merge branch 'main' into twn
Browse files Browse the repository at this point in the history
mazevedofs authored Jan 28, 2025
2 parents 2e87eb4 + f23b13e commit 1f1fb7f
Showing 10 changed files with 161 additions and 24 deletions.
2 changes: 2 additions & 0 deletions WMF Framework/Event Platform/EventPlatformClient.swift
Original file line number Diff line number Diff line change
@@ -133,6 +133,7 @@ import WMFData
case appDonorExperience = "app_donor_experience"
case editInteraction = "ios.edit_interaction"
case imageRecommendation = "android.image_recommendation_event"
case articleLinkInteraction = "ios.article_link_interaction"
}

/**
@@ -159,6 +160,7 @@ import WMFData
case watchlist = "/analytics/mobile_apps/ios_watchlists/4.1.0"
case appInteraction = "/analytics/mobile_apps/app_interaction/1.1.0"
case imageRecommendation = "/analytics/mobile_apps/android_image_recommendation_event/1.1.0"
case articleLinkInteraction = "/analytics/mobile_apps/ios_article_link_interaction/1.0.0"
}

/**
8 changes: 8 additions & 0 deletions Wikipedia.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
@@ -742,6 +742,9 @@
67B0B88E2BF51E3300480B46 /* ArticleCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B0B88D2BF51E3300480B46 /* ArticleCollectionViewController.swift */; };
67B0B88F2BF51E3300480B46 /* ArticleCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B0B88D2BF51E3300480B46 /* ArticleCollectionViewController.swift */; };
67B0B8902BF51E3300480B46 /* ArticleCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B0B88D2BF51E3300480B46 /* ArticleCollectionViewController.swift */; };
67B278EF2D47CEF300E2DF8A /* ArticleLinkInteractionFunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B278EE2D47CEEC00E2DF8A /* ArticleLinkInteractionFunnel.swift */; };
67B278F02D47CEF300E2DF8A /* ArticleLinkInteractionFunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B278EE2D47CEEC00E2DF8A /* ArticleLinkInteractionFunnel.swift */; };
67B278F12D47CEF300E2DF8A /* ArticleLinkInteractionFunnel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B278EE2D47CEEC00E2DF8A /* ArticleLinkInteractionFunnel.swift */; };
67B5334128416C0D00C33E13 /* UserDataExportCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B5333B28416A3B00C33E13 /* UserDataExportCache.swift */; };
67B5334228416C0E00C33E13 /* UserDataExportCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B5333B28416A3B00C33E13 /* UserDataExportCache.swift */; };
67B5334328416C0E00C33E13 /* UserDataExportCache.swift in Sources */ = {isa = PBXBuildFile; fileRef = 67B5333B28416A3B00C33E13 /* UserDataExportCache.swift */; };
@@ -3399,6 +3402,7 @@
67AD17FE2C49D3BB0027C630 /* WMFBarButtonItemPopoverMessageViewController.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = WMFBarButtonItemPopoverMessageViewController.storyboard; sourceTree = "<group>"; };
67ADEE9523A2CFFB0000CAF7 /* ArticleWebMessagingController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleWebMessagingController.swift; sourceTree = "<group>"; };
67B0B88D2BF51E3300480B46 /* ArticleCollectionViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleCollectionViewController.swift; sourceTree = "<group>"; };
67B278EE2D47CEEC00E2DF8A /* ArticleLinkInteractionFunnel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleLinkInteractionFunnel.swift; sourceTree = "<group>"; };
67B5333B28416A3B00C33E13 /* UserDataExportCache.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserDataExportCache.swift; sourceTree = "<group>"; };
67B64D562507DE3E00FA27F3 /* ArticleAsLivingDocSectionHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleAsLivingDocSectionHeaderView.swift; sourceTree = "<group>"; };
67B64D5B2507E9FD00FA27F3 /* ArticleAsLivingDocSmallEventCollectionViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ArticleAsLivingDocSmallEventCollectionViewCell.swift; sourceTree = "<group>"; };
@@ -5901,6 +5905,7 @@
0E7AAEEA1C21F4160046B5B6 /* Wikimedia Event Logging */ = {
isa = PBXGroup;
children = (
67B278EE2D47CEEC00E2DF8A /* ArticleLinkInteractionFunnel.swift */,
7AF1B19520A1E14F000C8DFE /* ReadingListsFunnel.swift */,
67E466F9241BED770014149B /* EditHistoryCompareFunnel.swift */,
7A25B1CB20A483F1008C6F29 /* LoginFunnel.swift */,
@@ -10286,6 +10291,7 @@
00D280F7247EFFFE006BEE23 /* Date+Extensions.swift in Sources */,
7A19C64820DD3440000EF7F7 /* BaseExploreFeedSettingsViewController.swift in Sources */,
6782DBD32343FE03003FA21B /* DiffListGroupViewModel.swift in Sources */,
67B278EF2D47CEF300E2DF8A /* ArticleLinkInteractionFunnel.swift in Sources */,
67059DB52260D034009811AA /* SchemeHandler.swift in Sources */,
FFE891462445150B0058B642 /* AppTabBarDelegate.swift in Sources */,
0042812D25E6E841004945B3 /* NYTPhotoCaptionView.m in Sources */,
@@ -11265,6 +11271,7 @@
8307951F2C9DA34F00E453BD /* WatchlistCoordinator.swift in Sources */,
D8CE25961E698E2400DAE2E0 /* MTLValueTransformer+WMFNumericValueTransformer.m in Sources */,
7AF6F76722395BEC00949393 /* EditingWelcomeViewController.swift in Sources */,
67B278F12D47CEF300E2DF8A /* ArticleLinkInteractionFunnel.swift in Sources */,
83C06895292EEF4A00DF1403 /* TalkPageTopicComposeViewController+TalkPageFormattingToolbar.swift in Sources */,
837A15F528DA591E00AAC3FC /* TalkPageCache.swift in Sources */,
BA7683C91F30D87F00A487AA /* ProminentSwitch.swift in Sources */,
@@ -11827,6 +11834,7 @@
7AF6F76822395BEC00949393 /* EditingWelcomeViewController.swift in Sources */,
830795212C9DA34F00E453BD /* WatchlistCoordinator.swift in Sources */,
7A4B333E2136EDED00C6C820 /* UnderlineButton.swift in Sources */,
67B278F02D47CEF300E2DF8A /* ArticleLinkInteractionFunnel.swift in Sources */,
83C06894292EEF4A00DF1403 /* TalkPageTopicComposeViewController+TalkPageFormattingToolbar.swift in Sources */,
D8C4D3DA1FD5D9260089CEC2 /* TUSafariActivity.m in Sources */,
837A15F428DA591E00AAC3FC /* TalkPageCache.swift in Sources */,
21 changes: 1 addition & 20 deletions Wikipedia/Code/ArticleFetchedResultsViewController.swift
Original file line number Diff line number Diff line change
@@ -48,26 +48,12 @@ class ArticleFetchedResultsViewController: ArticleCollectionViewController, Coll
var deleteAllConfirmationText: String? = nil
var deleteAllCancelText: String? = nil
var deleteAllText: String? = nil
var isDeleteAllVisible: Bool = false

open func deleteAll() {

}

fileprivate final func updateDeleteButton() {
guard isDeleteAllVisible else {
navigationItem.rightBarButtonItem = nil
return
}

if navigationItem.rightBarButtonItem == nil {
navigationItem.rightBarButtonItem = UIBarButtonItem(title: deleteAllButtonText, style: .plain, target: self, action: #selector(deleteButtonPressed(_:)))
}

navigationItem.rightBarButtonItem?.isEnabled = !isEmpty
}

@objc fileprivate final func deleteButtonPressed(_ sender: UIBarButtonItem) {
@objc final func deleteButtonPressed(_ sender: UIBarButtonItem) {
let alertController = UIAlertController(title: deleteAllConfirmationText, message: nil, preferredStyle: .actionSheet)
alertController.addAction(UIAlertAction(title: deleteAllText, style: .destructive, handler: { (action) in
self.deleteAll()
@@ -91,11 +77,6 @@ class ArticleFetchedResultsViewController: ArticleCollectionViewController, Coll
func collectionViewUpdater<T: NSFetchRequestResult>(_ updater: CollectionViewUpdater<T>, updateItemAtIndexPath indexPath: IndexPath, in collectionView: UICollectionView) {

}

override func isEmptyDidChange() {
super.isEmptyDidChange()
updateDeleteButton()
}

override func viewDidDisappear(_ animated: Bool) {
super.viewDidDisappear(animated)
37 changes: 37 additions & 0 deletions Wikipedia/Code/ArticleLinkInteractionFunnel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import Foundation
import WMF

final class ArticleLinkInteractionFunnel {

static let shared = ArticleLinkInteractionFunnel()

private enum Action: String, Codable {
case navigate = "navigate"
}

private struct Event: EventInterface {
static let schema: EventPlatformClient.Schema = .articleLinkInteraction
let action: Action
let pageID: Int
let wikiID: String

enum CodingKeys: String, CodingKey {
case action = "action"
case pageID = "page_id"
case wikiID = "wiki_db"
}
}

private func logEvent(action: ArticleLinkInteractionFunnel.Action, pageID: Int, project: WikimediaProject) {

let wikiID = project.notificationsApiWikiIdentifier

let event: ArticleLinkInteractionFunnel.Event = ArticleLinkInteractionFunnel.Event(action: action, pageID: pageID, wikiID: wikiID)
EventPlatformClient.shared.submit(stream: .articleLinkInteraction, event: event)
}

func logArticleView(pageID: Int, project: WikimediaProject) {
logEvent(action: .navigate, pageID: pageID, project: project)
}
}

8 changes: 8 additions & 0 deletions Wikipedia/Code/ArticleViewController.swift
Original file line number Diff line number Diff line change
@@ -627,6 +627,14 @@ class ArticleViewController: ThemeableViewController, HintPresenting, UIScrollVi

self.shareIfNecessary()
self.restoreScrollStateIfNecessary()

if let pageID = article.pageID,
let siteURL = self.articleURL.wmf_site,
let project = WikimediaProject(siteURL: siteURL) {
ArticleLinkInteractionFunnel.shared.logArticleView(pageID: pageID.intValue, project: project)
}


self.articleLoadWaitGroup = nil
}
}
104 changes: 102 additions & 2 deletions Wikipedia/Code/HistoryViewController.swift
Original file line number Diff line number Diff line change
@@ -9,6 +9,48 @@ class HistoryViewController: ArticleFetchedResultsViewController, WMFNavigationB

var topSafeAreaOverlayHeightConstraint: NSLayoutConstraint?
var topSafeAreaOverlayView: UIView?

// Properties needed for Profile Button

private var _yirCoordinator: YearInReviewCoordinator?
var yirCoordinator: YearInReviewCoordinator? {

guard let navigationController,
let yirDataController,
let dataStore else {
return nil
}

guard let existingYirCoordinator = _yirCoordinator else {
_yirCoordinator = YearInReviewCoordinator(navigationController: navigationController, theme: theme, dataStore: dataStore, dataController: yirDataController)
_yirCoordinator?.badgeDelegate = self
return _yirCoordinator
}

return existingYirCoordinator
}

private var _profileCoordinator: ProfileCoordinator?
private var profileCoordinator: ProfileCoordinator? {

guard let navigationController,
let yirCoordinator = self.yirCoordinator,
let dataStore else {
return nil
}

guard let existingProfileCoordinator = _profileCoordinator else {
_profileCoordinator = ProfileCoordinator(navigationController: navigationController, theme: theme, dataStore: dataStore, donateSouce: .savedProfile, logoutDelegate: self, sourcePage: ProfileCoordinatorSource.saved, yirCoordinator: yirCoordinator)
_profileCoordinator?.badgeDelegate = self
return _profileCoordinator
}

return existingProfileCoordinator
}

private var yirDataController: WMFYearInReviewDataController? {
return try? WMFYearInReviewDataController()
}

override var headerStyle: ColumnarCollectionViewController.HeaderStyle {
return .sections
@@ -32,7 +74,6 @@ class HistoryViewController: ArticleFetchedResultsViewController, WMFNavigationB
deleteAllConfirmationText = WMFLocalizedString("history-clear-confirmation-heading", value: "Are you sure you want to delete all your recent items?", comment: "Heading text of delete all confirmation dialog")
deleteAllCancelText = WMFLocalizedString("history-clear-cancel", value: "Cancel", comment: "Button text for cancelling delete all action {{Identical|Cancel}}")
deleteAllText = WMFLocalizedString("history-clear-delete-all", value: "Yes, delete all", comment: "Button text for confirming delete all action")
isDeleteAllVisible = true

setupTopSafeAreaOverlay(scrollView: collectionView)
}
@@ -137,8 +178,45 @@ class HistoryViewController: ArticleFetchedResultsViewController, WMFNavigationB
}

let hideNavigationBarOnScroll = !isEmpty

let deleteButton = UIBarButtonItem(title: deleteAllButtonText, style: .plain, target: self, action: #selector(deleteButtonPressed(_:)))
deleteButton.isEnabled = !isEmpty

let profileButtonConfig: WMFNavigationBarProfileButtonConfig?
if let dataStore {
profileButtonConfig = self.profileButtonConfig(target: self, action: #selector(userDidTapProfile), dataStore: dataStore, yirDataController: yirDataController, leadingBarButtonItem: deleteButton, trailingBarButtonItem: nil)
} else {
profileButtonConfig = nil
}

configureNavigationBar(titleConfig: titleConfig, closeButtonConfig: nil, profileButtonConfig: profileButtonConfig, searchBarConfig: nil, hideNavigationBarOnScroll: hideNavigationBarOnScroll)
}

private func updateProfileButton() {

configureNavigationBar(titleConfig: titleConfig, closeButtonConfig: nil, profileButtonConfig: nil, searchBarConfig: nil, hideNavigationBarOnScroll: hideNavigationBarOnScroll)
guard let dataStore else {
return
}

let config = self.profileButtonConfig(target: self, action: #selector(userDidTapProfile), dataStore: dataStore, yirDataController: yirDataController, leadingBarButtonItem: nil, trailingBarButtonItem: nil)
updateNavigationBarProfileButton(needsBadge: config.needsBadge, needsBadgeLabel: CommonStrings.profileButtonBadgeTitle, noBadgeLabel: CommonStrings.profileButtonTitle)
}

@objc func userDidTapProfile() {

guard let dataStore else {
return
}

guard let languageCode = dataStore.languageLinkController.appLanguage?.languageCode,
let metricsID = DonateCoordinator.metricsID(for: .savedProfile, languageCode: languageCode) else {
return
}

// TODO: Do we need logging like this?
// DonateFunnel.shared.logExploreProfile(metricsID: metricsID)

profileCoordinator?.start()
}

func titleForHeaderInSection(_ section: Int) -> String? {
@@ -184,6 +262,28 @@ class HistoryViewController: ArticleFetchedResultsViewController, WMFNavigationB
override func apply(theme: Theme) {
super.apply(theme: theme)

updateProfileButton()
profileCoordinator?.theme = theme

themeTopSafeAreaOverlay()
}
}

extension HistoryViewController: LogoutCoordinatorDelegate {
func didTapLogout() {

guard let dataStore else {
return
}

wmf_showKeepSavedArticlesOnDevicePanelIfNeeded(triggeredBy: .logout, theme: theme) {
dataStore.authenticationManager.logout(initiatedBy: .user)
}
}
}

extension HistoryViewController: YearInReviewBadgeDelegate {
func updateYIRBadgeVisibility() {
updateProfileButton()
}
}
1 change: 1 addition & 0 deletions Wikipedia/Code/SearchViewController.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import UIKit
import WMFComponents
import WMFData

class SearchViewController: ArticleCollectionViewController, WMFNavigationBarConfiguring, WMFNavigationBarHiding {

2 changes: 1 addition & 1 deletion Wikipedia/Code/YearInReviewCoordinator.swift
Original file line number Diff line number Diff line change
@@ -497,7 +497,7 @@ final class YearInReviewCoordinator: NSObject, Coordinator {
func personalizedYourEditsViewedSlideSubtitle(views: Int) -> String {
let format = WMFLocalizedString(
"year-in-review-personalized-edit-views-subtitle-format",
value: "Readers around the world appreciate your contributions. In the last 2 months, articles you've edited have received %1$@ total views. Thanks to editors like you, Wikipedia is a steadily improving, fact-based, and reliable knowledge resource for to the world",
value: "Readers around the world appreciate your contributions. In the last 2 months, articles you've edited have received %1$@ total views. Thanks to editors like you, Wikipedia is a steadily improving, fact-based, and reliable knowledge resource for the world",
comment: "Year in review, personalized slide subtitle for users that display how many views their edits have. %1$@ is replaced with the amount of edit views."
)

2 changes: 1 addition & 1 deletion Wikipedia/Localizations/en.lproj/Localizable.strings
Original file line number Diff line number Diff line change
@@ -1457,7 +1457,7 @@
"year-in-review-personalized-donate-subtitle" = "Thank you for investing in the future of free knowledge. This year, the Wikimedia Foundation improved the technology to serve every reader and volunteer better, developed tools that empower collaboration, and supported Wikipedia in more languages. [Learn more about our work]($1).";
"year-in-review-personalized-donate-title" = "Your generosity helped keep Wikipedia thriving";
"year-in-review-personalized-donation-thank-you" = "Wikimedia logo";
"year-in-review-personalized-edit-views-subtitle-format" = "Readers around the world appreciate your contributions. In the last 2 months, articles you've edited have received $1 total views. Thanks to editors like you, Wikipedia is a steadily improving, fact-based, and reliable knowledge resource for to the world";
"year-in-review-personalized-edit-views-subtitle-format" = "Readers around the world appreciate your contributions. In the last 2 months, articles you've edited have received $1 total views. Thanks to editors like you, Wikipedia is a steadily improving, fact-based, and reliable knowledge resource for the world";
"year-in-review-personalized-edit-views-title-format" = "Your edits have been viewed more than $1 times recently";
"year-in-review-personalized-editing-subtitle-format" = "You edited Wikipedia {{PLURAL:$1|$1 time|$1 times}}. Thank you for being one of the volunteer editors making a difference on Wikimedia projects around the world.";
"year-in-review-personalized-editing-subtitle-format-500plus" = "You edited Wikipedia 500+ times. Thank you for being one of the volunteer editors making a difference on Wikimedia projects around the world.";
Binary file modified Wikipedia/iOS Native Localizations/en.lproj/Localizable.strings
Binary file not shown.

0 comments on commit 1f1fb7f

Please sign in to comment.