Skip to content

Commit

Permalink
feat: Enable navigation from NotificationsInbox to Discussion
Browse files Browse the repository at this point in the history
- Allows users to move from the NotificationsInbox screen to the Discussion component

fix: LEARNER-10373
  • Loading branch information
omerhabib26 committed Jan 17, 2025
1 parent 5b7d1b8 commit 3b66cf5
Show file tree
Hide file tree
Showing 12 changed files with 168 additions and 17 deletions.
37 changes: 35 additions & 2 deletions app/src/main/java/org/openedx/app/AppRouter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -336,21 +336,54 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di
topicId: String,
title: String,
viewType: FragmentViewType,
) {
navigateToDiscussionThread(fm, action, courseId, topicId, "", "", "", title, viewType)
}

override fun navigateToDiscussionThread(
fm: FragmentManager,
action: String,
courseId: String,
topicId: String,
threadId: String,
responseId: String,
commentId: String,
title: String,
viewType: FragmentViewType,
) {
replaceFragmentWithBackStack(
fm,
DiscussionThreadsFragment.newInstance(action, courseId, topicId, title, viewType.name)
DiscussionThreadsFragment.newInstance(
action,
courseId,
topicId,
threadId,
responseId,
commentId,
title,
viewType.name
)
)
}

override fun navigateToDiscussionComments(
fm: FragmentManager,
courseId: String,
thread: Thread,
) {
navigateToDiscussionComments(fm, courseId, thread, "", "")
}

override fun navigateToDiscussionComments(
fm: FragmentManager,
courseId: String,
thread: Thread,
responseId: String,
commentId: String,
) {
replaceFragmentWithBackStack(
fm,
DiscussionCommentsFragment.newInstance(courseId, thread)
DiscussionCommentsFragment.newInstance(courseId, thread, responseId, commentId)
)
}

Expand Down
4 changes: 3 additions & 1 deletion app/src/main/java/org/openedx/app/di/ScreenModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -434,10 +434,12 @@ val screenModule = module {
get(),
)
}
viewModel { (courseId: String, thread: Thread) ->
viewModel { (courseId: String, thread: Thread, responseId: String, commentId: String) ->
DiscussionCommentsViewModel(
courseId,
thread,
responseId,
commentId,
get(),
get(),
get(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,8 @@ class CourseUnitContainerAdapter(
DiscussionTopicsViewModel.TOPIC,
viewModel.courseId,
block.studentViewData?.topicId ?: "",
"",
"",
block.displayName,
FragmentViewType.MAIN_CONTENT.name,
block.id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,14 @@ interface DiscussionRouter {
thread: Thread,
)

fun navigateToDiscussionComments(
fm: FragmentManager,
courseId: String,
thread: Thread,
responseId: String,
commentId: String,
)

fun navigateToDiscussionResponses(
fm: FragmentManager,
courseId: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,8 @@ class DiscussionCommentsFragment : Fragment() {
private val viewModel by viewModel<DiscussionCommentsViewModel> {
parametersOf(
requireArguments().getString(ARG_COURSE_ID, ""),
requireArguments().parcelable(ARG_THREAD)!!
requireArguments().parcelable(ARG_THREAD)!!,
requireArguments().getString(ARG_RESPONSE_ID, ""),
)
}
private val router by inject<DiscussionRouter>()
Expand Down Expand Up @@ -136,6 +137,8 @@ class DiscussionCommentsFragment : Fragment() {
canLoadMore = canLoadMore,
scrollToBottom = scrollToBottom,
refreshing = refreshing,
responseId = viewModel.responseId,
commentId = viewModel.commentId,
onSwipeRefresh = {
viewModel.updateThreadComments()
},
Expand Down Expand Up @@ -181,6 +184,8 @@ class DiscussionCommentsFragment : Fragment() {
)
}
}
requireArguments().putString(ARG_RESPONSE_ID, "")
requireArguments().putString(ARG_COMMENT_ID, "")
}

companion object {
Expand All @@ -192,15 +197,21 @@ class DiscussionCommentsFragment : Fragment() {

private const val ARG_COURSE_ID = "argCourseId"
private const val ARG_THREAD = "argThread"
private const val ARG_RESPONSE_ID = "argResponseId"
private const val ARG_COMMENT_ID = "argCommentId"

fun newInstance(
courseId: String,
thread: Thread,
responseId: String,
commentId: String,
): DiscussionCommentsFragment {
val fragment = DiscussionCommentsFragment()
fragment.arguments = bundleOf(
ARG_COURSE_ID to courseId,
ARG_THREAD to thread
ARG_THREAD to thread,
ARG_RESPONSE_ID to responseId,
ARG_COMMENT_ID to commentId,
)
return fragment
}
Expand All @@ -218,13 +229,15 @@ private fun DiscussionCommentsScreen(
canLoadMore: Boolean,
scrollToBottom: Boolean,
refreshing: Boolean,
responseId: String,
commentId: String,
onSwipeRefresh: () -> Unit,
paginationCallBack: () -> Unit,
onItemClick: (String, String, Boolean) -> Unit,
onCommentClick: (DiscussionComment) -> Unit,
onAddResponseClick: (String) -> Unit,
onBackClick: () -> Unit,
onUserPhotoClick: (String) -> Unit
onUserPhotoClick: (String) -> Unit,
) {
val scaffoldState = rememberScaffoldState()
val scrollState = rememberLazyListState()
Expand All @@ -238,6 +251,10 @@ private fun DiscussionCommentsScreen(
mutableStateOf("")
}

var fromNotificationNavigation by rememberSaveable {
mutableStateOf(responseId.isNotEmpty() && commentId.isNotEmpty())
}

val sendButtonAlpha = if (responseValue.isEmpty()) 0.3f else 1f

Scaffold(
Expand Down Expand Up @@ -379,6 +396,10 @@ private fun DiscussionCommentsScreen(
onUserPhotoClick = {
onUserPhotoClick(comment.author)
})
if (fromNotificationNavigation && commentId.isNotEmpty() && responseId == comment.id) {
onCommentClick(comment)
fromNotificationNavigation = false
}
}
item {
if (canLoadMore) {
Expand Down Expand Up @@ -514,7 +535,9 @@ private fun DiscussionCommentsScreenPreview() {
scrollToBottom = false,
refreshing = false,
onSwipeRefresh = {},
onUserPhotoClick = {}
onUserPhotoClick = {},
responseId = "",
commentId = "",
)
}
}
Expand Down Expand Up @@ -545,7 +568,9 @@ private fun DiscussionCommentsScreenTabletPreview() {
scrollToBottom = false,
refreshing = false,
onSwipeRefresh = {},
onUserPhotoClick = {}
onUserPhotoClick = {},
responseId = "",
commentId = "",
)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ import org.openedx.discussion.system.notifier.DiscussionThreadDataChanged
class DiscussionCommentsViewModel(
val courseId: String,
thread: Thread,
val responseId: String,
val commentId: String,
private val interactor: DiscussionInteractor,
private val resourceManager: ResourceManager,
private val notifier: DiscussionNotifier,
Expand Down Expand Up @@ -126,6 +128,17 @@ class DiscussionCommentsViewModel(
}
commentCount = response.pagination.count
comments.addAll(response.results)
if (responseId.isNotEmpty()) {
if(comments.find { it.id == responseId } == null) {
val comment = interactor.getResponse(responseId)
comments.add(0, comment)
commentCount.inc()
}else{
val comment = comments.find { it.id == responseId }
comments.remove(comment)
comments.add(0, comment!!)
}
}
_uiState.value =
DiscussionCommentsUIState.Success(thread, comments.toList(), commentCount)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ class DiscussionThreadsFragment : Fragment() {
savedInstanceState: Bundle?
) = ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
val threadId = requireArguments().getString(ARG_THREAD_ID, "")
val responseId = requireArguments().getString(ARG_RESPONSE_ID, "")
val commentId = requireArguments().getString(ARG_COMMENT_ID, "")
setContent {
OpenEdXTheme {
val windowSize = rememberWindowSize()
Expand All @@ -138,6 +141,7 @@ class DiscussionThreadsFragment : Fragment() {
DiscussionThreadsScreen(
windowSize = windowSize,
title = requireArguments().getString(ARG_TITLE, ""),
threadId = threadId,
uiState = uiState,
uiMessage = uiMessage,
canLoadMore = canLoadMore,
Expand All @@ -156,7 +160,9 @@ class DiscussionThreadsFragment : Fragment() {
router.navigateToDiscussionComments(
requireActivity().supportFragmentManager,
viewModel.courseId,
it
it,
responseId,
commentId,
)
},
onCreatePostClick = {
Expand All @@ -176,29 +182,41 @@ class DiscussionThreadsFragment : Fragment() {
)
}
}
requireArguments().putString(ARG_THREAD_ID, "")
requireArguments().putString(ARG_RESPONSE_ID, "")
requireArguments().putString(ARG_COMMENT_ID, "")
}

companion object {
private const val ARG_THREAD_TYPE = "threadType"
private const val ARG_COURSE_ID = "courseId"
private const val ARG_BLOCK_ID = "blockId"
private const val ARG_TOPIC_ID = "topicId"
private const val ARG_THREAD_ID = "threadId"
private const val ARG_RESPONSE_ID = "responseId"
private const val ARG_COMMENT_ID = "commentId"
private const val ARG_TITLE = "title"
private const val ARG_FRAGMENT_VIEW_TYPE = "fragmentViewType"

fun newInstance(
threadType: String,
courseId: String,
topicId: String,
threadId: String,
responseId: String,
commentId: String,
title: String,
viewType: String,
blockId: String = ""
blockId: String = "",
): DiscussionThreadsFragment {
val fragment = DiscussionThreadsFragment()
fragment.arguments = bundleOf(
ARG_THREAD_TYPE to threadType,
ARG_COURSE_ID to courseId,
ARG_TOPIC_ID to topicId,
ARG_THREAD_ID to threadId,
ARG_RESPONSE_ID to responseId,
ARG_COMMENT_ID to commentId,
ARG_TITLE to title,
ARG_FRAGMENT_VIEW_TYPE to viewType,
ARG_BLOCK_ID to blockId
Expand All @@ -213,6 +231,7 @@ class DiscussionThreadsFragment : Fragment() {
private fun DiscussionThreadsScreen(
windowSize: WindowSize,
title: String,
threadId: String = "",
uiState: DiscussionThreadsUIState,
uiMessage: UIMessage?,
canLoadMore: Boolean,
Expand All @@ -224,7 +243,7 @@ private fun DiscussionThreadsScreen(
onItemClick: (org.openedx.discussion.domain.model.Thread) -> Unit,
onCreatePostClick: () -> Unit,
paginationCallback: () -> Unit,
onBackClick: () -> Unit
onBackClick: () -> Unit,
) {

val scaffoldState = rememberScaffoldState()
Expand Down Expand Up @@ -270,6 +289,10 @@ private fun DiscussionThreadsScreen(

val isImeVisible by isImeVisibleState()

var fromNotificationNavigation by rememberSaveable {
mutableStateOf(threadId.isNotEmpty())
}

val scaffoldModifier = if (viewType == FragmentViewType.FULL_CONTENT) {
Modifier
.fillMaxSize()
Expand Down Expand Up @@ -563,6 +586,14 @@ private fun DiscussionThreadsScreen(
) {
paginationCallback()
}
if (fromNotificationNavigation && threadId.isNotEmpty() && uiState.data.isNotEmpty()) {
val index =
uiState.data.indexOfFirst { it.id == threadId }
if (index != -1) {
onItemClick(uiState.data[index])
}
fromNotificationNavigation = false
}
}
} else {
val noDiscussionsScrollState = rememberScrollState()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ data class NotificationItem(
@SerializedName("content_context") val contentContext: NotificationContent,
@SerializedName("content") val content: String,
@SerializedName("content_url") val contentUrl: String,
@SerializedName("course_id") val courseId: String?,
@SerializedName("last_read") val lastRead: String?,
@SerializedName("last_seen") val lastSeen: String?,
@SerializedName("created") val created: String,
Expand All @@ -76,6 +77,7 @@ data class NotificationItem(
contentContext = contentContext.mapToDomain(),
content = content,
contentUrl = contentUrl,
courseId = courseId.orEmpty(),
lastRead = TimeUtils.iso8601ToDate(lastRead ?: ""),
lastSeen = TimeUtils.iso8601ToDate(lastSeen ?: ""),
created = TimeUtils.iso8601ToDate(created),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ data class NotificationItem(
val contentContext: NotificationContent,
val content: String,
val contentUrl: String,
val courseId: String,
val lastRead: Date?,
val lastSeen: Date?,
val created: Date?,
Expand All @@ -46,4 +47,8 @@ data class NotificationContent(
val emailContent: String,
val authorName: String,
val authorPronoun: String,
)
){
val responseId = parentId.ifEmpty { commentId }

val responseCommentId = if(responseId == commentId) "" else commentId
}
Loading

0 comments on commit 3b66cf5

Please sign in to comment.