mirror of
https://github.com/Dimillian/IceCubesApp.git
synced 2024-11-25 09:41:02 +00:00
Add supports for notifications filter API
This commit is contained in:
parent
bb56047ee2
commit
5c32c24ae5
19 changed files with 1260 additions and 39 deletions
|
@ -11,6 +11,7 @@ import Models
|
|||
import StatusKit
|
||||
import SwiftUI
|
||||
import Timeline
|
||||
import Notifications
|
||||
|
||||
@MainActor
|
||||
extension View {
|
||||
|
@ -63,6 +64,12 @@ extension View {
|
|||
TrendingLinksListView(cards: cards)
|
||||
case let .tagsList(tags):
|
||||
TagsListView(tags: tags)
|
||||
case .notificationsRequests:
|
||||
NotificationsRequestsListView()
|
||||
case let .notificationForAccount(accountId):
|
||||
NotificationsListView(lockedType: nil ,
|
||||
lockedAccountId: accountId,
|
||||
scrollToTopSignal: .constant(0))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,13 +17,7 @@ struct NavigationSheet<Content: View>: View {
|
|||
NavigationStack {
|
||||
content()
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
Button {
|
||||
dismiss()
|
||||
} label: {
|
||||
Image(systemName: "xmark.circle")
|
||||
}
|
||||
}
|
||||
CloseToolbarItem()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34599,6 +34599,839 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"notifications.content-filter.newAccounts" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"be" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
},
|
||||
"ca" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
},
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
},
|
||||
"en-GB" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
},
|
||||
"eu" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
},
|
||||
"ko" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
},
|
||||
"nb" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
},
|
||||
"nl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
},
|
||||
"pl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
},
|
||||
"pt-BR" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
},
|
||||
"uk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "New accounts"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifications.content-filter.peopleNotFollowingYou" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"be" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
},
|
||||
"ca" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
},
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
},
|
||||
"en-GB" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
},
|
||||
"eu" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
},
|
||||
"ko" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
},
|
||||
"nb" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
},
|
||||
"nl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
},
|
||||
"pl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
},
|
||||
"pt-BR" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
},
|
||||
"uk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People not following you"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifications.content-filter.peopleYouDontFollow" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"be" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
},
|
||||
"ca" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
},
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
},
|
||||
"en-GB" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
},
|
||||
"eu" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
},
|
||||
"ko" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
},
|
||||
"nb" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
},
|
||||
"nl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
},
|
||||
"pl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
},
|
||||
"pt-BR" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
},
|
||||
"uk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "People you don't follow"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifications.content-filter.privateMentions" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"be" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Unsolicited private mentions"
|
||||
}
|
||||
},
|
||||
"ca" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Unsolicited private mentions"
|
||||
}
|
||||
},
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Unsolicited private mentions"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Unsolicited private mentions"
|
||||
}
|
||||
},
|
||||
"en-GB" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Unsolicited private mentions"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Unsolicited private mentions"
|
||||
}
|
||||
},
|
||||
"eu" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Unsolicited private mentions"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Unsolicited private mentions"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Unsolicited private mentions"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Unsolicited private mentions"
|
||||
}
|
||||
},
|
||||
"ko" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Unsolicited private mentions"
|
||||
}
|
||||
},
|
||||
"nb" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Unsolicited private mentions"
|
||||
}
|
||||
},
|
||||
"nl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Unsolicited private mentions"
|
||||
}
|
||||
},
|
||||
"pl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Unsolicited private mentions"
|
||||
}
|
||||
},
|
||||
"pt-BR" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : ""
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Unsolicited private mentions"
|
||||
}
|
||||
},
|
||||
"uk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Unsolicited private mentions"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : ""
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Unsolicited private mentions"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifications.content-filter.requests.title" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"be" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
},
|
||||
"ca" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
},
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
},
|
||||
"en-GB" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
},
|
||||
"eu" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
},
|
||||
"ko" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
},
|
||||
"nb" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
},
|
||||
"nl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
},
|
||||
"pl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
},
|
||||
"pt-BR" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
},
|
||||
"uk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filtered notifications"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifications.content-filter.title" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"be" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
},
|
||||
"ca" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
},
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
},
|
||||
"en-GB" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
},
|
||||
"eu" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
},
|
||||
"ko" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
},
|
||||
"nb" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
},
|
||||
"nl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
},
|
||||
"pl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
},
|
||||
"pt-BR" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
},
|
||||
"uk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Notifications Filter"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifications.content-filter.title-inline" : {
|
||||
"extractionState" : "manual",
|
||||
"localizations" : {
|
||||
"be" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
},
|
||||
"ca" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
},
|
||||
"de" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
},
|
||||
"en" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
},
|
||||
"en-GB" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
},
|
||||
"es" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
},
|
||||
"eu" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
},
|
||||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
},
|
||||
"ja" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
},
|
||||
"ko" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
},
|
||||
"nb" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
},
|
||||
"nl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
},
|
||||
"pl" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
},
|
||||
"pt-BR" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
},
|
||||
"tr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
},
|
||||
"uk" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
},
|
||||
"zh-Hans" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
},
|
||||
"zh-Hant" : {
|
||||
"stringUnit" : {
|
||||
"state" : "needs_review",
|
||||
"value" : "Filter out notifications from…"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"notifications.empty.message" : {
|
||||
"comment" : "MARK: Package: Notifications",
|
||||
"extractionState" : "manual",
|
||||
|
@ -38197,7 +39030,7 @@
|
|||
"fr" : {
|
||||
"stringUnit" : {
|
||||
"state" : "translated",
|
||||
"value" : "Toutes les notifications"
|
||||
"value" : "Notifications"
|
||||
}
|
||||
},
|
||||
"it" : {
|
||||
|
|
|
@ -56,11 +56,9 @@ public struct ConversationsListView: View {
|
|||
message: "conversations.error.message",
|
||||
buttonTitle: "conversations.error.button")
|
||||
{
|
||||
Task {
|
||||
await viewModel.fetchConversations()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if viewModel.nextPage != nil {
|
||||
HStack {
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
import SwiftUI
|
||||
|
||||
public struct CloseToolbarItem: ToolbarContent {
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
||||
public init() {}
|
||||
|
||||
public var body: some ToolbarContent {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
Button(action: {
|
||||
dismiss()
|
||||
}, label: {
|
||||
Image(systemName: "xmark.circle")
|
||||
})
|
||||
.keyboardShortcut(.cancelAction)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,9 +4,9 @@ public struct ErrorView: View {
|
|||
public let title: LocalizedStringKey
|
||||
public let message: LocalizedStringKey
|
||||
public let buttonTitle: LocalizedStringKey
|
||||
public let onButtonPress: () -> Void
|
||||
public let onButtonPress: (() async -> Void)
|
||||
|
||||
public init(title: LocalizedStringKey, message: LocalizedStringKey, buttonTitle: LocalizedStringKey, onButtonPress: @escaping (() -> Void)) {
|
||||
public init(title: LocalizedStringKey, message: LocalizedStringKey, buttonTitle: LocalizedStringKey, onButtonPress: @escaping (() async -> Void) ) {
|
||||
self.title = title
|
||||
self.message = message
|
||||
self.buttonTitle = buttonTitle
|
||||
|
@ -29,7 +29,9 @@ public struct ErrorView: View {
|
|||
.multilineTextAlignment(.center)
|
||||
.foregroundStyle(.secondary)
|
||||
Button {
|
||||
onButtonPress()
|
||||
Task {
|
||||
await onButtonPress()
|
||||
}
|
||||
} label: {
|
||||
Text(buttonTitle)
|
||||
}
|
||||
|
|
|
@ -35,6 +35,10 @@ import Observation
|
|||
version >= 4.1
|
||||
}
|
||||
|
||||
public var isNotificationsFilterSupported: Bool {
|
||||
version >= 4.3
|
||||
}
|
||||
|
||||
private init() {}
|
||||
|
||||
public func setClient(client: Client) {
|
||||
|
|
|
@ -23,6 +23,8 @@ public enum RouterDestination: Hashable {
|
|||
case trendingTimeline
|
||||
case trendingLinks(cards: [Card])
|
||||
case tagsList(tags: [Tag])
|
||||
case notificationsRequests
|
||||
case notificationForAccount(accountId: String)
|
||||
}
|
||||
|
||||
public enum WindowDestinationEditor: Hashable, Codable {
|
||||
|
|
14
Packages/Models/Sources/Models/NotificationsPolicy.swift
Normal file
14
Packages/Models/Sources/Models/NotificationsPolicy.swift
Normal file
|
@ -0,0 +1,14 @@
|
|||
import Foundation
|
||||
|
||||
public struct NotificationsPolicy: Codable, Sendable {
|
||||
public var filterNotFollowing: Bool
|
||||
public var filterNotFollowers: Bool
|
||||
public var filterNewAccounts: Bool
|
||||
public var filterPrivateMentions: Bool
|
||||
public let summary: Summary
|
||||
|
||||
public struct Summary: Codable, Sendable {
|
||||
public let pendingRequestsCount: String
|
||||
public let pendingNotificationsCount: String
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
import Foundation
|
||||
|
||||
public struct NotificationsRequest: Identifiable, Decodable, Sendable {
|
||||
public let id: String
|
||||
public let account: Account
|
||||
public let notificationsCount: String
|
||||
}
|
|
@ -1,26 +1,54 @@
|
|||
import Foundation
|
||||
import Models
|
||||
|
||||
public enum Notifications: Endpoint {
|
||||
case notifications(minId: String?,
|
||||
maxId: String?,
|
||||
types: [String]?,
|
||||
limit: Int)
|
||||
case notificationsForAccount(accountId: String, maxId: String?)
|
||||
case notification(id: String)
|
||||
case policy
|
||||
case putPolicy(policy: Models.NotificationsPolicy)
|
||||
case requests
|
||||
case acceptRequest(id: String)
|
||||
case dismissRequest(id: String)
|
||||
case clear
|
||||
|
||||
public func path() -> String {
|
||||
switch self {
|
||||
case .notifications:
|
||||
case .notifications, .notificationsForAccount:
|
||||
"notifications"
|
||||
case let .notification(id):
|
||||
"notifications/\(id)"
|
||||
case .policy, .putPolicy:
|
||||
"notifications/policy"
|
||||
case .requests:
|
||||
"notifications/requests"
|
||||
case let .acceptRequest(id):
|
||||
"notifications/requests/\(id)/accept"
|
||||
case let .dismissRequest(id):
|
||||
"notifications/requests/\(id)/dismiss"
|
||||
case .clear:
|
||||
"notifications/clear"
|
||||
}
|
||||
}
|
||||
|
||||
public var jsonValue: (any Encodable)? {
|
||||
switch self {
|
||||
case let .putPolicy(policy):
|
||||
return policy
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
public func queryItems() -> [URLQueryItem]? {
|
||||
switch self {
|
||||
case let .notificationsForAccount(accountId, maxId):
|
||||
var params = makePaginationParam(sinceId: nil, maxId: maxId, mindId: nil) ?? []
|
||||
params.append(.init(name: "account_id", value: accountId))
|
||||
return params
|
||||
case let .notifications(mindId, maxId, types, limit):
|
||||
var params = makePaginationParam(sinceId: nil, maxId: maxId, mindId: mindId) ?? []
|
||||
params.append(.init(name: "limit", value: String(limit)))
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
import SwiftUI
|
||||
import Models
|
||||
import DesignSystem
|
||||
import Env
|
||||
|
||||
struct NotificationsHeaderFilteredView: View {
|
||||
@Environment(Theme.self) private var theme
|
||||
@Environment(RouterPath.self) private var routerPath
|
||||
|
||||
let filteredNotifications: NotificationsPolicy.Summary
|
||||
|
||||
var body: some View {
|
||||
if let count = Int(filteredNotifications.pendingNotificationsCount), count > 0 {
|
||||
HStack {
|
||||
Label("notifications.content-filter.requests.title", systemImage: "archivebox")
|
||||
.foregroundStyle(.secondary)
|
||||
Spacer()
|
||||
Text(filteredNotifications.pendingNotificationsCount)
|
||||
.font(.footnote)
|
||||
.fontWeight(.semibold)
|
||||
.monospacedDigit()
|
||||
.foregroundStyle(theme.primaryBackgroundColor)
|
||||
.padding(8)
|
||||
.background(.secondary)
|
||||
.clipShape(Circle())
|
||||
Image(systemName: "chevron.right")
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
.onTapGesture {
|
||||
routerPath.navigate(to: .notificationsRequests)
|
||||
}
|
||||
.listRowBackground(theme.secondaryBackgroundColor)
|
||||
.listRowInsets(.init(top: 12,
|
||||
leading: .layoutPadding,
|
||||
bottom: 12,
|
||||
trailing: .layoutPadding))
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,18 +7,26 @@ import SwiftUI
|
|||
@MainActor
|
||||
public struct NotificationsListView: View {
|
||||
@Environment(\.scenePhase) private var scenePhase
|
||||
|
||||
@Environment(Theme.self) private var theme
|
||||
@Environment(StreamWatcher.self) private var watcher
|
||||
@Environment(Client.self) private var client
|
||||
@Environment(RouterPath.self) private var routerPath
|
||||
@Environment(CurrentAccount.self) private var account
|
||||
@Environment(CurrentInstance.self) private var currentInstance
|
||||
|
||||
@State private var viewModel = NotificationsViewModel()
|
||||
@State private var isNotificationsPolicyPresented: Bool = false
|
||||
@Binding var scrollToTopSignal: Int
|
||||
|
||||
let lockedType: Models.Notification.NotificationType?
|
||||
let lockedAccountId: String?
|
||||
|
||||
public init(lockedType: Models.Notification.NotificationType?, scrollToTopSignal: Binding<Int>) {
|
||||
public init(lockedType: Models.Notification.NotificationType? = nil,
|
||||
lockedAccountId: String? = nil,
|
||||
scrollToTopSignal: Binding<Int>) {
|
||||
self.lockedType = lockedType
|
||||
self.lockedAccountId = lockedAccountId
|
||||
_scrollToTopSignal = scrollToTopSignal
|
||||
}
|
||||
|
||||
|
@ -27,6 +35,9 @@ public struct NotificationsListView: View {
|
|||
List {
|
||||
scrollToTopView
|
||||
topPaddingView
|
||||
if lockedAccountId == nil, let summary = viewModel.policy?.summary {
|
||||
NotificationsHeaderFilteredView(filteredNotifications: summary)
|
||||
}
|
||||
notificationsView
|
||||
}
|
||||
.id(account.account?.id)
|
||||
|
@ -58,7 +69,7 @@ public struct NotificationsListView: View {
|
|||
}
|
||||
}
|
||||
.toolbar {
|
||||
if lockedType == nil {
|
||||
if lockedType == nil && lockedAccountId == nil {
|
||||
ToolbarTitleMenu {
|
||||
Button {
|
||||
viewModel.selectedType = nil
|
||||
|
@ -83,9 +94,20 @@ public struct NotificationsListView: View {
|
|||
}
|
||||
}
|
||||
}
|
||||
if currentInstance.isNotificationsFilterSupported {
|
||||
Divider()
|
||||
Button {
|
||||
isNotificationsPolicyPresented = true
|
||||
} label: {
|
||||
Label("notifications.content-filter.title", systemImage: "line.3.horizontal.decrease")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $isNotificationsPolicyPresented) {
|
||||
NotificationsPolicyView()
|
||||
}
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
#if !os(visionOS)
|
||||
.scrollContentBackground(.hidden)
|
||||
|
@ -97,11 +119,14 @@ public struct NotificationsListView: View {
|
|||
if let lockedType {
|
||||
viewModel.isLockedType = true
|
||||
viewModel.selectedType = lockedType
|
||||
} else if let lockedAccountId {
|
||||
viewModel.lockedAccountId = lockedAccountId
|
||||
} else {
|
||||
viewModel.loadSelectedType()
|
||||
}
|
||||
Task {
|
||||
await viewModel.fetchNotifications()
|
||||
await viewModel.fetchPolicy()
|
||||
}
|
||||
}
|
||||
.refreshable {
|
||||
|
@ -203,10 +228,8 @@ public struct NotificationsListView: View {
|
|||
message: "notifications.error.message",
|
||||
buttonTitle: "action.retry")
|
||||
{
|
||||
Task {
|
||||
await viewModel.fetchNotifications()
|
||||
}
|
||||
}
|
||||
#if !os(visionOS)
|
||||
.listRowBackground(theme.primaryBackgroundColor)
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
import SwiftUI
|
||||
import Network
|
||||
import DesignSystem
|
||||
import Models
|
||||
|
||||
@MainActor
|
||||
struct NotificationsPolicyView: View {
|
||||
@Environment(\.dismiss) private var dismiss
|
||||
|
||||
@Environment(Client.self) private var client
|
||||
@Environment(Theme.self) private var theme
|
||||
|
||||
@State private var policy: NotificationsPolicy?
|
||||
@State private var isUpdating: Bool = false
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
Form {
|
||||
Section("notifications.content-filter.title-inline") {
|
||||
Toggle(isOn: .init(get: { policy?.filterNotFollowing == true },
|
||||
set: { newValue in
|
||||
policy?.filterNotFollowing = newValue
|
||||
Task { await updatePolicy() }
|
||||
}), label: {
|
||||
Text("notifications.content-filter.peopleYouDontFollow")
|
||||
})
|
||||
Toggle(isOn: .init(get: { policy?.filterNotFollowers == true },
|
||||
set: { newValue in
|
||||
policy?.filterNotFollowers = newValue
|
||||
Task { await updatePolicy() }
|
||||
}), label: {
|
||||
Text("notifications.content-filter.peopleNotFollowingYou")
|
||||
})
|
||||
Toggle(isOn: .init(get: { policy?.filterNewAccounts == true },
|
||||
set: { newValue in
|
||||
policy?.filterNewAccounts = newValue
|
||||
Task { await updatePolicy() }
|
||||
}), label: {
|
||||
Text("notifications.content-filter.newAccounts")
|
||||
})
|
||||
Toggle(isOn: .init(get: { policy?.filterPrivateMentions == true },
|
||||
set: { newValue in
|
||||
policy?.filterPrivateMentions = newValue
|
||||
Task { await updatePolicy() }
|
||||
}), label: {
|
||||
Text("notifications.content-filter.privateMentions")
|
||||
})
|
||||
}
|
||||
#if !os(visionOS)
|
||||
.listRowBackground(theme.primaryBackgroundColor)
|
||||
#endif
|
||||
}
|
||||
.formStyle(.grouped)
|
||||
.navigationTitle("notifications.content-filter.title")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.scrollContentBackground(.hidden)
|
||||
.toolbar { CloseToolbarItem() }
|
||||
.disabled(policy == nil || isUpdating)
|
||||
.task {
|
||||
await getPolicy()
|
||||
}
|
||||
}
|
||||
.presentationDetents([.medium])
|
||||
.presentationBackground(.thinMaterial)
|
||||
}
|
||||
|
||||
private func getPolicy() async {
|
||||
defer {
|
||||
isUpdating = false
|
||||
}
|
||||
do {
|
||||
isUpdating = true
|
||||
policy = try await client.get(endpoint: Notifications.policy)
|
||||
} catch {
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
|
||||
private func updatePolicy() async {
|
||||
if let policy {
|
||||
defer {
|
||||
isUpdating = false
|
||||
}
|
||||
do {
|
||||
isUpdating = true
|
||||
self.policy = try await client.put(endpoint: Notifications.putPolicy(policy: policy))
|
||||
} catch { }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -39,6 +39,8 @@ import SwiftUI
|
|||
private let filterKey = "notification-filter"
|
||||
var state: State = .loading
|
||||
var isLockedType: Bool = false
|
||||
var lockedAccountId: String? = nil
|
||||
var policy: Models.NotificationsPolicy?
|
||||
var selectedType: Models.Notification.NotificationType? {
|
||||
didSet {
|
||||
guard oldValue != selectedType,
|
||||
|
@ -82,11 +84,16 @@ import SwiftUI
|
|||
var nextPageState: State.PagingState = .hasNextPage
|
||||
if consolidatedNotifications.isEmpty {
|
||||
state = .loading
|
||||
let notifications: [Models.Notification] =
|
||||
try await client.get(endpoint: Notifications.notifications(minId: nil,
|
||||
let notifications: [Models.Notification]
|
||||
if let lockedAccountId {
|
||||
notifications = try await client.get(endpoint: Notifications.notificationsForAccount(accountId: lockedAccountId,
|
||||
maxId: nil))
|
||||
} else {
|
||||
notifications = try await client.get(endpoint: Notifications.notifications(minId: nil,
|
||||
maxId: nil,
|
||||
types: queryTypes,
|
||||
limit: Constants.notificationLimit))
|
||||
}
|
||||
consolidatedNotifications = await notifications.consolidated(selectedType: selectedType)
|
||||
markAsRead()
|
||||
nextPageState = notifications.count < Constants.notificationLimit ? .none : .hasNextPage
|
||||
|
@ -119,7 +126,7 @@ import SwiftUI
|
|||
}
|
||||
|
||||
private func fetchNewPages(minId: String, maxPages: Int) async -> [Models.Notification] {
|
||||
guard let client else { return [] }
|
||||
guard let client, lockedAccountId == nil else { return [] }
|
||||
var pagesLoaded = 0
|
||||
var allNotifications: [Models.Notification] = []
|
||||
var latestMinId = minId
|
||||
|
@ -146,11 +153,17 @@ import SwiftUI
|
|||
func fetchNextPage() async throws {
|
||||
guard let client else { return }
|
||||
guard let lastId = consolidatedNotifications.last?.notificationIds.last else { return }
|
||||
let newNotifications: [Models.Notification] =
|
||||
let newNotifications: [Models.Notification]
|
||||
if let lockedAccountId {
|
||||
newNotifications =
|
||||
try await client.get(endpoint: Notifications.notificationsForAccount(accountId: lockedAccountId, maxId: lastId))
|
||||
} else {
|
||||
newNotifications =
|
||||
try await client.get(endpoint: Notifications.notifications(minId: nil,
|
||||
maxId: lastId,
|
||||
types: queryTypes,
|
||||
limit: Constants.notificationLimit))
|
||||
}
|
||||
await consolidatedNotifications.append(contentsOf: newNotifications.consolidated(selectedType: selectedType))
|
||||
if consolidatedNotifications.contains(where: { $0.type == .follow_request }) {
|
||||
await currentAccount?.fetchFollowerRequests()
|
||||
|
@ -168,12 +181,17 @@ import SwiftUI
|
|||
}
|
||||
}
|
||||
|
||||
func fetchPolicy() async {
|
||||
policy = try? await client?.get(endpoint: Notifications.policy)
|
||||
}
|
||||
|
||||
func handleEvent(event: any StreamEvent) {
|
||||
Task {
|
||||
// Check if the event is a notification,
|
||||
// if it is not already in the list,
|
||||
// and if it can be shown (no selected type or the same as the received notification type)
|
||||
if let event = event as? StreamEventNotification,
|
||||
if lockedAccountId == nil,
|
||||
let event = event as? StreamEventNotification,
|
||||
!consolidatedNotifications.flatMap(\.notificationIds).contains(event.notification.id),
|
||||
selectedType == nil || selectedType?.rawValue == event.notification.type
|
||||
{
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
import SwiftUI
|
||||
import Network
|
||||
import Models
|
||||
import DesignSystem
|
||||
|
||||
@MainActor
|
||||
public struct NotificationsRequestsListView: View {
|
||||
@Environment(Client.self) private var client
|
||||
@Environment(Theme.self) private var theme
|
||||
|
||||
enum ViewState {
|
||||
case loading
|
||||
case error
|
||||
case requests(_ data: [NotificationsRequest])
|
||||
}
|
||||
@State private var viewState: ViewState = .loading
|
||||
|
||||
public init() { }
|
||||
|
||||
public var body: some View {
|
||||
List {
|
||||
switch viewState {
|
||||
case .loading:
|
||||
ProgressView()
|
||||
#if !os(visionOS)
|
||||
.listRowBackground(theme.primaryBackgroundColor)
|
||||
#endif
|
||||
.listSectionSeparator(.hidden)
|
||||
case .error:
|
||||
ErrorView(title: "notifications.error.title",
|
||||
message: "notifications.error.message",
|
||||
buttonTitle: "action.retry")
|
||||
{
|
||||
await fetchRequests()
|
||||
}
|
||||
#if !os(visionOS)
|
||||
.listRowBackground(theme.primaryBackgroundColor)
|
||||
#endif
|
||||
.listSectionSeparator(.hidden)
|
||||
case let .requests(data):
|
||||
ForEach(data) { request in
|
||||
NotificationsRequestsRowView(request: request)
|
||||
.swipeActions {
|
||||
Button {
|
||||
Task { await acceptRequest(request) }
|
||||
} label: {
|
||||
Label("account.follow-request.accept", systemImage: "checkmark")
|
||||
}
|
||||
|
||||
Button {
|
||||
Task { await dismissRequest(request) }
|
||||
} label: {
|
||||
Label("account.follow-request.reject", systemImage: "xmark")
|
||||
}
|
||||
.tint(.red)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
.listStyle(.plain)
|
||||
#if !os(visionOS)
|
||||
.scrollContentBackground(.hidden)
|
||||
.background(theme.primaryBackgroundColor)
|
||||
#endif
|
||||
.navigationTitle("notifications.content-filter.requests.title")
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.task {
|
||||
await fetchRequests()
|
||||
}
|
||||
.refreshable {
|
||||
await fetchRequests()
|
||||
}
|
||||
}
|
||||
|
||||
private func fetchRequests() async {
|
||||
do {
|
||||
viewState = .requests(try await client.get(endpoint: Notifications.requests))
|
||||
} catch {
|
||||
viewState = .error
|
||||
}
|
||||
}
|
||||
|
||||
private func acceptRequest(_ request: NotificationsRequest) async {
|
||||
_ = try? await client.post(endpoint: Notifications.acceptRequest(id: request.id))
|
||||
await fetchRequests()
|
||||
}
|
||||
|
||||
private func dismissRequest(_ request: NotificationsRequest) async {
|
||||
_ = try? await client.post(endpoint: Notifications.dismissRequest(id: request.id))
|
||||
await fetchRequests()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
import SwiftUI
|
||||
import Models
|
||||
import DesignSystem
|
||||
import Env
|
||||
import Network
|
||||
|
||||
struct NotificationsRequestsRowView: View {
|
||||
@Environment(Theme.self) private var theme
|
||||
@Environment(RouterPath.self) private var routerPath
|
||||
@Environment(Client.self) private var client
|
||||
|
||||
let request: NotificationsRequest
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .center, spacing: 8) {
|
||||
AvatarView(request.account.avatar, config: .embed)
|
||||
|
||||
VStack(alignment: .leading) {
|
||||
EmojiTextApp(request.account.cachedDisplayName, emojis: request.account.emojis)
|
||||
.font(.scaledBody)
|
||||
.foregroundStyle(theme.labelColor)
|
||||
.lineLimit(1)
|
||||
Text(request.account.acct)
|
||||
.font(.scaledFootnote)
|
||||
.fontWeight(.semibold)
|
||||
.foregroundStyle(.secondary)
|
||||
.lineLimit(1)
|
||||
}
|
||||
.padding(.vertical, 4)
|
||||
Spacer()
|
||||
Text(request.notificationsCount)
|
||||
.font(.footnote)
|
||||
.monospacedDigit()
|
||||
.foregroundStyle(theme.primaryBackgroundColor)
|
||||
.padding(8)
|
||||
.background(.secondary)
|
||||
.clipShape(Circle())
|
||||
|
||||
Image(systemName: "chevron.right")
|
||||
.foregroundStyle(.secondary)
|
||||
}
|
||||
.onTapGesture {
|
||||
routerPath.navigate(to: .notificationForAccount(accountId: request.account.id))
|
||||
}
|
||||
.listRowInsets(.init(top: 12,
|
||||
leading: .layoutPadding,
|
||||
bottom: 12,
|
||||
trailing: .layoutPadding))
|
||||
#if os(visionOS)
|
||||
.listRowBackground(RoundedRectangle(cornerRadius: 8)
|
||||
.foregroundStyle(.background))
|
||||
#else
|
||||
.listRowBackground(theme.primaryBackgroundColor)
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -152,9 +152,7 @@ public struct StatusDetailView: View {
|
|||
message: "status.error.message",
|
||||
buttonTitle: "action.retry")
|
||||
{
|
||||
Task {
|
||||
await viewModel.fetch()
|
||||
}
|
||||
_ = await viewModel.fetch()
|
||||
}
|
||||
#if !os(visionOS)
|
||||
.listRowBackground(theme.primaryBackgroundColor)
|
||||
|
|
|
@ -38,10 +38,8 @@ public struct StatusesListView<Fetcher>: View where Fetcher: StatusesFetcher {
|
|||
message: "status.error.loading.message",
|
||||
buttonTitle: "action.retry")
|
||||
{
|
||||
Task {
|
||||
await fetcher.fetchNewestStatuses(pullToRefresh: false)
|
||||
}
|
||||
}
|
||||
.listRowBackground(theme.primaryBackgroundColor)
|
||||
.listRowSeparator(.hidden)
|
||||
|
||||
|
|
Loading…
Reference in a new issue