diff --git a/IceCubesApp/App/Tabs/NotificationTab.swift b/IceCubesApp/App/Tabs/NotificationTab.swift index 5180f5eb..89e6b3ea 100644 --- a/IceCubesApp/App/Tabs/NotificationTab.swift +++ b/IceCubesApp/App/Tabs/NotificationTab.swift @@ -4,6 +4,7 @@ import Network import Notifications import SwiftUI import Timeline +import Models struct NotificationsTab: View { @EnvironmentObject private var client: Client @@ -12,10 +13,12 @@ struct NotificationsTab: View { @EnvironmentObject private var userPreferences: UserPreferences @StateObject private var routerPath = RouterPath() @Binding var popToRootTab: Tab + + let lockedType: Models.Notification.NotificationType? var body: some View { NavigationStack(path: $routerPath.path) { - NotificationsListView() + NotificationsListView(lockedType: lockedType) .withAppRouter() .withSheetDestinations(sheetDestinations: $routerPath.presentedSheet) .toolbar { diff --git a/IceCubesApp/App/Tabs/Tabs.swift b/IceCubesApp/App/Tabs/Tabs.swift index 808c12ed..cc2ed08f 100644 --- a/IceCubesApp/App/Tabs/Tabs.swift +++ b/IceCubesApp/App/Tabs/Tabs.swift @@ -5,7 +5,7 @@ import Status import SwiftUI enum Tab: Int, Identifiable, Hashable { - case timeline, notifications, explore, messages, settings, other + case timeline, notifications, mentions, explore, messages, settings, other case trending, federated, local case profile @@ -19,7 +19,7 @@ enum Tab: Int, Identifiable, Hashable { static func loggedInTabs() -> [Tab] { if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac { - return [.timeline, .trending, .federated, .local, .notifications, .explore, .messages, .settings] + return [.timeline, .trending, .federated, .local, .notifications, .mentions, .explore, .messages, .settings] } else { return [.timeline, .notifications, .explore, .messages, .settings] } @@ -37,7 +37,9 @@ enum Tab: Int, Identifiable, Hashable { case .federated: TimelineTab(popToRootTab: popToRootTab, timeline: .federated) case .notifications: - NotificationsTab(popToRootTab: popToRootTab) + NotificationsTab(popToRootTab: popToRootTab, lockedType: nil) + case .mentions: + NotificationsTab(popToRootTab: popToRootTab, lockedType: .mention) case .explore: ExploreTab(popToRootTab: popToRootTab) case .messages: @@ -62,6 +64,8 @@ enum Tab: Int, Identifiable, Hashable { Label("Federated", systemImage: iconName) case .notifications: Label("Notifications", systemImage: iconName) + case .mentions: + Label("Notifications", systemImage: iconName) case .explore: Label("Explore", systemImage: iconName) case .messages: @@ -85,6 +89,8 @@ enum Tab: Int, Identifiable, Hashable { return "globe.americas" case .notifications: return "bell" + case .mentions: + return "at" case .explore: return "magnifyingglass" case .messages: diff --git a/Packages/Network/Sources/Network/Endpoint/Notifications.swift b/Packages/Network/Sources/Network/Endpoint/Notifications.swift index 3ffbc193..0b0db8ec 100644 --- a/Packages/Network/Sources/Network/Endpoint/Notifications.swift +++ b/Packages/Network/Sources/Network/Endpoint/Notifications.swift @@ -21,7 +21,7 @@ public enum Notifications: Endpoint { var params = makePaginationParam(sinceId: sinceId, maxId: maxId, mindId: nil) ?? [] if let types { for type in types { - params.append(.init(name: "types[]", value: type)) + params.append(.init(name: "exclude_types[]", value: type)) } } return params diff --git a/Packages/Notifications/Sources/Notifications/NotificationTypeExt.swift b/Packages/Notifications/Sources/Notifications/NotificationTypeExt.swift index 51b79e9e..23c6c5c7 100644 --- a/Packages/Notifications/Sources/Notifications/NotificationTypeExt.swift +++ b/Packages/Notifications/Sources/Notifications/NotificationTypeExt.swift @@ -46,7 +46,7 @@ extension Models.Notification.NotificationType { case .status: return "Post" case .mention: - return "Mention" + return "Mentions" case .reblog: return "Boost" case .follow: diff --git a/Packages/Notifications/Sources/Notifications/NotificationsListView.swift b/Packages/Notifications/Sources/Notifications/NotificationsListView.swift index 5608d37f..e047a238 100644 --- a/Packages/Notifications/Sources/Notifications/NotificationsListView.swift +++ b/Packages/Notifications/Sources/Notifications/NotificationsListView.swift @@ -11,8 +11,12 @@ public struct NotificationsListView: View { @EnvironmentObject private var watcher: StreamWatcher @EnvironmentObject private var client: Client @StateObject private var viewModel = NotificationsViewModel() + + let lockedType: Models.Notification.NotificationType? - public init() {} + public init(lockedType: Models.Notification.NotificationType?) { + self.lockedType = lockedType + } public var body: some View { ScrollView { @@ -23,21 +27,23 @@ public struct NotificationsListView: View { .padding(.top, .layoutPadding + 16) .background(theme.primaryBackgroundColor) } - .navigationTitle(viewModel.selectedType?.menuTitle() ?? "All Notifications") + .navigationTitle(lockedType?.menuTitle() ?? viewModel.selectedType?.menuTitle() ?? "All Notifications") .navigationBarTitleDisplayMode(.inline) .toolbar { - ToolbarTitleMenu { - Button { - viewModel.selectedType = nil - } label: { - Label("All Notifications", systemImage: "bell.fill") - } - Divider() - ForEach(Notification.NotificationType.allCases, id: \.self) { type in + if lockedType == nil { + ToolbarTitleMenu { Button { - viewModel.selectedType = type + viewModel.selectedType = nil } label: { - Label(type.menuTitle(), systemImage: type.iconName()) + Label("All Notifications", systemImage: "bell.fill") + } + Divider() + ForEach(Notification.NotificationType.allCases, id: \.self) { type in + Button { + viewModel.selectedType = type + } label: { + Label(type.menuTitle(), systemImage: type.iconName()) + } } } } @@ -46,6 +52,9 @@ public struct NotificationsListView: View { .background(theme.primaryBackgroundColor) .task { viewModel.client = client + if let lockedType { + viewModel.selectedType = lockedType + } await viewModel.fetchNotifications() } .refreshable { diff --git a/Packages/Notifications/Sources/Notifications/NotificationsViewModel.swift b/Packages/Notifications/Sources/Notifications/NotificationsViewModel.swift index 7490fb56..43bb4c12 100644 --- a/Packages/Notifications/Sources/Notifications/NotificationsViewModel.swift +++ b/Packages/Notifications/Sources/Notifications/NotificationsViewModel.swift @@ -39,7 +39,12 @@ class NotificationsViewModel: ObservableObject { } private var queryTypes: [String]? { - selectedType != nil ? [selectedType!.rawValue] : nil + if let selectedType { + var excludedTypes = Models.Notification.NotificationType.allCases + excludedTypes.removeAll(where: { $0 == selectedType}) + return excludedTypes.map{ $0.rawValue } + } + return nil } private var notifications: [Models.Notification] = [] @@ -98,7 +103,8 @@ class NotificationsViewModel: ObservableObject { } func handleEvent(event: any StreamEvent) { - if let event = event as? StreamEventNotification, + if selectedType == nil, + let event = event as? StreamEventNotification, !notifications.contains(where: { $0.id == event.notification.id }) { notifications.insert(event.notification, at: 0)