mirror of
https://github.com/mastodon/mastodon-ios.git
synced 2025-01-31 17:45:17 +01:00
feat: Implement follow/unfollow tag functionality
This commit is contained in:
parent
b020f566f4
commit
b9e4c69576
@ -28,6 +28,8 @@ final class HashtagTimelineHeaderView: UIView {
|
||||
|
||||
private var widthConstraint: NSLayoutConstraint!
|
||||
|
||||
var onButtonTapped: (() -> Void)?
|
||||
|
||||
let followButton: UIButton = {
|
||||
let button = RoundedEdgesButton(type: .custom)
|
||||
button.cornerRadius = 10
|
||||
@ -69,7 +71,11 @@ private extension HashtagTimelineHeaderView {
|
||||
postCountDescLabel.text = "posts"
|
||||
participantsDescLabel.text = "participants"
|
||||
postsTodayDescLabel.text = "posts today"
|
||||
|
||||
|
||||
followButton.addAction(UIAction(handler: { [weak self] _ in
|
||||
self?.onButtonTapped?()
|
||||
}), for: .touchUpInside)
|
||||
|
||||
widthConstraint = widthAnchor.constraint(equalToConstant: 0)
|
||||
|
||||
NSLayoutConstraint.activate([
|
||||
@ -133,7 +139,7 @@ extension HashtagTimelineHeaderView {
|
||||
postsTodayLabel.text = history.first?.uses
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
func updateWidthConstraint(_ constant: CGFloat) {
|
||||
widthConstraint.constant = constant
|
||||
}
|
||||
|
@ -177,6 +177,16 @@ extension HashtagTimelineViewController {
|
||||
tableView.tableHeaderView = headerView
|
||||
}
|
||||
headerView.update(tag)
|
||||
headerView.onButtonTapped = { [weak self] in
|
||||
switch tag.following {
|
||||
case .some(false):
|
||||
self?.viewModel.followTag()
|
||||
case .some(true):
|
||||
self?.viewModel.unfollowTag()
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews() {
|
||||
|
@ -72,6 +72,30 @@ final class HashtagTimelineViewModel {
|
||||
|
||||
}
|
||||
|
||||
extension HashtagTimelineViewModel {
|
||||
func followTag() {
|
||||
self.hashtagDetails.send(hashtagDetails.value?.copy(following: true))
|
||||
Task { @MainActor in
|
||||
let tag = try? await context.apiService.followTag(
|
||||
for: hashtag,
|
||||
authenticationBox: authContext.mastodonAuthenticationBox
|
||||
).value
|
||||
self.hashtagDetails.send(tag)
|
||||
}
|
||||
}
|
||||
|
||||
func unfollowTag() {
|
||||
self.hashtagDetails.send(hashtagDetails.value?.copy(following: false))
|
||||
Task { @MainActor in
|
||||
let tag = try? await context.apiService.unfollowTag(
|
||||
for: hashtag,
|
||||
authenticationBox: authContext.mastodonAuthenticationBox
|
||||
).value
|
||||
self.hashtagDetails.send(tag)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension HashtagTimelineViewModel {
|
||||
func updateTagInformation() {
|
||||
Task { @MainActor in
|
||||
|
@ -21,13 +21,57 @@ extension APIService {
|
||||
let domain = authenticationBox.domain
|
||||
let authorization = authenticationBox.userAuthorization
|
||||
|
||||
let response = try await Mastodon.API.Tags.tag(
|
||||
let response = try await Mastodon.API.Tags.getTagInformation(
|
||||
session: session,
|
||||
domain: domain,
|
||||
tagId: tag,
|
||||
authorization: authorization
|
||||
).singleOutput()
|
||||
|
||||
return try await persistTag(from: response, domain: domain, authenticationBox: authenticationBox)
|
||||
} // end func
|
||||
|
||||
public func followTag(
|
||||
for tag: String,
|
||||
authenticationBox: MastodonAuthenticationBox
|
||||
) async throws -> Mastodon.Response.Content<Mastodon.Entity.Tag> {
|
||||
let domain = authenticationBox.domain
|
||||
let authorization = authenticationBox.userAuthorization
|
||||
|
||||
let response = try await Mastodon.API.Tags.followTag(
|
||||
session: session,
|
||||
domain: domain,
|
||||
tagId: tag,
|
||||
authorization: authorization
|
||||
).singleOutput()
|
||||
|
||||
return try await persistTag(from: response, domain: domain, authenticationBox: authenticationBox)
|
||||
} // end func
|
||||
|
||||
public func unfollowTag(
|
||||
for tag: String,
|
||||
authenticationBox: MastodonAuthenticationBox
|
||||
) async throws -> Mastodon.Response.Content<Mastodon.Entity.Tag> {
|
||||
let domain = authenticationBox.domain
|
||||
let authorization = authenticationBox.userAuthorization
|
||||
|
||||
let response = try await Mastodon.API.Tags.unfollowTag(
|
||||
session: session,
|
||||
domain: domain,
|
||||
tagId: tag,
|
||||
authorization: authorization
|
||||
).singleOutput()
|
||||
|
||||
return try await persistTag(from: response, domain: domain, authenticationBox: authenticationBox)
|
||||
} // end func
|
||||
}
|
||||
|
||||
fileprivate extension APIService {
|
||||
func persistTag(
|
||||
from response: Mastodon.Response.Content<Mastodon.Entity.Tag>,
|
||||
domain: String,
|
||||
authenticationBox: MastodonAuthenticationBox
|
||||
) async throws -> Mastodon.Response.Content<Mastodon.Entity.Tag> {
|
||||
let managedObjectContext = self.backgroundManagedObjectContext
|
||||
try await managedObjectContext.performChanges {
|
||||
let me = authenticationBox.authenticationRecord.object(in: managedObjectContext)?.user
|
||||
@ -44,6 +88,5 @@ extension APIService {
|
||||
}
|
||||
|
||||
return response
|
||||
} // end func
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -14,9 +14,9 @@ extension Mastodon.API.Tags {
|
||||
.appendingPathComponent("tags")
|
||||
}
|
||||
|
||||
/// Followed Tags
|
||||
/// Tags
|
||||
///
|
||||
/// View your followed hashtags.
|
||||
/// View information about a single tag.
|
||||
///
|
||||
/// - Since: 4.0.0
|
||||
/// - Version: 4.0.3
|
||||
@ -28,7 +28,7 @@ extension Mastodon.API.Tags {
|
||||
/// - authorization: User token
|
||||
/// - tagId: The Hashtag
|
||||
/// - Returns: `AnyPublisher` contains `Tag` nested in the response
|
||||
public static func tag(
|
||||
public static func getTagInformation(
|
||||
session: URLSession,
|
||||
domain: String,
|
||||
tagId: String,
|
||||
@ -46,4 +46,72 @@ extension Mastodon.API.Tags {
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
/// Tags
|
||||
///
|
||||
/// Follow a hashtag.
|
||||
///
|
||||
/// - Since: 4.0.0
|
||||
/// - Version: 4.0.3
|
||||
/// # Reference
|
||||
/// [Document](https://docs.joinmastodon.org/methods/tags/)
|
||||
/// - Parameters:
|
||||
/// - session: `URLSession`
|
||||
/// - domain: Mastodon instance domain. e.g. "example.com"
|
||||
/// - authorization: User token
|
||||
/// - tagId: The Hashtag
|
||||
/// - Returns: `AnyPublisher` contains `Tag` nested in the response
|
||||
public static func followTag(
|
||||
session: URLSession,
|
||||
domain: String,
|
||||
tagId: String,
|
||||
authorization: Mastodon.API.OAuth.Authorization
|
||||
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Tag>, Error> {
|
||||
let request = Mastodon.API.post(
|
||||
url: tagsEndpointURL(domain: domain).appendingPathComponent(tagId)
|
||||
.appendingPathComponent("follow"),
|
||||
query: nil,
|
||||
authorization: authorization
|
||||
)
|
||||
return session.dataTaskPublisher(for: request)
|
||||
.tryMap { data, response in
|
||||
let value = try Mastodon.API.decode(type: Mastodon.Entity.Tag.self, from: data, response: response)
|
||||
return Mastodon.Response.Content(value: value, response: response)
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
/// Tags
|
||||
///
|
||||
/// Unfollow a hashtag.
|
||||
///
|
||||
/// - Since: 4.0.0
|
||||
/// - Version: 4.0.3
|
||||
/// # Reference
|
||||
/// [Document](https://docs.joinmastodon.org/methods/tags/)
|
||||
/// - Parameters:
|
||||
/// - session: `URLSession`
|
||||
/// - domain: Mastodon instance domain. e.g. "example.com"
|
||||
/// - authorization: User token
|
||||
/// - tagId: The Hashtag
|
||||
/// - Returns: `AnyPublisher` contains `Tag` nested in the response
|
||||
public static func unfollowTag(
|
||||
session: URLSession,
|
||||
domain: String,
|
||||
tagId: String,
|
||||
authorization: Mastodon.API.OAuth.Authorization
|
||||
) -> AnyPublisher<Mastodon.Response.Content<Mastodon.Entity.Tag>, Error> {
|
||||
let request = Mastodon.API.post(
|
||||
url: tagsEndpointURL(domain: domain).appendingPathComponent(tagId)
|
||||
.appendingPathComponent("unfollow"),
|
||||
query: nil,
|
||||
authorization: authorization
|
||||
)
|
||||
return session.dataTaskPublisher(for: request)
|
||||
.tryMap { data, response in
|
||||
let value = try Mastodon.API.decode(type: Mastodon.Entity.Tag.self, from: data, response: response)
|
||||
return Mastodon.Response.Content(value: value, response: response)
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
}
|
||||
|
@ -41,5 +41,9 @@ extension Mastodon.Entity {
|
||||
hasher.combine(name)
|
||||
hasher.combine(url)
|
||||
}
|
||||
|
||||
public func copy(following: Bool?) -> Self {
|
||||
Tag(name: name, url: url, history: history, following: following)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user