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

ALTAPPS-506: Shared load gems and streak on the Track screen #315

Merged
merged 21 commits into from
Jan 16, 2023
Merged
Show file tree
Hide file tree
Changes from 14 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
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ import org.hyperskill.app.main.injection.MainComponent
import org.hyperskill.app.main.injection.MainComponentImpl
import org.hyperskill.app.main.injection.PlatformMainComponent
import org.hyperskill.app.main.injection.PlatformMainComponentImpl
import org.hyperskill.app.navigation_bar_items.injection.NavigationBarItemsComponent
import org.hyperskill.app.navigation_bar_items.injection.NavigationBarItemsComponentImpl
import org.hyperskill.app.network.injection.NetworkComponent
import org.hyperskill.app.network.injection.NetworkComponentImpl
import org.hyperskill.app.notification.injection.NotificationComponent
Expand Down Expand Up @@ -99,6 +101,8 @@ import org.hyperskill.app.step_quiz_hints.injection.PlatformStepQuizHintsCompone
import org.hyperskill.app.step_quiz_hints.injection.PlatformStepQuizHintsComponentImpl
import org.hyperskill.app.step_quiz_hints.injection.StepQuizHintsComponent
import org.hyperskill.app.step_quiz_hints.injection.StepQuizHintsComponentImpl
import org.hyperskill.app.streaks.injection.StreaksDataComponent
import org.hyperskill.app.streaks.injection.StreaksDataComponentImpl
import org.hyperskill.app.topics.injection.TopicsDataComponent
import org.hyperskill.app.topics.injection.TopicsDataComponentImpl
import org.hyperskill.app.topics_repetitions.injection.PlatformTopicsRepetitionComponent
Expand Down Expand Up @@ -346,4 +350,10 @@ class AndroidAppComponentImpl(

override fun buildItemsDataComponent(): ItemsDataComponent =
ItemsDataComponentImpl(this)

override fun buildStreaksDataComponent(): StreaksDataComponent =
StreaksDataComponentImpl(this)

override fun buildNavigationBarItemsComponent(): NavigationBarItemsComponent =
NavigationBarItemsComponentImpl(this)
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import org.hyperskill.app.android.view.base.ui.extension.setElevationOnCollapsed
import org.hyperskill.app.android.view.base.ui.extension.snackbar
import org.hyperskill.app.home.presentation.HomeFeature
import org.hyperskill.app.home.presentation.HomeViewModel
import org.hyperskill.app.navigation_bar_items.domain.model.NavigationBarItemsScreen
import org.hyperskill.app.navigation_bar_items.presentation.NavigationBarItemsFeature
import org.hyperskill.app.step.domain.model.StepRoute
import ru.nobird.android.view.base.ui.delegate.ViewStateDelegate
import ru.nobird.android.view.base.ui.extension.showIfNotExists
Expand All @@ -47,7 +49,7 @@ class HomeFragment :

private val viewBinding: FragmentHomeBinding by viewBinding(FragmentHomeBinding::bind)
private val homeViewModel: HomeViewModel by reduxViewModel(this) { viewModelFactory }
private val viewStateDelegate: ViewStateDelegate<HomeFeature.State> = ViewStateDelegate()
private val viewStateDelegate: ViewStateDelegate<HomeFeature.HomeState> = ViewStateDelegate()

private lateinit var problemOfDayCardFormDelegate: ProblemOfDayCardFormDelegate
private val topicsRepetitionDelegate: TopicsRepetitionCardFormDelegate by lazy(LazyThreadSafetyMode.NONE) {
Expand All @@ -59,6 +61,14 @@ class HomeFragment :
override fun onResume(owner: LifecycleOwner) {
super.onResume(owner)
homeViewModel.onNewMessage(HomeFeature.Message.Initialize(forceUpdate = true))
homeViewModel.onNewMessage(
HomeFeature.Message.NavigationBarItemsMessage(
NavigationBarItemsFeature.Message.Initialize(
screen = NavigationBarItemsScreen.HOME,
forceUpdate = true
)
)
)
}
}

Expand All @@ -78,16 +88,30 @@ class HomeFragment :
homeScreenAppBar.setExpanded(true)

homeScreenGemsCountTextView.setOnClickListener {
homeViewModel.onNewMessage(HomeFeature.Message.ClickedGemsBarButtonItem)
requireMainRouter().switch(ProfileScreen(isInitCurrent = true))
homeViewModel.onNewMessage(
HomeFeature.Message.NavigationBarItemsMessage(
NavigationBarItemsFeature.Message.ClickedGems(screen = NavigationBarItemsScreen.HOME)
)
)
}
homeScreenStreakDurationTextView.setOnClickListener {
homeViewModel.onNewMessage(HomeFeature.Message.ClickedStreakBarButtonItem)
requireMainRouter().switch(ProfileScreen(isInitCurrent = true))
homeViewModel.onNewMessage(
HomeFeature.Message.NavigationBarItemsMessage(
NavigationBarItemsFeature.Message.ClickedStreak(screen = NavigationBarItemsScreen.HOME)
)
)
}

homeScreenError.tryAgain.setOnClickListener {
homeViewModel.onNewMessage(HomeFeature.Message.Initialize(forceUpdate = false))
homeViewModel.onNewMessage(HomeFeature.Message.Initialize(forceUpdate = true))
homeViewModel.onNewMessage(
HomeFeature.Message.NavigationBarItemsMessage(
NavigationBarItemsFeature.Message.Initialize(
screen = NavigationBarItemsScreen.HOME,
forceUpdate = true
)
)
)
}
homeScreenKeepLearningInWebButton.setOnClickListener {
homeViewModel.onNewMessage(HomeFeature.Message.ClickedContinueLearningOnWeb)
Expand All @@ -109,6 +133,15 @@ class HomeFragment :

homeViewModel.onNewMessage(HomeFeature.Message.Initialize(forceUpdate = false))
homeViewModel.onNewMessage(HomeFeature.Message.ViewedEventMessage)

homeViewModel.onNewMessage(
HomeFeature.Message.NavigationBarItemsMessage(
NavigationBarItemsFeature.Message.Initialize(
screen = NavigationBarItemsScreen.HOME,
forceUpdate = false
)
)
)
}

override fun onDestroy() {
Expand All @@ -129,10 +162,10 @@ class HomeFragment :

private fun initViewStateDelegate() {
with(viewStateDelegate) {
addState<HomeFeature.State.Idle>()
addState<HomeFeature.State.Loading>(viewBinding.homeScreenSkeleton.root, viewBinding.homeScreenAppBar)
addState<HomeFeature.State.NetworkError>(viewBinding.homeScreenError.root)
addState<HomeFeature.State.Content>(viewBinding.homeScreenContainer, viewBinding.homeScreenAppBar)
addState<HomeFeature.HomeState.Idle>()
addState<HomeFeature.HomeState.Loading>(viewBinding.homeScreenSkeleton.root, viewBinding.homeScreenAppBar)
addState<HomeFeature.HomeState.NetworkError>(viewBinding.homeScreenError.root)
addState<HomeFeature.HomeState.Content>(viewBinding.homeScreenContainer, viewBinding.homeScreenAppBar)
}
}

Expand All @@ -147,29 +180,40 @@ class HomeFragment :
is HomeFeature.Action.ViewAction.NavigateTo.TopicsRepetitionsScreen -> {
requireRouter().navigateTo(TopicsRepetitionScreen())
}
is HomeFeature.Action.ViewAction.NavigationBarItemsViewAction ->
when (action.viewAction) {
is NavigationBarItemsFeature.Action.ViewAction.ShowProfileTab ->
requireMainRouter().switch(ProfileScreen(isInitCurrent = true))
}
else -> {
// no op
}
}
}

override fun render(state: HomeFeature.State) {
viewStateDelegate.switchState(state)
viewStateDelegate.switchState(state.homeState)

TransitionManager.beginDelayedTransition(viewBinding.root, AutoTransition())
if (state is HomeFeature.State.Content) {
if (state.isLoadingMagicLink) {

if (state.homeState is HomeFeature.HomeState.Content) {
val castedHomeState = state.homeState as HomeFeature.HomeState.Content
if (castedHomeState.isLoadingMagicLink) {
LoadingProgressDialogFragment.newInstance()
.showIfNotExists(childFragmentManager, LoadingProgressDialogFragment.TAG)
} else {
childFragmentManager.dismissDialogFragmentIfExists(LoadingProgressDialogFragment.TAG)
}
renderMenuItems(state)
renderProblemOfDayCardDelegate(state.problemOfDayState)
renderTopicsRepetition(state.repetitionsState)
renderProblemOfDayCardDelegate(castedHomeState.problemOfDayState)
renderTopicsRepetition(castedHomeState.repetitionsState)
}

if (state.navigationBarItemsState is NavigationBarItemsFeature.State.Content) {
renderMenuItems(state.navigationBarItemsState as NavigationBarItemsFeature.State.Content)
}
}

private fun renderMenuItems(state: HomeFeature.State.Content) {
private fun renderMenuItems(state: NavigationBarItemsFeature.State.Content) {
with(viewBinding.homeScreenStreakDurationTextView) {
isVisible = true
val streakDuration = state.streak?.currentStreak ?: 0
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import androidx.core.view.isVisible
import org.hyperskill.app.android.R
import org.hyperskill.app.android.databinding.LayoutProfileStreakCardBinding
import org.hyperskill.app.profile.presentation.ProfileFeature
import org.hyperskill.app.streak.domain.model.HistoricalStreak
import org.hyperskill.app.streak.domain.model.Streak
import org.hyperskill.app.streak.domain.model.StreakState
import org.hyperskill.app.streaks.domain.model.HistoricalStreak
import org.hyperskill.app.streaks.domain.model.Streak
import org.hyperskill.app.streaks.domain.model.StreakState
import ru.nobird.android.view.base.ui.extension.setTextIfChanged

class StreakCardFormDelegate(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,23 @@ import coil.ImageLoader
import coil.decode.SvgDecoder
import coil.load
import coil.size.Scale
import kotlin.math.roundToInt
import org.hyperskill.app.SharedResources
import org.hyperskill.app.android.HyperskillApp
import org.hyperskill.app.android.R
import org.hyperskill.app.android.core.extensions.openUrl
import org.hyperskill.app.android.core.view.ui.dialog.LoadingProgressDialogFragment
import org.hyperskill.app.android.core.view.ui.dialog.dismissDialogFragmentIfExists
import org.hyperskill.app.android.core.view.ui.adapter.decoration.HorizontalMarginItemDecoration
import org.hyperskill.app.android.core.view.ui.adapter.decoration.VerticalMarginItemDecoration
import org.hyperskill.app.android.core.view.ui.dialog.LoadingProgressDialogFragment
import org.hyperskill.app.android.core.view.ui.dialog.dismissDialogFragmentIfExists
import org.hyperskill.app.android.core.view.ui.navigation.requireMainRouter
import org.hyperskill.app.android.core.view.ui.navigation.requireRouter
import org.hyperskill.app.android.databinding.FragmentTrackBinding
import org.hyperskill.app.android.profile.view.navigation.ProfileScreen
import org.hyperskill.app.android.step.view.screen.StepScreen
import org.hyperskill.app.android.view.base.ui.extension.snackbar
import org.hyperskill.app.navigation_bar_items.domain.model.NavigationBarItemsScreen
import org.hyperskill.app.navigation_bar_items.presentation.NavigationBarItemsFeature
import org.hyperskill.app.step.domain.model.StepRoute
import org.hyperskill.app.topics.domain.model.Topic
import org.hyperskill.app.track.domain.model.Track
Expand All @@ -39,7 +44,6 @@ import ru.nobird.android.view.base.ui.delegate.ViewStateDelegate
import ru.nobird.android.view.base.ui.extension.showIfNotExists
import ru.nobird.android.view.redux.ui.extension.reduxViewModel
import ru.nobird.app.presentation.redux.container.ReduxView
import kotlin.math.roundToInt

class TrackFragment :
Fragment(R.layout.fragment_track),
Expand All @@ -53,7 +57,7 @@ class TrackFragment :

private val viewBinding: FragmentTrackBinding by viewBinding(FragmentTrackBinding::bind)
private val trackViewModel: TrackViewModel by reduxViewModel(this) { viewModelFactory }
private val viewStateDelegate: ViewStateDelegate<TrackFeature.State> = ViewStateDelegate()
private val viewStateDelegate: ViewStateDelegate<TrackFeature.TrackState> = ViewStateDelegate()

private val nextTopicsAdapter by lazy(LazyThreadSafetyMode.NONE) {
DefaultDelegateAdapter<Topic>().apply {
Expand All @@ -71,10 +75,26 @@ class TrackFragment :
initViewStateDelegate()
viewBinding.trackError.tryAgain.setOnClickListener {
trackViewModel.onNewMessage(TrackFeature.Message.Initialize(forceUpdate = true))
// TODO: Delete before merge or support in Android
trackViewModel.onNewMessage(
TrackFeature.Message.NavigationBarItemsMessage(
NavigationBarItemsFeature.Message.Initialize(
screen = NavigationBarItemsScreen.TRACK,
forceUpdate = true
)
)
)
}
setupTopicsRecycler()
trackViewModel.onNewMessage(TrackFeature.Message.Initialize())
trackViewModel.onNewMessage(TrackFeature.Message.ViewedEventMessage)

// TODO: Delete before merge or support in Android
trackViewModel.onNewMessage(
TrackFeature.Message.NavigationBarItemsMessage(
NavigationBarItemsFeature.Message.Initialize(NavigationBarItemsScreen.TRACK)
)
)
}

private fun injectComponents() {
Expand All @@ -85,10 +105,10 @@ class TrackFragment :

private fun initViewStateDelegate() {
with(viewStateDelegate) {
addState<TrackFeature.State.Idle>()
addState<TrackFeature.State.Loading>(viewBinding.trackSkeleton.root)
addState<TrackFeature.State.NetworkError>(viewBinding.trackError.root)
addState<TrackFeature.State.Content>(viewBinding.trackContainer)
addState<TrackFeature.TrackState.Idle>()
addState<TrackFeature.TrackState.Loading>(viewBinding.trackSkeleton.root)
addState<TrackFeature.TrackState.NetworkError>(viewBinding.trackError.root)
addState<TrackFeature.TrackState.Content>(viewBinding.trackContainer)
}
}

Expand All @@ -100,6 +120,11 @@ class TrackFragment :
requireContext().openUrl(action.url)
is TrackFeature.Action.ViewAction.ShowGetMagicLinkError ->
viewBinding.root.snackbar(SharedResources.strings.common_error.resourceId)
is TrackFeature.Action.ViewAction.NavigationBarItemsViewAction ->
when (action.viewAction) {
is NavigationBarItemsFeature.Action.ViewAction.ShowProfileTab ->
requireMainRouter().switch(ProfileScreen(isInitCurrent = true))
}
}
}

Expand All @@ -125,14 +150,14 @@ class TrackFragment :
}

override fun render(state: TrackFeature.State) {
viewStateDelegate.switchState(state)
viewStateDelegate.switchState(state.trackState)
TransitionManager.beginDelayedTransition(viewBinding.root, AutoTransition())
if (state is TrackFeature.State.Content) {
renderContent(state)
if (state.trackState is TrackFeature.TrackState.Content) {
renderContent(state.trackState as TrackFeature.TrackState.Content)
}
}

private fun renderContent(content: TrackFeature.State.Content) {
private fun renderContent(content: TrackFeature.TrackState.Content) {
if (content.isLoadingMagicLink) {
LoadingProgressDialogFragment.newInstance()
.showIfNotExists(childFragmentManager, LoadingProgressDialogFragment.TAG)
Expand Down Expand Up @@ -161,7 +186,7 @@ class TrackFragment :
viewBinding.trackNameTextView.text = track.title
}

private fun renderCards(content: TrackFeature.State.Content) {
private fun renderCards(content: TrackFeature.TrackState.Content) {
with(viewBinding) {
if (content.studyPlan != null) {
trackTimeToCompleteTextView.text =
Expand Down Expand Up @@ -201,7 +226,7 @@ class TrackFragment :
}
}

private fun renderAboutSection(content: TrackFeature.State.Content) {
private fun renderAboutSection(content: TrackFeature.TrackState.Content) {
with(viewBinding) {
trackAboutUsefulnessTextView.text = "${content.trackProgress.averageRating}"
val hoursToComplete = (content.track.secondsToComplete / 3600).roundToInt()
Expand Down
Loading