Skip to content

Commit

Permalink
Merge pull request #420 from hyperskill/release/1.13
Browse files Browse the repository at this point in the history
Release 1.13
  • Loading branch information
ivan-magda authored Apr 4, 2023
2 parents 56c281d + 35e9188 commit 94f0731
Show file tree
Hide file tree
Showing 64 changed files with 880 additions and 172 deletions.
7 changes: 5 additions & 2 deletions androidHyperskillApp/fastlane/release-notes.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
What to Test:
1. Dark mode support for the code editor ALTAPPS-583
2. Fix passed tracks count calculation ALTAPPS-646
1. Optimize determine user account on application launch ALTAPPS-532
2. Daily limits for learners with Freemium ALTAPPS-668
3. Fix next topic card can't be render if there is no topic to load ALTAPPS-689
4. Fix app crash after limit is reached bottom sheet (navigate to HomeScreen) ALTAPPS-692
5. Fix app blocked if no track selected in mobile and selected in web in the same time ALTAPPS-693
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.Context
import org.hyperskill.app.android.code.injection.PlatformCodeEditorComponent
import org.hyperskill.app.android.image_loading.injection.ImageLoadingComponent
import org.hyperskill.app.android.latex.injection.PlatformLatexComponent
import org.hyperskill.app.android.main.injection.NavigationComponent
import org.hyperskill.app.android.notification.injection.PlatformNotificationComponent
import org.hyperskill.app.auth.injection.AuthCredentialsComponent
import org.hyperskill.app.auth.injection.AuthSocialComponent
Expand All @@ -20,6 +21,7 @@ import org.hyperskill.app.onboarding.injection.OnboardingComponent
import org.hyperskill.app.onboarding.injection.PlatformOnboardingComponent
import org.hyperskill.app.placeholder_new_user.injection.PlaceholderNewUserComponent
import org.hyperskill.app.placeholder_new_user.injection.PlatformPlaceholderNewUserComponent
import org.hyperskill.app.problems_limit.injection.PlatformProblemsLimitComponent
import org.hyperskill.app.profile.injection.PlatformProfileComponent
import org.hyperskill.app.profile.injection.ProfileComponent
import org.hyperskill.app.profile_settings.injection.PlatformProfileSettingsComponent
Expand All @@ -41,6 +43,7 @@ interface AndroidAppComponent : AppGraph {
val platformMainComponent: PlatformMainComponent
val platformNotificationComponent: PlatformNotificationComponent
val imageLoadingComponent: ImageLoadingComponent
val navigationComponent: NavigationComponent

fun buildPlatformAuthSocialWebViewComponent(): PlatformAuthSocialWebViewComponent
fun buildPlatformAuthSocialComponent(authSocialComponent: AuthSocialComponent): PlatformAuthSocialComponent
Expand All @@ -59,4 +62,6 @@ interface AndroidAppComponent : AppGraph {
fun buildPlatformTopicsRepetitionsComponent(): PlatformTopicsRepetitionComponent
fun buildPlatformDebugComponent(debugComponent: DebugComponent): PlatformDebugComponent
fun buildPlatformStageImplementationComponent(projectId: Long, stageId: Long): PlatformStageImplementationComponent

fun buildPlatformProblemsLimitComponent(): PlatformProblemsLimitComponent
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ import org.hyperskill.app.android.image_loading.injection.ImageLoadingComponent
import org.hyperskill.app.android.image_loading.injection.ImageLoadingComponentImpl
import org.hyperskill.app.android.latex.injection.PlatformLatexComponent
import org.hyperskill.app.android.latex.injection.PlatformLatexComponentImpl
import org.hyperskill.app.android.main.injection.NavigationComponent
import org.hyperskill.app.android.main.injection.NavigationComponentImpl
import org.hyperskill.app.android.notification.injection.PlatformNotificationComponent
import org.hyperskill.app.android.notification.injection.PlatformNotificationComponentImpl
import org.hyperskill.app.android.sentry.domain.model.manager.SentryManagerImpl
Expand All @@ -30,6 +32,8 @@ import org.hyperskill.app.comments.injection.CommentsDataComponentImpl
import org.hyperskill.app.core.domain.BuildVariant
import org.hyperskill.app.core.injection.CommonComponent
import org.hyperskill.app.core.injection.CommonComponentImpl
import org.hyperskill.app.core.injection.StateRepositoriesComponent
import org.hyperskill.app.core.injection.StateRepositoriesComponentImpl
import org.hyperskill.app.core.remote.UserAgentInfo
import org.hyperskill.app.debug.injection.DebugComponent
import org.hyperskill.app.debug.injection.DebugComponentImpl
Expand Down Expand Up @@ -73,6 +77,8 @@ import org.hyperskill.app.placeholder_new_user.injection.PlaceholderNewUserCompo
import org.hyperskill.app.placeholder_new_user.injection.PlaceholderNewUserComponentImpl
import org.hyperskill.app.placeholder_new_user.injection.PlatformPlaceholderNewUserComponent
import org.hyperskill.app.placeholder_new_user.injection.PlatformPlaceholderNewUserComponentImpl
import org.hyperskill.app.problems_limit.injection.PlatformProblemsLimitComponent
import org.hyperskill.app.problems_limit.injection.PlatformProblemsLimitComponentImpl
import org.hyperskill.app.problems_limit.injection.ProblemsLimitComponent
import org.hyperskill.app.problems_limit.injection.ProblemsLimitComponentImpl
import org.hyperskill.app.products.injection.ProductsDataComponent
Expand Down Expand Up @@ -132,8 +138,6 @@ import org.hyperskill.app.streaks.injection.StreaksDataComponent
import org.hyperskill.app.streaks.injection.StreaksDataComponentImpl
import org.hyperskill.app.study_plan.injection.StudyPlanDataComponent
import org.hyperskill.app.study_plan.injection.StudyPlanDataComponentImpl
import org.hyperskill.app.subscriptions.injection.SubscriptionsDataComponent
import org.hyperskill.app.subscriptions.injection.SubscriptionsDataComponentImpl
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 @@ -187,6 +191,9 @@ class AndroidAppComponentImpl(
override val authComponent: AuthComponent =
AuthComponentImpl(this)

override val navigationComponent: NavigationComponent =
NavigationComponentImpl()

override val profileHypercoinsDataComponent: ProfileHypercoinsDataComponent =
ProfileHypercoinsDataComponentImpl()

Expand All @@ -205,8 +212,8 @@ class AndroidAppComponentImpl(
override val notificationFlowDataComponent: NotificationFlowDataComponent =
NotificationFlowDataComponentImpl()

override val subscriptionsDataComponent: SubscriptionsDataComponent =
SubscriptionsDataComponentImpl(this)
override val stateRepositoriesComponent: StateRepositoriesComponent =
StateRepositoriesComponentImpl(this)

override val sentryComponent: SentryComponent =
SentryComponentImpl(SentryManagerImpl(commonComponent.buildKonfig))
Expand Down Expand Up @@ -414,6 +421,15 @@ class AndroidAppComponentImpl(
override fun buildTopicsToDiscoverNextDataComponent(): TopicsToDiscoverNextDataComponent =
TopicsToDiscoverNextDataComponentImpl(this)

/**
* ProblemsLimit component
*/
override fun buildProblemsLimitComponent(): ProblemsLimitComponent =
ProblemsLimitComponentImpl(this)

override fun buildPlatformProblemsLimitComponent(): PlatformProblemsLimitComponent =
PlatformProblemsLimitComponentImpl(problemsLimitComponent = buildProblemsLimitComponent())

override fun buildUserStorageComponent(): UserStorageComponent =
UserStorageComponentImpl(this)

Expand Down Expand Up @@ -464,7 +480,4 @@ class AndroidAppComponentImpl(

override fun buildFreemiumDataComponent(): FreemiumDataComponent =
FreemiumDataComponentImpl(this)

override fun buildProblemsLimitComponent(): ProblemsLimitComponent =
ProblemsLimitComponentImpl(this)
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
package org.hyperskill.app.android.core.view.ui.navigation

import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import com.github.terrakok.cicerone.Router
import org.hyperskill.app.android.core.view.ui.fragment.parentOfType
import ru.nobird.android.view.navigation.router.RetainedRouter
import ru.nobird.android.view.navigation.ui.fragment.NavigationContainer
import ru.nobird.app.core.model.safeCast
import org.hyperskill.app.android.main.view.ui.navigation.MainScreen

fun Fragment.requireAppRouter(): Router =
requireNotNull(parentOfType(AppNavigationContainer::class.java)?.router) {
Expand All @@ -18,19 +14,3 @@ fun Fragment.requireRouter(): Router =
requireNotNull(parentOfType(NavigationContainer::class.java)?.router) {
"Fragment $this not attached to a NavigationContainer."
}

/**
* Is used to retrieve router from [MainScreen]s child fragment
* */
fun Fragment.requireMainRouter(): RetainedRouter =
requireNotNull(parentOfType(MainNavigationContainer::class.java)?.router) {
"Fragment $this not attached to a MainNavigationContainer."
}

/**
* I used to retrieve router from non [MainScreen]s child fragment.
* */
fun FragmentManager.requireMainRouter(): RetainedRouter =
requireNotNull(findFragmentByTag(MainNavigationContainer.ContainerTag)?.safeCast<MainNavigationContainer>()?.router) {
"FragmentManger $this does not contain Fragment implemented MainNavigationContainer"
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,13 @@ 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.navigation.requireMainRouter
import org.hyperskill.app.android.core.view.ui.fragment.setChildFragment
import org.hyperskill.app.android.core.view.ui.navigation.requireRouter
import org.hyperskill.app.android.databinding.FragmentHomeBinding
import org.hyperskill.app.android.gamification_toolbar.view.ui.delegate.GamificationToolbarDelegate
import org.hyperskill.app.android.main.view.ui.navigation.MainScreenRouter
import org.hyperskill.app.android.problem_of_day.view.delegate.ProblemOfDayCardFormDelegate
import org.hyperskill.app.android.problems_limit.fragment.ProblemsLimitFragment
import org.hyperskill.app.android.profile.view.navigation.ProfileScreen
import org.hyperskill.app.android.step.view.screen.StepScreen
import org.hyperskill.app.android.topics.view.delegate.TopicsToDiscoverNextDelegate
Expand Down Expand Up @@ -82,6 +84,9 @@ class HomeFragment :
}
}

private val mainScreenRouter: MainScreenRouter =
HyperskillApp.graph().navigationComponent.mainScreenCicerone.router

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
injectComponents()
Expand All @@ -90,6 +95,7 @@ class HomeFragment :

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setProblemsLimitFragment()
initViewStateDelegate()
initGamificationToolbarDelegate()
problemOfDayCardFormDelegate.setup(viewBinding.homeScreenProblemOfDayCard)
Expand All @@ -114,10 +120,14 @@ class HomeFragment :
homeViewModel.onNewMessage(HomeFeature.Message.ViewedEventMessage)
}

override fun onDestroyView() {
super.onDestroyView()
gamificationToolbarDelegate = null
}

override fun onDestroy() {
super.onDestroy()
requireActivity().lifecycle.removeObserver(onForegroundObserver)
gamificationToolbarDelegate = null
}

private fun injectComponents() {
Expand Down Expand Up @@ -147,7 +157,8 @@ class HomeFragment :
viewBinding.homeScreenKeepPracticingTextView,
viewBinding.homeScreenProblemOfDayCard.root,
viewBinding.homeScreenTopicsRepetitionCard.root,
viewBinding.homeScreenKeepLearningInWebButton
viewBinding.homeScreenKeepLearningInWebButton,
viewBinding.homeProblemsLimit
)
}
}
Expand Down Expand Up @@ -178,7 +189,7 @@ class HomeFragment :
is HomeFeature.Action.ViewAction.GamificationToolbarViewAction ->
when (action.viewAction) {
is GamificationToolbarFeature.Action.ViewAction.ShowProfileTab ->
requireMainRouter().switch(ProfileScreen(isInitCurrent = true))
mainScreenRouter.switch(ProfileScreen(isInitCurrent = true))
}
is HomeFeature.Action.ViewAction.TopicsToDiscoverNextViewAction -> {
when (action.viewAction) {
Expand All @@ -201,8 +212,8 @@ class HomeFragment :
val homeState = state.homeState
if (homeState is HomeFeature.HomeState.Content) {
renderMagicLinkState(homeState.isLoadingMagicLink)
renderProblemOfDay(viewBinding, homeState.problemOfDayState)
renderTopicsRepetition(homeState.repetitionsState)
renderProblemOfDay(viewBinding, homeState.problemOfDayState, homeState.isFreemiumEnabled)
renderTopicsRepetition(homeState.repetitionsState, homeState.isFreemiumEnabled)
}

gamificationToolbarDelegate?.render(state.toolbarState)
Expand All @@ -219,20 +230,33 @@ class HomeFragment :
}
}

private fun renderProblemOfDay(viewBinding: FragmentHomeBinding, state: HomeFeature.ProblemOfDayState) {
problemOfDayCardFormDelegate.render(requireContext(), viewBinding.homeScreenProblemOfDayCard, state)
private fun renderProblemOfDay(
viewBinding: FragmentHomeBinding,
state: HomeFeature.ProblemOfDayState,
isFreemiumEnabled: Boolean
) {
problemOfDayCardFormDelegate.render(
context = requireContext(),
binding = viewBinding.homeScreenProblemOfDayCard,
state = state,
isFreemiumEnabled = isFreemiumEnabled
)
viewBinding.homeScreenKeepLearningInWebButton.isVisible =
state is HomeFeature.ProblemOfDayState.Solved || state is HomeFeature.ProblemOfDayState.Empty
}

private fun renderTopicsRepetition(repetitionsState: HomeFeature.RepetitionsState) {
private fun renderTopicsRepetition(
repetitionsState: HomeFeature.RepetitionsState,
isFreemiumEnabled: Boolean
) {
viewBinding.homeScreenTopicsRepetitionCard.root.isVisible =
repetitionsState is HomeFeature.RepetitionsState.Available
if (repetitionsState is HomeFeature.RepetitionsState.Available) {
topicsRepetitionDelegate.render(
requireContext(),
viewBinding.homeScreenTopicsRepetitionCard,
repetitionsState.recommendedRepetitionsCount
context = requireContext(),
binding = viewBinding.homeScreenTopicsRepetitionCard,
recommendedRepetitionsCount = repetitionsState.recommendedRepetitionsCount,
isFreemiumEnabled = isFreemiumEnabled
)
}
}
Expand All @@ -247,4 +271,10 @@ class HomeFragment :
}
topicsToDiscoverNextDelegate.render(state)
}

private fun setProblemsLimitFragment() {
setChildFragment(R.id.homeProblemsLimit, ProblemsLimitFragment.TAG) {
ProblemsLimitFragment.newInstance()
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package org.hyperskill.app.android.main.injection

import com.github.terrakok.cicerone.Cicerone
import org.hyperskill.app.android.main.view.ui.navigation.MainScreenRouter

interface NavigationComponent {
val mainScreenCicerone: Cicerone<MainScreenRouter>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.hyperskill.app.android.main.injection

import com.github.terrakok.cicerone.Cicerone
import org.hyperskill.app.android.main.view.ui.navigation.MainScreenRouter

class NavigationComponentImpl : NavigationComponent {

override val mainScreenCicerone: Cicerone<MainScreenRouter> by lazy {
Cicerone.create(MainScreenRouter())
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package org.hyperskill.app.android.main.view.ui.activity

import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner

class BackToForegroundObserver(
private val onBackToForeground: () -> Unit
) : DefaultLifecycleObserver {

private var hasBeenStopped: Boolean = false

override fun onStart(owner: LifecycleOwner) {
if (hasBeenStopped) {
onBackToForeground()
hasBeenStopped = false
}
}

override fun onStop(owner: LifecycleOwner) {
hasBeenStopped = true
}

override fun onDestroy(owner: LifecycleOwner) {
owner.lifecycle.removeObserver(this)
}
}
Loading

0 comments on commit 94f0731

Please sign in to comment.