Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions app/src/main/java/org/openedx/app/AppRouter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,13 @@ class AppRouter :
HandoutsWebViewFragment.newInstance(type.name, courseId)
)
}

override fun navigateToCertificate(fm: FragmentManager, title: String, url: String) {
replaceFragmentWithBackStack(
fm,
WebContentFragment.newInstance(title = title, url = url)
)
}
// endregion

// region DiscussionRouter
Expand Down
51 changes: 51 additions & 0 deletions core/src/main/java/org/openedx/core/extension/WebViewExt.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package org.openedx.core.extension

import android.webkit.WebView

/**
* Injects CSS to hide common headers and footers in web pages.
*
* Also removes padding/margins from body to eliminate empty space.
*/
fun WebView.injectHeaderFooterHidingCss() {
val css = """
/* Hide common site headers/footers */
header, footer,
[role="banner"], [role="contentinfo"],
.site-header, .site-footer,
.global-header, .global-footer,
.header, .footer,
.navbar-fixed-top, .navbar, .topbar,
.bottom-bar, .cookie-banner, .gdpr-banner,
.certificate .wrapper-banner.wrapper-banner-user,
#header, #footer, #masthead, #site-footer, #site-header {
display: none !important;
visibility: hidden !important;
height: 0 !important;
min-height: 0 !important;
max-height: 0 !important;
margin: 0 !important;
padding: 0 !important;
border: 0 !important;
}

/* Remove empty space created by fixed headers */
body {
padding-top: 0 !important;
padding-bottom: 0 !important;
margin-top: 0 !important;
margin-bottom: 0 !important;
}
"""

val js = """
(function() {
var style = document.createElement('style');
style.type = 'text/css';
style.appendChild(document.createTextNode(`$css`));
document.head.appendChild(style);
})();
""".trimIndent()

evaluateJavascript(js, null)
}
22 changes: 10 additions & 12 deletions core/src/main/java/org/openedx/core/ui/WebContentScreen.kt
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.viewinterop.AndroidView
import androidx.compose.ui.zIndex
import org.openedx.core.extension.injectHeaderFooterHidingCss
import org.openedx.core.ui.theme.appColors
import org.openedx.core.ui.theme.getDarkThemeFromPreferences
import org.openedx.core.utils.EmailUtil
Expand All @@ -53,6 +54,7 @@ fun WebContentScreen(
onBackClick: () -> Unit,
htmlBody: String? = null,
contentUrl: String? = null,
hideHeaderFooter: Boolean = true,
) {
val scaffoldState = rememberScaffoldState()
Scaffold(
Expand Down Expand Up @@ -111,6 +113,7 @@ fun WebContentScreen(
apiHostUrl = apiHostUrl,
body = htmlBody,
contentUrl = contentUrl,
hideHeaderFooter = hideHeaderFooter,
onWebPageLoaded = {
webViewAlpha = 1f
}
Expand All @@ -129,6 +132,7 @@ private fun WebViewContent(
apiHostUrl: String? = null,
body: String? = null,
contentUrl: String? = null,
hideHeaderFooter: Boolean = true,
onWebPageLoaded: () -> Unit
) {
val context = LocalContext.current
Expand Down Expand Up @@ -165,11 +169,12 @@ private fun WebViewContent(

override fun onPageFinished(view: WebView?, url: String?) {
super.onPageFinished(view, url)
val css = when {
url?.contains("privacy", ignoreCase = true) == true -> PRIVACY_PAGE_CSS
else -> return
if (hideHeaderFooter) {
if (url?.contains("privacy", ignoreCase = true) == true) {
injectCss(view, PRIVACY_PAGE_ADDITIONAL_CSS)
}
view?.injectHeaderFooterHidingCss()
}
injectCss(view, css)
}
}
with(settings) {
Expand Down Expand Up @@ -214,14 +219,7 @@ private fun WebViewContent(
)
}

private const val PRIVACY_PAGE_CSS = """
header, footer {
display: none !important;
}
body {
margin-top: 0 !important;
padding-top: 0 !important;
}
private const val PRIVACY_PAGE_ADDITIONAL_CSS = """
.content-wrapper {
padding: 0 !important;
margin: 0;
Expand Down
3 changes: 3 additions & 0 deletions core/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -200,4 +200,7 @@

<!-- Language Options -->
<string name="core_language">Language</string>

<!-- Certificate -->
<string name="core_certificate">Certificate</string>
</resources>
Original file line number Diff line number Diff line change
Expand Up @@ -66,4 +66,6 @@ interface CourseRouter {
fun navigateToVideoQuality(fm: FragmentManager, videoQualityType: VideoQualityType)

fun navigateToDiscover(fm: FragmentManager)

fun navigateToCertificate(fm: FragmentManager, title: String, url: String)
}
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,6 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.AndroidUriHandler
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.pluralStringResource
import androidx.compose.ui.res.stringResource
Expand Down Expand Up @@ -87,7 +85,6 @@ fun CourseOutlineScreen(
val uiState by viewModel.uiState.collectAsState()
val uiMessage by viewModel.uiMessage.collectAsState(null)
val resumeBlockId by viewModel.resumeBlockId.collectAsState("")
val context = LocalContext.current

LaunchedEffect(resumeBlockId) {
if (resumeBlockId.isNotEmpty()) {
Expand Down Expand Up @@ -156,7 +153,7 @@ fun CourseOutlineScreen(
onCertificateClick = {
viewModel.viewCertificateTappedEvent()
it.takeIfNotEmpty()
?.let { url -> AndroidUriHandler(context).openUri(url) }
?.let { url -> viewModel.navigateToCertificate(fragmentManager, url) }
}
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,15 @@ class CourseOutlineViewModel(
)
}

fun navigateToCertificate(fm: FragmentManager, url: String) {
viewCertificateTappedEvent()
courseRouter.navigateToCertificate(
fm = fm,
title = resourceManager.getString(org.openedx.core.R.string.core_certificate),
url = url
)
}

private fun resumeCourseTappedEvent(blockId: String) {
val currentState = uiState.value
if (currentState is CourseOutlineUIState.CourseData) {
Expand Down
Loading