Skip to content
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

refactor: support info section #160

Merged
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
5 changes: 5 additions & 0 deletions app/src/main/java/org/openedx/app/AnalyticsManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@ class AnalyticsManager(
logEvent(Event.PRIVACY_POLICY_CLICKED)
}

override fun termsOfUseClickedEvent() {
logEvent(Event.TERMS_OF_USE_CLICKED)
}

override fun cookiePolicyClickedEvent() {
logEvent(Event.COOKIE_POLICY_CLICKED)
}
Expand Down Expand Up @@ -415,6 +419,7 @@ private enum class Event(val eventName: String) {
PROFILE_DELETE_ACCOUNT_CLICKED("Profile_Delete_Account_Clicked"),
PROFILE_VIDEO_SETTINGS_CLICKED("Profile_Video_settings_Clicked"),
PRIVACY_POLICY_CLICKED("Privacy_Policy_Clicked"),
TERMS_OF_USE_CLICKED("Terms_Of_Use_Clicked"),
COOKIE_POLICY_CLICKED("Cookie_Policy_Clicked"),
EMAIL_SUPPORT_CLICKED("Email_Support_Clicked"),
COURSE_ENROLL_CLICKED("Course_Enroll_Clicked"),
Expand Down
12 changes: 10 additions & 2 deletions app/src/main/java/org/openedx/app/AppRouter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ import org.openedx.core.domain.model.CoursewareAccess
import org.openedx.core.presentation.course.CourseViewMode
import org.openedx.core.presentation.global.app_upgrade.AppUpgradeRouter
import org.openedx.core.presentation.global.app_upgrade.UpgradeRequiredFragment
import org.openedx.core.presentation.global.webview.WebContentFragment
import org.openedx.course.presentation.CourseRouter
import org.openedx.course.presentation.container.CourseContainerFragment
import org.openedx.course.presentation.container.NoAccessCourseContainerFragment
import org.openedx.course.presentation.detail.CourseDetailsFragment
import org.openedx.course.presentation.handouts.HandoutsType
import org.openedx.course.presentation.handouts.WebViewFragment
import org.openedx.course.presentation.handouts.HandoutsWebViewFragment
import org.openedx.course.presentation.section.CourseSectionFragment
import org.openedx.course.presentation.unit.container.CourseUnitContainerFragment
import org.openedx.course.presentation.unit.video.VideoFullScreenFragment
Expand Down Expand Up @@ -204,7 +205,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di
) {
replaceFragmentWithBackStack(
fm,
WebViewFragment.newInstance(title, type.name, courseId)
HandoutsWebViewFragment.newInstance(title, type.name, courseId)
)
}
//endregion
Expand Down Expand Up @@ -288,6 +289,13 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di
replaceFragmentWithBackStack(fm, DeleteProfileFragment())
}

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

override fun restartApp(fm: FragmentManager, isLogistrationEnabled: Boolean) {
fm.apply {
for (fragment in fragments) {
Expand Down
20 changes: 11 additions & 9 deletions app/src/main/java/org/openedx/app/di/ScreenModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,17 @@ val screenModule = module {
factory { ProfileInteractor(get()) }
viewModel {
ProfileViewModel(
get(),
get(),
get(),
get(),
get(named("IODispatcher")),
get(),
get(),
get(),
get()
appData = get(),
config = get(),
interactor = get(),
resourceManager = get(),
notifier = get(),
dispatcher = get(named("IODispatcher")),
cookieManager = get(),
workerController = get(),
analytics = get(),
appUpgradeNotifier = get(),
router = get(),
)
}
viewModel { (account: Account) -> EditProfileViewModel(get(), get(), get(), get(), account) }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package org.openedx.core.presentation.global.webview

import android.os.Bundle
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.compose.ui.platform.ComposeView
import androidx.compose.ui.platform.ViewCompositionStrategy
import androidx.core.os.bundleOf
import androidx.fragment.app.Fragment
import org.openedx.core.ui.WebContentScreen
import org.openedx.core.ui.rememberWindowSize
import org.openedx.core.ui.theme.OpenEdXTheme

class WebContentFragment : Fragment() {
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
) = ComposeView(requireContext()).apply {
setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed)
setContent {
OpenEdXTheme {
val windowSize = rememberWindowSize()
WebContentScreen(
windowSize = windowSize,
title = requireArguments().getString(ARG_TITLE, ""),
contentUrl = requireArguments().getString(ARG_URL, ""),
onBackClick = {
requireActivity().supportFragmentManager.popBackStack()
})
}
}
}

companion object {
private const val ARG_TITLE = "argTitle"
private const val ARG_URL = "argUrl"

fun newInstance(title: String, url: String): WebContentFragment {
val fragment = WebContentFragment()
fragment.arguments = bundleOf(
ARG_TITLE to title,
ARG_URL to url,
)
return fragment
}
}
}
213 changes: 213 additions & 0 deletions core/src/main/java/org/openedx/core/ui/WebContentScreen.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
package org.openedx.core.ui

import android.annotation.SuppressLint
import android.content.Intent
import android.net.Uri
import android.webkit.WebResourceRequest
import android.webkit.WebView
import android.webkit.WebViewClient
import androidx.compose.foundation.background
import androidx.compose.foundation.isSystemInDarkTheme
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.widthIn
import androidx.compose.material.CircularProgressIndicator
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Scaffold
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.material.rememberScaffoldState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableFloatStateOf
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.text.style.TextOverflow
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.isEmailValid
import org.openedx.core.extension.replaceLinkTags
import org.openedx.core.ui.theme.appColors
import org.openedx.core.ui.theme.appTypography
import org.openedx.core.utils.EmailUtil
import java.nio.charset.StandardCharsets

@Composable
fun WebContentScreen(
windowSize: WindowSize,
apiHostUrl: String? = null,
title: String,
onBackClick: () -> Unit,
htmlBody: String? = null,
contentUrl: String? = null,
) {
val scaffoldState = rememberScaffoldState()
Scaffold(
modifier = Modifier
.fillMaxSize()
.padding(bottom = 16.dp),
scaffoldState = scaffoldState,
backgroundColor = MaterialTheme.appColors.background
) {

val screenWidth by remember(key1 = windowSize) {
mutableStateOf(
windowSize.windowSizeValue(
expanded = Modifier.widthIn(Dp.Unspecified, 560.dp),
compact = Modifier.fillMaxWidth()
)
)
}

Box(
modifier = Modifier
.fillMaxWidth()
.padding(it)
.statusBarsInset()
.displayCutoutForLandscape(),
contentAlignment = Alignment.TopCenter
) {
Column(screenWidth) {
Box(
Modifier
.fillMaxWidth()
.zIndex(1f),
contentAlignment = Alignment.CenterStart
) {
BackBtn {
onBackClick()
}

Text(
modifier = Modifier
.fillMaxWidth()
.padding(horizontal = 56.dp),
text = title,
color = MaterialTheme.appColors.textPrimary,
style = MaterialTheme.appTypography.titleMedium,
maxLines = 1,
overflow = TextOverflow.Ellipsis,
textAlign = TextAlign.Center
)
}
Spacer(Modifier.height(6.dp))
Surface(
Modifier.fillMaxSize(),
color = MaterialTheme.appColors.background
) {
if (htmlBody.isNullOrEmpty() && contentUrl.isNullOrEmpty()) {
Box(
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.appColors.background)
.zIndex(1f),
contentAlignment = Alignment.Center
) {
CircularProgressIndicator(color = MaterialTheme.appColors.primary)
}
} else {
var webViewAlpha by rememberSaveable { mutableFloatStateOf(0f) }
Surface(
Modifier
.padding(horizontal = 16.dp, vertical = 24.dp)
.alpha(webViewAlpha),
color = MaterialTheme.appColors.background
) {
WebViewContent(
apiHostUrl = apiHostUrl,
body = htmlBody,
contentUrl = contentUrl,
onWebPageLoaded = {
webViewAlpha = 1f
})
}
}
}
}
}
}
}

@Composable
@SuppressLint("SetJavaScriptEnabled")
private fun WebViewContent(
apiHostUrl: String? = null,
body: String? = null,
contentUrl: String? = null,
onWebPageLoaded: () -> Unit
) {
val context = LocalContext.current
val isDarkTheme = isSystemInDarkTheme()
AndroidView(
factory = {
WebView(context).apply {
webViewClient = object : WebViewClient() {
override fun onPageCommitVisible(view: WebView?, url: String?) {
super.onPageCommitVisible(view, url)
onWebPageLoaded()
}

override fun shouldOverrideUrlLoading(
view: WebView?,
request: WebResourceRequest?
): Boolean {
val clickUrl = request?.url?.toString() ?: ""
return if (clickUrl.isNotEmpty() &&
(clickUrl.startsWith("http://") ||
clickUrl.startsWith("https://"))
) {
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(clickUrl)))
true
} else if (clickUrl.startsWith("mailto:")) {
val email = clickUrl.replace("mailto:", "")
if (email.isEmailValid()) {
EmailUtil.sendEmailIntent(context, email, "", "")
true
} else {
false
}
} else {
false
}
}
}
with(settings) {
javaScriptEnabled = true
loadWithOverviewMode = true
builtInZoomControls = false
setSupportZoom(true)
loadsImagesAutomatically = true
domStorageEnabled = true
}
isVerticalScrollBarEnabled = false
isHorizontalScrollBarEnabled = false
body?.let {
loadDataWithBaseURL(
apiHostUrl,
body.replaceLinkTags(isDarkTheme),
"text/html",
StandardCharsets.UTF_8.name(),
null
)
}
contentUrl?.let {
loadUrl(it)
}
}
},
)
}
12 changes: 7 additions & 5 deletions core/src/main/java/org/openedx/core/utils/EmailUtil.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package org.openedx.core.utils
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import android.widget.Toast
import org.openedx.core.R
Expand Down Expand Up @@ -37,11 +38,12 @@ object EmailUtil {
subject: String,
email: String
) {
val emailIntent = Intent(Intent.ACTION_SEND)
emailIntent.putExtra(Intent.EXTRA_EMAIL, arrayOf(to))
emailIntent.putExtra(Intent.EXTRA_SUBJECT, subject)
emailIntent.putExtra(Intent.EXTRA_TEXT, email)
emailIntent.type = "plain/text"
val emailIntent = Intent(Intent.ACTION_SENDTO).apply {
data = Uri.parse("mailto:")
putExtra(Intent.EXTRA_EMAIL, arrayOf(to))
putExtra(Intent.EXTRA_SUBJECT, subject)
putExtra(Intent.EXTRA_TEXT, email)
}
try {
emailIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
context?.let {
Expand Down
Loading