Notification navigation
This commit is contained in:
parent
980c5f0099
commit
f924062814
|
@ -145,7 +145,7 @@
|
|||
"main-navigation.notifications" = "Notifications";
|
||||
"main-navigation.conversations" = "Messages";
|
||||
"metatext" = "Metatext";
|
||||
"notification.signed-in-as-%@" = "Signed in as %@";
|
||||
"notification.signed-in-as-%@" = "Logged in as %@";
|
||||
"notifications.all" = "All";
|
||||
"notifications.mentions" = "Mentions";
|
||||
"ok" = "OK";
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
// Copyright © 2020 Metabolist. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import HTTP
|
||||
import Mastodon
|
||||
|
||||
public enum NotificationEndpoint {
|
||||
case notification(id: MastodonNotification.Id)
|
||||
}
|
||||
|
||||
extension NotificationEndpoint: Endpoint {
|
||||
public typealias ResultType = MastodonNotification
|
||||
|
||||
public var context: [String] {
|
||||
defaultContext + ["notifications"]
|
||||
}
|
||||
|
||||
public var pathComponentsInContext: [String] {
|
||||
switch self {
|
||||
case let .notification(id):
|
||||
return [id]
|
||||
}
|
||||
}
|
||||
|
||||
public var method: HTTPMethod {
|
||||
switch self {
|
||||
case .notification:
|
||||
return .get
|
||||
}
|
||||
}
|
||||
}
|
|
@ -247,6 +247,21 @@ public extension IdentityService {
|
|||
mastodonAPIClient.request(StatusEndpoint.post(statusComponents)).map(\.id).eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func notificationService(pushNotification: PushNotification) -> AnyPublisher<NotificationService, Error> {
|
||||
mastodonAPIClient.request(NotificationEndpoint.notification(id: .init(pushNotification.notificationId)))
|
||||
.flatMap { notification in
|
||||
contentDatabase.insert(notifications: [notification])
|
||||
.collect()
|
||||
.map { _ in
|
||||
NotificationService(
|
||||
notification: notification,
|
||||
mastodonAPIClient: mastodonAPIClient,
|
||||
contentDatabase: contentDatabase)
|
||||
}
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
}
|
||||
|
||||
func service(accountList: AccountsEndpoint, titleComponents: [String]? = nil) -> AccountListService {
|
||||
AccountListService(
|
||||
endpoint: accountList,
|
||||
|
|
|
@ -10,6 +10,7 @@ public enum Navigation {
|
|||
case url(URL)
|
||||
case collection(CollectionService)
|
||||
case profile(ProfileService)
|
||||
case notification(NotificationService)
|
||||
case searchScope(SearchScope)
|
||||
case webfingerStart
|
||||
case webfingerEnd
|
||||
|
|
|
@ -33,7 +33,7 @@ final class MainNavigationViewController: UITabBarController {
|
|||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
viewModel.$presentingSecondaryNavigation.sink { [weak self] in
|
||||
viewModel.$presentingSecondaryNavigation.removeDuplicates().sink { [weak self] in
|
||||
if $0 {
|
||||
self?.presentSecondaryNavigation()
|
||||
} else {
|
||||
|
@ -182,27 +182,40 @@ private extension MainNavigationViewController {
|
|||
}
|
||||
|
||||
func handle(navigation: Navigation) {
|
||||
let vc: UIViewController
|
||||
|
||||
switch navigation {
|
||||
case let .collection(collectionService):
|
||||
vc = TableViewController(
|
||||
let vc = TableViewController(
|
||||
viewModel: CollectionItemsViewModel(
|
||||
collectionService: collectionService,
|
||||
identityContext: viewModel.identityContext),
|
||||
rootViewModel: rootViewModel)
|
||||
|
||||
selectedViewController?.show(vc, sender: self)
|
||||
case let .profile(profileService):
|
||||
vc = ProfileViewController(
|
||||
let vc = ProfileViewController(
|
||||
viewModel: ProfileViewModel(
|
||||
profileService: profileService,
|
||||
identityContext: viewModel.identityContext),
|
||||
rootViewModel: rootViewModel,
|
||||
identityContext: viewModel.identityContext,
|
||||
parentNavigationController: nil)
|
||||
default:
|
||||
return
|
||||
}
|
||||
|
||||
selectedViewController?.show(vc, sender: self)
|
||||
case .notification:
|
||||
let index = NavigationViewModel.Tab.notifications.rawValue
|
||||
|
||||
guard let viewControllers = viewControllers,
|
||||
viewControllers.count > index,
|
||||
let notificationsNavigationController = viewControllers[index] as? UINavigationController,
|
||||
let notificationsViewController =
|
||||
notificationsNavigationController.viewControllers.first as? NotificationsViewController
|
||||
else { break }
|
||||
|
||||
selectedIndex = index
|
||||
notificationsNavigationController.popToRootViewController(animated: false)
|
||||
notificationsViewController.handle(navigation: navigation)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -71,6 +71,21 @@ final class NotificationsViewController: UIPageViewController {
|
|||
}
|
||||
}
|
||||
|
||||
extension NotificationsViewController {
|
||||
func handle(navigation: Navigation) {
|
||||
switch navigation {
|
||||
case .notification:
|
||||
guard let firstViewController = notificationViewControllers.first else { return }
|
||||
|
||||
segmentedControl.selectedSegmentIndex = 0
|
||||
setViewControllers([firstViewController], direction: .reverse, animated: false)
|
||||
firstViewController.handle(navigation: navigation)
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension NotificationsViewController: UIPageViewControllerDataSource {
|
||||
func pageViewController(_ pageViewController: UIPageViewController,
|
||||
viewControllerAfter viewController: UIViewController) -> UIViewController? {
|
||||
|
|
|
@ -195,6 +195,48 @@ extension TableViewController {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func handle(navigation: Navigation) {
|
||||
switch navigation {
|
||||
case let .collection(collectionService):
|
||||
let vc = TableViewController(
|
||||
viewModel: CollectionItemsViewModel(
|
||||
collectionService: collectionService,
|
||||
identityContext: viewModel.identityContext),
|
||||
rootViewModel: rootViewModel,
|
||||
parentNavigationController: parentNavigationController)
|
||||
|
||||
if let parentNavigationController = parentNavigationController {
|
||||
parentNavigationController.pushViewController(vc, animated: true)
|
||||
} else {
|
||||
show(vc, sender: self)
|
||||
}
|
||||
case let .profile(profileService):
|
||||
let vc = ProfileViewController(
|
||||
viewModel: ProfileViewModel(
|
||||
profileService: profileService,
|
||||
identityContext: viewModel.identityContext),
|
||||
rootViewModel: rootViewModel,
|
||||
identityContext: viewModel.identityContext,
|
||||
parentNavigationController: parentNavigationController)
|
||||
|
||||
if let parentNavigationController = parentNavigationController {
|
||||
parentNavigationController.pushViewController(vc, animated: true)
|
||||
} else {
|
||||
show(vc, sender: self)
|
||||
}
|
||||
case let .notification(notificationService):
|
||||
navigate(toNotification: notificationService.notification)
|
||||
case let .url(url):
|
||||
present(SFSafariViewController(url: url), animated: true)
|
||||
case .searchScope:
|
||||
break
|
||||
case .webfingerStart:
|
||||
webfingerIndicatorView.startAnimating()
|
||||
case .webfingerEnd:
|
||||
webfingerIndicatorView.stopAnimating()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension TableViewController: UITableViewDataSourcePrefetching {
|
||||
|
@ -374,44 +416,18 @@ private extension TableViewController {
|
|||
}
|
||||
}
|
||||
|
||||
func handle(navigation: Navigation) {
|
||||
switch navigation {
|
||||
case let .collection(collectionService):
|
||||
let vc = TableViewController(
|
||||
viewModel: CollectionItemsViewModel(
|
||||
collectionService: collectionService,
|
||||
identityContext: viewModel.identityContext),
|
||||
rootViewModel: rootViewModel,
|
||||
parentNavigationController: parentNavigationController)
|
||||
func navigate(toNotification: MastodonNotification) {
|
||||
guard let item = dataSource.snapshot().itemIdentifiers.first(where: {
|
||||
guard case let .notification(notification, _) = $0 else { return false }
|
||||
|
||||
if let parentNavigationController = parentNavigationController {
|
||||
parentNavigationController.pushViewController(vc, animated: true)
|
||||
} else {
|
||||
show(vc, sender: self)
|
||||
}
|
||||
case let .profile(profileService):
|
||||
let vc = ProfileViewController(
|
||||
viewModel: ProfileViewModel(
|
||||
profileService: profileService,
|
||||
identityContext: viewModel.identityContext),
|
||||
rootViewModel: rootViewModel,
|
||||
identityContext: viewModel.identityContext,
|
||||
parentNavigationController: parentNavigationController)
|
||||
return notification.id == toNotification.id
|
||||
}),
|
||||
let indexPath = dataSource.indexPath(for: item)
|
||||
else { return }
|
||||
|
||||
if let parentNavigationController = parentNavigationController {
|
||||
parentNavigationController.pushViewController(vc, animated: true)
|
||||
} else {
|
||||
show(vc, sender: self)
|
||||
}
|
||||
case let .url(url):
|
||||
present(SFSafariViewController(url: url), animated: true)
|
||||
case .searchScope:
|
||||
break
|
||||
case .webfingerStart:
|
||||
webfingerIndicatorView.startAnimating()
|
||||
case .webfingerEnd:
|
||||
webfingerIndicatorView.stopAnimating()
|
||||
}
|
||||
tableView.scrollToRow(at: indexPath, at: .none, animated: !UIAccessibility.isReduceMotionEnabled)
|
||||
|
||||
viewModel.select(indexPath: indexPath)
|
||||
}
|
||||
|
||||
func present(attachmentViewModel: AttachmentViewModel, statusViewModel: StatusViewModel) {
|
||||
|
|
|
@ -95,24 +95,39 @@ public extension NavigationViewModel {
|
|||
|
||||
func navigateToProfile(id: Account.Id) {
|
||||
presentingSecondaryNavigation = false
|
||||
presentedNewStatusViewModel = nil
|
||||
navigationsSubject.send(.profile(identityContext.service.navigationService.profileService(id: id)))
|
||||
}
|
||||
|
||||
func navigate(timeline: Timeline) {
|
||||
presentingSecondaryNavigation = false
|
||||
presentedNewStatusViewModel = nil
|
||||
navigationsSubject.send(
|
||||
.collection(identityContext.service.navigationService.timelineService(timeline: timeline)))
|
||||
}
|
||||
|
||||
func navigateToFollowerRequests() {
|
||||
presentingSecondaryNavigation = false
|
||||
presentedNewStatusViewModel = nil
|
||||
navigationsSubject.send(.collection(identityContext.service.service(
|
||||
accountList: .followRequests,
|
||||
titleComponents: ["follow-requests"])))
|
||||
}
|
||||
|
||||
func navigate(pushNotification: PushNotification) {
|
||||
// TODO
|
||||
switch pushNotification.notificationType {
|
||||
case .followRequest:
|
||||
navigateToFollowerRequests()
|
||||
default:
|
||||
identityContext.service.notificationService(pushNotification: pushNotification)
|
||||
.assignErrorsToAlertItem(to: \.alertItem, on: self)
|
||||
.sink { [weak self] in
|
||||
self?.presentingSecondaryNavigation = false
|
||||
self?.presentedNewStatusViewModel = nil
|
||||
self?.navigationsSubject.send(.notification($0))
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
}
|
||||
|
||||
func viewModel(timeline: Timeline) -> CollectionItemsViewModel {
|
||||
|
|
Loading…
Reference in New Issue