From ad8561c8f7a6b17b83583fd37966396dfb59cba5 Mon Sep 17 00:00:00 2001 From: shannon Date: Wed, 6 Nov 2024 15:09:28 -0500 Subject: [PATCH] Add memoing of previously dismissed and contributed donation campaigns. --- Mastodon/Scene/Donation/DonationBanner.swift | 6 ++-- .../Donation/DonationCampaignViewModel.swift | 1 + .../Donation/DonationViewController.swift | 2 +- .../Donation/NewDonationNavigationFlow.swift | 1 + .../HomeTimelineViewController.swift | 5 ++- .../HomeTimelineViewModel+Donation.swift | 1 + .../SettingsViewController.swift | 1 + .../Mastodon+Entity+DonationCampaign.swift | 31 ++++++++++++++++++- 8 files changed, 42 insertions(+), 6 deletions(-) diff --git a/Mastodon/Scene/Donation/DonationBanner.swift b/Mastodon/Scene/Donation/DonationBanner.swift index 58c1b16650..cba429712a 100644 --- a/Mastodon/Scene/Donation/DonationBanner.swift +++ b/Mastodon/Scene/Donation/DonationBanner.swift @@ -10,7 +10,7 @@ class DonationBanner: UIView { static let textToButtonPadding: CGFloat = 48 } - private var campaign: Mastodon.Entity.DonationCampaign? + public private(set) var campaign: Mastodon.Entity.DonationCampaign? private lazy var backgroundImageView = UIImageView( image: Asset.Asset.scribble.image) private let messageLabel = UILabel() @@ -32,7 +32,7 @@ class DonationBanner: UIView { setupViews() } - var onClose: (() -> Void)? + var onClose: ((String?) -> Void)? var onShowDonationDialog: ((Mastodon.Entity.DonationCampaign) -> Void)? required init?(coder: NSCoder) { @@ -114,7 +114,7 @@ class DonationBanner: UIView { @objc private func closeButtonPressed(_ sender: Any?) { - onClose?() + onClose?(campaign?.id) } @objc diff --git a/Mastodon/Scene/Donation/DonationCampaignViewModel.swift b/Mastodon/Scene/Donation/DonationCampaignViewModel.swift index 049f561d8a..c18a0f03db 100644 --- a/Mastodon/Scene/Donation/DonationCampaignViewModel.swift +++ b/Mastodon/Scene/Donation/DonationCampaignViewModel.swift @@ -20,6 +20,7 @@ typealias DonationFrequency = Mastodon.Entity.DonationCampaign.DonationFrequency typealias DonationSource = Mastodon.Entity.DonationCampaign.DonationSource protocol DonationCampaignViewModel { + var id: String { get } func paymentURL( currency: String, source: DonationSource, frequency: Mastodon.Entity.DonationCampaign.DonationFrequency, diff --git a/Mastodon/Scene/Donation/DonationViewController.swift b/Mastodon/Scene/Donation/DonationViewController.swift index 9978579173..c79ee65a61 100644 --- a/Mastodon/Scene/Donation/DonationViewController.swift +++ b/Mastodon/Scene/Donation/DonationViewController.swift @@ -224,7 +224,7 @@ struct DonationButtonStyle: ButtonStyle { } struct DefaultDonationViewModel: DonationCampaignViewModel { - + var id: String = "default" var paymentBaseURL: URL? { if Mastodon.API.isTestingDonations { URL(string: "https://sponsor.staging.joinmastodon.org/donation/new") diff --git a/Mastodon/Scene/Donation/NewDonationNavigationFlow.swift b/Mastodon/Scene/Donation/NewDonationNavigationFlow.swift index bf1b4f2219..59cb7ded23 100644 --- a/Mastodon/Scene/Donation/NewDonationNavigationFlow.swift +++ b/Mastodon/Scene/Donation/NewDonationNavigationFlow.swift @@ -74,6 +74,7 @@ class NewDonationNavigationFlow: NavigationFlow { case "success": result = .successful(suggestedPost: campaign.donationSuccessPost) showDonationCompletionMessage(result) + Mastodon.Entity.DonationCampaign.didContribute(campaign.id) case "failure": let alert = UIAlertController( title: L10n.Scene.Donation.Success.serverErrorTitle, diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift index 57ede770ae..fa2ae8f7d1 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewController.swift @@ -451,8 +451,11 @@ extension HomeTimelineViewController { view.addSubview(donationBanner) donationBanner.alpha = 0 donationBanner.translatesAutoresizingMaskIntoConstraints = false - donationBanner.onClose = { [weak self] in + donationBanner.onClose = { [weak self] campaignID in self?.hideDonationCampaignBanner() + if let campaignID { + Mastodon.Entity.DonationCampaign.didDismiss(campaignID) + } } donationBanner.onShowDonationDialog = { [weak self] campaign in self?.showDonationCampaign(campaign) diff --git a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Donation.swift b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Donation.swift index 45af175a30..8cef7ae457 100644 --- a/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Donation.swift +++ b/Mastodon/Scene/HomeTimeline/HomeTimelineViewModel+Donation.swift @@ -25,6 +25,7 @@ extension HomeTimelineViewModel { do { let campaign = try await self.context.apiService .getDonationCampaign(seed: seed, source: nil).value + guard !Mastodon.Entity.DonationCampaign.hasPreviouslyDismissed(campaign.id) && !Mastodon.Entity.DonationCampaign.hasPreviouslyContributed(campaign.id) else { return } onPresentDonationCampaign.send(campaign) } catch { // no-op diff --git a/Mastodon/Scene/Settings/Settings Overview/SettingsViewController.swift b/Mastodon/Scene/Settings/Settings Overview/SettingsViewController.swift index 53f864d64e..64f40be81d 100644 --- a/Mastodon/Scene/Settings/Settings Overview/SettingsViewController.swift +++ b/Mastodon/Scene/Settings/Settings Overview/SettingsViewController.swift @@ -12,6 +12,7 @@ protocol SettingsViewControllerDelegate: AnyObject { class SettingsViewController: UIViewController { let sections: [SettingsSection] + var donationCampaign: Mastodon.Entity.DonationCampaign? weak var delegate: SettingsViewControllerDelegate? var tableViewDataSource: UITableViewDiffableDataSource? diff --git a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+DonationCampaign.swift b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+DonationCampaign.swift index 4217f214ac..92702928ab 100644 --- a/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+DonationCampaign.swift +++ b/MastodonSDK/Sources/MastodonSDK/Entity/Mastodon+Entity+DonationCampaign.swift @@ -2,6 +2,10 @@ import Foundation +private let maxCampaignsToRemember = 25 +private let dismissedCampaignsKey = "dismissed_donation_campaigns" +private let contributedCampaignsKey = "contributed_donation_campaigns" + extension Mastodon.Entity { public enum DonationError: Swift.Error { @@ -9,7 +13,7 @@ extension Mastodon.Entity { } public struct DonationCampaign: Codable { - + public enum DonationSource { case campaign(id: String) case menu @@ -113,5 +117,30 @@ extension Mastodon.Entity { case donationSuccessPost = "donation_success_post" case amounts } + + static public func hasPreviouslyDismissed(_ campaign: String) -> Bool { + let ids = UserDefaults.standard.array(forKey: dismissedCampaignsKey) as? [String] + return ids?.contains(campaign) ?? false + } + static public func hasPreviouslyContributed(_ campaign: String) -> Bool { + let ids = UserDefaults.standard.array(forKey: contributedCampaignsKey) as? [String] + return ids?.contains(campaign) ?? false + } + static public func didDismiss(_ campaign: String) { + var ids = UserDefaults.standard.array(forKey: dismissedCampaignsKey) as? [String] ?? [] + if ids.count == maxCampaignsToRemember { + ids.removeFirst() + } + ids.append(campaign) + UserDefaults.standard.setValue(ids, forKey: dismissedCampaignsKey) + } + static public func didContribute(_ campaign: String) { + var ids = UserDefaults.standard.array(forKey: contributedCampaignsKey) as? [String] ?? [] + if ids.count == maxCampaignsToRemember { + ids.removeFirst() + } + ids.append(campaign) + UserDefaults.standard.setValue(ids, forKey: contributedCampaignsKey) + } } }