-
-
Notifications
You must be signed in to change notification settings - Fork 274
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add ability to donate to Mastodon from the app (#1353)
This change only affects users logged in to mastodon.social or mastodon.online. A banner may be periodically displayed at the bottom of the homescreen encouraging donations and menu options are now available in Settings to make new donations or manage existing ones. Amounts will not necessarily be returned from the server in order. The first amount returned is taken as the default and the amounts are sorted before display. --------- Co-authored-by: Marcus Kida <[email protected]>
- Loading branch information
1 parent
fdca501
commit 9d774cb
Showing
41 changed files
with
1,862 additions
and
40 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,125 @@ | ||
// Copyright © 2024 Mastodon gGmbH. All rights reserved. | ||
|
||
import MastodonAsset | ||
import MastodonSDK | ||
import UIKit | ||
|
||
class DonationBanner: UIView { | ||
private enum Constants { | ||
static let padding: CGFloat = 16 | ||
static let textToButtonPadding: CGFloat = 48 | ||
} | ||
|
||
public private(set) var campaign: Mastodon.Entity.DonationCampaign? | ||
private lazy var backgroundImageView = UIImageView( | ||
image: Asset.Asset.scribble.image) | ||
private let messageLabel = UILabel() | ||
private lazy var closeButton: UIButton = { | ||
let button = UIButton(type: .custom) | ||
button.setImage(.init(systemName: "xmark"), for: .normal) | ||
return button | ||
}() | ||
private lazy var tapGestureRecognizer: UITapGestureRecognizer = { | ||
let gestureRecognizer = UITapGestureRecognizer( | ||
target: self, action: #selector(showDonationDialogPressed(_:))) | ||
gestureRecognizer.numberOfTapsRequired = 1 | ||
return gestureRecognizer | ||
}() | ||
|
||
init() { | ||
super.init(frame: .zero) | ||
self.overrideUserInterfaceStyle = .dark | ||
setupViews() | ||
} | ||
|
||
var onClose: ((String?) -> Void)? | ||
var onShowDonationDialog: ((Mastodon.Entity.DonationCampaign) -> Void)? | ||
|
||
required init?(coder: NSCoder) { | ||
fatalError("init(coder:) has not been implemented") | ||
} | ||
|
||
func update(campaign: Mastodon.Entity.DonationCampaign) { | ||
self.campaign = campaign | ||
let spacing = " " | ||
let stringValue = | ||
"\(campaign.bannerMessage)\(spacing)\(campaign.bannerButtonText)" | ||
let attributedString = NSMutableAttributedString(string: stringValue) | ||
let fullTextRange = NSRange(location: 0, length: stringValue.length) | ||
let buttonRange = NSRange( | ||
location: campaign.bannerMessage.length + spacing.length, | ||
length: campaign.bannerButtonText.length) | ||
attributedString.addAttributes( | ||
[ | ||
.font: UIFontMetrics(forTextStyle: .body).scaledFont( | ||
for: .systemFont(ofSize: 14, weight: .regular)), | ||
.foregroundColor: Asset.Colors.Secondary.onContainer.color, | ||
], | ||
range: fullTextRange | ||
) | ||
attributedString.addAttributes( | ||
[ | ||
.font: UIFontMetrics(forTextStyle: .body).scaledFont( | ||
for: .systemFont(ofSize: 14, weight: .bold)), | ||
.underlineStyle: NSUnderlineStyle.single.rawValue, | ||
.underlineColor: Asset.Colors.goldenrod.color, | ||
.foregroundColor: Asset.Colors.goldenrod.color, | ||
], | ||
range: buttonRange | ||
) | ||
messageLabel.attributedText = attributedString | ||
} | ||
|
||
private func setupViews() { | ||
addGestureRecognizer(tapGestureRecognizer) | ||
backgroundColor = Asset.Colors.Secondary.container.color | ||
addSubview(backgroundImageView) | ||
backgroundImageView.translatesAutoresizingMaskIntoConstraints = false | ||
backgroundImageView.alpha = 0.08 | ||
|
||
closeButton.tintColor = Asset.Colors.Secondary.onContainer.color | ||
|
||
messageLabel.translatesAutoresizingMaskIntoConstraints = false | ||
messageLabel.numberOfLines = 0 | ||
|
||
closeButton.translatesAutoresizingMaskIntoConstraints = false | ||
closeButton.setContentCompressionResistancePriority( | ||
.required, for: .horizontal) | ||
closeButton.addTarget( | ||
self, action: #selector(closeButtonPressed(_:)), for: .touchUpInside | ||
) | ||
addSubview(messageLabel) | ||
addSubview(closeButton) | ||
|
||
NSLayoutConstraint.activate([ | ||
backgroundImageView.trailingAnchor.constraint( | ||
equalTo: trailingAnchor), | ||
backgroundImageView.centerYAnchor.constraint( | ||
equalTo: centerYAnchor), | ||
messageLabel.leadingAnchor.constraint( | ||
equalTo: leadingAnchor, constant: Constants.padding), | ||
messageLabel.topAnchor.constraint( | ||
equalTo: topAnchor, constant: Constants.padding), | ||
messageLabel.bottomAnchor.constraint( | ||
equalTo: bottomAnchor, constant: -Constants.padding), | ||
messageLabel.trailingAnchor.constraint( | ||
equalTo: closeButton.leadingAnchor, | ||
constant: -Constants.padding * 2), | ||
closeButton.trailingAnchor.constraint( | ||
equalTo: trailingAnchor, constant: -Constants.padding / 2), | ||
closeButton.topAnchor.constraint(equalTo: topAnchor), | ||
closeButton.bottomAnchor.constraint(equalTo: bottomAnchor), | ||
]) | ||
} | ||
|
||
@objc | ||
private func closeButtonPressed(_ sender: Any?) { | ||
onClose?(campaign?.id) | ||
} | ||
|
||
@objc | ||
private func showDonationDialogPressed(_ sender: Any?) { | ||
guard let campaign else { return } | ||
onShowDonationDialog?(campaign) | ||
} | ||
} |
Oops, something went wrong.