diff --git a/app/src/main/java/org/openedx/app/AppRouter.kt b/app/src/main/java/org/openedx/app/AppRouter.kt index 17b47d11d..fe4394cde 100644 --- a/app/src/main/java/org/openedx/app/AppRouter.kt +++ b/app/src/main/java/org/openedx/app/AppRouter.kt @@ -128,8 +128,8 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di replaceFragmentWithBackStack(fm, AllEnrolledCoursesFragment()) } - override fun getProgramFragmentInstance(): Fragment { - return ProgramFragment(myPrograms = true, isNestedFragment = true) + override fun getProgramFragment(): Fragment { + return ProgramFragment.newInstance(isNestedFragment = true) } override fun navigateToCourseInfo( @@ -144,7 +144,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di fm: FragmentManager, courseId: String, courseTitle: String, - enrollmentMode: String + enrollmentMode: String, ) { replaceFragmentWithBackStack( fm, @@ -161,21 +161,30 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di courseTitle: String, enrollmentMode: String, openTab: String, - resumeBlockId: String + resumeBlockId: String, ) { replaceFragmentWithBackStack( fm, - CourseContainerFragment.newInstance(courseId, courseTitle, enrollmentMode, openTab, resumeBlockId) + CourseContainerFragment.newInstance( + courseId, + courseTitle, + enrollmentMode, + openTab, + resumeBlockId + ) ) } override fun navigateToEnrolledProgramInfo(fm: FragmentManager, pathId: String) { - replaceFragmentWithBackStack(fm, ProgramFragment.newInstance(pathId)) + replaceFragmentWithBackStack( + fm, + ProgramFragment.newInstance(pathId = pathId, isNestedFragment = false) + ) } override fun navigateToNoAccess( fm: FragmentManager, - title: String + title: String, ) { replaceFragment(fm, NoAccessCourseContainerFragment.newInstance(title)) } @@ -189,7 +198,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di subSectionId: String, unitId: String, componentId: String, - mode: CourseViewMode + mode: CourseViewMode, ) { replaceFragmentWithBackStack( fm, @@ -208,7 +217,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di courseId: String, unitId: String, componentId: String, - mode: CourseViewMode + mode: CourseViewMode, ) { replaceFragmentWithBackStack( fm, @@ -226,7 +235,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di courseId: String, unitId: String, componentId: String, - mode: CourseViewMode + mode: CourseViewMode, ) { replaceFragment( fm, @@ -246,7 +255,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di videoTime: Long, blockId: String, courseId: String, - isPlaying: Boolean + isPlaying: Boolean, ) { replaceFragmentWithBackStack( fm, @@ -260,7 +269,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di videoTime: Long, blockId: String, courseId: String, - isPlaying: Boolean + isPlaying: Boolean, ) { replaceFragmentWithBackStack( fm, @@ -278,7 +287,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di fm: FragmentManager, courseId: String, title: String, - type: HandoutsType + type: HandoutsType, ) { replaceFragmentWithBackStack( fm, @@ -294,7 +303,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di courseId: String, topicId: String, title: String, - viewType: FragmentViewType + viewType: FragmentViewType, ) { replaceFragmentWithBackStack( fm, @@ -312,7 +321,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di override fun navigateToDiscussionResponses( fm: FragmentManager, comment: DiscussionComment, - isClosed: Boolean + isClosed: Boolean, ) { replaceFragmentWithBackStack( fm, @@ -340,7 +349,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di override fun navigateToAnothersProfile( fm: FragmentManager, - username: String + username: String, ) { replaceFragmentWithBackStack( fm, @@ -410,7 +419,7 @@ class AppRouter : AuthRouter, DiscoveryRouter, DashboardRouter, CourseRouter, Di private fun replaceFragment( fm: FragmentManager, fragment: Fragment, - transaction: Int = FragmentTransaction.TRANSIT_NONE + transaction: Int = FragmentTransaction.TRANSIT_NONE, ) { fm.beginTransaction() .setTransition(transaction) diff --git a/app/src/main/java/org/openedx/app/MainFragment.kt b/app/src/main/java/org/openedx/app/MainFragment.kt index fc4fb1b22..7087fee8f 100644 --- a/app/src/main/java/org/openedx/app/MainFragment.kt +++ b/app/src/main/java/org/openedx/app/MainFragment.kt @@ -11,13 +11,12 @@ 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.DashboardNavigator import org.openedx.app.databinding.FragmentMainBinding import org.openedx.core.adapter.NavigationFragmentAdapter import org.openedx.core.presentation.global.app_upgrade.UpgradeRequiredFragment import org.openedx.core.presentation.global.viewBinding -import org.openedx.discovery.presentation.DiscoveryNavigator import org.openedx.discovery.presentation.DiscoveryRouter +import org.openedx.learn.presentation.LearnFragment import org.openedx.profile.presentation.profile.ProfileFragment class MainFragment : Fragment(R.layout.fragment_main) { @@ -97,12 +96,9 @@ class MainFragment : Fragment(R.layout.fragment_main) { binding.viewPager.orientation = ViewPager2.ORIENTATION_HORIZONTAL binding.viewPager.offscreenPageLimit = 4 - val discoveryFragment = DiscoveryNavigator(viewModel.isDiscoveryTypeWebView).getDiscoveryFragment() - val dashboardFragment = DashboardNavigator(viewModel.dashboardType).getDashboardFragment() - adapter = NavigationFragmentAdapter(this).apply { - addFragment(dashboardFragment) - addFragment(discoveryFragment) + addFragment(LearnFragment()) + addFragment(viewModel.getDiscoveryFragment) addFragment(ProfileFragment()) } binding.viewPager.adapter = adapter diff --git a/app/src/main/java/org/openedx/app/MainViewModel.kt b/app/src/main/java/org/openedx/app/MainViewModel.kt index eed901039..f3d62c04f 100644 --- a/app/src/main/java/org/openedx/app/MainViewModel.kt +++ b/app/src/main/java/org/openedx/app/MainViewModel.kt @@ -14,6 +14,8 @@ import org.openedx.core.BaseViewModel import org.openedx.core.config.Config import org.openedx.core.system.notifier.DiscoveryNotifier import org.openedx.core.system.notifier.NavigationToDiscovery +import org.openedx.dashboard.presentation.DashboardRouter +import org.openedx.discovery.presentation.DiscoveryNavigator class MainViewModel( private val config: Config, @@ -30,7 +32,7 @@ class MainViewModel( get() = _navigateToDiscovery.asSharedFlow() val isDiscoveryTypeWebView get() = config.getDiscoveryConfig().isViewTypeWebView() - val dashboardType get() = config.getDashboardConfig().getType() + val getDiscoveryFragment get() = DiscoveryNavigator(isDiscoveryTypeWebView).getDiscoveryFragment() override fun onCreate(owner: LifecycleOwner) { super.onCreate(owner) diff --git a/dashboard/src/main/java/org/openedx/DashboardNavigator.kt b/dashboard/src/main/java/org/openedx/DashboardNavigator.kt index 9e5f4c900..1705860b6 100644 --- a/dashboard/src/main/java/org/openedx/DashboardNavigator.kt +++ b/dashboard/src/main/java/org/openedx/DashboardNavigator.kt @@ -2,15 +2,15 @@ package org.openedx import androidx.fragment.app.Fragment import org.openedx.core.config.DashboardConfig +import org.openedx.courses.presentation.DashboardGalleryFragment import org.openedx.dashboard.presentation.DashboardListFragment -import org.openedx.learn.presentation.LearnFragment class DashboardNavigator( private val dashboardType: DashboardConfig.DashboardType, ) { fun getDashboardFragment(): Fragment { return when (dashboardType) { - DashboardConfig.DashboardType.GALLERY -> LearnFragment() + DashboardConfig.DashboardType.GALLERY -> DashboardGalleryFragment() else -> DashboardListFragment() } } diff --git a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt index 0a7f59c93..31aaa2e3c 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardListFragment.kt @@ -42,6 +42,7 @@ import androidx.compose.material.rememberScaffoldState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.livedata.observeAsState +import androidx.compose.runtime.mutableIntStateOf import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.saveable.rememberSaveable @@ -84,13 +85,11 @@ import org.openedx.core.presentation.global.app_upgrade.AppUpgradeRecommendedBox import org.openedx.core.system.notifier.AppUpgradeEvent import org.openedx.core.ui.HandleUIMessage import org.openedx.core.ui.OfflineModeDialog -import org.openedx.core.ui.Toolbar import org.openedx.core.ui.WindowSize import org.openedx.core.ui.WindowType import org.openedx.core.ui.displayCutoutForLandscape import org.openedx.core.ui.rememberWindowSize import org.openedx.core.ui.shouldLoadMore -import org.openedx.core.ui.statusBarsInset import org.openedx.core.ui.theme.OpenEdXTheme import org.openedx.core.ui.theme.appColors import org.openedx.core.ui.theme.appShapes @@ -158,9 +157,6 @@ class DashboardListFragment : Fragment() { AppUpdateState.openPlayMarket(requireContext()) }, ), - onSettingsClick = { - router.navigateToSettings(requireActivity().supportFragmentManager) - } ) } } @@ -180,7 +176,6 @@ internal fun DashboardListView( onReloadClick: () -> Unit, onSwipeRefresh: () -> Unit, paginationCallback: () -> Unit, - onSettingsClick: () -> Unit, onItemClick: (EnrolledCourse) -> Unit, appUpgradeParameters: AppUpdateState.AppUpgradeParameters, ) { @@ -193,7 +188,7 @@ internal fun DashboardListView( } val scrollState = rememberLazyListState() val firstVisibleIndex = remember { - mutableStateOf(scrollState.firstVisibleItemIndex) + mutableIntStateOf(scrollState.firstVisibleItemIndex) } Scaffold( @@ -244,15 +239,9 @@ internal fun DashboardListView( Column( modifier = Modifier .padding(paddingValues) - .statusBarsInset() .displayCutoutForLandscape(), horizontalAlignment = Alignment.CenterHorizontally ) { - Toolbar( - label = stringResource(id = R.string.dashboard_title), - canShowSettingsIcon = true, - onSettingsClick = onSettingsClick - ) Surface( color = MaterialTheme.appColors.background, @@ -285,12 +274,6 @@ internal fun DashboardListView( state = scrollState, contentPadding = contentPaddings, content = { - item() { - Column { - Header() - Spacer(modifier = Modifier.height(16.dp)) - } - } items(state.courses) { course -> CourseItem( apiHostUrl, @@ -329,7 +312,6 @@ internal fun DashboardListView( .then(contentWidth) .then(emptyStatePaddings) ) { - Header() EmptyState() } } @@ -491,24 +473,6 @@ private fun CourseItem( } } -@Composable -private fun Header() { - Text( - modifier = Modifier.testTag("txt_courses_title"), - text = stringResource(id = R.string.dashboard_courses), - color = MaterialTheme.appColors.textPrimary, - style = MaterialTheme.appTypography.displaySmall - ) - Text( - modifier = Modifier - .testTag("txt_courses_description") - .padding(top = 4.dp), - text = stringResource(id = R.string.dashboard_welcome_back), - color = MaterialTheme.appColors.textPrimaryVariant, - style = MaterialTheme.appTypography.titleSmall - ) -} - @Composable private fun EmptyState() { Box( @@ -542,7 +506,7 @@ private fun EmptyState() { @Preview(uiMode = UI_MODE_NIGHT_YES) @Composable private fun CourseItemPreview() { - OpenEdXTheme() { + OpenEdXTheme { CourseItem( "http://localhost:8000", mockCourseEnrolled, @@ -577,7 +541,6 @@ private fun DashboardListViewPreview() { refreshing = false, canLoadMore = false, paginationCallback = {}, - onSettingsClick = {}, appUpgradeParameters = AppUpdateState.AppUpgradeParameters() ) } @@ -609,7 +572,6 @@ private fun DashboardListViewTabletPreview() { refreshing = false, canLoadMore = false, paginationCallback = {}, - onSettingsClick = {}, appUpgradeParameters = AppUpdateState.AppUpgradeParameters() ) } diff --git a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardRouter.kt b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardRouter.kt index 4d9b5cdbc..2c712bad6 100644 --- a/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardRouter.kt +++ b/dashboard/src/main/java/org/openedx/dashboard/presentation/DashboardRouter.kt @@ -20,5 +20,5 @@ interface DashboardRouter { fun navigateToAllEnrolledCourses(fm: FragmentManager) - fun getProgramFragmentInstance(): Fragment + fun getProgramFragment(): Fragment } diff --git a/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt b/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt index b2de66cd4..7a79f3c2e 100644 --- a/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt +++ b/dashboard/src/main/java/org/openedx/learn/presentation/LearnFragment.kt @@ -39,8 +39,8 @@ import androidx.compose.ui.unit.dp import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentManager import androidx.viewpager2.widget.ViewPager2 -import org.koin.android.ext.android.inject import org.koin.androidx.compose.koinViewModel +import org.koin.androidx.viewmodel.ext.android.viewModel import org.openedx.core.adapter.NavigationFragmentAdapter import org.openedx.core.presentation.global.viewBinding import org.openedx.core.ui.crop @@ -51,17 +51,15 @@ import org.openedx.core.ui.theme.OpenEdXTheme import org.openedx.core.ui.theme.appColors import org.openedx.core.ui.theme.appTypography import org.openedx.core.ui.windowSizeValue -import org.openedx.courses.presentation.DashboardGalleryFragment import org.openedx.dashboard.R import org.openedx.dashboard.databinding.FragmentLearnBinding -import org.openedx.dashboard.presentation.DashboardRouter import org.openedx.learn.LearnType import org.openedx.core.R as CoreR class LearnFragment : Fragment(R.layout.fragment_learn) { private val binding by viewBinding(FragmentLearnBinding::bind) - private val router by inject() + private val viewModel by viewModel() private lateinit var adapter: NavigationFragmentAdapter override fun onViewCreated(view: View, savedInstanceState: Bundle?) { @@ -82,8 +80,8 @@ class LearnFragment : Fragment(R.layout.fragment_learn) { binding.viewPager.offscreenPageLimit = 2 adapter = NavigationFragmentAdapter(this).apply { - addFragment(DashboardGalleryFragment()) - addFragment(router.getProgramFragmentInstance()) + addFragment(viewModel.getDashboardFragment) + addFragment(viewModel.getProgramFragment) } binding.viewPager.adapter = adapter binding.viewPager.setUserInputEnabled(false) @@ -93,7 +91,7 @@ class LearnFragment : Fragment(R.layout.fragment_learn) { @Composable private fun Header( fragmentManager: FragmentManager, - viewPager: ViewPager2 + viewPager: ViewPager2, ) { val viewModel: LearnViewModel = koinViewModel() val windowSize = rememberWindowSize() @@ -120,7 +118,6 @@ private fun Header( viewModel.onSettingsClick(fragmentManager) } ) - if (viewModel.isProgramTypeWebView) { LearnDropdownMenu( modifier = Modifier @@ -136,7 +133,7 @@ private fun Header( private fun Title( modifier: Modifier = Modifier, label: String, - onSettingsClick: () -> Unit + onSettingsClick: () -> Unit, ) { Box( modifier = modifier.fillMaxWidth() @@ -169,7 +166,7 @@ private fun Title( @Composable private fun LearnDropdownMenu( modifier: Modifier = Modifier, - viewPager: ViewPager2 + viewPager: ViewPager2, ) { var expanded by remember { mutableStateOf(false) } var currentValue by remember { mutableStateOf(LearnType.COURSES) } @@ -212,7 +209,12 @@ private fun LearnDropdownMenu( MaterialTheme( colors = MaterialTheme.colors.copy(surface = MaterialTheme.appColors.background), - shapes = MaterialTheme.shapes.copy(medium = RoundedCornerShape(bottomStart = 8.dp, bottomEnd = 8.dp)) + shapes = MaterialTheme.shapes.copy( + medium = RoundedCornerShape( + bottomStart = 8.dp, + bottomEnd = 8.dp + ) + ) ) { DropdownMenu( modifier = Modifier diff --git a/dashboard/src/main/java/org/openedx/learn/presentation/LearnViewModel.kt b/dashboard/src/main/java/org/openedx/learn/presentation/LearnViewModel.kt index d2300f652..62ee774cb 100644 --- a/dashboard/src/main/java/org/openedx/learn/presentation/LearnViewModel.kt +++ b/dashboard/src/main/java/org/openedx/learn/presentation/LearnViewModel.kt @@ -1,18 +1,24 @@ package org.openedx.learn.presentation import androidx.fragment.app.FragmentManager +import org.openedx.DashboardNavigator import org.openedx.core.BaseViewModel import org.openedx.core.config.Config import org.openedx.dashboard.presentation.DashboardRouter class LearnViewModel( private val config: Config, - private val dashboardRouter: DashboardRouter + private val dashboardRouter: DashboardRouter, ) : BaseViewModel() { + private val dashboardType get() = config.getDashboardConfig().getType() val isProgramTypeWebView get() = config.getProgramConfig().isViewTypeWebView() fun onSettingsClick(fragmentManager: FragmentManager) { dashboardRouter.navigateToSettings(fragmentManager) } + + val getDashboardFragment get() = DashboardNavigator(dashboardType).getDashboardFragment() + + val getProgramFragment get() = dashboardRouter.getProgramFragment() } diff --git a/dashboard/src/main/res/values-uk/strings.xml b/dashboard/src/main/res/values-uk/strings.xml index a7b3ef9d3..bf1c7da16 100644 --- a/dashboard/src/main/res/values-uk/strings.xml +++ b/dashboard/src/main/res/values-uk/strings.xml @@ -1,8 +1,6 @@ - Мої курси Курси - Ласкаво просимо назад. Продовжуймо навчатися. You are not enrolled in any courses yet. \ No newline at end of file diff --git a/dashboard/src/main/res/values/strings.xml b/dashboard/src/main/res/values/strings.xml index 4ca0c4fce..529f64fbf 100644 --- a/dashboard/src/main/res/values/strings.xml +++ b/dashboard/src/main/res/values/strings.xml @@ -1,8 +1,6 @@ - Dashboard Courses - Welcome back. Let\'s keep learning. You are not enrolled in any courses yet. Learn Programs diff --git a/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramFragment.kt b/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramFragment.kt index 3b74dbc42..ef79e1f32 100644 --- a/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramFragment.kt +++ b/discovery/src/main/java/org/openedx/discovery/presentation/program/ProgramFragment.kt @@ -46,6 +46,7 @@ import kotlinx.coroutines.launch import org.koin.androidx.compose.koinViewModel import org.koin.androidx.viewmodel.ext.android.viewModel import org.openedx.core.extension.loadUrl +import org.openedx.core.extension.takeIfNotEmpty import org.openedx.core.extension.toastMessage import org.openedx.core.presentation.dialog.alert.ActionDialogFragment import org.openedx.core.presentation.dialog.alert.InfoDialogFragment @@ -68,16 +69,15 @@ import org.openedx.discovery.presentation.catalog.WebViewLink import org.openedx.core.R as coreR import org.openedx.discovery.presentation.catalog.WebViewLink.Authority as linkAuthority -class ProgramFragment( - private val myPrograms: Boolean = false, - private val isNestedFragment: Boolean = false -) : Fragment() { +class ProgramFragment : Fragment() { private val viewModel by viewModel() + private var isNestedFragment = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - if (myPrograms.not()) { + isNestedFragment = arguments?.getBoolean(ARG_NESTED_FRAGMENT, false) ?: false + if (isNestedFragment.not()) { lifecycle.addObserver(viewModel) } } @@ -85,7 +85,7 @@ class ProgramFragment( override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, - savedInstanceState: Bundle? + savedInstanceState: Bundle?, ) = ComposeView(requireContext()).apply { setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) setContent { @@ -96,7 +96,7 @@ class ProgramFragment( mutableStateOf(viewModel.hasInternetConnection) } - if (myPrograms.not()) { + if (isNestedFragment.not()) { DisposableEffect(uiState is ProgramUIState.CourseEnrolled) { if (uiState is ProgramUIState.CourseEnrolled) { @@ -157,7 +157,8 @@ class ProgramFragment( } linkAuthority.PROGRAM_INFO, - linkAuthority.COURSE_INFO -> { + linkAuthority.COURSE_INFO, + -> { viewModel.onViewCourseClick( fragmentManager = requireActivity().supportFragmentManager, courseId = param, @@ -198,23 +199,26 @@ class ProgramFragment( } private fun getInitialUrl(): String { - return arguments?.let { args -> - val pathId = args.getString(ARG_PATH_ID) ?: "" - viewModel.programConfig.programDetailUrlTemplate.replace("{$ARG_PATH_ID}", pathId) + val pathId = arguments?.getString(ARG_PATH_ID, "") + return pathId?.takeIfNotEmpty()?.let { + viewModel.programConfig.programDetailUrlTemplate.replace("{$ARG_PATH_ID}", it) } ?: viewModel.programConfig.programUrl } companion object { private const val ARG_PATH_ID = "path_id" + private const val ARG_NESTED_FRAGMENT = "nested_fragment" fun newInstance( - pathId: String, + pathId: String = "", + isNestedFragment: Boolean = false, ): ProgramFragment { - val fragment = ProgramFragment(false) - fragment.arguments = bundleOf( - ARG_PATH_ID to pathId, - ) - return fragment + return ProgramFragment().apply { + arguments = bundleOf( + ARG_PATH_ID to pathId, + ARG_NESTED_FRAGMENT to isNestedFragment + ) + } } } }