Add a specific tab for mention on macOS and iPadOS fix #111

This commit is contained in:
Thomas Ricouard 2023-01-19 07:24:24 +01:00
parent 22c9d51941
commit 3e3e353fdd
6 changed files with 44 additions and 20 deletions

View file

@ -4,6 +4,7 @@ import Network
import Notifications import Notifications
import SwiftUI import SwiftUI
import Timeline import Timeline
import Models
struct NotificationsTab: View { struct NotificationsTab: View {
@EnvironmentObject private var client: Client @EnvironmentObject private var client: Client
@ -12,10 +13,12 @@ struct NotificationsTab: View {
@EnvironmentObject private var userPreferences: UserPreferences @EnvironmentObject private var userPreferences: UserPreferences
@StateObject private var routerPath = RouterPath() @StateObject private var routerPath = RouterPath()
@Binding var popToRootTab: Tab @Binding var popToRootTab: Tab
let lockedType: Models.Notification.NotificationType?
var body: some View { var body: some View {
NavigationStack(path: $routerPath.path) { NavigationStack(path: $routerPath.path) {
NotificationsListView() NotificationsListView(lockedType: lockedType)
.withAppRouter() .withAppRouter()
.withSheetDestinations(sheetDestinations: $routerPath.presentedSheet) .withSheetDestinations(sheetDestinations: $routerPath.presentedSheet)
.toolbar { .toolbar {

View file

@ -5,7 +5,7 @@ import Status
import SwiftUI import SwiftUI
enum Tab: Int, Identifiable, Hashable { 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 trending, federated, local
case profile case profile
@ -19,7 +19,7 @@ enum Tab: Int, Identifiable, Hashable {
static func loggedInTabs() -> [Tab] { static func loggedInTabs() -> [Tab] {
if UIDevice.current.userInterfaceIdiom == .pad || UIDevice.current.userInterfaceIdiom == .mac { 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 { } else {
return [.timeline, .notifications, .explore, .messages, .settings] return [.timeline, .notifications, .explore, .messages, .settings]
} }
@ -37,7 +37,9 @@ enum Tab: Int, Identifiable, Hashable {
case .federated: case .federated:
TimelineTab(popToRootTab: popToRootTab, timeline: .federated) TimelineTab(popToRootTab: popToRootTab, timeline: .federated)
case .notifications: case .notifications:
NotificationsTab(popToRootTab: popToRootTab) NotificationsTab(popToRootTab: popToRootTab, lockedType: nil)
case .mentions:
NotificationsTab(popToRootTab: popToRootTab, lockedType: .mention)
case .explore: case .explore:
ExploreTab(popToRootTab: popToRootTab) ExploreTab(popToRootTab: popToRootTab)
case .messages: case .messages:
@ -62,6 +64,8 @@ enum Tab: Int, Identifiable, Hashable {
Label("Federated", systemImage: iconName) Label("Federated", systemImage: iconName)
case .notifications: case .notifications:
Label("Notifications", systemImage: iconName) Label("Notifications", systemImage: iconName)
case .mentions:
Label("Notifications", systemImage: iconName)
case .explore: case .explore:
Label("Explore", systemImage: iconName) Label("Explore", systemImage: iconName)
case .messages: case .messages:
@ -85,6 +89,8 @@ enum Tab: Int, Identifiable, Hashable {
return "globe.americas" return "globe.americas"
case .notifications: case .notifications:
return "bell" return "bell"
case .mentions:
return "at"
case .explore: case .explore:
return "magnifyingglass" return "magnifyingglass"
case .messages: case .messages:

View file

@ -21,7 +21,7 @@ public enum Notifications: Endpoint {
var params = makePaginationParam(sinceId: sinceId, maxId: maxId, mindId: nil) ?? [] var params = makePaginationParam(sinceId: sinceId, maxId: maxId, mindId: nil) ?? []
if let types { if let types {
for type in types { for type in types {
params.append(.init(name: "types[]", value: type)) params.append(.init(name: "exclude_types[]", value: type))
} }
} }
return params return params

View file

@ -46,7 +46,7 @@ extension Models.Notification.NotificationType {
case .status: case .status:
return "Post" return "Post"
case .mention: case .mention:
return "Mention" return "Mentions"
case .reblog: case .reblog:
return "Boost" return "Boost"
case .follow: case .follow:

View file

@ -11,8 +11,12 @@ public struct NotificationsListView: View {
@EnvironmentObject private var watcher: StreamWatcher @EnvironmentObject private var watcher: StreamWatcher
@EnvironmentObject private var client: Client @EnvironmentObject private var client: Client
@StateObject private var viewModel = NotificationsViewModel() @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 { public var body: some View {
ScrollView { ScrollView {
@ -23,21 +27,23 @@ public struct NotificationsListView: View {
.padding(.top, .layoutPadding + 16) .padding(.top, .layoutPadding + 16)
.background(theme.primaryBackgroundColor) .background(theme.primaryBackgroundColor)
} }
.navigationTitle(viewModel.selectedType?.menuTitle() ?? "All Notifications") .navigationTitle(lockedType?.menuTitle() ?? viewModel.selectedType?.menuTitle() ?? "All Notifications")
.navigationBarTitleDisplayMode(.inline) .navigationBarTitleDisplayMode(.inline)
.toolbar { .toolbar {
ToolbarTitleMenu { if lockedType == nil {
Button { ToolbarTitleMenu {
viewModel.selectedType = nil
} label: {
Label("All Notifications", systemImage: "bell.fill")
}
Divider()
ForEach(Notification.NotificationType.allCases, id: \.self) { type in
Button { Button {
viewModel.selectedType = type viewModel.selectedType = nil
} label: { } 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) .background(theme.primaryBackgroundColor)
.task { .task {
viewModel.client = client viewModel.client = client
if let lockedType {
viewModel.selectedType = lockedType
}
await viewModel.fetchNotifications() await viewModel.fetchNotifications()
} }
.refreshable { .refreshable {

View file

@ -39,7 +39,12 @@ class NotificationsViewModel: ObservableObject {
} }
private var queryTypes: [String]? { 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] = [] private var notifications: [Models.Notification] = []
@ -98,7 +103,8 @@ class NotificationsViewModel: ObservableObject {
} }
func handleEvent(event: any StreamEvent) { 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.contains(where: { $0.id == event.notification.id })
{ {
notifications.insert(event.notification, at: 0) notifications.insert(event.notification, at: 0)