Skip to content

Commit

Permalink
feat: NoAvailableUnitFragment
Browse files Browse the repository at this point in the history
  • Loading branch information
PavloNetrebchuk committed Jun 24, 2024
1 parent 7de4862 commit 27069f7
Show file tree
Hide file tree
Showing 6 changed files with 174 additions and 101 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ fun CourseVideosScreen(
fragmentManager,
courseId = viewModel.courseId,
unitId = unit.id,
mode = CourseViewMode.FULL
mode = CourseViewMode.VIDEOS
)
}
} else {
Expand All @@ -121,7 +121,7 @@ fun CourseVideosScreen(
fm = fragmentManager,
courseId = viewModel.courseId,
subSectionId = subSectionBlock.id,
mode = CourseViewMode.FULL
mode = CourseViewMode.VIDEOS
)
}
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,25 @@ package org.openedx.course.presentation.unit
import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.compose.foundation.layout.*
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.material.*
import androidx.compose.material.Button
import androidx.compose.material.ButtonDefaults
import androidx.compose.material.Icon
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.Text
import androidx.compose.material.rememberScaffoldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
Expand All @@ -22,6 +37,7 @@ import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import org.openedx.core.extension.parcelable
import org.openedx.core.ui.WindowSize
import org.openedx.core.ui.rememberWindowSize
import org.openedx.core.ui.theme.OpenEdXTheme
Expand All @@ -31,7 +47,7 @@ import org.openedx.core.ui.theme.appTypography
import org.openedx.core.ui.windowSizeValue
import org.openedx.course.R as courseR

class NotSupportedUnitFragment : Fragment() {
class NotAvailableUnitFragment : Fragment() {

private var blockId: String? = null

Expand All @@ -49,9 +65,40 @@ class NotSupportedUnitFragment : Fragment() {
setContent {
OpenEdXTheme {
val windowSize = rememberWindowSize()
NotSupportedUnitScreen(
val uriHandler = LocalUriHandler.current
val uri = requireArguments().getString(ARG_BLOCK_URL, "")
val title: String
val description: String
var buttonAction: (() -> Unit)? = null
when (requireArguments().parcelable<NotAvailableUnitType>(ARG_UNIT_TYPE)) {
NotAvailableUnitType.MOBILE_UNSUPPORTED -> {
title = stringResource(id = courseR.string.course_this_interactive_component)
description = stringResource(id = courseR.string.course_explore_other_parts_on_web)
buttonAction = {
uriHandler.openUri(uri)
}
}

NotAvailableUnitType.OFFLINE_UNSUPPORTED -> {
title = stringResource(id = courseR.string.course_not_available_offline)
description = stringResource(id = courseR.string.course_explore_other_parts_when_reconnect)
}

NotAvailableUnitType.NOT_DOWNLOADED -> {
title = stringResource(id = courseR.string.course_not_downloaded)
description =
stringResource(id = courseR.string.course_explore_other_parts_when_reconnect_or_download)
}

else -> {
return@OpenEdXTheme
}
}
NotAvailableUnitScreen(
windowSize = windowSize,
uri = requireArguments().getString(ARG_BLOCK_URL, "")
title = title,
description = description,
buttonAction = buttonAction
)
}
}
Expand All @@ -60,14 +107,17 @@ class NotSupportedUnitFragment : Fragment() {
companion object {
private const val ARG_BLOCK_ID = "blockId"
private const val ARG_BLOCK_URL = "blockUrl"
private const val ARG_UNIT_TYPE = "notAvailableUnitType"
fun newInstance(
blockId: String,
blockUrl: String
): NotSupportedUnitFragment {
val fragment = NotSupportedUnitFragment()
blockUrl: String,
unitType: NotAvailableUnitType,
): NotAvailableUnitFragment {
val fragment = NotAvailableUnitFragment()
fragment.arguments = bundleOf(
ARG_BLOCK_ID to blockId,
ARG_BLOCK_URL to blockUrl
ARG_BLOCK_URL to blockUrl,
ARG_UNIT_TYPE to unitType
)
return fragment
}
Expand All @@ -76,12 +126,13 @@ class NotSupportedUnitFragment : Fragment() {
}

@Composable
private fun NotSupportedUnitScreen(
private fun NotAvailableUnitScreen(
windowSize: WindowSize,
uri: String
title: String,
description: String,
buttonAction: (() -> Unit)? = null,
) {
val scaffoldState = rememberScaffoldState()
val uriHandler = LocalUriHandler.current
val scrollState = rememberScrollState()
Scaffold(
modifier = Modifier.fillMaxSize(),
Expand Down Expand Up @@ -120,37 +171,39 @@ private fun NotSupportedUnitScreen(
Spacer(Modifier.height(36.dp))
Text(
modifier = Modifier.fillMaxWidth(),
text = stringResource(id = courseR.string.course_this_interactive_component),
text = title,
style = MaterialTheme.appTypography.titleLarge,
color = MaterialTheme.appColors.textPrimary,
textAlign = TextAlign.Center
)
Spacer(Modifier.height(12.dp))
Text(
modifier = Modifier.fillMaxWidth(),
text = stringResource(id = courseR.string.course_explore_other_parts),
text = description,
style = MaterialTheme.appTypography.bodyLarge,
color = MaterialTheme.appColors.textPrimary,
textAlign = TextAlign.Center
)
Spacer(Modifier.height(40.dp))
Button(modifier = Modifier
.width(216.dp)
.height(42.dp),
shape = MaterialTheme.appShapes.buttonShape,
colors = ButtonDefaults.buttonColors(
backgroundColor = MaterialTheme.appColors.primaryButtonBackground
),
onClick = {
uriHandler.openUri(uri)
}) {
Text(
text = stringResource(id = courseR.string.course_open_in_browser),
color = MaterialTheme.appColors.primaryButtonText,
style = MaterialTheme.appTypography.labelLarge
)
if (buttonAction != null) {
Button(
modifier = Modifier
.width(216.dp)
.height(42.dp),
shape = MaterialTheme.appShapes.buttonShape,
colors = ButtonDefaults.buttonColors(
backgroundColor = MaterialTheme.appColors.primaryButtonBackground
),
onClick = buttonAction
) {
Text(
text = stringResource(id = courseR.string.course_open_in_browser),
color = MaterialTheme.appColors.primaryButtonText,
style = MaterialTheme.appTypography.labelLarge
)
}
Spacer(Modifier.height(20.dp))
}
Spacer(Modifier.height(20.dp))
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.openedx.course.presentation.unit

import android.os.Parcelable
import kotlinx.parcelize.Parcelize

@Parcelize
enum class NotAvailableUnitType : Parcelable {
MOBILE_UNSUPPORTED, OFFLINE_UNSUPPORTED, NOT_DOWNLOADED
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import androidx.fragment.app.Fragment
import androidx.viewpager2.adapter.FragmentStateAdapter
import org.openedx.core.FragmentViewType
import org.openedx.core.domain.model.Block
import org.openedx.course.presentation.unit.NotSupportedUnitFragment
import org.openedx.course.presentation.unit.NotAvailableUnitFragment
import org.openedx.course.presentation.unit.NotAvailableUnitType
import org.openedx.course.presentation.unit.html.HtmlUnitFragment
import org.openedx.course.presentation.unit.video.VideoUnitFragment
import org.openedx.course.presentation.unit.video.YoutubeVideoUnitFragment
Expand All @@ -23,73 +24,40 @@ class CourseUnitContainerAdapter(
override fun createFragment(position: Int): Fragment = unitBlockFragment(blocks[position])

private fun unitBlockFragment(block: Block): Fragment {
return when {
(block.isVideoBlock &&
(block.studentViewData?.encodedVideos?.hasVideoUrl == true ||
block.studentViewData?.encodedVideos?.hasYoutubeUrl == true)) -> {
val encodedVideos = block.studentViewData?.encodedVideos!!
val transcripts = block.studentViewData!!.transcripts
with(encodedVideos) {
var isDownloaded = false
val videoUrl = if (viewModel.getDownloadModelById(block.id) != null) {
isDownloaded = true
viewModel.getDownloadModelById(block.id)!!.path
} else videoUrl
if (videoUrl.isNotEmpty()) {
VideoUnitFragment.newInstance(
block.id,
viewModel.courseId,
videoUrl,
transcripts?.toMap() ?: emptyMap(),
block.displayName,
isDownloaded
)
} else {
YoutubeVideoUnitFragment.newInstance(
block.id,
viewModel.courseId,
encodedVideos.youtube?.url ?: "",
transcripts?.toMap() ?: emptyMap(),
block.displayName
)
}
}
val downloadedModel = viewModel.getDownloadModelById(block.id)
val offlineUrl = downloadedModel?.let { it.path + File.separator + "index.html" } ?: ""
val noNetwork = !viewModel.hasNetworkConnection

if (noNetwork) {
if (block.isDownloadable && offlineUrl.isEmpty()) {
return createNotAvailableUnitFragment(block, NotAvailableUnitType.NOT_DOWNLOADED)
}
if (!block.isDownloadable) {
return createNotAvailableUnitFragment(block, NotAvailableUnitType.OFFLINE_UNSUPPORTED)
}
}

(block.isDiscussionBlock && block.studentViewData?.topicId.isNullOrEmpty().not()) -> {
DiscussionThreadsFragment.newInstance(
DiscussionTopicsViewModel.TOPIC,
viewModel.courseId,
block.studentViewData?.topicId ?: "",
block.displayName,
FragmentViewType.MAIN_CONTENT.name,
block.id
)
when {
block.isVideoBlock && block.studentViewData?.encodedVideos?.run { hasVideoUrl || hasYoutubeUrl } == true -> {
return createVideoFragment(block)
}

block.studentViewMultiDevice.not() -> {
NotSupportedUnitFragment.newInstance(
block.id,
block.lmsWebUrl
)
block.isDiscussionBlock && !block.studentViewData?.topicId.isNullOrEmpty() -> {
return createDiscussionFragment(block)
}

block.isHTMLBlock ||
block.isProblemBlock ||
block.isOpenAssessmentBlock ||
block.isDragAndDropBlock ||
block.isWordCloudBlock ||
block.isLTIConsumerBlock ||
block.isSurveyBlock -> {
val downloadedModel = viewModel.getDownloadModelById(block.id)
val offlineUrl = downloadedModel?.let { it.path + File.separator + "index.html" } ?: ""
val lastModified: String =
if (downloadedModel != null && !viewModel.hasNetworkConnection) {
downloadedModel.lastModified ?: ""
} else {
""
}
HtmlUnitFragment.newInstance(
!block.studentViewMultiDevice -> {
return createNotAvailableUnitFragment(block, NotAvailableUnitType.MOBILE_UNSUPPORTED)
}

block.isHTMLBlock || block.isProblemBlock || block.isOpenAssessmentBlock || block.isDragAndDropBlock ||
block.isWordCloudBlock || block.isLTIConsumerBlock || block.isSurveyBlock -> {
val lastModified = if (downloadedModel != null && noNetwork) {
downloadedModel.lastModified ?: ""
} else {
""
}
return HtmlUnitFragment.newInstance(
block.id,
block.studentViewUrl,
viewModel.courseId,
Expand All @@ -99,11 +67,50 @@ class CourseUnitContainerAdapter(
}

else -> {
NotSupportedUnitFragment.newInstance(
block.id,
block.lmsWebUrl
)
return createNotAvailableUnitFragment(block, NotAvailableUnitType.MOBILE_UNSUPPORTED)
}
}
}

private fun createNotAvailableUnitFragment(block: Block, type: NotAvailableUnitType): Fragment {
return NotAvailableUnitFragment.newInstance(block.id, block.lmsWebUrl, type)
}

private fun createVideoFragment(block: Block): Fragment {
val encodedVideos = block.studentViewData!!.encodedVideos!!
val transcripts = block.studentViewData!!.transcripts ?: emptyMap()
val downloadedModel = viewModel.getDownloadModelById(block.id)
val isDownloaded = downloadedModel != null
val videoUrl = downloadedModel?.path ?: encodedVideos.videoUrl

return if (videoUrl.isNotEmpty()) {
VideoUnitFragment.newInstance(
block.id,
viewModel.courseId,
videoUrl,
transcripts,
block.displayName,
isDownloaded
)
} else {
YoutubeVideoUnitFragment.newInstance(
block.id,
viewModel.courseId,
encodedVideos.youtube?.url ?: "",
transcripts,
block.displayName
)
}
}

private fun createDiscussionFragment(block: Block): Fragment {
return DiscussionThreadsFragment.newInstance(
DiscussionTopicsViewModel.TOPIC,
viewModel.courseId,
block.studentViewData?.topicId ?: "",
block.displayName,
FragmentViewType.MAIN_CONTENT.name,
block.id
)
}
}
2 changes: 1 addition & 1 deletion course/src/main/res/values-uk/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
<string name="core_course_container_nav_more">Матеріали</string>
<string name="course_can_download_only_with_wifi">Ви можете завантажувати контент тільки через Wi-Fi</string>
<string name="course_this_interactive_component">Ця інтерактивна компонента ще не доступна</string>
<string name="course_explore_other_parts">Досліджуйте інші частини цього курсу або перегляньте це на веб-сайті.</string>
<string name="course_explore_other_parts_on_web">Досліджуйте інші частини цього курсу або перегляньте це на веб-сайті.</string>
<string name="course_open_in_browser">Відкрити в браузері</string>
<string name="course_subtitles">Субтитри</string>
<string name="course_continue_with">Остання активність:</string>
Expand Down
Loading

0 comments on commit 27069f7

Please sign in to comment.