mirror of
https://github.com/mastodon/mastodon-ios.git
synced 2025-02-01 18:07:22 +01:00
Implement "Followed Hashtags" (IOS-102)
This commit is contained in:
parent
f03ef0dfc7
commit
0a887a4841
@ -481,6 +481,9 @@
|
||||
"lists": {
|
||||
"title": "Lists",
|
||||
"manage_lists": "Manage Lists"
|
||||
},
|
||||
"hashtags": {
|
||||
"title": "Followed Hashtags"
|
||||
}
|
||||
},
|
||||
"timeline_pill": {
|
||||
|
@ -127,7 +127,6 @@ extension HashtagTimelineViewModel.State {
|
||||
Task {
|
||||
do {
|
||||
let response = try await viewModel.context.apiService.hashtagTimeline(
|
||||
domain: viewModel.authContext.mastodonAuthenticationBox.domain,
|
||||
maxID: maxID,
|
||||
hashtag: viewModel.hashtag,
|
||||
authenticationBox: viewModel.authContext.mastodonAuthenticationBox
|
||||
|
@ -143,6 +143,9 @@ final class HomeTimelineViewController: UIViewController, NeedsDependency, Media
|
||||
case .list:
|
||||
showLocalTimelineAction.state = .off
|
||||
showFollowingAction.state = .off
|
||||
case .hashtag:
|
||||
showLocalTimelineAction.state = .off
|
||||
showFollowingAction.state = .off
|
||||
}
|
||||
}
|
||||
|
||||
@ -190,7 +193,43 @@ final class HomeTimelineViewController: UIViewController, NeedsDependency, Media
|
||||
children: [listsSubmenu]
|
||||
)
|
||||
|
||||
let listsDivider = UIMenu(title: "", options: .displayInline, children: [listsMenu])
|
||||
let hashtagsSubmenu = UIDeferredMenuElement.uncached { [weak self] callback in
|
||||
guard let self else { return callback([]) }
|
||||
|
||||
Task { @MainActor in
|
||||
let lists = (try? await Mastodon.API.Account.followedTags(
|
||||
session: .shared,
|
||||
domain: self.authContext.mastodonAuthenticationBox.domain,
|
||||
query: .init(limit: nil),
|
||||
authorization: self.authContext.mastodonAuthenticationBox.userAuthorization
|
||||
).singleOutput().value) ?? []
|
||||
|
||||
let listEntries = lists.map { entry in
|
||||
return LabeledAction(title: entry.name, image: nil, handler: { [weak self] in
|
||||
guard let self, let viewModel = self.viewModel else { return }
|
||||
viewModel.timelineContext = .hashtag(entry.name)
|
||||
viewModel.loadLatestStateMachine.enter(HomeTimelineViewModel.LoadLatestState.ContextSwitch.self)
|
||||
timelineSelectorButton.setAttributedTitle(
|
||||
.init(string: entry.name, attributes: [
|
||||
.font: UIFontMetrics(forTextStyle: .headline).scaledFont(for: .systemFont(ofSize: 20, weight: .semibold))
|
||||
]),
|
||||
for: .normal)
|
||||
timelineSelectorButton.sizeToFit()
|
||||
timelineSelectorButton.menu = generateTimelineSelectorMenu()
|
||||
}).menuElement
|
||||
}
|
||||
|
||||
callback(listEntries)
|
||||
}
|
||||
}
|
||||
|
||||
let hashtagsMenu = UIMenu(
|
||||
title: L10n.Scene.HomeTimeline.TimelineMenu.Hashtags.title,
|
||||
image: UIImage(systemName: "number"),
|
||||
children: [hashtagsSubmenu]
|
||||
)
|
||||
|
||||
let listsDivider = UIMenu(title: "", options: .displayInline, children: [listsMenu, hashtagsMenu])
|
||||
|
||||
return UIMenu(children: [showFollowingAction, showLocalTimelineAction, listsDivider])
|
||||
}
|
||||
|
@ -138,6 +138,11 @@ extension HomeTimelineViewModel.LoadLatestState {
|
||||
query: .init(sinceID: sinceID),
|
||||
authenticationBox: viewModel.authContext.mastodonAuthenticationBox
|
||||
)
|
||||
case let .hashtag(tag):
|
||||
response = try await viewModel.context.apiService.hashtagTimeline(
|
||||
hashtag: tag,
|
||||
authenticationBox: viewModel.authContext.mastodonAuthenticationBox
|
||||
)
|
||||
}
|
||||
|
||||
enter(state: Idle.self)
|
||||
|
@ -80,6 +80,11 @@ extension HomeTimelineViewModel.LoadOldestState {
|
||||
query: .init(local: true, maxID: maxID),
|
||||
authenticationBox: viewModel.authContext.mastodonAuthenticationBox
|
||||
)
|
||||
case let .hashtag(tag):
|
||||
response = try await viewModel.context.apiService.hashtagTimeline(
|
||||
hashtag: tag,
|
||||
authenticationBox: viewModel.authContext.mastodonAuthenticationBox
|
||||
)
|
||||
}
|
||||
|
||||
let statuses = response.value
|
||||
|
@ -180,6 +180,11 @@ extension HomeTimelineViewModel {
|
||||
query: .init(local: true, maxID: status.id),
|
||||
authenticationBox: authContext.mastodonAuthenticationBox
|
||||
)
|
||||
case let .hashtag(tag):
|
||||
response = try? await context.apiService.hashtagTimeline(
|
||||
hashtag: tag,
|
||||
authenticationBox: authContext.mastodonAuthenticationBox
|
||||
)
|
||||
}
|
||||
|
||||
// insert missing items
|
||||
|
@ -190,6 +190,11 @@ private extension FeedDataController {
|
||||
query: .init(maxID: maxID),
|
||||
authenticationBox: authContext.mastodonAuthenticationBox
|
||||
)
|
||||
case let .hashtag(tag):
|
||||
response = try await context.apiService.hashtagTimeline(
|
||||
hashtag: tag,
|
||||
authenticationBox: authContext.mastodonAuthenticationBox
|
||||
)
|
||||
}
|
||||
|
||||
return response.value.map { .fromStatus(.fromEntity($0), kind: .home) }
|
||||
|
@ -14,7 +14,6 @@ import MastodonSDK
|
||||
extension APIService {
|
||||
|
||||
public func hashtagTimeline(
|
||||
domain: String,
|
||||
sinceID: Mastodon.Entity.Status.ID? = nil,
|
||||
maxID: Mastodon.Entity.Status.ID? = nil,
|
||||
limit: Int = onceRequestStatusMaxCount,
|
||||
|
@ -862,6 +862,10 @@ public enum L10n {
|
||||
public static let following = L10n.tr("Localizable", "Scene.HomeTimeline.TimelineMenu.Following", fallback: "Following")
|
||||
/// Local
|
||||
public static let localCommunity = L10n.tr("Localizable", "Scene.HomeTimeline.TimelineMenu.LocalCommunity", fallback: "Local")
|
||||
public enum Hashtags {
|
||||
/// Followed Hashtags
|
||||
public static let title = L10n.tr("Localizable", "Scene.HomeTimeline.TimelineMenu.Hashtags.Title", fallback: "Followed Hashtags")
|
||||
}
|
||||
public enum Lists {
|
||||
/// Manage Lists
|
||||
public static let manageLists = L10n.tr("Localizable", "Scene.HomeTimeline.TimelineMenu.Lists.ManageLists", fallback: "Manage Lists")
|
||||
|
@ -307,6 +307,7 @@ uploaded to Mastodon.";
|
||||
"Scene.HomeTimeline.TimelineMenu.LocalCommunity" = "Local";
|
||||
"Scene.HomeTimeline.TimelineMenu.Lists.Title" = "Lists";
|
||||
"Scene.HomeTimeline.TimelineMenu.Lists.ManageLists" = "Manage Lists";
|
||||
"Scene.HomeTimeline.TimelineMenu.Hashtags.Title" = "Followed Hashtags";
|
||||
"Scene.HomeTimeline.TimelinePill.NewPosts" = "New Posts";
|
||||
"Scene.HomeTimeline.TimelinePill.Offline" = "Offline";
|
||||
"Scene.HomeTimeline.TimelinePill.PostSent" = "Post Sent";
|
||||
|
@ -15,6 +15,7 @@ public final class MastodonFeed {
|
||||
case home
|
||||
case `public`
|
||||
case list(String)
|
||||
case hashtag(String)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ extension HashtagWidgetProvider {
|
||||
do {
|
||||
let mostRecentStatuses = try await WidgetExtension.appContext
|
||||
.apiService
|
||||
.hashtagTimeline(domain: authBox.domain, limit: 40, hashtag: desiredHashtag, authenticationBox: authBox)
|
||||
.hashtagTimeline(limit: 40, hashtag: desiredHashtag, authenticationBox: authBox)
|
||||
.value
|
||||
|
||||
let filteredStatuses: [Mastodon.Entity.Status]
|
||||
|
Loading…
x
Reference in New Issue
Block a user