Skip to content

Commit

Permalink
Merge pull request #4818 from wikimedia/image-rec-metrics
Browse files Browse the repository at this point in the history
Image Recommendations - Add metrics
  • Loading branch information
mazevedofs committed Apr 24, 2024
2 parents 3cb1998 + 1b35fc9 commit e3dd3c4
Show file tree
Hide file tree
Showing 19 changed files with 716 additions and 69 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,15 @@ public final class WKImageRecommendationsSurveyViewModel {
return localizedStrings.other
}
}

var otherText: String? {
switch self {
case .other(let reason):
return reason
default:
return nil
}
}

var apiIdentifier: String {
switch self {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ final public class WKImageRecommendationsBottomSheetViewController: WKCanvasView
public var viewModel: WKImageRecommendationsViewModel
public var tooltipViewModels: [WKTooltipViewModel] = []
weak var delegate: WKImageRecommendationsDelegate?
weak var loggingDelegate: WKImageRecommendationsLoggingDelegate?
private(set) var bottomSheetView: WKImageRecommendationBottomSheetView?

// MARK: Lifecycle

public init(viewModel: WKImageRecommendationsViewModel, delegate: WKImageRecommendationsDelegate) {
public init(viewModel: WKImageRecommendationsViewModel, delegate: WKImageRecommendationsDelegate, loggingDelegate: WKImageRecommendationsLoggingDelegate) {
self.viewModel = viewModel
self.delegate = delegate
self.loggingDelegate = loggingDelegate
super.init()
}

Expand All @@ -31,6 +33,12 @@ final public class WKImageRecommendationsBottomSheetViewController: WKCanvasView
self.bottomSheetView = bottomSheetView
}
}

public override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)

loggingDelegate?.logBottomSheetDidAppear()
}

// MARK: Methods

Expand Down Expand Up @@ -66,6 +74,8 @@ extension WKImageRecommendationsBottomSheetViewController: WKImageRecommendation
}

func goToImageCommonsPage() {

loggingDelegate?.logBottomSheetDidTapFileName()

guard let currentRecommendation = viewModel.currentRecommendation,
let url = URL(string: currentRecommendation.imageData.descriptionURL) else {
Expand All @@ -79,22 +89,40 @@ extension WKImageRecommendationsBottomSheetViewController: WKImageRecommendation
if let imageData = viewModel.currentRecommendation?.imageData, let title = viewModel.currentRecommendation?.title {
self.dismiss(animated: true) {
self.delegate?.imageRecommendationsUserDidTapInsertImage(viewModel: self.viewModel, title: title, with: imageData)
self.loggingDelegate?.logBottomSheetDidTapYes()
}
}
}

func didTapNoButton() {
loggingDelegate?.logBottomSheetDidTapNo()

let surveyView = WKImageRecommendationsSurveyView(
viewModel: WKImageRecommendationsSurveyViewModel(localizedStrings: viewModel.localizedStrings.surveyLocalizedStrings),
cancelAction: { [weak self] in
self?.loggingDelegate?.logRejectSurveyDidTapCancel()

self?.dismiss(animated: true)
},
submitAction: { [weak self] reasons in
self?.viewModel.sendFeedback(editRevId: nil, accepted: false, reasons: reasons.map { $0.apiIdentifier } , caption: nil, completion: { result in

guard let self,
let currentRecommendation = self.viewModel.currentRecommendation else {
return
}

// Logging
let rejectionReasons = reasons.map { $0.apiIdentifier }
let otherReason = reasons.first(where: {$0.otherText != nil})

self.loggingDelegate?.logRejectSurveyDidTapSubmit(rejectionReasons: rejectionReasons, otherReason: otherReason?.otherText, fileName: currentRecommendation.imageData.filename, recommendationSource: currentRecommendation.imageData.source)

// Send feedback API call
self.viewModel.sendFeedback(editRevId: nil, accepted: false, reasons: reasons.map { $0.apiIdentifier } , caption: nil, completion: { result in

})
// Dismisses Survey View
self?.dismiss(animated: true, completion: { [weak self] in
self.dismiss(animated: true, completion: { [weak self] in
// Dismisses Bottom Sheet
self?.dismiss(animated: true, completion: { [weak self] in
self?.viewModel.next {
Expand All @@ -106,9 +134,13 @@ extension WKImageRecommendationsBottomSheetViewController: WKImageRecommendation

let hostedView = WKComponentHostingController(rootView: surveyView)
present(hostedView, animated: true)

loggingDelegate?.logRejectSurveyDidAppear()
}

func didTapSkipButton() {
loggingDelegate?.logBottomSheetDidTapNotSure()

self.dismiss(animated: true) {
self.viewModel.next {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,26 @@ public protocol WKImageRecommendationsDelegate: AnyObject {
func imageRecommendationsUserDidTapReportIssue()
}

public protocol WKImageRecommendationsLoggingDelegate: AnyObject {
func logOnboardingDidTapPrimaryButton()
func logOnboardingDidTapSecondaryButton()
func logTooltipsDidTapFirstNext()
func logTooltipsDidTapSecondNext()
func logTooltipsDidTapThirdOK()
func logBottomSheetDidAppear()
func logBottomSheetDidTapYes()
func logBottomSheetDidTapNo()
func logBottomSheetDidTapNotSure()
func logOverflowDidTapLearnMore()
func logOverflowDidTapTutorial()
func logOverflowDidTapProblem()
func logBottomSheetDidTapFileName()
func logRejectSurveyDidAppear()
func logRejectSurveyDidTapCancel()
func logRejectSurveyDidTapSubmit(rejectionReasons: [String], otherReason: String?, fileName: String, recommendationSource: String)
func logEmptyStateDidTapBack()
}

fileprivate final class WKImageRecommendationsHostingViewController: WKComponentHostingController<WKImageRecommendationsView> {

init(viewModel: WKImageRecommendationsViewModel, delegate: WKImageRecommendationsDelegate, tooltipGeometryValues: WKTooltipGeometryValues) {
Expand All @@ -32,20 +52,24 @@ public final class WKImageRecommendationsViewController: WKCanvasViewController

fileprivate let hostingViewController: WKImageRecommendationsHostingViewController
private weak var delegate: WKImageRecommendationsDelegate?
private weak var loggingDelegate: WKImageRecommendationsLoggingDelegate?
@ObservedObject private var viewModel: WKImageRecommendationsViewModel
private var imageRecommendationBottomSheetController: WKImageRecommendationsBottomSheetViewController
private var cancellables = Set<AnyCancellable>()

private var overflowMenu: UIMenu {

let learnMore = UIAction(title: viewModel.localizedStrings.learnMoreButtonTitle, image: UIImage(systemName: "info.circle"), handler: { [weak self] _ in
self?.loggingDelegate?.logOverflowDidTapLearnMore()
self?.goToFAQ()
})
let tutorial = UIAction(title: viewModel.localizedStrings.tutorialButtonTitle, image: UIImage(systemName: "lightbulb.min"), handler: { [weak self] _ in
self?.loggingDelegate?.logOverflowDidTapTutorial()
self?.showTutorial()
})

let reportIssues = UIAction(title: viewModel.localizedStrings.problemWithFeatureButtonTitle, image: UIImage(systemName: "flag"), handler: { [weak self] _ in
self?.loggingDelegate?.logOverflowDidTapProblem()
self?.reportIssue()
})

Expand All @@ -59,11 +83,12 @@ public final class WKImageRecommendationsViewController: WKCanvasViewController
private let dataController = WKImageRecommendationsDataController()
private let tooltipGeometryValues = WKTooltipGeometryValues()

public init(viewModel: WKImageRecommendationsViewModel, delegate: WKImageRecommendationsDelegate) {
public init(viewModel: WKImageRecommendationsViewModel, delegate: WKImageRecommendationsDelegate, loggingDelegate: WKImageRecommendationsLoggingDelegate) {
self.hostingViewController = WKImageRecommendationsHostingViewController(viewModel: viewModel, delegate: delegate, tooltipGeometryValues: tooltipGeometryValues)
self.delegate = delegate
self.loggingDelegate = loggingDelegate
self.viewModel = viewModel
self.imageRecommendationBottomSheetController = WKImageRecommendationsBottomSheetViewController(viewModel: viewModel, delegate: delegate)
self.imageRecommendationBottomSheetController = WKImageRecommendationsBottomSheetViewController(viewModel: viewModel, delegate: delegate, loggingDelegate: loggingDelegate)
super.init()
}

Expand All @@ -77,6 +102,10 @@ public final class WKImageRecommendationsViewController: WKCanvasViewController
navigationItem.backButtonDisplayMode = .generic
setupOverflowMenu()
addComponent(hostingViewController, pinToEdges: true)

navigationController?.interactivePopGestureRecognizer?.isEnabled = false
let image = WKSFSymbolIcon.for(symbol: .chevronBackward, font: .boldBody)
navigationItem.leftBarButtonItem = UIBarButtonItem(image: image, style: .plain, target: self, action: #selector(tappedBack))
}

public override func viewWillAppear(_ animated: Bool) {
Expand Down Expand Up @@ -108,6 +137,16 @@ public final class WKImageRecommendationsViewController: WKCanvasViewController
}

// MARK: Private methods

@objc private func tappedBack() {

if viewModel.imageRecommendations.isEmpty {
loggingDelegate?.logEmptyStateDidTapBack()
}

navigationController?.interactivePopGestureRecognizer?.isEnabled = true
navigationController?.popViewController(animated: true)
}

private func setupOverflowMenu() {
let rightBarButtonItem = UIBarButtonItem(image: UIImage(systemName: "ellipsis.circle"), primaryAction: nil, menu: overflowMenu)
Expand All @@ -123,6 +162,7 @@ public final class WKImageRecommendationsViewController: WKCanvasViewController
bottomSheet.prefersGrabberVisible = true
bottomSheet.widthFollowsPreferredContentSizeWhenEdgeAttached = true
}

navigationController?.present(imageRecommendationBottomSheetController, animated: true, completion: {

DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { [weak self] in
Expand Down Expand Up @@ -176,16 +216,16 @@ public final class WKImageRecommendationsViewController: WKCanvasViewController
articleSummaryDivSourceRect = divGlobalFrame
}

let viewModel1 = WKTooltipViewModel(localizedStrings: viewModel.localizedStrings.firstTooltipStrings, buttonNeedsDisclosure: true, sourceView: hostingView, sourceRect: articleSummaryDivSourceRect, permittedArrowDirections: .up) {
print("do some logging 1")
let viewModel1 = WKTooltipViewModel(localizedStrings: viewModel.localizedStrings.firstTooltipStrings, buttonNeedsDisclosure: true, sourceView: hostingView, sourceRect: articleSummaryDivSourceRect, permittedArrowDirections: .up) { [weak self] in
self?.loggingDelegate?.logTooltipsDidTapFirstNext()
}

let viewModel2 = WKTooltipViewModel(localizedStrings: viewModel.localizedStrings.secondTooltipStrings, buttonNeedsDisclosure: true, sourceView: bottomSheetView, sourceRect: bottomSheetView.bounds) {
print("do some logging 2")
let viewModel2 = WKTooltipViewModel(localizedStrings: viewModel.localizedStrings.secondTooltipStrings, buttonNeedsDisclosure: true, sourceView: bottomSheetView, sourceRect: bottomSheetView.bounds) { [weak self] in
self?.loggingDelegate?.logTooltipsDidTapSecondNext()
}

let viewModel3 = WKTooltipViewModel(localizedStrings: viewModel.localizedStrings.thirdTooltipStrings, buttonNeedsDisclosure: false, sourceView: bottomSheetView, sourceRect: bottomSheetView.toolbar.frame) {
print("do some logging 3")
let viewModel3 = WKTooltipViewModel(localizedStrings: viewModel.localizedStrings.thirdTooltipStrings, buttonNeedsDisclosure: false, sourceView: bottomSheetView, sourceRect: bottomSheetView.toolbar.frame) { [weak self] in
self?.loggingDelegate?.logTooltipsDidTapThirdOK()
}

bottomSheetViewController.displayTooltips(tooltipViewModels: [viewModel1, viewModel2, viewModel3])
Expand Down Expand Up @@ -251,6 +291,8 @@ extension WKImageRecommendationsViewController: WKOnboardingViewDelegate {

}
})

loggingDelegate?.logOnboardingDidTapPrimaryButton()
}

public func onboardingViewDidClickSecondaryButton() {
Expand All @@ -259,6 +301,8 @@ extension WKImageRecommendationsViewController: WKOnboardingViewDelegate {
}

UIApplication.shared.open(url)

loggingDelegate?.logOnboardingDidTapSecondaryButton()
}

public func onboardingViewWillSwipeToDismiss() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public final class WKImageRecommendationsViewModel: ObservableObject {
public let image: String
public let filename: String
public let displayFilename: String
public let source: String
public let thumbUrl: String
public let fullUrl: String
public let description: String?
Expand All @@ -90,12 +91,13 @@ public final class WKImageRecommendationsViewModel: ObservableObject {
public internal(set) var uiImage: UIImage?
public let wikitext: String?

public init(pageId: Int, pageTitle: String, image: String, filename: String, displayFilename: String, thumbUrl: String, fullUrl: String, description: String?, descriptionURL: String, reason: String, wikitext: String?) {
public init(pageId: Int, pageTitle: String, image: String, filename: String, displayFilename: String, source: String, thumbUrl: String, fullUrl: String, description: String?, descriptionURL: String, reason: String, wikitext: String?) {
self.pageId = pageId
self.pageTitle = pageTitle
self.image = image
self.filename = filename
self.displayFilename = displayFilename
self.source = source
self.thumbUrl = thumbUrl
self.fullUrl = fullUrl
self.description = description
Expand All @@ -112,6 +114,8 @@ public final class WKImageRecommendationsViewModel: ObservableObject {
@Published var articleSummary: WKArticleSummary? = nil
public let imageData: WKImageRecommendationData
public var caption: String?
public var altText: String?
public var suggestionAcceptDate: Date?

fileprivate init(pageId: Int, title: String, articleSummary: WKArticleSummary? = nil, imageData: WKImageRecommendationData) {
self.pageId = pageId
Expand Down Expand Up @@ -322,6 +326,7 @@ public final class WKImageRecommendationsViewModel: ObservableObject {
image: firstImage.image,
filename: firstImage.image,
displayFilename: firstImage.displayFilename,
source: firstImage.source,
thumbUrl: metadata.thumbUrl,
fullUrl: metadata.fullUrl,
description: metadata.description,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ public struct WKImageRecommendation {
public struct ImageSuggestion: Codable {
public let image: String
public let displayFilename: String
let source: String
public let source: String
let projects: [String]
public let metadata: ImageMetadata
}
Expand Down
1 change: 0 additions & 1 deletion WKData/Sources/WKData/Models/Shared/WKEditSummaryTag.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,4 @@ public enum WKEditSummaryTag: String {
case diffRollback = "#diff-rollback"
case talkReply = "#talk-reply"
case talkTopic = "#talk-topic"
case suggestedEditsAddImageTop = "#suggestededit-add-image-top"
}
2 changes: 2 additions & 0 deletions WMF Framework/Event Platform/EventPlatformClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,7 @@ import CocoaLumberjackSwift
case watchlist = "ios.watchlists"
case appDonorExperience = "app_donor_experience"
case editInteraction = "ios.edit_interaction"
case imageRecommendation = "android.image_recommendation_event"
}

/**
Expand All @@ -156,6 +157,7 @@ import CocoaLumberjackSwift
case editAttempt = "/analytics/legacy/editattemptstep/2.0.3"
case watchlist = "/analytics/mobile_apps/ios_watchlists/4.0.0"
case appInteraction = "/analytics/mobile_apps/app_interaction/1.0.0"
case imageRecommendation = "/analytics/mobile_apps/android_image_recommendation_event/1.0.0"
}

/**
Expand Down

0 comments on commit e3dd3c4

Please sign in to comment.