Skip to content

Commit

Permalink
Fix brave/brave-ios#8211: Remove the dislike swipe action on ads (bra…
Browse files Browse the repository at this point in the history
…ve/brave-ios#8304)

This also cleans up and removes the unused open swipe action and accompanying pan gesture
  • Loading branch information
kylehickinson authored Oct 23, 2023
1 parent b5e354f commit 46d8bf6
Show file tree
Hide file tree
Showing 7 changed files with 1 addition and 164 deletions.

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

0 comments on commit 46d8bf6

Please sign in to comment.