chore: renaming reblog

This commit is contained in:
CMK 2021-03-15 18:19:45 +08:00
parent 4005581d24
commit 6eb3816bab
8 changed files with 94 additions and 91 deletions

View File

@ -294,7 +294,7 @@ extension StatusSection {
let toot = object as? Toot else { return } let toot = object as? Toot else { return }
StatusSection.configureActionToolBar(cell: cell, toot: toot, requestUserID: requestUserID) StatusSection.configureActionToolBar(cell: cell, toot: toot, requestUserID: requestUserID)
os_log("%{public}s[%{public}ld], %{public}s: boost count label for toot %s did update: %ld", (#file as NSString).lastPathComponent, #line, #function, toot.id, toot.reblogsCount.intValue) os_log("%{public}s[%{public}ld], %{public}s: reblog count label for toot %s did update: %ld", (#file as NSString).lastPathComponent, #line, #function, toot.id, toot.reblogsCount.intValue)
os_log("%{public}s[%{public}ld], %{public}s: like count label for toot %s did update: %ld", (#file as NSString).lastPathComponent, #line, #function, toot.id, toot.favouritesCount.intValue) os_log("%{public}s[%{public}ld], %{public}s: like count label for toot %s did update: %ld", (#file as NSString).lastPathComponent, #line, #function, toot.id, toot.favouritesCount.intValue)
} }
.store(in: &cell.disposeBag) .store(in: &cell.disposeBag)
@ -313,14 +313,14 @@ extension StatusSection {
return StatusSection.formattedNumberTitleForActionButton(count) return StatusSection.formattedNumberTitleForActionButton(count)
}() }()
cell.statusView.actionToolbarContainer.replyButton.setTitle(replyCountTitle, for: .normal) cell.statusView.actionToolbarContainer.replyButton.setTitle(replyCountTitle, for: .normal)
// set boost // set reblog
let isBoosted = toot.rebloggedBy.flatMap { $0.contains(where: { $0.id == requestUserID }) } ?? false let isReblogged = toot.rebloggedBy.flatMap { $0.contains(where: { $0.id == requestUserID }) } ?? false
let boostCountTitle: String = { let reblogCountTitle: String = {
let count = toot.reblogsCount.intValue let count = toot.reblogsCount.intValue
return StatusSection.formattedNumberTitleForActionButton(count) return StatusSection.formattedNumberTitleForActionButton(count)
}() }()
cell.statusView.actionToolbarContainer.boostButton.setTitle(boostCountTitle, for: .normal) cell.statusView.actionToolbarContainer.reblogButton.setTitle(reblogCountTitle, for: .normal)
cell.statusView.actionToolbarContainer.isBoostButtonHighlight = isBoosted cell.statusView.actionToolbarContainer.isReblogButtonHighlight = isReblogged
// set like // set like
let isLike = toot.favouritedBy.flatMap { $0.contains(where: { $0.id == requestUserID }) } ?? false let isLike = toot.favouritedBy.flatMap { $0.contains(where: { $0.id == requestUserID }) } ?? false
let favoriteCountTitle: String = { let favoriteCountTitle: String = {

View File

@ -16,8 +16,8 @@ import ActiveLabel
// MARK: - ActionToolbarContainerDelegate // MARK: - ActionToolbarContainerDelegate
extension StatusTableViewCellDelegate where Self: StatusProvider { extension StatusTableViewCellDelegate where Self: StatusProvider {
func statusTableViewCell(_ cell: StatusTableViewCell, actionToolbarContainer: ActionToolbarContainer, boostButtonDidPressed sender: UIButton) { func statusTableViewCell(_ cell: StatusTableViewCell, actionToolbarContainer: ActionToolbarContainer, reblogButtonDidPressed sender: UIButton) {
StatusProviderFacade.responseToStatusBoostAction(provider: self, cell: cell) StatusProviderFacade.responseToStatusReblogAction(provider: self, cell: cell)
} }
func statusTableViewCell(_ cell: StatusTableViewCell, actionToolbarContainer: ActionToolbarContainer, likeButtonDidPressed sender: UIButton) { func statusTableViewCell(_ cell: StatusTableViewCell, actionToolbarContainer: ActionToolbarContainer, likeButtonDidPressed sender: UIButton) {

View File

@ -130,7 +130,7 @@ extension StatusProviderFacade {
) )
} }
static func responseToStatusBoostAction(provider: StatusProvider, cell: UITableViewCell) { static func responseToStatusReblogAction(provider: StatusProvider, cell: UITableViewCell) {
_responseToStatusBoostAction( _responseToStatusBoostAction(
provider: provider, provider: provider,
toot: provider.toot(for: cell, indexPath: nil) toot: provider.toot(for: cell, indexPath: nil)
@ -160,21 +160,21 @@ extension StatusProviderFacade {
let responseFeedbackGenerator = UIImpactFeedbackGenerator(style: .medium) let responseFeedbackGenerator = UIImpactFeedbackGenerator(style: .medium)
toot toot
.compactMap { toot -> (NSManagedObjectID, Mastodon.API.Reblog.BoostKind)? in .compactMap { toot -> (NSManagedObjectID, Mastodon.API.Reblog.ReblogKind)? in
guard let toot = toot?.reblog ?? toot else { return nil } guard let toot = toot?.reblog ?? toot else { return nil }
let boostKind: Mastodon.API.Reblog.BoostKind = { let reblogKind: Mastodon.API.Reblog.ReblogKind = {
let isBoosted = toot.rebloggedBy.flatMap { $0.contains(where: { $0.id == mastodonUserID }) } ?? false let isReblogged = toot.rebloggedBy.flatMap { $0.contains(where: { $0.id == mastodonUserID }) } ?? false
return isBoosted ? .undoBoost : .boost return isReblogged ? .undoReblog : .reblog(query: .init(visibility: nil))
}() }()
return (toot.objectID, boostKind) return (toot.objectID, reblogKind)
} }
.map { tootObjectID, boostKind -> AnyPublisher<(Toot.ID, Mastodon.API.Reblog.BoostKind), Error> in .map { tootObjectID, reblogKind -> AnyPublisher<(Toot.ID, Mastodon.API.Reblog.ReblogKind), Error> in
return context.apiService.boost( return context.apiService.reblog(
tootObjectID: tootObjectID, tootObjectID: tootObjectID,
mastodonUserObjectID: mastodonUserObjectID, mastodonUserObjectID: mastodonUserObjectID,
boostKind: boostKind reblogKind: reblogKind
) )
.map { tootID in (tootID, boostKind) } .map { tootID in (tootID, reblogKind) }
.eraseToAnyPublisher() .eraseToAnyPublisher()
} }
.setFailureType(to: Error.self) .setFailureType(to: Error.self)
@ -184,9 +184,14 @@ extension StatusProviderFacade {
.handleEvents { _ in .handleEvents { _ in
generator.prepare() generator.prepare()
responseFeedbackGenerator.prepare() responseFeedbackGenerator.prepare()
} receiveOutput: { _, boostKind in } receiveOutput: { _, reblogKind in
generator.impactOccurred() generator.impactOccurred()
os_log("%{public}s[%{public}ld], %{public}s: [Boost] update local toot reblog status to: %s", ((#file as NSString).lastPathComponent), #line, #function, boostKind == .boost ? "boost" : "unboost") switch reblogKind {
case .reblog:
os_log("%{public}s[%{public}ld], %{public}s: [Reblog] update local toot reblog status to: %s", ((#file as NSString).lastPathComponent), #line, #function, "reblog")
case .undoReblog:
os_log("%{public}s[%{public}ld], %{public}s: [Reblog] update local toot reblog status to: %s", ((#file as NSString).lastPathComponent), #line, #function, "unboost")
}
} receiveCompletion: { completion in } receiveCompletion: { completion in
switch completion { switch completion {
case .failure: case .failure:
@ -196,10 +201,10 @@ extension StatusProviderFacade {
break break
} }
} }
.map { tootID, boostKind in .map { tootID, reblogKind in
return context.apiService.boost( return context.apiService.reblog(
statusID: tootID, statusID: tootID,
boostKind: boostKind, reblogKind: reblogKind,
mastodonAuthenticationBox: activeMastodonAuthenticationBox mastodonAuthenticationBox: activeMastodonAuthenticationBox
) )
} }
@ -212,9 +217,9 @@ extension StatusProviderFacade {
} }
switch completion { switch completion {
case .failure(let error): case .failure(let error):
os_log("%{public}s[%{public}ld], %{public}s: [Boost] remote boost request fail: %{public}s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription) os_log("%{public}s[%{public}ld], %{public}s: [Reblog] remote reblog request fail: %{public}s", ((#file as NSString).lastPathComponent), #line, #function, error.localizedDescription)
case .finished: case .finished:
os_log("%{public}s[%{public}ld], %{public}s: [Boost] remote boost request success", ((#file as NSString).lastPathComponent), #line, #function) os_log("%{public}s[%{public}ld], %{public}s: [Reblog] remote reblog request success", ((#file as NSString).lastPathComponent), #line, #function)
} }
} receiveValue: { response in } receiveValue: { response in
// do nothing // do nothing

View File

@ -49,7 +49,7 @@ final class StatusView: UIView {
let label = UILabel() let label = UILabel()
label.font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .medium)) label.font = UIFontMetrics(forTextStyle: .footnote).scaledFont(for: .systemFont(ofSize: 13, weight: .medium))
label.textColor = Asset.Colors.Label.secondary.color label.textColor = Asset.Colors.Label.secondary.color
label.text = "Bob boosted" label.text = "Bob reblogged"
return label return label
}() }()
@ -491,7 +491,7 @@ struct StatusView_Previews: PreviewProvider {
return statusView return statusView
} }
.previewLayout(.fixed(width: 375, height: 200)) .previewLayout(.fixed(width: 375, height: 200))
.previewDisplayName("Boost") .previewDisplayName("Reblog")
UIViewPreview(width: 375) { UIViewPreview(width: 375) {
let statusView = StatusView(frame: CGRect(x: 0, y: 0, width: 375, height: 500)) let statusView = StatusView(frame: CGRect(x: 0, y: 0, width: 375, height: 500))
statusView.configure( statusView.configure(

View File

@ -25,7 +25,7 @@ protocol StatusTableViewCellDelegate: class {
func statusTableViewCell(_ cell: StatusTableViewCell, mosaicImageViewContainer: MosaicImageViewContainer, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView) func statusTableViewCell(_ cell: StatusTableViewCell, mosaicImageViewContainer: MosaicImageViewContainer, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
func statusTableViewCell(_ cell: StatusTableViewCell, mosaicImageViewContainer: MosaicImageViewContainer, didTapImageView imageView: UIImageView, atIndex index: Int) func statusTableViewCell(_ cell: StatusTableViewCell, mosaicImageViewContainer: MosaicImageViewContainer, didTapImageView imageView: UIImageView, atIndex index: Int)
func statusTableViewCell(_ cell: StatusTableViewCell, playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView) func statusTableViewCell(_ cell: StatusTableViewCell, playerContainerView: PlayerContainerView, contentWarningOverlayViewDidPressed contentWarningOverlayView: ContentWarningOverlayView)
func statusTableViewCell(_ cell: StatusTableViewCell, actionToolbarContainer: ActionToolbarContainer, boostButtonDidPressed sender: UIButton) func statusTableViewCell(_ cell: StatusTableViewCell, actionToolbarContainer: ActionToolbarContainer, reblogButtonDidPressed sender: UIButton)
func statusTableViewCell(_ cell: StatusTableViewCell, actionToolbarContainer: ActionToolbarContainer, likeButtonDidPressed sender: UIButton) func statusTableViewCell(_ cell: StatusTableViewCell, actionToolbarContainer: ActionToolbarContainer, likeButtonDidPressed sender: UIButton)
func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, pollVoteButtonPressed button: UIButton) func statusTableViewCell(_ cell: StatusTableViewCell, statusView: StatusView, pollVoteButtonPressed button: UIButton)
@ -227,8 +227,8 @@ extension StatusTableViewCell: ActionToolbarContainerDelegate {
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, replayButtonDidPressed sender: UIButton) { func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, replayButtonDidPressed sender: UIButton) {
} }
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, boostButtonDidPressed sender: UIButton) { func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, reblogButtonDidPressed sender: UIButton) {
delegate?.statusTableViewCell(self, actionToolbarContainer: actionToolbarContainer, boostButtonDidPressed: sender) delegate?.statusTableViewCell(self, actionToolbarContainer: actionToolbarContainer, reblogButtonDidPressed: sender)
} }
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, starButtonDidPressed sender: UIButton) { func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, starButtonDidPressed sender: UIButton) {
delegate?.statusTableViewCell(self, actionToolbarContainer: actionToolbarContainer, likeButtonDidPressed: sender) delegate?.statusTableViewCell(self, actionToolbarContainer: actionToolbarContainer, likeButtonDidPressed: sender)

View File

@ -10,7 +10,7 @@ import UIKit
protocol ActionToolbarContainerDelegate: class { protocol ActionToolbarContainerDelegate: class {
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, replayButtonDidPressed sender: UIButton) func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, replayButtonDidPressed sender: UIButton)
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, boostButtonDidPressed sender: UIButton) func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, reblogButtonDidPressed sender: UIButton)
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, starButtonDidPressed sender: UIButton) func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, starButtonDidPressed sender: UIButton)
func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, moreButtonDidPressed sender: UIButton) func actionToolbarContainer(_ actionToolbarContainer: ActionToolbarContainer, moreButtonDidPressed sender: UIButton)
} }
@ -19,12 +19,12 @@ protocol ActionToolbarContainerDelegate: class {
final class ActionToolbarContainer: UIView { final class ActionToolbarContainer: UIView {
let replyButton = HitTestExpandedButton() let replyButton = HitTestExpandedButton()
let boostButton = HitTestExpandedButton() let reblogButton = HitTestExpandedButton()
let favoriteButton = HitTestExpandedButton() let favoriteButton = HitTestExpandedButton()
let moreButton = HitTestExpandedButton() let moreButton = HitTestExpandedButton()
var isBoostButtonHighlight: Bool = false { var isReblogButtonHighlight: Bool = false {
didSet { isBoostButtonHighlightStateDidChange(to: isBoostButtonHighlight) } didSet { isReblogButtonHighlightStateDidChange(to: isReblogButtonHighlight) }
} }
var isFavoriteButtonHighlight: Bool = false { var isFavoriteButtonHighlight: Bool = false {
@ -61,7 +61,7 @@ extension ActionToolbarContainer {
]) ])
replyButton.addTarget(self, action: #selector(ActionToolbarContainer.replyButtonDidPressed(_:)), for: .touchUpInside) replyButton.addTarget(self, action: #selector(ActionToolbarContainer.replyButtonDidPressed(_:)), for: .touchUpInside)
boostButton.addTarget(self, action: #selector(ActionToolbarContainer.boostButtonDidPressed(_:)), for: .touchUpInside) reblogButton.addTarget(self, action: #selector(ActionToolbarContainer.reblogButtonDidPressed(_:)), for: .touchUpInside)
favoriteButton.addTarget(self, action: #selector(ActionToolbarContainer.favoriteButtonDidPressed(_:)), for: .touchUpInside) favoriteButton.addTarget(self, action: #selector(ActionToolbarContainer.favoriteButtonDidPressed(_:)), for: .touchUpInside)
moreButton.addTarget(self, action: #selector(ActionToolbarContainer.moreButtonDidPressed(_:)), for: .touchUpInside) moreButton.addTarget(self, action: #selector(ActionToolbarContainer.moreButtonDidPressed(_:)), for: .touchUpInside)
} }
@ -93,7 +93,7 @@ extension ActionToolbarContainer {
subview.removeFromSuperview() subview.removeFromSuperview()
} }
let buttons = [replyButton, boostButton, favoriteButton, moreButton] let buttons = [replyButton, reblogButton, favoriteButton, moreButton]
buttons.forEach { button in buttons.forEach { button in
button.tintColor = Asset.Colors.Button.actionToolbar.color button.tintColor = Asset.Colors.Button.actionToolbar.color
button.titleLabel?.font = .monospacedDigitSystemFont(ofSize: 12, weight: .regular) button.titleLabel?.font = .monospacedDigitSystemFont(ofSize: 12, weight: .regular)
@ -113,7 +113,7 @@ extension ActionToolbarContainer {
button.contentHorizontalAlignment = .leading button.contentHorizontalAlignment = .leading
} }
replyButton.setImage(replyImage, for: .normal) replyButton.setImage(replyImage, for: .normal)
boostButton.setImage(reblogImage, for: .normal) reblogButton.setImage(reblogImage, for: .normal)
favoriteButton.setImage(starImage, for: .normal) favoriteButton.setImage(starImage, for: .normal)
moreButton.setImage(moreImage, for: .normal) moreButton.setImage(moreImage, for: .normal)
@ -121,19 +121,19 @@ extension ActionToolbarContainer {
container.distribution = .fill container.distribution = .fill
replyButton.translatesAutoresizingMaskIntoConstraints = false replyButton.translatesAutoresizingMaskIntoConstraints = false
boostButton.translatesAutoresizingMaskIntoConstraints = false reblogButton.translatesAutoresizingMaskIntoConstraints = false
favoriteButton.translatesAutoresizingMaskIntoConstraints = false favoriteButton.translatesAutoresizingMaskIntoConstraints = false
moreButton.translatesAutoresizingMaskIntoConstraints = false moreButton.translatesAutoresizingMaskIntoConstraints = false
container.addArrangedSubview(replyButton) container.addArrangedSubview(replyButton)
container.addArrangedSubview(boostButton) container.addArrangedSubview(reblogButton)
container.addArrangedSubview(favoriteButton) container.addArrangedSubview(favoriteButton)
container.addArrangedSubview(moreButton) container.addArrangedSubview(moreButton)
NSLayoutConstraint.activate([ NSLayoutConstraint.activate([
replyButton.heightAnchor.constraint(equalToConstant: 44).priority(.defaultHigh), replyButton.heightAnchor.constraint(equalToConstant: 44).priority(.defaultHigh),
replyButton.heightAnchor.constraint(equalTo: boostButton.heightAnchor).priority(.defaultHigh), replyButton.heightAnchor.constraint(equalTo: reblogButton.heightAnchor).priority(.defaultHigh),
replyButton.heightAnchor.constraint(equalTo: favoriteButton.heightAnchor).priority(.defaultHigh), replyButton.heightAnchor.constraint(equalTo: favoriteButton.heightAnchor).priority(.defaultHigh),
replyButton.heightAnchor.constraint(equalTo: moreButton.heightAnchor).priority(.defaultHigh), replyButton.heightAnchor.constraint(equalTo: moreButton.heightAnchor).priority(.defaultHigh),
replyButton.widthAnchor.constraint(equalTo: boostButton.widthAnchor).priority(.defaultHigh), replyButton.widthAnchor.constraint(equalTo: reblogButton.widthAnchor).priority(.defaultHigh),
replyButton.widthAnchor.constraint(equalTo: favoriteButton.widthAnchor).priority(.defaultHigh), replyButton.widthAnchor.constraint(equalTo: favoriteButton.widthAnchor).priority(.defaultHigh),
]) ])
moreButton.setContentHuggingPriority(.defaultHigh, for: .horizontal) moreButton.setContentHuggingPriority(.defaultHigh, for: .horizontal)
@ -144,7 +144,7 @@ extension ActionToolbarContainer {
button.contentHorizontalAlignment = .center button.contentHorizontalAlignment = .center
} }
replyButton.setImage(replyImage, for: .normal) replyButton.setImage(replyImage, for: .normal)
boostButton.setImage(reblogImage, for: .normal) reblogButton.setImage(reblogImage, for: .normal)
favoriteButton.setImage(starImage, for: .normal) favoriteButton.setImage(starImage, for: .normal)
container.axis = .horizontal container.axis = .horizontal
@ -152,7 +152,7 @@ extension ActionToolbarContainer {
container.distribution = .fillEqually container.distribution = .fillEqually
container.addArrangedSubview(replyButton) container.addArrangedSubview(replyButton)
container.addArrangedSubview(boostButton) container.addArrangedSubview(reblogButton)
container.addArrangedSubview(favoriteButton) container.addArrangedSubview(favoriteButton)
} }
} }
@ -162,11 +162,11 @@ extension ActionToolbarContainer {
return oldStyle != style return oldStyle != style
} }
private func isBoostButtonHighlightStateDidChange(to isHighlight: Bool) { private func isReblogButtonHighlightStateDidChange(to isHighlight: Bool) {
let tintColor = isHighlight ? Asset.Colors.systemGreen.color : Asset.Colors.Button.actionToolbar.color let tintColor = isHighlight ? Asset.Colors.systemGreen.color : Asset.Colors.Button.actionToolbar.color
boostButton.tintColor = tintColor reblogButton.tintColor = tintColor
boostButton.setTitleColor(tintColor, for: .normal) reblogButton.setTitleColor(tintColor, for: .normal)
boostButton.setTitleColor(tintColor, for: .highlighted) reblogButton.setTitleColor(tintColor, for: .highlighted)
} }
private func isFavoriteButtonHighlightStateDidChange(to isHighlight: Bool) { private func isFavoriteButtonHighlightStateDidChange(to isHighlight: Bool) {
@ -184,9 +184,9 @@ extension ActionToolbarContainer {
delegate?.actionToolbarContainer(self, replayButtonDidPressed: sender) delegate?.actionToolbarContainer(self, replayButtonDidPressed: sender)
} }
@objc private func boostButtonDidPressed(_ sender: UIButton) { @objc private func reblogButtonDidPressed(_ sender: UIButton) {
os_log("%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function) os_log("%{public}s[%{public}ld], %{public}s", ((#file as NSString).lastPathComponent), #line, #function)
delegate?.actionToolbarContainer(self, boostButtonDidPressed: sender) delegate?.actionToolbarContainer(self, reblogButtonDidPressed: sender)
} }
@objc private func favoriteButtonDidPressed(_ sender: UIButton) { @objc private func favoriteButtonDidPressed(_ sender: UIButton) {

View File

@ -15,10 +15,10 @@ import CommonOSLog
extension APIService { extension APIService {
// make local state change only // make local state change only
func boost( func reblog(
tootObjectID: NSManagedObjectID, tootObjectID: NSManagedObjectID,
mastodonUserObjectID: NSManagedObjectID, mastodonUserObjectID: NSManagedObjectID,
boostKind: Mastodon.API.Reblog.BoostKind reblogKind: Mastodon.API.Reblog.ReblogKind
) -> AnyPublisher<Toot.ID, Error> { ) -> AnyPublisher<Toot.ID, Error> {
var _targetTootID: Toot.ID? var _targetTootID: Toot.ID?
let managedObjectContext = backgroundManagedObjectContext let managedObjectContext = backgroundManagedObjectContext
@ -29,7 +29,12 @@ extension APIService {
let targetTootID = targetToot.id let targetTootID = targetToot.id
_targetTootID = targetTootID _targetTootID = targetTootID
targetToot.update(reblogged: boostKind == .boost, mastodonUser: mastodonUser) switch reblogKind {
case .reblog:
targetToot.update(reblogged: true, mastodonUser: mastodonUser)
case .undoReblog:
targetToot.update(reblogged: false, mastodonUser: mastodonUser)
}
} }
.tryMap { result in .tryMap { result in
@ -48,20 +53,20 @@ extension APIService {
.eraseToAnyPublisher() .eraseToAnyPublisher()
} }
// send boost request to remote // send reblog request to remote
func boost( func reblog(
statusID: Mastodon.Entity.Status.ID, statusID: Mastodon.Entity.Status.ID,
boostKind: Mastodon.API.Reblog.BoostKind, reblogKind: Mastodon.API.Reblog.ReblogKind,
mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox mastodonAuthenticationBox: AuthenticationService.MastodonAuthenticationBox
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Status>, Error> { ) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Status>, Error> {
let domain = mastodonAuthenticationBox.domain let domain = mastodonAuthenticationBox.domain
let authorization = mastodonAuthenticationBox.userAuthorization let authorization = mastodonAuthenticationBox.userAuthorization
let requestMastodonUserID = mastodonAuthenticationBox.userID let requestMastodonUserID = mastodonAuthenticationBox.userID
return Mastodon.API.Reblog.boost( return Mastodon.API.Reblog.reblog(
session: session, session: session,
domain: domain, domain: domain,
statusID: statusID, statusID: statusID,
boostKind: boostKind, reblogKind: reblogKind,
authorization: authorization authorization: authorization
) )
.map { response -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Status>, Error> in .map { response -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Status>, Error> in
@ -92,10 +97,13 @@ extension APIService {
} }
APIService.CoreData.merge(toot: oldToot, entity: entity.reblog ?? entity, requestMastodonUser: requestMastodonUser, domain: mastodonAuthenticationBox.domain, networkDate: response.networkDate) APIService.CoreData.merge(toot: oldToot, entity: entity.reblog ?? entity, requestMastodonUser: requestMastodonUser, domain: mastodonAuthenticationBox.domain, networkDate: response.networkDate)
if boostKind == .undoBoost { switch reblogKind {
case .undoReblog:
oldToot.update(reblogsCount: NSNumber(value: max(0, oldToot.reblogsCount.intValue - 1))) oldToot.update(reblogsCount: NSNumber(value: max(0, oldToot.reblogsCount.intValue - 1)))
default:
break
} }
os_log(.info, log: log, "%{public}s[%{public}ld], %{public}s: did update toot %{public}s reblog status to: %{public}s. now %ld boosts", ((#file as NSString).lastPathComponent), #line, #function, entity.id, entity.reblogged.flatMap { $0 ? "boost" : "unboost" } ?? "<nil>", entity.reblogsCount ) os_log(.info, log: log, "%{public}s[%{public}ld], %{public}s: did update toot %{public}s reblog status to: %{public}s. now %ld reblog", ((#file as NSString).lastPathComponent), #line, #function, entity.id, entity.reblogged.flatMap { $0 ? "reblog" : "unreblog" } ?? "<nil>", entity.reblogsCount )
} }
.setFailureType(to: Error.self) .setFailureType(to: Error.self)
.tryMap { result -> Mastodon.Response.Content<Mastodon.Entity.Status> in .tryMap { result -> Mastodon.Response.Content<Mastodon.Entity.Status> in

View File

@ -10,7 +10,7 @@ import Combine
extension Mastodon.API.Reblog { extension Mastodon.API.Reblog {
static func boostedByEndpointURL(domain: String, statusID: Mastodon.Entity.Status.ID) -> URL { static func rebloggedByEndpointURL(domain: String, statusID: Mastodon.Entity.Status.ID) -> URL {
let pathComponent = "statuses/" + statusID + "/reblogged_by" let pathComponent = "statuses/" + statusID + "/reblogged_by"
return Mastodon.API.endpointURL(domain: domain).appendingPathComponent(pathComponent) return Mastodon.API.endpointURL(domain: domain).appendingPathComponent(pathComponent)
} }
@ -22,7 +22,7 @@ extension Mastodon.API.Reblog {
/// - Since: 0.0.0 /// - Since: 0.0.0
/// - Version: 3.3.0 /// - Version: 3.3.0
/// # Last Update /// # Last Update
/// 2021/3/9 /// 2021/3/15
/// # Reference /// # Reference
/// [Document](https://docs.joinmastodon.org/methods/statuses/) /// [Document](https://docs.joinmastodon.org/methods/statuses/)
/// - Parameters: /// - Parameters:
@ -31,14 +31,14 @@ extension Mastodon.API.Reblog {
/// - statusID: id for status /// - statusID: id for status
/// - authorization: User token. Could be nil if status is public /// - authorization: User token. Could be nil if status is public
/// - Returns: `AnyPublisher` contains `Status` nested in the response /// - Returns: `AnyPublisher` contains `Status` nested in the response
public static func poll( public static func rebloggedBy(
session: URLSession, session: URLSession,
domain: String, domain: String,
statusID: Mastodon.Entity.Status.ID, statusID: Mastodon.Entity.Status.ID,
authorization: Mastodon.API.OAuth.Authorization? authorization: Mastodon.API.OAuth.Authorization?
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Status>, Error> { ) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Status>, Error> {
let request = Mastodon.API.get( let request = Mastodon.API.get(
url: boostedByEndpointURL(domain: domain, statusID: statusID), url: rebloggedByEndpointURL(domain: domain, statusID: statusID),
query: nil, query: nil,
authorization: authorization authorization: authorization
) )
@ -66,7 +66,7 @@ extension Mastodon.API.Reblog {
/// - Since: 0.0.0 /// - Since: 0.0.0
/// - Version: 3.3.0 /// - Version: 3.3.0
/// # Last Update /// # Last Update
/// 2021/3/9 /// 2021/3/15
/// # Reference /// # Reference
/// [Document](https://docs.joinmastodon.org/methods/statuses/) /// [Document](https://docs.joinmastodon.org/methods/statuses/)
/// - Parameters: /// - Parameters:
@ -75,11 +75,11 @@ extension Mastodon.API.Reblog {
/// - statusID: id for status /// - statusID: id for status
/// - authorization: User token. /// - authorization: User token.
/// - Returns: `AnyPublisher` contains `Status` nested in the response /// - Returns: `AnyPublisher` contains `Status` nested in the response
public static func boost( public static func reblog(
session: URLSession, session: URLSession,
domain: String, domain: String,
statusID: Mastodon.Entity.Status.ID, statusID: Mastodon.Entity.Status.ID,
query: BoostQuery, query: ReblogQuery,
authorization: Mastodon.API.OAuth.Authorization authorization: Mastodon.API.OAuth.Authorization
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Status>, Error> { ) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Status>, Error> {
let request = Mastodon.API.post( let request = Mastodon.API.post(
@ -97,10 +97,10 @@ extension Mastodon.API.Reblog {
public typealias Visibility = Mastodon.Entity.Source.Privacy public typealias Visibility = Mastodon.Entity.Source.Privacy
public struct BoostQuery: Codable, PostQuery { public struct ReblogQuery: Codable, PostQuery {
public let visibility: Visibility public let visibility: Visibility?
public init(visibility: Visibility) { public init(visibility: Visibility?) {
self.visibility = visibility self.visibility = visibility
} }
} }
@ -114,7 +114,7 @@ extension Mastodon.API.Reblog {
return Mastodon.API.endpointURL(domain: domain).appendingPathComponent(pathComponent) return Mastodon.API.endpointURL(domain: domain).appendingPathComponent(pathComponent)
} }
/// Undo boost /// Undo reblog
/// ///
/// Undo a reshare of a status. /// Undo a reshare of a status.
/// ///
@ -130,7 +130,7 @@ extension Mastodon.API.Reblog {
/// - statusID: id for status /// - statusID: id for status
/// - authorization: User token. /// - authorization: User token.
/// - Returns: `AnyPublisher` contains `Status` nested in the response /// - Returns: `AnyPublisher` contains `Status` nested in the response
public static func undoBoost( public static func undoReblog(
session: URLSession, session: URLSession,
domain: String, domain: String,
statusID: Mastodon.Entity.Status.ID, statusID: Mastodon.Entity.Status.ID,
@ -153,34 +153,24 @@ extension Mastodon.API.Reblog {
extension Mastodon.API.Reblog { extension Mastodon.API.Reblog {
public enum BoostKind { public enum ReblogKind {
case boost case reblog(query: ReblogQuery)
case undoBoost case undoReblog
} }
public static func boost( public static func reblog(
session: URLSession, session: URLSession,
domain: String, domain: String,
statusID: Mastodon.Entity.Status.ID, statusID: Mastodon.Entity.Status.ID,
boostKind: BoostKind, reblogKind: ReblogKind,
authorization: Mastodon.API.OAuth.Authorization authorization: Mastodon.API.OAuth.Authorization
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Status>, Error> { ) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Status>, Error> {
let url: URL switch reblogKind {
switch boostKind { case .reblog(let query):
case .boost: url = reblogEndpointURL(domain: domain, statusID: statusID) return reblog(session: session, domain: domain, statusID: statusID, query: query, authorization: authorization)
case .undoBoost: url = unreblogEndpointURL(domain: domain, statusID: statusID) case .undoReblog:
return undoReblog(session: session, domain: domain, statusID: statusID, authorization: authorization)
} }
let request = Mastodon.API.post(
url: url,
query: nil,
authorization: authorization
)
return session.dataTaskPublisher(for: request)
.tryMap { data, response in
let value = try Mastodon.API.decode(type: Mastodon.Entity.Status.self, from: data, response: response)
return Mastodon.Response.Content(value: value, response: response)
}
.eraseToAnyPublisher()
} }
} }