-
Notifications
You must be signed in to change notification settings - Fork 16
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
feat: Dates Tab integration with Calendar #347
feat: Dates Tab integration with Calendar #347
Conversation
Hey @shafqat-muneer, thanks, looks great! 🚀 RPReplay_Final1710750802.mp4 |
OpenEdX/Info.plist
Outdated
<key>NSCalendarsUsageDescription</key> | ||
<string>edX would like to use your calendar list to subscribe to your personalized edX calendar for this course.</string> | ||
<key>NSCalendarsFullAccessUsageDescription</key> | ||
<string>edX would like to use your calendar list to subscribe to your personalized edX calendar for this course.</string> |
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.
Could you please not hardcode the name of the edX app?
Ideally, we should use platformName
or something similar from the config.yaml
.
Hi @volodymyr-chekyrta, thanks for the review. |
Makes sense to me, thank you! 👍 |
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, some small changes
import Core | ||
import BranchSDK | ||
|
||
enum DeepLinkType: String { |
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.
@shafqat-muneer maybe we could re-use DeepLinkType
and DeepLinkKeys
defined in DeepLink
class to avoid duplication?
Thank you
courseID: courseID, | ||
title: calendarName, | ||
isOn: true, | ||
modalPresented: false) |
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.
Could you move the bracket to the next line to respect the "parameter on its own line" style?
@@ -41,7 +41,53 @@ public struct CourseDatesView: View { | |||
} | |||
|
|||
if viewModel.dueDatesShifted { | |||
DatesShiftedSuccessView(selectedTab: .dates, courseDatesViewModel: viewModel) | |||
DatesSuccessView(title: CourseLocalization.CourseDates.toastSuccessTitle, |
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.
"parameter on its own line" style please
CoreAssets.syncToCalendar.swiftUIImage | ||
Toggle( | ||
CourseLocalization.CourseDates.syncToCalendar, | ||
isOn: $viewModel.isOn) |
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.
"parameter on its own line" style please
@@ -153,7 +153,10 @@ public struct CourseOutlineView: View { | |||
.accessibilityAction {} | |||
|
|||
if viewModel.dueDatesShifted && !isVideo { | |||
DatesShiftedSuccessView(selectedTab: .course, courseContainerViewModel: viewModel) { | |||
DatesSuccessView(title: CourseLocalization.CourseDates.toastSuccessTitle, |
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.
"parameter on its own line" style please
23b03dc
to
9ad0c82
Compare
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.
- On adding the second calendar the
syncing calendar
keeps on screen and never goes away. - On selecting
cancel
remove on remove calendar alert, the switch should turns back on.
DatesSuccessView( | ||
title: CourseLocalization.CourseDates.calendarEvents, | ||
message: CourseLocalization.CourseDates.calendarEventsAdded, | ||
selectedTab: .dates | ||
) { | ||
Task { | ||
await MainActor.run { | ||
viewModel.calendarEventsAdded = false | ||
} | ||
} | ||
} |
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 code is being shared between the following three conditions calendarEventsAdded
, calendarEventsRemoved
, and calendarEventsUpdated
. How about moving it to a function and use that. Even that func can be used for dueDatesShifted
with an additional param.
@Published var calendarEventsAdded: Bool = false | ||
@Published var calendarEventsRemoved: Bool = false | ||
@Published var calendarEventsUpdated: Bool = false |
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.
Instead of using a boolean for each condition, how about using an enum for these cases?
}, | ||
okTapped: { | ||
self.router.dismiss(animated: true) | ||
self.removeCourseCalendar { [weak self] success in |
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.
success is unused here, so it can be replaced with _.
positiveAction: CourseLocalization.CourseDates.calendarShiftPromptUpdateNow, | ||
onCloseTapped: { | ||
// Remove course calendar | ||
self.router.dismiss(animated: true) |
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.
How about using weak self in closures? if so please update it for all alert functions.
get { | ||
if let calendarEntry = calendarEntry, | ||
let localCalendar = localCalendar { | ||
if calendarEntry.identifier == localCalendar.calendarIdentifier { |
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.
Is it possible to move this if condition to where clause of if let
?
@saeedbashir I have made the recommended adjustments. Kindly review them. |
} else { | ||
if let localCalendar = localCalendar { |
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 else and il let can be merged like else if let
), | ||
positiveAction: CoreLocalization.Alert.accept, | ||
onCloseTapped: { [weak self] in | ||
guard let self else { return } |
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 seems strong reference if self
isn't required in this type of blocks because if the self will be nill, by using the optional self will not crash the app and following code will automatically be ignored.
@saeedbashir I have addressed requested changes. @volodymyr-chekyrta Please also review this pull request. Thank you. |
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 👍
Just one question
return DatesSuccessView( | ||
title: title, | ||
message: message, | ||
selectedTab: .dates | ||
) { | ||
Task { | ||
await MainActor.run { | ||
viewModel.eventState = CourseDatesViewModel.EventState.none | ||
} | ||
} | ||
} |
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.
Can it be simplified just to something like this?
return DatesSuccessView(
title: title,
message: message,
selectedTab: .dates
) {
viewModel.eventState = CourseDatesViewModel.EventState.none
}
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 a bit odd. We switch to a Task
only to switch back to the MainActor.
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.
@volodymyr-chekyrta Thank you for bringing that to my attention. I've streamlined the logic for simplification.
Explanation:
The DatesSuccessView
struct
was previously invoking action closures asynchronously on a background thread. Upon receiving the closure action, we had to switch back to the main thread to avoid warnings such as:
Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates.
I've refactored this logic so that the action closures in DatesSuccessView
are no longer asynchronous.
8363d7f
Jira Tickets:
Github Issues:
Demos
Light Mode: Sync and un-sync events in calendar application:
Simulator.Screen.Recording.-.iPhone.15.-.2024-03-15.at.12.42.44.mp4
Light Mode: Update out dated calendar:
Simulator.Screen.Recording.-.iPhone.15.-.2024-03-15.at.12.49.21.mp4
Light Mode: Deep Linking:
RPReplay_Final1710750802.mp4
Dark Mode: Sync and un-sync events in calendar application:
Simulator.Screen.Recording.-.iPhone.15.-.2024-03-15.at.12.43.27.mp4
Dark Mode: Update out dated calendar:
Simulator.Screen.Recording.-.iPhone.15.-.2024-03-15.at.12.50.38.mp4