Skip to content
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

Merged
merged 14 commits into from
Jan 14, 2025

Conversation

saeedbashir
Copy link

@saeedbashir saeedbashir commented Jan 1, 2025

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

  • Notifications permission has been given to the app by the user &&

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:

  1. Fresh start

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

  1. Normal start
    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

  1. General flow
    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

@@ -86,6 +86,9 @@ public protocol BaseRouter {

@MainActor
func hideRestoreProgressView()

@MainActor
func performNotificationRegistration()
Copy link

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?

Copy link
Author

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.

Copy link

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?

Copy link
Author

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()
Copy link

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.

Copy link
Author

@saeedbashir saeedbashir Jan 2, 2025

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.

Core/Core/Data/CoreStorage.swift Outdated Show resolved Hide resolved
}

@MainActor
public func toggleNotificationsPermissionAction() async {
Copy link

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.

Copy link
Author

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.

Copy link

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.

Copy link
Author

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.

@saeedbashir saeedbashir requested a review from mta452 January 3, 2025 04:44
Comment on lines 66 to 78
.simultaneousGesture(
TapGesture().onEnded {
Task {
await viewModel.toggleNotificationsPermissionAction()
}
}
)
.simultaneousGesture(
DragGesture(minimumDistance: 20, coordinateSpace: .local).onEnded { _ in
Task {
await viewModel.toggleNotificationsPermissionAction()
}
})

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.

OpenEdX/Data/AppStorage.swift Outdated Show resolved Hide resolved
@shafqat-muneer
Copy link

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.

@saeedbashir
Copy link
Author

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.

@rnr
Copy link
Collaborator

rnr commented Jan 3, 2025

Screen.Recording.2025-01-03.at.14.43.43.mov

First run, user goes to Settings and tap on some preference Toggle

  1. Do we need to show alert which says "You need to allow notifications in settings" (which means you will redirect to the Settings app) and second immediately after this with request permissions? Why just not request permissions?
  2. Why after user allowed notifications Toggle is still opted off? If user tapped this and gave permissions the user expects it will be opted on, right?

@saeedbashir WDYT?

@saeedbashir
Copy link
Author

  • Do we need to show alert which says "You need to allow notifications in settings" (which means you will redirect to the Settings app) and second immediately after this with request permissions? Why just not request permissions?
  • Why after user allowed notifications Toggle is still opted off? If user tapped this and gave permissions the user expects it will be opted on, right?

Yes after giving the permission, the switch should turn on automatically. Let me check why it's not turning on.

@rnr
Copy link
Collaborator

rnr commented Jan 3, 2025

@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)?

@rnr
Copy link
Collaborator

rnr commented Jan 3, 2025

@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?
Maybe it would be better to show some indicator in the push notification settings, for example: Push notifications are not allowed in the Settings app - please allow to use this feature.

@saeedbashir
Copy link
Author

@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)?

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.

@saeedbashir
Copy link
Author

  • Do we need to show alert which says "You need to allow notifications in settings" (which means you will redirect to the Settings app) and second immediately after this with request permissions? Why just not request permissions?
  • Why after user allowed notifications Toggle is still opted off? If user tapped this and gave permissions the user expects it will be opted on, right?

Yes after giving the permission, the switch should turn on automatically. Let me check why it's not turning on.

@rnr Change is pushed and ready to review.

@rnr
Copy link
Collaborator

rnr commented Jan 3, 2025

@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)?

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.

Yes, I realise that the user will not receive push notifications without permissions.
I mean it's weird to show all preferences disabled, but actually have them enabled. Is this a product/design decision @moiz994 @touchapp ?
If we want to restrict the user from viewing/editing push notification preferences on a device without push enabled, perhaps we should check permissions one level higher and not allow the user to open the push notification settings View without permissions at all?

@saeedbashir
Copy link
Author

@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)?

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.

Yes, I realise that the user will not receive push notifications without permissions. I mean it's weird to show all preferences disabled, but actually have them enabled. Is this a product/design decision @moiz994 @touchapp ? If we want to restrict the user from viewing/editing push notification preferences on a device without push enabled, perhaps we should check permissions one level higher and not allow the user to open the push notification settings View without permissions at all?

We don't have such a design at the moment; we might cater / consider it in the 2nd phase of push notifications.

@rnr
Copy link
Collaborator

rnr commented Jan 3, 2025

@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)?

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.

Yes, I realise that the user will not receive push notifications without permissions. I mean it's weird to show all preferences disabled, but actually have them enabled. Is this a product/design decision @moiz994 @touchapp ? If we want to restrict the user from viewing/editing push notification preferences on a device without push enabled, perhaps we should check permissions one level higher and not allow the user to open the push notification settings View without permissions at all?

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)?

@saeedbashir
Copy link
Author

@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)?

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.

Yes, I realise that the user will not receive push notifications without permissions. I mean it's weird to show all preferences disabled, but actually have them enabled. Is this a product/design decision @moiz994 @touchapp ? If we want to restrict the user from viewing/editing push notification preferences on a device without push enabled, perhaps we should check permissions one level higher and not allow the user to open the push notification settings View without permissions at all?

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.

@rnr
Copy link
Collaborator

rnr commented Jan 6, 2025

On the iPad, the notification icon in the Learn view looks displaced

Learn Profile

@rnr
Copy link
Collaborator

rnr commented Jan 6, 2025

UI bug for Notifications Settings View on iPad

@mta452
Copy link

mta452 commented Jan 10, 2025

On the iPad, the notification icon in the Learn view looks displaced

Learn Profile

This needs to handled as a separate task.

CC: @moiz994 @miankhalid

@mta452 mta452 requested review from rnr and shafqat-muneer and removed request for mta452 January 13, 2025 09:00
@rnr
Copy link
Collaborator

rnr commented Jan 13, 2025

@mta452
Do we have Figma design for Settings page? Asking because I see the difference between these Push Settings and Video Settings for example
Screenshot 2025-01-13 at 13 01 15

@moiz994
Copy link

moiz994 commented Jan 13, 2025

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.

@mta452
Copy link

mta452 commented Jan 14, 2025

I have updated the design.

iPhone iPad
Simulator Screenshot - iPhone 16 Pro - 2025-01-14 at 12 50 48 Simulator Screenshot - iPad Pro 11-inch (M4) - 2025-01-14 at 13 49 58

Copy link
Collaborator

@rnr rnr left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link

@shafqat-muneer shafqat-muneer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM 👍

@mta452 mta452 merged commit 57bf369 into 2U/develop Jan 14, 2025
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants