Skip to content

Commit 5d8e453

Browse files
authored
Notification Filtering (IOS-241) (#1319)
- Adds a new cell on the "Everything"-notification-screen to show unwanted notifications - Users can define what "unwanted" means to them using the new "Filter"-button in the upper right corner of the Notification-screen - Filtered notifications are sorted by account and users can dismiss/accept if they want to get notifications of that user (it's some standard table-views and delegates) ## Screenshots ![ios_241_1](https://github.com/user-attachments/assets/b2297a13-e220-4916-b3b9-24dfcef431de) ![ios_241_2](https://github.com/user-attachments/assets/5fd5b894-cd4e-40f9-abce-56ff17d41dfa)
2 parents aa7b6ff + bac8c23 commit 5d8e453

File tree

49 files changed

+4018
-2416
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

49 files changed

+4018
-2416
lines changed

Localization/Localizable.stringsdict

Lines changed: 597 additions & 581 deletions
Large diffs are not rendered by default.

Localization/StringsConvertor/input/Base.lproj/Localizable.stringsdict

Lines changed: 597 additions & 581 deletions
Large diffs are not rendered by default.

Localization/StringsConvertor/input/Base.lproj/app.json

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -477,7 +477,15 @@
477477
"title": "Home",
478478
"timeline_menu": {
479479
"following": "Following",
480-
"local_community": "Local"
480+
"local_community": "Local",
481+
"lists": {
482+
"title": "Lists",
483+
"empty_message": "You don't have any Lists"
484+
},
485+
"hashtags": {
486+
"title": "Followed Hashtags",
487+
"empty_message": "You don't follow any Hashtags"
488+
}
481489
},
482490
"timeline_pill": {
483491
"offline": "Offline",
@@ -744,6 +752,30 @@
744752
"silence": "Your account has been limited.",
745753
"suspend": "Your account has been suspended.",
746754
"learn_more": "Learn More"
755+
},
756+
"filtered_notification": {
757+
"title": "Filtered Notifications",
758+
"accept": "Accept",
759+
"dismiss": "Dismiss",
760+
},
761+
"policy": {
762+
"title": "Filter Notifications from…",
763+
"not_following": {
764+
"title": "People you don't follow",
765+
"subtitle": "Until you manually approve them"
766+
},
767+
"no_follower": {
768+
"title": "People not following you",
769+
"subtitle": "Including people who have been following you fewer than 3 days"
770+
},
771+
"new_account": {
772+
"title": "New accounts",
773+
"subtitle": "Created within the past 30 days"
774+
},
775+
"private_mentions": {
776+
"title": "Unsolicited private mentions",
777+
"subtitle": "Filtered unless it’s in reply to your own mention or if you follow the sender"
778+
}
747779
}
748780
},
749781
"thread": {

Localization/app.json

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -755,6 +755,30 @@
755755
"silence": "Your account has been limited.",
756756
"suspend": "Your account has been suspended.",
757757
"learn_more": "Learn More"
758+
},
759+
"filtered_notification": {
760+
"title": "Filtered Notifications",
761+
"accept": "Accept",
762+
"dismiss": "Dismiss",
763+
},
764+
"policy": {
765+
"title": "Filter Notifications from…",
766+
"not_following": {
767+
"title": "People you don't follow",
768+
"subtitle": "Until you manually approve them"
769+
},
770+
"no_follower": {
771+
"title": "People not following you",
772+
"subtitle": "Including people who have been following you fewer than 3 days"
773+
},
774+
"new_account": {
775+
"title": "New accounts",
776+
"subtitle": "Created within the past 30 days"
777+
},
778+
"private_mentions": {
779+
"title": "Unsolicited private mentions",
780+
"subtitle": "Filtered unless it’s in reply to your own mention or if you follow the sender"
781+
}
758782
}
759783
},
760784
"thread": {

Mastodon.xcodeproj/project.pbxproj

Lines changed: 65 additions & 0 deletions
Large diffs are not rendered by default.

Mastodon/Coordinator/SceneCoordinator.swift

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,12 @@ extension SceneCoordinator {
205205

206206
// setting
207207
case settings(setting: Setting)
208-
208+
209+
// Notifications
210+
case notificationPolicy(viewModel: NotificationFilterViewModel)
211+
case notificationRequests(viewModel: NotificationRequestsViewModel)
212+
case accountNotificationTimeline(viewModel: NotificationTimelineViewModel, request: Mastodon.Entity.NotificationRequest)
213+
209214
// report
210215
case report(viewModel: ReportViewModel)
211216
case reportServerRules(viewModel: ReportServerRulesViewModel)
@@ -558,6 +563,12 @@ private extension SceneCoordinator {
558563
case .editStatus(let viewModel):
559564
let composeViewController = ComposeViewController(viewModel: viewModel)
560565
viewController = composeViewController
566+
case .notificationRequests(let viewModel):
567+
viewController = NotificationRequestsTableViewController(viewModel: viewModel)
568+
case .notificationPolicy(let viewModel):
569+
viewController = NotificationPolicyViewController(viewModel: viewModel)
570+
case .accountNotificationTimeline(let viewModel, let request):
571+
viewController = AccountNotificationTimelineViewController(viewModel: viewModel, context: appContext, coordinator: self, notificationRequest: request)
561572
}
562573

563574
setupDependency(for: viewController as? NeedsDependency)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
// Copyright © 2024 Mastodon gGmbH. All rights reserved.
2+
3+
import Foundation
4+
import MastodonCore
5+
import MastodonSDK
6+
7+
extension DataSourceFacade {
8+
@MainActor
9+
static func coordinateToNotificationRequests(
10+
provider: DataSourceProvider & AuthContextProvider
11+
) async {
12+
provider.coordinator.showLoading()
13+
14+
do {
15+
let notificationRequests = try await provider.context.apiService.notificationRequests(authenticationBox: provider.authContext.mastodonAuthenticationBox).value
16+
let viewModel = NotificationRequestsViewModel(appContext: provider.context, authContext: provider.authContext, coordinator: provider.coordinator, requests: notificationRequests)
17+
18+
provider.coordinator.hideLoading()
19+
20+
let transition: SceneCoordinator.Transition
21+
22+
if provider.traitCollection.userInterfaceIdiom == .phone {
23+
transition = .show
24+
} else {
25+
transition = .modal(animated: true)
26+
}
27+
28+
provider.coordinator.present(scene: .notificationRequests(viewModel: viewModel), transition: transition)
29+
} catch {
30+
//TODO: Error Handling
31+
provider.coordinator.hideLoading()
32+
}
33+
}
34+
35+
@MainActor
36+
static func coordinateToNotificationRequest(
37+
request: Mastodon.Entity.NotificationRequest,
38+
provider: ViewControllerWithDependencies & AuthContextProvider
39+
) async -> AccountNotificationTimelineViewController? {
40+
provider.coordinator.showLoading()
41+
42+
let notificationTimelineViewModel = NotificationTimelineViewModel(context: provider.context, authContext: provider.authContext, scope: .fromAccount(request.account))
43+
44+
provider.coordinator.hideLoading()
45+
46+
guard let viewController = provider.coordinator.present(scene: .accountNotificationTimeline(viewModel: notificationTimelineViewModel, request: request), transition: .show) as? AccountNotificationTimelineViewController else { return nil }
47+
48+
return viewController
49+
50+
}
51+
52+
}

Mastodon/Protocol/Provider/DataSourceFacade+SearchHistory.swift

Lines changed: 21 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -17,32 +17,30 @@ extension DataSourceFacade {
1717
item: DataSourceItem
1818
) async {
1919
switch item {
20-
case .account(account: let account, relationship: _):
21-
let now = Date()
22-
let userID = provider.authContext.mastodonAuthenticationBox.userID
23-
let searchEntry = Persistence.SearchHistory.Item(
24-
updatedAt: now,
25-
userID: userID,
26-
account: account,
27-
hashtag: nil
28-
)
20+
case .account(account: let account, relationship: _):
21+
let now = Date()
22+
let userID = provider.authContext.mastodonAuthenticationBox.userID
23+
let searchEntry = Persistence.SearchHistory.Item(
24+
updatedAt: now,
25+
userID: userID,
26+
account: account,
27+
hashtag: nil
28+
)
2929

30-
try? FileManager.default.addSearchItem(searchEntry, for: provider.authContext.mastodonAuthenticationBox)
31-
case .hashtag(let tag):
30+
try? FileManager.default.addSearchItem(searchEntry, for: provider.authContext.mastodonAuthenticationBox)
31+
case .hashtag(let tag):
3232

33-
let now = Date()
34-
let userID = provider.authContext.mastodonAuthenticationBox.userID
35-
let searchEntry = Persistence.SearchHistory.Item(
36-
updatedAt: now,
37-
userID: userID,
38-
account: nil,
39-
hashtag: tag
40-
)
33+
let now = Date()
34+
let userID = provider.authContext.mastodonAuthenticationBox.userID
35+
let searchEntry = Persistence.SearchHistory.Item(
36+
updatedAt: now,
37+
userID: userID,
38+
account: nil,
39+
hashtag: tag
40+
)
4141

42-
try? FileManager.default.addSearchItem(searchEntry, for: provider.authContext.mastodonAuthenticationBox)
43-
case .status:
44-
break
45-
case .notification:
42+
try? FileManager.default.addSearchItem(searchEntry, for: provider.authContext.mastodonAuthenticationBox)
43+
case .status, .notification, .notificationBanner(_):
4644
break
4745

4846
}

Mastodon/Protocol/Provider/DataSourceProvider+NotificationTableViewCellDelegate.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -514,10 +514,9 @@ extension NotificationTableViewCellDelegate where Self: DataSourceProvider & Aut
514514
)
515515
case .account(let account, _):
516516
await DataSourceFacade.coordinateToProfileScene(provider: self, account: account)
517-
case .notification:
518-
assertionFailure("TODO")
519-
case .hashtag(_):
520-
assertionFailure("TODO")
517+
case .notification, .hashtag(_), .notificationBanner(_):
518+
// not supposed to happen
519+
break
521520
}
522521
} // end Task
523522
}

Mastodon/Protocol/Provider/DataSourceProvider+StatusTableViewCellDelegate.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -618,10 +618,9 @@ extension StatusTableViewCellDelegate where Self: DataSourceProvider & AuthConte
618618
provider: self,
619619
account: account
620620
)
621-
case .notification:
622-
assertionFailure("TODO")
623-
case .hashtag(_):
624-
assertionFailure("TODO")
621+
case .notification, .hashtag(_), .notificationBanner(_):
622+
// not supposed to happen
623+
break
625624
}
626625
}
627626
}

0 commit comments

Comments
 (0)