Skip to content

Commit

Permalink
feat: Add hyperlink for assessments in Dates Tab (openedx#137)
Browse files Browse the repository at this point in the history
* feat: Add hyperlink for assessments in Dates Tab

- Update CourseDateBlock Model
- Add Underline text decorations for clickable text
- Navigate to Component Screen on tapping hyperlinks
- Maintain stack of navigation
fix: LEARNER-9696

* fix: resolve conflicts

* fix: remove unnecessary code from domain model

* fix: Address PR comments - 2
  • Loading branch information
omerhabib26 authored and k1rill committed Dec 4, 2023
1 parent 7bae109 commit 01b5960
Show file tree
Hide file tree
Showing 9 changed files with 129 additions and 39 deletions.
28 changes: 20 additions & 8 deletions app/src/main/java/org/openedx/app/AppRouter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -105,7 +105,10 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di
coursewareAccess: CoursewareAccess,
auditAccessExpires: Date?
) {
replaceFragment(fm, NoAccessCourseContainerFragment.newInstance(title,coursewareAccess, auditAccessExpires))
replaceFragment(
fm,
NoAccessCourseContainerFragment.newInstance(title, coursewareAccess, auditAccessExpires)
)
}
//endregion

Expand All @@ -116,36 +119,35 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di
courseId: String,
blockId: String,
mode: CourseViewMode,
descendantId: String?
) {
replaceFragmentWithBackStack(
fm,
CourseSectionFragment.newInstance(courseId, blockId, mode)
CourseSectionFragment.newInstance(courseId, blockId, mode, descendantId)
)
}

override fun navigateToCourseContainer(
fm: FragmentManager,
blockId: String,
courseId: String,
courseName: String,
mode: CourseViewMode
) {
replaceFragmentWithBackStack(
fm,
CourseUnitContainerFragment.newInstance(blockId, courseId, courseName, mode)
CourseUnitContainerFragment.newInstance(blockId, courseId, mode)
)
}

override fun replaceCourseContainer(
fm: FragmentManager,
blockId: String,
courseId: String,
courseName: String,
mode: CourseViewMode
) {
replaceFragment(
fm,
CourseUnitContainerFragment.newInstance(blockId, courseId, courseName, mode),
CourseUnitContainerFragment.newInstance(blockId, courseId, mode),
FragmentTransaction.TRANSIT_FRAGMENT_FADE
)
}
Expand Down Expand Up @@ -174,7 +176,13 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di
) {
replaceFragmentWithBackStack(
fm,
YoutubeVideoFullScreenFragment.newInstance(videoUrl, videoTime, blockId, courseId, isPlaying)
YoutubeVideoFullScreenFragment.newInstance(
videoUrl,
videoTime,
blockId,
courseId,
isPlaying
)
)
}

Expand Down Expand Up @@ -289,7 +297,11 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di
.commit()
}

private fun replaceFragment(fm: FragmentManager, fragment: Fragment, transaction: Int = FragmentTransaction.TRANSIT_NONE) {
private fun replaceFragment(
fm: FragmentManager,
fragment: Fragment,
transaction: Int = FragmentTransaction.TRANSIT_NONE
) {
fm.beginTransaction()
.setTransition(transaction)
.replace(R.id.container, fragment, fragment.javaClass.simpleName)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ data class CourseDates(
complete = item.complete,
learnerHasAccess = item.learnerHasAccess,
dateType = item.dateType,
dateBlockBadge = CourseDatesBadge.BLANK
dateBlockBadge = CourseDatesBadge.BLANK,
assignmentType = item.assignmentType
)
if (courseDates.containsKey(key)) {
(courseDates[key] as ArrayList).add(dateBlock)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ data class CourseDateBlock(
val complete: Boolean = false,
val date: Date?,
val dateType: DateType = DateType.NONE,
val assignmentType: String? = "",
var dateBlockBadge: CourseDatesBadge = CourseDatesBadge.BLANK,
) {
companion object {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package org.openedx.core.domain.model

import java.util.*
import org.openedx.core.BlockType
import java.util.Date

data class CourseStructure(
val root: String,
Expand All @@ -17,4 +18,12 @@ data class CourseStructure(
val media: Media?,
val certificate: Certificate?,
val isSelfPaced: Boolean
)
) {
fun getVerticalBlocks(): List<Block> {
return blockData.filter { it.type == BlockType.VERTICAL }
}

fun getSequentialBlocks(): List<Block> {
return blockData.filter { it.type == BlockType.SEQUENTIAL }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,20 @@ interface CourseRouter {
courseId: String,
blockId: String,
mode: CourseViewMode,
descendantId: String? = ""
)

fun navigateToCourseContainer(
fm: FragmentManager,
blockId: String,
courseId: String,
courseName: String,
mode: CourseViewMode
)

fun replaceCourseContainer(
fm: FragmentManager,
blockId: String,
courseId: String,
courseName: String,
mode: CourseViewMode
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.IntrinsicSize
Expand Down Expand Up @@ -61,6 +62,7 @@ import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.tooling.preview.Devices
Expand All @@ -75,11 +77,13 @@ import androidx.fragment.app.Fragment
import me.saket.extendedspans.ExtendedSpans
import me.saket.extendedspans.RoundedCornerSpanPainter
import me.saket.extendedspans.drawBehind
import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.koin.core.parameter.parametersOf
import org.openedx.core.UIMessage
import org.openedx.core.domain.model.CourseDateBlock
import org.openedx.core.presentation.course.CourseDatesBadge
import org.openedx.core.presentation.course.CourseViewMode
import org.openedx.core.ui.BackBtn
import org.openedx.core.ui.HandleUIMessage
import org.openedx.core.ui.OfflineModeDialog
Expand All @@ -95,13 +99,15 @@ import org.openedx.core.ui.theme.appTypography
import org.openedx.core.ui.windowSizeValue
import org.openedx.core.utils.TimeUtils
import org.openedx.course.R
import org.openedx.course.presentation.CourseRouter
import java.util.Date

class CourseDatesFragment : Fragment() {

private val viewModel by viewModel<CourseDatesViewModel> {
parametersOf(requireArguments().getString(ARG_COURSE_ID, ""))
}
private val router by inject<CourseRouter>()

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Expand Down Expand Up @@ -136,6 +142,22 @@ class CourseDatesFragment : Fragment() {
onSwipeRefresh = {
viewModel.getCourseDates()
},
onItemClick = { blockId ->
if (blockId.isNotEmpty()) {
viewModel.getVerticalBlock(blockId)?.let { verticalBlock ->
viewModel.getSequentialBlock(verticalBlock.id)
?.let { sequentialBlock ->
router.navigateToCourseSubsections(
requireActivity().supportFragmentManager,
blockId = sequentialBlock.id,
courseId = viewModel.courseId,
mode = CourseViewMode.FULL,
descendantId = verticalBlock.id
)
}
}
}
},
onBackClick = {
requireActivity().supportFragmentManager.popBackStack()
})
Expand Down Expand Up @@ -165,6 +187,7 @@ internal fun CourseDatesScreen(
hasInternetConnection: Boolean,
onReloadClick: () -> Unit,
onSwipeRefresh: () -> Unit,
onItemClick: (String) -> Unit,
onBackClick: () -> Unit
) {
val scaffoldState = rememberScaffoldState()
Expand Down Expand Up @@ -261,7 +284,8 @@ internal fun CourseDatesScreen(
itemsIndexed(uiState.courseDates.keys.toList()) { dateIndex, _ ->
CourseDateBlockSection(
courseDates = uiState.courseDates,
dateIndex = dateIndex
dateIndex = dateIndex,
onItemClick = onItemClick
)
}
}
Expand Down Expand Up @@ -308,7 +332,9 @@ internal fun CourseDatesScreen(

@Composable
private fun CourseDateBlockSection(
courseDates: LinkedHashMap<String, ArrayList<CourseDateBlock>>, dateIndex: Int
courseDates: LinkedHashMap<String, ArrayList<CourseDateBlock>>,
dateIndex: Int,
onItemClick: (String) -> Unit
) {
Row(
modifier = Modifier
Expand All @@ -326,7 +352,7 @@ private fun CourseDateBlockSection(
isLastIndex = dateIndex == courseDates.size - 1,
dateBlock = dateBlockItem
)
DateBlock(dateBlocks)
DateBlock(dateBlocks, onItemClick)
}
}
}
Expand Down Expand Up @@ -408,7 +434,7 @@ private fun DateBullet(
}

@Composable
private fun DateBlock(dateBlocks: ArrayList<CourseDateBlock>) {
private fun DateBlock(dateBlocks: ArrayList<CourseDateBlock>, onItemClick: (String) -> Unit) {
Column(
modifier = Modifier
.wrapContentHeight()
Expand All @@ -429,7 +455,7 @@ private fun DateBlock(dateBlocks: ArrayList<CourseDateBlock>) {
) {
val parentBadgeAdded = hasSameDateTypes(dateBlocks)
dateBlocks.forEach { courseDateItem ->
CourseDateItem(courseDateItem, parentBadgeAdded)
CourseDateItem(courseDateItem, parentBadgeAdded, onItemClick)
}
}
}
Expand Down Expand Up @@ -544,7 +570,11 @@ private fun PlaceDateBadge(title: String, titleSize: TextUnit, blockBadge: Cours
}

@Composable
private fun CourseDateItem(courseDateItem: CourseDateBlock, parentBadgeAdded: Boolean) {
private fun CourseDateItem(
courseDateItem: CourseDateBlock,
parentBadgeAdded: Boolean,
onItemClick: (String) -> Unit
) {
Column(
modifier = Modifier
.wrapContentHeight()
Expand All @@ -556,10 +586,14 @@ private fun CourseDateItem(courseDateItem: CourseDateBlock, parentBadgeAdded: Bo
PlaceDateBadge(courseDateItem.title, 16.sp, courseDateItem.dateBlockBadge)
} else {
Text(
modifier = Modifier.clickable {
onItemClick(courseDateItem.blockId)
},
text = courseDateItem.title,
fontSize = 16.sp,
fontWeight = FontWeight.SemiBold,
lineHeight = 20.sp
lineHeight = 20.sp,
textDecoration = if (courseDateItem.blockId.isNotEmpty()) TextDecoration.Underline else TextDecoration.None
)
}
if (!TextUtils.isEmpty(courseDateItem.description)) {
Expand Down Expand Up @@ -603,6 +637,7 @@ private fun CourseDatesScreenPreview() {
refreshing = false,
onSwipeRefresh = {},
onReloadClick = {},
onItemClick = {},
onBackClick = {})
}
}
Expand All @@ -620,6 +655,7 @@ private fun CourseDatesScreenTabletPreview() {
refreshing = false,
onSwipeRefresh = {},
onReloadClick = {},
onItemClick = {},
onBackClick = {})
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import org.openedx.core.BaseViewModel
import org.openedx.core.R
import org.openedx.core.SingleEventLiveData
import org.openedx.core.UIMessage
import org.openedx.core.domain.model.Block
import org.openedx.core.extension.isInternetError
import org.openedx.core.system.ResourceManager
import org.openedx.core.system.connection.NetworkConnection
Expand Down Expand Up @@ -68,4 +69,22 @@ class CourseDatesViewModel(
_updating.value = false
}
}

fun getVerticalBlock(blockId: String): Block? {
return try {
val courseStructure = interactor.getCourseStructureFromCache()
courseStructure.getVerticalBlocks().find { it.descendants.contains(blockId) }
} catch (e: Exception) {
null
}
}

fun getSequentialBlock(blockId: String): Block? {
return try {
val courseStructure = interactor.getCourseStructureFromCache()
courseStructure.getSequentialBlocks().find { it.descendants.contains(blockId) }
} catch (e: Exception) {
null
}
}
}
Loading

0 comments on commit 01b5960

Please sign in to comment.