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

feat: Added webView based myPrograms #176

Merged
merged 13 commits into from
Jan 22, 2024
2 changes: 1 addition & 1 deletion app/src/main/java/org/openedx/app/AnalyticsManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import org.openedx.app.analytics.FirebaseAnalytics
import org.openedx.auth.presentation.AuthAnalytics
import org.openedx.core.config.Config
import org.openedx.course.presentation.CourseAnalytics
import org.openedx.dashboard.presentation.DashboardAnalytics
import org.openedx.dashboard.presentation.dashboard.DashboardAnalytics
import org.openedx.discovery.presentation.DiscoveryAnalytics
import org.openedx.discussion.presentation.DiscussionAnalytics
import org.openedx.profile.presentation.ProfileAnalytics
Expand Down
6 changes: 5 additions & 1 deletion app/src/main/java/org/openedx/app/AppRouter.kt
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import org.openedx.course.presentation.unit.container.CourseUnitContainerFragmen
import org.openedx.course.presentation.unit.video.VideoFullScreenFragment
import org.openedx.course.presentation.unit.video.YoutubeVideoFullScreenFragment
import org.openedx.dashboard.presentation.DashboardRouter
import org.openedx.dashboard.presentation.program.ProgramFragment
import org.openedx.discovery.presentation.DiscoveryRouter
import org.openedx.discovery.presentation.NativeDiscoveryFragment
import org.openedx.discovery.presentation.search.CourseSearchFragment
Expand All @@ -46,7 +47,6 @@ import org.openedx.profile.presentation.settings.video.VideoQualityFragment
import org.openedx.profile.presentation.settings.video.VideoSettingsFragment
import org.openedx.whatsnew.WhatsNewRouter
import org.openedx.whatsnew.presentation.whatsnew.WhatsNewFragment
import java.util.Date

class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, DiscussionRouter,
ProfileRouter, AppUpgradeRouter, WhatsNewRouter {
Expand Down Expand Up @@ -131,6 +131,10 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di
)
}

override fun navigateToProgramInfo(fm: FragmentManager, pathId: String) {
replaceFragmentWithBackStack(fm, ProgramFragment.newInstance(pathId))
}

override fun navigateToNoAccess(
fm: FragmentManager,
title: String
Expand Down
26 changes: 22 additions & 4 deletions app/src/main/java/org/openedx/app/MainFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,20 @@ package org.openedx.app
import android.os.Bundle
import android.view.View
import androidx.core.os.bundleOf
import androidx.core.view.forEach
import androidx.fragment.app.Fragment
import androidx.fragment.app.setFragmentResultListener
import androidx.lifecycle.lifecycleScope
import androidx.viewpager2.widget.ViewPager2
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.openedx.app.adapter.MainNavigationFragmentAdapter
import org.openedx.app.databinding.FragmentMainBinding
import org.openedx.core.presentation.global.app_upgrade.UpgradeRequiredFragment
import org.openedx.core.presentation.global.viewBinding
import org.openedx.dashboard.presentation.DashboardFragment
import org.openedx.dashboard.presentation.dashboard.DashboardFragment
import org.openedx.dashboard.presentation.program.ProgramFragment
import org.openedx.discovery.presentation.DiscoveryNavigator
import org.openedx.discovery.presentation.DiscoveryRouter
import org.openedx.profile.presentation.profile.ProfileFragment
Expand All @@ -28,6 +32,7 @@ class MainFragment : Fragment(R.layout.fragment_main) {

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
lifecycle.addObserver(viewModel)
setFragmentResultListener(UpgradeRequiredFragment.REQUEST_KEY) { _, _ ->
binding.bottomNavView.selectedItemId = R.id.fragmentProfile
viewModel.enableBottomBar(false)
Expand Down Expand Up @@ -68,6 +73,14 @@ class MainFragment : Fragment(R.layout.fragment_main) {
enableBottomBar(isBottomBarEnabled)
}

viewLifecycleOwner.lifecycleScope.launch {
viewModel.navigateToDiscovery.collect { shouldNavigateToDiscovery ->
if (shouldNavigateToDiscovery) {
binding.bottomNavView.selectedItemId = R.id.fragmentHome
}
}
}

requireArguments().apply {
this.getString(ARG_COURSE_ID, null)?.apply {
router.navigateToCourseDetail(parentFragmentManager, this)
Expand All @@ -82,20 +95,25 @@ class MainFragment : Fragment(R.layout.fragment_main) {

val discoveryFragment = DiscoveryNavigator(viewModel.isDiscoveryTypeWebView)
.getDiscoveryFragment()
val programFragment = if (viewModel.isProgramTypeWebView) {
ProgramFragment(true)
} else {
InDevelopmentFragment()
}

adapter = MainNavigationFragmentAdapter(this).apply {
addFragment(discoveryFragment)
addFragment(DashboardFragment())
addFragment(InDevelopmentFragment())
addFragment(programFragment)
addFragment(ProfileFragment())
}
binding.viewPager.adapter = adapter
binding.viewPager.isUserInputEnabled = false
}

private fun enableBottomBar(enable: Boolean) {
for (i in 0 until binding.bottomNavView.menu.size()) {
binding.bottomNavView.menu.getItem(i).isEnabled = enable
binding.bottomNavView.menu.forEach {
it.isEnabled = enable
}
}

Expand Down
28 changes: 27 additions & 1 deletion app/src/main/java/org/openedx/app/MainViewModel.kt
Original file line number Diff line number Diff line change
@@ -1,20 +1,46 @@
package org.openedx.app

import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.SharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import org.openedx.core.BaseViewModel
import org.openedx.core.config.Config
import org.openedx.dashboard.notifier.DashboardEvent
import org.openedx.dashboard.notifier.DashboardNotifier

class MainViewModel(
private val config: Config
private val config: Config,
private val notifier: DashboardNotifier,
) : BaseViewModel() {

private val _isBottomBarEnabled = MutableLiveData(true)
val isBottomBarEnabled: LiveData<Boolean>
get() = _isBottomBarEnabled

private val _navigateToDiscovery = MutableSharedFlow<Boolean>()
val navigateToDiscovery: SharedFlow<Boolean>
get() = _navigateToDiscovery.asSharedFlow()

val isDiscoveryTypeWebView get() = config.getDiscoveryConfig().isViewTypeWebView()

val isProgramTypeWebView get() = config.getProgramConfig().isViewTypeWebView()

override fun onCreate(owner: LifecycleOwner) {
super.onCreate(owner)
notifier.notifier.onEach {
if (it is DashboardEvent.NavigationToDiscovery) {
_navigateToDiscovery.emit(true)
}
}.distinctUntilChanged().launchIn(viewModelScope)
}

fun enableBottomBar(enable: Boolean) {
_isBottomBarEnabled.value = enable
}
Expand Down
8 changes: 7 additions & 1 deletion app/src/main/java/org/openedx/app/di/AppModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import org.openedx.auth.presentation.sso.MicrosoftAuthHelper
import org.openedx.core.config.Config
import org.openedx.core.data.storage.CorePreferences
import org.openedx.core.data.storage.InAppReviewPreferences
import org.openedx.core.interfaces.EnrollInCourseInteractor
import org.openedx.core.module.DownloadWorkerController
import org.openedx.core.module.TranscriptManager
import org.openedx.core.module.download.FileDownloader
Expand All @@ -38,9 +39,11 @@ import org.openedx.core.system.ResourceManager
import org.openedx.core.system.connection.NetworkConnection
import org.openedx.core.system.notifier.AppUpgradeNotifier
import org.openedx.core.system.notifier.CourseNotifier
import org.openedx.course.domain.interactor.CourseInteractor
import org.openedx.dashboard.notifier.DashboardNotifier
import org.openedx.course.presentation.CourseAnalytics
import org.openedx.course.presentation.CourseRouter
import org.openedx.dashboard.presentation.DashboardAnalytics
import org.openedx.dashboard.presentation.dashboard.DashboardAnalytics
import org.openedx.dashboard.presentation.DashboardRouter
import org.openedx.discovery.presentation.DiscoveryAnalytics
import org.openedx.discovery.presentation.DiscoveryRouter
Expand Down Expand Up @@ -75,6 +78,7 @@ val appModule = module {
single { DiscussionNotifier() }
single { ProfileNotifier() }
single { AppUpgradeNotifier() }
single { DashboardNotifier() }

single { AppRouter() }
single<AuthRouter> { get<AppRouter>() }
Expand Down Expand Up @@ -153,4 +157,6 @@ val appModule = module {
factory { FacebookAuthHelper() }
factory { GoogleAuthHelper(get()) }
factory { MicrosoftAuthHelper() }

factory<EnrollInCourseInteractor> { CourseInteractor(get()) }
}
21 changes: 9 additions & 12 deletions app/src/main/java/org/openedx/app/di/ScreenModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@ import org.openedx.course.presentation.unit.video.VideoViewModel
import org.openedx.course.presentation.videos.CourseVideoViewModel
import org.openedx.dashboard.data.repository.DashboardRepository
import org.openedx.dashboard.domain.interactor.DashboardInteractor
import org.openedx.dashboard.presentation.DashboardViewModel
import org.openedx.dashboard.presentation.dashboard.DashboardViewModel
import org.openedx.dashboard.presentation.program.ProgramViewModel
import org.openedx.discovery.data.repository.DiscoveryRepository
import org.openedx.discovery.domain.interactor.DiscoveryInteractor
import org.openedx.discovery.presentation.NativeDiscoveryViewModel
Expand Down Expand Up @@ -58,7 +59,7 @@ import org.openedx.whatsnew.presentation.whatsnew.WhatsNewViewModel
val screenModule = module {

viewModel { AppViewModel(get(), get(), get(), get(), get(named("IODispatcher")), get()) }
viewModel { MainViewModel(get()) }
viewModel { MainViewModel(get(), get()) }

factory { AuthRepository(get(), get(), get()) }
factory { AuthInteractor(get()) }
Expand All @@ -85,7 +86,7 @@ val screenModule = module {

factory { DashboardRepository(get(), get(), get()) }
factory { DashboardInteractor(get()) }
viewModel { DashboardViewModel(get(), get(), get(), get(), get(), get(), get()) }
viewModel { DashboardViewModel(get(), get(), get(), get(), get(), get(), get(), get()) }

factory { DiscoveryRepository(get(), get()) }
factory { DiscoveryInteractor(get()) }
Expand Down Expand Up @@ -130,9 +131,10 @@ val screenModule = module {
get()
)
}
viewModel { (courseId: String) ->
viewModel { (courseId: String, courseTitle: String) ->
CourseContainerViewModel(
courseId,
courseTitle,
get(),
get(),
get(),
Expand Down Expand Up @@ -257,12 +259,7 @@ val screenModule = module {
}

viewModel { (courseId: String?) -> WhatsNewViewModel(courseId, get()) }
viewModel {
HtmlUnitViewModel(
get(),
get(),
get(),
get()
)
}
viewModel { HtmlUnitViewModel(get(), get(), get(), get()) }

viewModel { ProgramViewModel(get(), get(), get(), get(), get(), get(), get()) }
}
15 changes: 15 additions & 0 deletions core/src/main/java/org/openedx/core/config/Config.kt
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,10 @@ class Config(context: Context) {
return getString(API_HOST_URL, "")
}

fun getUriScheme(): String {
return getString(URI_SCHEME, "")
}

fun getOAuthClientId(): String {
return getString(OAUTH_CLIENT_ID, "")
}
Expand Down Expand Up @@ -71,6 +75,10 @@ class Config(context: Context) {
return getObjectOrNewInstance(DISCOVERY, DiscoveryConfig::class.java)
}

fun getProgramConfig(): ProgramConfig {
return getObjectOrNewInstance(PROGRAM, ProgramConfig::class.java)
}

fun isWhatsNewEnabled(): Boolean {
return getBoolean(WHATS_NEW_ENABLED, false)
}
Expand Down Expand Up @@ -131,6 +139,7 @@ class Config(context: Context) {

companion object {
private const val API_HOST_URL = "API_HOST_URL"
private const val URI_SCHEME = "URI_SCHEME"
private const val OAUTH_CLIENT_ID = "OAUTH_CLIENT_ID"
private const val TOKEN_TYPE = "TOKEN_TYPE"
private const val FAQ_URL = "FAQ_URL"
Expand All @@ -144,9 +153,15 @@ class Config(context: Context) {
private const val MICROSOFT = "MICROSOFT"
private const val PRE_LOGIN_EXPERIENCE_ENABLED = "PRE_LOGIN_EXPERIENCE_ENABLED"
private const val DISCOVERY = "DISCOVERY"
private const val PROGRAM = "PROGRAM"
private const val COURSE_NESTED_LIST_ENABLED = "COURSE_NESTED_LIST_ENABLED"
private const val COURSE_BANNER_ENABLED = "COURSE_BANNER_ENABLED"
private const val COURSE_TOP_TAB_BAR_ENABLED = "COURSE_TOP_TAB_BAR_ENABLED"
private const val COURSE_UNIT_PROGRESS_ENABLED = "COURSE_UNIT_PROGRESS_ENABLED"
}

enum class ViewType {
NATIVE,
WEBVIEW
}
}
11 changes: 2 additions & 9 deletions core/src/main/java/org/openedx/core/config/DiscoveryConfig.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,28 +4,21 @@ import com.google.gson.annotations.SerializedName

data class DiscoveryConfig(
@SerializedName("TYPE")
private val viewType: String = Type.NATIVE.name,
private val viewType: String = Config.ViewType.NATIVE.name,

@SerializedName("WEBVIEW")
val webViewConfig: DiscoveryWebViewConfig = DiscoveryWebViewConfig(),
) {
enum class Type {
NATIVE,
WEBVIEW
}

fun isViewTypeWebView(): Boolean {
return Type.WEBVIEW.name.equals(viewType, ignoreCase = true)
return Config.ViewType.WEBVIEW.name.equals(viewType, ignoreCase = true)
}
}

data class DiscoveryWebViewConfig(
@SerializedName("BASE_URL")
val baseUrl: String = "",

@SerializedName("URI_SCHEME")
val uriScheme: String = "",

@SerializedName("COURSE_DETAIL_TEMPLATE")
val courseUrlTemplate: String = "",

Expand Down
21 changes: 21 additions & 0 deletions core/src/main/java/org/openedx/core/config/ProgramConfig.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package org.openedx.core.config

import com.google.gson.annotations.SerializedName

data class ProgramConfig(
@SerializedName("TYPE")
private val viewType: String = Config.ViewType.NATIVE.name,
@SerializedName("WEBVIEW")
val webViewConfig: ProgramWebViewConfig = ProgramWebViewConfig(),
){
fun isViewTypeWebView(): Boolean {
return Config.ViewType.WEBVIEW.name.equals(viewType, ignoreCase = true)
}
}

data class ProgramWebViewConfig(
@SerializedName("PROGRAM_URL")
val programUrl: String = "",
@SerializedName("PROGRAM_DETAIL_URL_TEMPLATE")
val programDetailUrlTemplate: String = "",
)
7 changes: 6 additions & 1 deletion core/src/main/java/org/openedx/core/extension/ViewExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import android.graphics.Rect
import android.util.DisplayMetrics
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.DialogFragment

fun Context.dpToPixel(dp: Int): Float {
Expand Down Expand Up @@ -40,4 +41,8 @@ fun DialogFragment.setWidthPercent(percentage: Int) {
val rect = dm.run { Rect(0, 0, widthPixels, heightPixels) }
val percentWidth = rect.width() * percent
dialog?.window?.setLayout(percentWidth.toInt(), ViewGroup.LayoutParams.WRAP_CONTENT)
}
}

fun Context.toastMessage(message: String) {
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package org.openedx.core.interfaces

interface EnrollInCourseInteractor {
suspend fun enrollInACourse(id: String)
}
Loading