-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
chore: notifications preferences screen implementation with edge cases #111
Conversation
@@ -86,6 +86,9 @@ public protocol BaseRouter { | |||
|
|||
@MainActor | |||
func hideRestoreProgressView() | |||
|
|||
@MainActor | |||
func performNotificationRegistration() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't router responsible for navigation purposes only?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
PushNotificationsManager
belongs to OpenedX
target and Notifications
is added as a framework to it. And accessing the parent from the child isn't a good idea. That's why it's here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we should create a protocol in Core
, implement it in PushNotificationsManager
and access it from there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It already move to the OEXFoundation
a plugin based architecture, moving this there will make it harder to move to the plugin architecture, thats why I keep it simple.
@@ -773,6 +773,10 @@ public class Router: AuthorizationRouter, | |||
// show notifications inbox screen | |||
} | |||
|
|||
public func performNotificationRegistration() { | |||
Container.shared.resolve(PushNotificationsManager.self)?.performRegistration() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like business logic. Please move this function to relevant screen.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we move it to the Notifications
framework, then we have to do some work that needs to be performed after requesting the permissions. PushNotificationsManager
is responsible for doing all the notification related stuff.
Notifications/Notifications/Presentation/Settings/NotificationsSettingsViewModel.swift
Outdated
Show resolved
Hide resolved
Notifications/Notifications/Presentation/Settings/NotificationsSettingsViewModel.swift
Outdated
Show resolved
Hide resolved
Notifications/Notifications/Presentation/Settings/NotificationsSettingsViewModel.swift
Outdated
Show resolved
Hide resolved
Notifications/Notifications/Presentation/Settings/NotificationsSettingsViewModel.swift
Outdated
Show resolved
Hide resolved
Notifications/Notifications/Presentation/Settings/NotificationsSettingsViewModel.swift
Outdated
Show resolved
Hide resolved
} | ||
|
||
@MainActor | ||
public func toggleNotificationsPermissionAction() async { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A better name of this function would be syncDiscussionsActivitySetting
if I'm understanding its functionality correctly. Also, the async
nature of this function requires calling it from a Task
; would be better to keep it a regular function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
API calls cannot be made from a normal function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the API part can be handled in a separate function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess there isn't a need of a new function because that function will be called with await.
.simultaneousGesture( | ||
TapGesture().onEnded { | ||
Task { | ||
await viewModel.toggleNotificationsPermissionAction() | ||
} | ||
} | ||
) | ||
.simultaneousGesture( | ||
DragGesture(minimumDistance: 20, coordinateSpace: .local).onEnded { _ in | ||
Task { | ||
await viewModel.toggleNotificationsPermissionAction() | ||
} | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It appears there is an issue with the toggles; if I long-press the switch, it turns on or off without making any API calls.
Suggestion: Maybe we should add a network indicator or some kind of progress during notification preference toggle API call. This would let the user know something is happening in the background and also prevent multiple interactions with the toggle switch. |
It was added and then removed as we don't want to show loader on this screen. |
Screen.Recording.2025-01-03.at.14.43.43.movFirst run, user goes to Settings and tap on some preference Toggle
@saeedbashir WDYT? |
Yes after giving the permission, the switch should turn on automatically. Let me check why it's not turning on. |
@saeedbashir The second question is why preferences showing state is depend on device permissions status? Preferences are something stored on backend and user should have ability to see and change this independent on permissions on particular device, no? For example user has two devices: first one has push notifications allowed and second one doesn't have. So user will see different values on different devices (actual state for first and all disabled on second one)? |
For example, one day we got the ability to change push settings on a website (as other systems do). This does not depend on whether push notifications are allowed or not on the user's device. Why do we limit this capability to the device? |
The user will not be able to receive the notifications regardless of the server saved value if the user denied / not given the notification permissions to the app. That's why it's dependent on the device settings / permissions. |
@rnr Change is pushed and ready to review. |
Yes, I realise that the user will not receive push notifications without permissions. |
We don't have such a design at the moment; we might cater / consider it in the 2nd phase of push notifications. |
I don't think we need to wait for 2nd phase to fix showing preferences with the wrong state, what do you think? Do we need to open discussion about this (in Slack for example)? |
Yes a slack thread would be nice. |
Notifications/Notifications/Data/Network/NotificationsEndpoint.swift
Outdated
Show resolved
Hide resolved
Notifications/Notifications/Domain/NotificationsInteractor.swift
Outdated
Show resolved
Hide resolved
Notifications/Notifications/Presentation/Settings/NotificationsSettingsViewModel.swift
Outdated
Show resolved
Hide resolved
Notifications/Notifications/Presentation/Settings/NotificationsSettingsViewModel.swift
Outdated
Show resolved
Hide resolved
Notifications/Notifications/Presentation/Settings/NotificationsSettingsViewModel.swift
Outdated
Show resolved
Hide resolved
This needs to handled as a separate task. CC: @moiz994 @miankhalid |
@mta452 |
Hey Anton, the UX team did not create the design I did really since we were short on UX bandwidth. I created the design just to give an idea of what it will look like. We should definitely follow the same pattern as the video settings example you have quoted. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍
Description
Jira: LEARNER-10361
APIs to implement
GET /api/notifications/configurations
POST /api/notifications/preferences/update-all/
Only APIs Implementation
/api/notifications/read/
/api/notifications/mark-seen/discussion/
Note: These APIs will be helpful in implementing the Inbox screen of notifications and will be used in a different PR.
Preference switch’s On/Off edge cases
Switch is ON
in the GET /api/notifications/configurations API’s response, following should be true:
data > discussion > enabled == true
data > discussion > notification_types > core > push == true
Switch is OFF
app hasn’t requested notifications permission from the user
app hasn’t been granted notifications permission from the user
the GET /api/notifications/configurations has failed for some reason
in the GET /api/notifications/configurations API’s response, any of the following is false:
data > discussion > enabled
data > discussion > notification_types > core > push
User’s interaction with the switch
The switch is OFF and the user tries to turn it ON, here’s what we’d need to do incase of:
Show an info popup to guide user into giving the notification permission and why it’s needed with 2 CTAs:
Cancel: dismiss the popup
Continue: send a system request for the OS to allow / decline notifications for the app. If the user:
Declines: the switch stays OFF
Accepts: the switch changes to ON and we hit the POST API to let our server know
Given that user had previously declined the notifications permission, show the same info popup to guide user into giving the notification permission and why it’s needed with 2 CTAs:
Cancel: dismiss the popup
Continue: open the system’s Settings screen for our app where the user can update the notifications permission and comes back to app while turning/keeping the system’s switch to:
OFF: the switch stays OFF
ON: the switch changes to ON and we hit the POST API to let our server know
User has given the notifications permission and they try to turn the switch ON / OFF, we just hit the POST API and handle the API’s error cases as follows.
Error cases
Persist the state of the switch in shared preferences and initially load the switch according to it while hitting the GET API in the background upon whose response the state of the switch will be updated.
Incase the user tries to change the state of the switch while they’re offline or the GET API fails for some reason we need to:
return the switch back to its previous state
and show an error message in a snack bar