Skip to content
This repository has been archived by the owner on May 10, 2024. It is now read-only.

Fix #8211: Remove the dislike swipe action on ads #8304

Merged
merged 1 commit into from
Oct 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

This file was deleted.

This file was deleted.

Binary file not shown.
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@ class RewardsNotification: NSObject, BraveNotification {
case dismissed
/// The user ignored the ad for a given amount of time for it to automatically dismiss
case timedOut
/// The user clicked the thumbs down button by swiping on the ad
case disliked
}

var view: UIView
Expand All @@ -31,14 +29,13 @@ class RewardsNotification: NSObject, BraveNotification {
if !AppConstants.buildChannel.isPublic, let override = Preferences.Rewards.adsDurationOverride.value, override > 0 {
dismissTimeInterval = TimeInterval(override)
}
return adView.swipeTranslation != 0 ? .explicit : .automatic(after: dismissTimeInterval)
return .automatic(after: dismissTimeInterval)
}

private let handler: (Action) -> Void

func willDismiss(timedOut: Bool) {
guard let adView = view as? AdView else { return }
adView.setSwipeTranslation(0, animated: true)
handler(timedOut ? .timedOut : .dismissed)
}

Expand All @@ -60,88 +57,13 @@ class RewardsNotification: NSObject, BraveNotification {
adView.adContentButton.bodyLabel.text = ad.body

adView.adContentButton.addTarget(self, action: #selector(tappedAdView(_:)), for: .touchUpInside)
adView.openSwipeButton.addTarget(self, action: #selector(tappedOpen(_:)), for: .touchUpInside)
adView.dislikeSwipeButton.addTarget(self, action: #selector(tappedDisliked(_:)), for: .touchUpInside)

let swipePanGesture = UIPanGestureRecognizer(target: self, action: #selector(swipePannedAdView(_:)))
swipePanGesture.delegate = self
adView.addGestureRecognizer(swipePanGesture)
}

@objc private func tappedAdView(_ sender: AdContentButton) {
guard let adView = sender.superview as? AdView else { return }
if sender.transform.tx != 0 {
adView.setSwipeTranslation(0, animated: true)
return
}
dismissAction?()
handler(.opened)
}

@objc private func tappedOpen(_ sender: AdSwipeButton) {
dismissAction?()
handler(.opened)
}

@objc private func tappedDisliked(_ sender: AdSwipeButton) {
dismissAction?()
handler(.disliked)
}

// Distance travelled after decelerating to zero velocity at a constant rate
private func project(initialVelocity: CGFloat, decelerationRate: CGFloat) -> CGFloat {
return (initialVelocity / 1000.0) * decelerationRate / (1.0 - decelerationRate)
}

private let actionTriggerThreshold: CGFloat = 180.0
private let actionRestThreshold: CGFloat = 90.0

private var swipeState: CGFloat = 0
@objc private func swipePannedAdView(_ pan: UIPanGestureRecognizer) {
guard let adView = pan.view as? AdView else { return }
switch pan.state {
case .began:
swipeState = adView.adContentButton.transform.tx
case .changed:
let tx = swipeState + pan.translation(in: adView).x
if tx < -actionTriggerThreshold && !adView.dislikeSwipeButton.isHighlighted {
UIImpactFeedbackGenerator(style: .medium).bzzt()
}
adView.dislikeSwipeButton.isHighlighted = tx < -actionTriggerThreshold
adView.adContentButton.transform.tx = min(0, tx)
adView.setNeedsLayout()
case .ended:
let velocity = pan.velocity(in: adView).x
let tx = swipeState + pan.translation(in: adView).x
let projected = project(initialVelocity: velocity, decelerationRate: UIScrollView.DecelerationRate.normal.rawValue)
if /*tx > actionTriggerThreshold ||*/ tx < -actionTriggerThreshold {
adView.setSwipeTranslation(0, animated: true, panVelocity: velocity)
dismissAction?()
handler(tx > 0 ? .opened : .disliked)
break
} else if /*tx + projected > actionRestThreshold ||*/ tx + projected < -actionRestThreshold {
adView.setSwipeTranslation((tx + projected) > 0 ? actionRestThreshold : -actionRestThreshold, animated: true, panVelocity: velocity)
break
}
fallthrough
case .cancelled:
adView.setSwipeTranslation(0, animated: true)
default:
break
}
}
}

extension RewardsNotification: UIGestureRecognizerDelegate {

func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
if let pan = gestureRecognizer as? UIPanGestureRecognizer {
let velocity = pan.velocity(in: pan.view)
// Horizontal only
return abs(velocity.x) > abs(velocity.y)
}
return false
}
}

extension RewardsNotification {
Expand Down
54 changes: 0 additions & 54 deletions Sources/Brave/Frontend/Brave Rewards/Ads/AdView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,71 +8,17 @@ import Shared

public class AdView: UIView {
let adContentButton = AdContentButton()
let openSwipeButton = AdSwipeButton(contentType: .text(Strings.Ads.open, textColor: .white)).then {
$0.backgroundColor = .braveBlurpleTint
}
let dislikeSwipeButton = AdSwipeButton(contentType: .image(UIImage(named: "dislike-ad-icon", in: .module, compatibleWith: nil)!)).then {
$0.backgroundColor = .braveErrorLabel
}

public override init(frame: CGRect) {
super.init(frame: frame)

addSubview(adContentButton)
// addSubview(openSwipeButton)
addSubview(dislikeSwipeButton)

adContentButton.snp.makeConstraints {
$0.edges.equalTo(self)
}
}

public override func layoutSubviews() {
super.layoutSubviews()

// let openWidth = max(0, adContentButton.frame.minX - 8)
// openSwipeButton.frame = CGRect(
// x: 0,
// y: 0,
// width: openWidth,
// height: adContentButton.bounds.height
// )
// openSwipeButton.alpha = max(0, openWidth - 30) / 20

let dislikeWidth = max(0, bounds.width - adContentButton.frame.maxX - 8)
dislikeSwipeButton.frame = CGRect(
x: adContentButton.frame.maxX + 8,
y: 0,
width: dislikeWidth,
height: adContentButton.bounds.height
)
dislikeSwipeButton.alpha = max(0, dislikeWidth - 30) / 20
}

var swipeTranslation: CGFloat {
return adContentButton.transform.tx
}

/// Set the horizontal swipe translation
func setSwipeTranslation(_ tx: CGFloat, animated: Bool = false, panVelocity: CGFloat? = nil, completionBlock: (() -> Void)? = nil) {
if animated {
let springTiming = UISpringTimingParameters(dampingRatio: 0.9)
let animator = UIViewPropertyAnimator(duration: 0.3, timingParameters: springTiming)
animator.addAnimations { [self] in
adContentButton.transform.tx = tx
setNeedsLayout()
layoutIfNeeded()
}
animator.addCompletion { _ in
completionBlock?()
}
animator.startAnimation()
} else {
adContentButton.transform.tx = tx
setNeedsLayout()
}
}

@available(*, unavailable)
required init(coder: NSCoder) {
fatalError()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,6 @@ class AdsNotificationHandler: BraveAdsNotificationHandler {
self.ads.reportNotificationAdEvent(notification.placementID, eventType: .dismissed, completion: { _ in })
case .timedOut:
self.ads.reportNotificationAdEvent(notification.placementID, eventType: .timedOut, completion: { _ in })
case .disliked:
self.ads.reportNotificationAdEvent(notification.placementID, eventType: .dismissed, completion: { _ in })
self.ads.toggleThumbsDown(forAd: notification.creativeInstanceID, advertiserId: notification.advertiserID, segment: notification.segment)
}
self.actionOccured?(notification, action)
}
Expand Down