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
61 changes: 61 additions & 0 deletions app/src/main/java/org/openedx/app/MainFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,11 @@ package org.openedx.app
import android.os.Bundle
import android.view.Menu
import android.view.View
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.getValue
import androidx.compose.runtime.livedata.observeAsState
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.core.os.bundleOf
import androidx.core.view.forEach
import androidx.fragment.app.Fragment
Expand All @@ -14,9 +19,14 @@ import org.koin.android.ext.android.inject
import org.koin.androidx.viewmodel.ext.android.viewModel
import org.openedx.app.databinding.FragmentMainBinding
import org.openedx.app.deeplink.HomeTab
import org.openedx.core.AppUpdateState
import org.openedx.core.AppUpdateState.wasUpgradeDialogClosed
import org.openedx.core.adapter.NavigationFragmentAdapter
import org.openedx.core.presentation.dialog.appupgrade.AppUpgradeDialogFragment
import org.openedx.core.presentation.global.appupgrade.AppUpgradeRecommendedBox
import org.openedx.core.presentation.global.appupgrade.UpgradeRequiredFragment
import org.openedx.core.presentation.global.viewBinding
import org.openedx.core.system.notifier.app.AppUpgradeEvent
import org.openedx.discovery.presentation.DiscoveryRouter
import org.openedx.downloads.presentation.download.DownloadsFragment
import org.openedx.learn.presentation.LearnFragment
Expand Down Expand Up @@ -45,6 +55,7 @@ class MainFragment : Fragment(R.layout.fragment_main) {
handleArguments()
setupBottomNavigation()
setupViewPager()
setupBottomPopup()
observeViewModel()
}

Expand Down Expand Up @@ -186,6 +197,56 @@ class MainFragment : Fragment(R.layout.fragment_main) {
}
}

private fun setupBottomPopup() {
binding.composeBottomPopup.setContent {
val appUpgradeEvent by viewModel.appUpgradeEvent.observeAsState()
val wasUpgradeDialogClosed by remember { wasUpgradeDialogClosed }
val appUpgradeParameters = AppUpdateState.AppUpgradeParameters(
appUpgradeEvent = appUpgradeEvent,
wasUpgradeDialogClosed = wasUpgradeDialogClosed,
appUpgradeRecommendedDialog = {
val dialog = AppUpgradeDialogFragment.newInstance()
dialog.show(
requireActivity().supportFragmentManager,
AppUpgradeDialogFragment::class.simpleName
)
},
onAppUpgradeRecommendedBoxClick = {
AppUpdateState.openPlayMarket(requireContext())
},
onAppUpgradeRequired = {
router.navigateToUpgradeRequired(
requireActivity().supportFragmentManager
)
}
)
when (appUpgradeParameters.appUpgradeEvent) {
is AppUpgradeEvent.UpgradeRecommendedEvent -> {
if (appUpgradeParameters.wasUpgradeDialogClosed) {
AppUpgradeRecommendedBox(
modifier = Modifier.fillMaxWidth(),
onClick = appUpgradeParameters.onAppUpgradeRecommendedBoxClick
)
} else {
if (!AppUpdateState.wasUpdateDialogDisplayed) {
AppUpdateState.wasUpdateDialogDisplayed = true
appUpgradeParameters.appUpgradeRecommendedDialog()
}
}
}

is AppUpgradeEvent.UpgradeRequiredEvent -> {
if (!AppUpdateState.wasUpdateDialogDisplayed) {
AppUpdateState.wasUpdateDialogDisplayed = true
appUpgradeParameters.onAppUpgradeRequired()
}
}

else -> {}
}
}
}

companion object {
private const val ARG_COURSE_ID = "courseId"
private const val ARG_INFO_TYPE = "info_type"
Expand Down
42 changes: 34 additions & 8 deletions app/src/main/java/org/openedx/app/MainViewModel.kt
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,20 @@ import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import org.openedx.core.config.Config
import org.openedx.core.system.notifier.DiscoveryNotifier
import org.openedx.core.system.notifier.NavigationToDiscovery
import org.openedx.core.system.notifier.app.AppNotifier
import org.openedx.core.system.notifier.app.AppUpgradeEvent
import org.openedx.discovery.presentation.DiscoveryNavigator
import org.openedx.foundation.presentation.BaseViewModel

class MainViewModel(
private val config: Config,
private val notifier: DiscoveryNotifier,
private val analytics: AppAnalytics,
private val appNotifier: AppNotifier,
) : BaseViewModel() {

private val _isBottomBarEnabled = MutableLiveData(true)
Expand All @@ -30,21 +34,19 @@ class MainViewModel(
val navigateToDiscovery: SharedFlow<Boolean>
get() = _navigateToDiscovery.asSharedFlow()

private val _appUpgradeEvent = MutableLiveData<AppUpgradeEvent>()
val appUpgradeEvent: LiveData<AppUpgradeEvent>
get() = _appUpgradeEvent

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

val isDownloadsFragmentEnabled get() = config.getDownloadsConfig().isEnabled

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

fun enableBottomBar(enable: Boolean) {
Expand Down Expand Up @@ -75,4 +77,28 @@ class MainViewModel(
}
)
}

private fun collectDiscoveryEvents() {
notifier.notifier
.onEach {
if (it is NavigationToDiscovery) {
_navigateToDiscovery.emit(true)
}
}
.distinctUntilChanged()
.launchIn(viewModelScope)
}

private fun collectAppUpgradeEvent() {
viewModelScope.launch {
appNotifier.notifier
.onEach { event ->
if (event is AppUpgradeEvent) {
_appUpgradeEvent.value = event
}
}
.distinctUntilChanged()
.launchIn(viewModelScope)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import kotlinx.coroutines.runBlocking
import okhttp3.Interceptor
import okhttp3.Response
import org.openedx.app.BuildConfig
import org.openedx.core.AppUpdateState
import org.openedx.core.system.notifier.app.AppNotifier
import org.openedx.core.system.notifier.app.AppUpgradeEvent
import org.openedx.core.utils.TimeUtils
Expand All @@ -17,23 +18,30 @@ class AppUpgradeInterceptor(
val responseCode = response.code
val latestAppVersion = response.header(HEADER_APP_LATEST_VERSION) ?: ""
val lastSupportedDateString = response.header(HEADER_APP_VERSION_LAST_SUPPORTED_DATE) ?: ""
val lastSupportedDateTime = TimeUtils.iso8601WithTimeZoneToDate(lastSupportedDateString)?.time ?: 0L
val lastSupportedDateTime =
TimeUtils.iso8601WithTimeZoneToDate(lastSupportedDateString)?.time ?: 0L
runBlocking {
when {
val appUpgradeEvent = when {
responseCode == 426 -> {
appNotifier.send(AppUpgradeEvent.UpgradeRequiredEvent)
AppUpgradeEvent.UpgradeRequiredEvent
}

BuildConfig.VERSION_NAME != latestAppVersion && lastSupportedDateTime > Date().time -> {
appNotifier.send(AppUpgradeEvent.UpgradeRecommendedEvent(latestAppVersion))
AppUpgradeEvent.UpgradeRecommendedEvent(latestAppVersion)
}

latestAppVersion.isNotEmpty() &&
BuildConfig.VERSION_NAME != latestAppVersion &&
lastSupportedDateTime < Date().time -> {
appNotifier.send(AppUpgradeEvent.UpgradeRequiredEvent)
AppUpgradeEvent.UpgradeRequiredEvent
}

else -> {
return@runBlocking
}
}
AppUpdateState.lastAppUpgradeEvent = appUpgradeEvent
appNotifier.send(appUpgradeEvent)
}
return response
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,13 @@
package org.openedx.app.data.networking

import android.content.Context
import okhttp3.Interceptor
import okhttp3.Response
import org.openedx.app.BuildConfig
import org.openedx.core.config.Config
import org.openedx.core.data.storage.CorePreferences
import org.openedx.core.presentation.global.AppData

class HeadersInterceptor(
private val context: Context,
private val appData: AppData,
private val config: Config,
private val preferencesManager: CorePreferences,
) : Interceptor {
Expand All @@ -26,13 +25,7 @@ class HeadersInterceptor(
addHeader("Accept", "application/json")

val httpAgent = System.getProperty("http.agent") ?: ""
addHeader(
"User-Agent",
httpAgent + " " +
context.getString(org.openedx.core.R.string.app_name) + "/" +
BuildConfig.APPLICATION_ID + "/" +
BuildConfig.VERSION_NAME
)
addHeader("User-Agent", "$httpAgent ${appData.versionName}")
}.build()
)
}
Expand Down
6 changes: 3 additions & 3 deletions app/src/main/java/org/openedx/app/di/ScreenModule.kt
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ val screenModule = module {
get(),
)
}
viewModel { MainViewModel(get(), get(), get()) }
viewModel { MainViewModel(get(), get(), get(), get()) }

factory { AuthRepository(get(), get(), get()) }
factory { AuthInteractor(get()) }
Expand Down Expand Up @@ -148,7 +148,7 @@ val screenModule = module {

factory { DashboardRepository(get(), get(), get(), get()) }
factory { DashboardInteractor(get()) }
viewModel { DashboardListViewModel(get(), get(), get(), get(), get(), get(), get()) }
viewModel { DashboardListViewModel(get(), get(), get(), get(), get(), get()) }
viewModel { (windowSize: WindowSize) ->
DashboardGalleryViewModel(
get(),
Expand All @@ -169,7 +169,7 @@ val screenModule = module {

factory { DiscoveryRepository(get(), get(), get()) }
factory { DiscoveryInteractor(get()) }
viewModel { NativeDiscoveryViewModel(get(), get(), get(), get(), get(), get(), get()) }
viewModel { NativeDiscoveryViewModel(get(), get(), get(), get(), get(), get()) }
viewModel { (querySearch: String) ->
WebViewDiscoveryViewModel(
querySearch,
Expand Down
7 changes: 7 additions & 0 deletions app/src/main/res/layout/fragment_main.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,11 @@
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent" />

<androidx.compose.ui.platform.ComposeView
android:id="@+id/compose_bottom_popup"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="24.dp"
app:layout_constraintBottom_toBottomOf="@+id/view_pager" />

</androidx.constraintlayout.widget.ConstraintLayout>
16 changes: 11 additions & 5 deletions core/src/main/java/org/openedx/core/AppUpdateState.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,37 @@ package org.openedx.core
import android.content.ActivityNotFoundException
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.compose.runtime.mutableStateOf
import androidx.core.net.toUri
import org.openedx.core.system.notifier.app.AppUpgradeEvent

object AppUpdateState {
var wasUpdateDialogDisplayed = false
var wasUpdateDialogClosed = mutableStateOf(false)
var wasUpgradeDialogClosed = mutableStateOf(false)
var lastAppUpgradeEvent: AppUpgradeEvent? = null

fun openPlayMarket(context: Context) {
try {
context.startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=${context.packageName}")))
context.startActivity(
Intent(
Intent.ACTION_VIEW,
"market://details?id=${context.packageName}".toUri()
)
)
} catch (e: ActivityNotFoundException) {
e.printStackTrace()
context.startActivity(
Intent(
Intent.ACTION_VIEW,
Uri.parse("https://play.google.com/store/apps/details?id=${context.packageName}")
"https://play.google.com/store/apps/details?id=${context.packageName}".toUri()
)
)
}
}

data class AppUpgradeParameters(
val appUpgradeEvent: AppUpgradeEvent? = null,
val wasUpdateDialogClosed: Boolean = AppUpdateState.wasUpdateDialogClosed.value,
val wasUpgradeDialogClosed: Boolean = AppUpdateState.wasUpgradeDialogClosed.value,
val appUpgradeRecommendedDialog: () -> Unit = {},
val onAppUpgradeRecommendedBoxClick: () -> Unit = {},
val onAppUpgradeRequired: () -> Unit = {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,12 +33,12 @@ class AppUpgradeDialogFragment : DialogFragment() {
}

private fun onNotNowClick() {
AppUpdateState.wasUpdateDialogClosed.value = true
AppUpdateState.wasUpgradeDialogClosed.value = true
dismiss()
}

private fun onUpdateClick() {
AppUpdateState.wasUpdateDialogClosed.value = true
AppUpdateState.wasUpgradeDialogClosed.value = true
dismiss()
AppUpdateState.openPlayMarket(requireContext())
}
Expand Down
Loading