Skip to content

Commit

Permalink
Merge pull request #731 from hyperskill/release/1.40
Browse files Browse the repository at this point in the history
Release 1.40
  • Loading branch information
ivan-magda authored Nov 7, 2023
2 parents 9bfed93 + 66f652a commit c2e8d7c
Show file tree
Hide file tree
Showing 65 changed files with 747 additions and 807 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ import androidx.fragment.app.viewModels
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider
import by.kirich1409.viewbindingdelegate.viewBinding
import coil.ImageLoader
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.hyperskill.app.android.HyperskillApp
import org.hyperskill.app.android.R
import org.hyperskill.app.android.core.extensions.argument
import org.hyperskill.app.android.core.view.ui.fragment.parentOfType
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.FragmentStepQuizBinding
import org.hyperskill.app.android.databinding.LayoutStepQuizDescriptionBinding
Expand All @@ -40,7 +40,7 @@ import org.hyperskill.app.android.step_quiz.view.delegate.StepQuizFormDelegate
import org.hyperskill.app.android.step_quiz.view.factory.StepQuizViewStateDelegateFactory
import org.hyperskill.app.android.step_quiz.view.mapper.StepQuizFeedbackMapper
import org.hyperskill.app.android.step_quiz.view.model.StepQuizFeedbackState
import org.hyperskill.app.android.step_quiz_hints.fragment.StepQuizHintsFragment
import org.hyperskill.app.android.step_quiz_hints.delegate.StepQuizHintsDelegate
import org.hyperskill.app.android.step_quiz_parsons.view.dialog.ParsonsStepQuizOnboardingBottomSheetDialogFragment
import org.hyperskill.app.android.view.base.ui.extension.snackbar
import org.hyperskill.app.step.domain.model.BlockName
Expand All @@ -56,6 +56,7 @@ import org.hyperskill.app.step_quiz.presentation.StepQuizViewModel
import org.hyperskill.app.step_quiz.view.mapper.StepQuizStatsTextMapper
import org.hyperskill.app.step_quiz.view.mapper.StepQuizTitleMapper
import org.hyperskill.app.step_quiz_hints.presentation.StepQuizHintsFeature
import org.hyperskill.app.step_quiz_hints.view.mapper.StepQuizHintsViewStateMapper
import ru.nobird.android.view.base.ui.delegate.ViewStateDelegate
import ru.nobird.android.view.base.ui.extension.showIfNotExists
import ru.nobird.app.presentation.redux.container.ReduxView
Expand All @@ -67,10 +68,6 @@ abstract class DefaultStepQuizFragment :
MenuProvider,
ParsonsStepQuizOnboardingBottomSheetDialogFragment.Callback {

companion object {
private const val STEP_HINTS_FRAGMENT_TAG = "step_hints"
}

private lateinit var viewModelFactory: ViewModelProvider.Factory

private val stepQuizViewModel: StepQuizViewModel by viewModels { viewModelFactory }
Expand All @@ -83,6 +80,8 @@ abstract class DefaultStepQuizFragment :
private var stepQuizFormDelegate: StepQuizFormDelegate? = null
private var stepQuizButtonsViewStateDelegate: ViewStateDelegate<StepQuizButtonsState>? = null

private var stepQuizHintsDelegate: StepQuizHintsDelegate? = null

private var stepQuizStatsTextMapper: StepQuizStatsTextMapper? = null
private var stepQuizTitleMapper: StepQuizTitleMapper? = null
private val stepQuizFeedbackMapper by lazy(LazyThreadSafetyMode.NONE) {
Expand All @@ -103,6 +102,10 @@ abstract class DefaultStepQuizFragment :

private var isKeyboardShown: Boolean = false

private val svgImageLoader: ImageLoader by lazy(LazyThreadSafetyMode.NONE) {
HyperskillApp.graph().imageLoadingComponent.imageLoader
}

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
injectComponent()
Expand Down Expand Up @@ -139,6 +142,13 @@ abstract class DefaultStepQuizFragment :
stepQuizFormDelegate = createStepQuizFormDelegate().also { delegate ->
delegate.customizeSubmissionButton(viewBinding.stepQuizButtons.stepQuizSubmitButton)
}
stepQuizHintsDelegate = StepQuizHintsDelegate(
binding = viewBinding.stepQuizHints,
imageLoader = svgImageLoader,
onNewMessage = { message ->
stepQuizViewModel.onNewMessage(StepQuizFeature.Message.StepQuizHintsMessage(message))
}
)
renderStatistics(viewBinding.stepQuizStatistics, step)
initButtonsViewStateDelegate()
setupQuizButtons()
Expand Down Expand Up @@ -199,6 +209,7 @@ abstract class DefaultStepQuizFragment :
stepQuizButtonsViewStateDelegate = null
stepQuizFeedbackBlocksDelegate = null
stepQuizFormDelegate = null
stepQuizHintsDelegate = null
}

override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
Expand Down Expand Up @@ -278,6 +289,9 @@ abstract class DefaultStepQuizFragment :
ParsonsStepQuizOnboardingBottomSheetDialogFragment.newInstance()
.showIfNotExists(childFragmentManager, ParsonsStepQuizOnboardingBottomSheetDialogFragment.TAG)
}
is StepQuizFeature.Action.ViewAction.StepQuizHintsViewAction -> {
stepQuizHintsDelegate?.onAction(action.viewAction)
}
}
}

Expand Down Expand Up @@ -315,7 +329,6 @@ abstract class DefaultStepQuizFragment :
stepQuizFeedbackBlocksDelegate?.setState(StepQuizFeedbackState.Unsupported)
}
is StepQuizFeature.StepQuizState.AttemptLoaded -> {
setStepHintsFragment(step)
renderAttemptLoaded(stepQuizState)
}
else -> {
Expand All @@ -324,6 +337,7 @@ abstract class DefaultStepQuizFragment :
}

renderTheoryButton(state.stepQuizState)
renderHints(state.stepQuizHintsState)

onNewState(state)
}
Expand Down Expand Up @@ -386,14 +400,9 @@ abstract class DefaultStepQuizFragment :
}
}

private fun setStepHintsFragment(step: Step) {
val isFeatureEnabled = StepQuizHintsFeature.isHintsFeatureAvailable(step)
viewBinding.stepQuizHints.isVisible = isFeatureEnabled
if (isFeatureEnabled) {
setChildFragment(R.id.stepQuizHints, STEP_HINTS_FRAGMENT_TAG) {
StepQuizHintsFragment.newInstance(stepRoute, step)
}
}
private fun renderHints(state: StepQuizHintsFeature.State) {
val viewState = StepQuizHintsViewStateMapper.mapState(state)
stepQuizHintsDelegate?.render(requireContext(), viewState)
}

final override fun render(isPracticingLoading: Boolean) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,21 @@ package org.hyperskill.app.android.step_quiz_hints.delegate

import android.content.Context
import android.text.method.LinkMovementMethod
import android.view.ViewGroup
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.core.view.updateMargins
import coil.ImageLoader
import coil.load
import coil.transform.CircleCropTransformation
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import org.hyperskill.app.R
import org.hyperskill.app.android.databinding.LayoutStepQuizHintsBinding
import org.hyperskill.app.reactions.domain.model.ReactionType
import org.hyperskill.app.step_quiz_hints.presentation.StepQuizHintsFeature
import ru.nobird.android.view.base.ui.delegate.ViewStateDelegate
import ru.nobird.android.view.base.ui.extension.setTextIfChanged
import ru.nobird.android.view.base.ui.extension.snackbar

class StepQuizHintsDelegate(
private val binding: LayoutStepQuizHintsBinding,
Expand All @@ -21,7 +26,7 @@ class StepQuizHintsDelegate(
init {
with(binding) {
with(stepQuizSeeHintsButton.root) {
setText(org.hyperskill.app.R.string.step_quiz_hints_show_button_text)
setText(R.string.step_quiz_hints_show_button_text)
setOnClickListener {
onNewMessage(StepQuizHintsFeature.Message.LoadHintButtonClicked)
}
Expand All @@ -31,7 +36,7 @@ class StepQuizHintsDelegate(
stepQuizHintContentTextView.movementMethod = LinkMovementMethod.getInstance()
stepQuizHintContentTextView.setTextIsSelectable(true)

stepQuizSeeNextHintButton.root.setText(org.hyperskill.app.R.string.step_quiz_hints_see_next_hint)
stepQuizSeeNextHintButton.root.setText(R.string.step_quiz_hints_see_next_hint)
stepQuizSeeNextHintButton.root.setOnClickListener {
onNewMessage(StepQuizHintsFeature.Message.LoadHintButtonClicked)
}
Expand All @@ -58,40 +63,67 @@ class StepQuizHintsDelegate(
addState<StepQuizHintsFeature.ViewState.Error>(binding.stepQuizHintsRetryButton)
}

fun onAction(action: StepQuizHintsFeature.Action.ViewAction) {
when (action) {
StepQuizHintsFeature.Action.ViewAction.ShowNetworkError ->
binding.root.snackbar(messageRes = R.string.connection_error)
}
}

fun render(context: Context, state: StepQuizHintsFeature.ViewState) {
viewStateDelegate.switchState(state)
if (state is StepQuizHintsFeature.ViewState.Content.HintCard) {
with(binding.stepQuizHintCard) {
stepQuizHintNameTextView.setTextIfChanged(state.authorName)
stepQuizHintAvatarImageView.load(state.authorAvatar, imageLoader) {
transformations(CircleCropTransformation())
}
if (stepQuizHintContentTextView.originalText != state.hintText) {
stepQuizHintContentTextView.originalText = state.hintText
}
stepQuizHintBeforeRateGroup.isVisible =
state.hintState == StepQuizHintsFeature.ViewState.HintState.REACT_TO_HINT
stepQuizSeeNextHintButton.root.isVisible =
state.hintState == StepQuizHintsFeature.ViewState.HintState.SEE_NEXT_HINT
stepQuizHintDescriptionTextView.isVisible =
state.hintState != StepQuizHintsFeature.ViewState.HintState.SEE_NEXT_HINT
if (state.hintState != StepQuizHintsFeature.ViewState.HintState.SEE_NEXT_HINT) {
@Suppress("KotlinConstantConditions")
stepQuizHintDescriptionTextView.setTextIfChanged(
when (state.hintState) {
StepQuizHintsFeature.ViewState.HintState.REACT_TO_HINT ->
org.hyperskill.app.R.string.step_quiz_hints_helpful_question_text
StepQuizHintsFeature.ViewState.HintState.LAST_HINT ->
org.hyperskill.app.R.string.step_quiz_hints_last_hint_text
StepQuizHintsFeature.ViewState.HintState.SEE_NEXT_HINT ->
error("Can't evaluate text for state = $state")
}.let(context::getString)
binding.root.updateLayoutParams<ViewGroup.MarginLayoutParams> {
updateMargins(
top = if (state is StepQuizHintsFeature.ViewState.Idle) {
0
} else {
context.resources.getDimensionPixelOffset(
org.hyperskill.app.android.R.dimen.step_quiz_hints_top_margin
)
}
if (state.hintState == StepQuizHintsFeature.ViewState.HintState.REACT_TO_HINT) {
stepQuizHintReportTextView.setOnClickListener {
handleHintReportClick(context, onNewMessage)
}
)
}
if (state is StepQuizHintsFeature.ViewState.Content.HintCard) {
renderCardState(state, context)
}
}

private fun renderCardState(
state: StepQuizHintsFeature.ViewState.Content.HintCard,
context: Context
) {
with(binding.stepQuizHintCard) {
stepQuizHintNameTextView.setTextIfChanged(state.authorName)
stepQuizHintAvatarImageView.load(state.authorAvatar, imageLoader) {
transformations(CircleCropTransformation())
}
if (stepQuizHintContentTextView.originalText != state.hintText) {
stepQuizHintContentTextView.originalText = state.hintText
}
stepQuizHintBeforeRateGroup.isVisible =
state.hintState == StepQuizHintsFeature.ViewState.HintState.REACT_TO_HINT
stepQuizSeeNextHintButton.root.isVisible =
state.hintState == StepQuizHintsFeature.ViewState.HintState.SEE_NEXT_HINT
stepQuizHintDescriptionTextView.isVisible =
state.hintState != StepQuizHintsFeature.ViewState.HintState.SEE_NEXT_HINT
if (state.hintState != StepQuizHintsFeature.ViewState.HintState.SEE_NEXT_HINT) {
@Suppress("KotlinConstantConditions")
stepQuizHintDescriptionTextView.setTextIfChanged(
when (state.hintState) {
StepQuizHintsFeature.ViewState.HintState.REACT_TO_HINT ->
R.string.step_quiz_hints_helpful_question_text

StepQuizHintsFeature.ViewState.HintState.LAST_HINT ->
R.string.step_quiz_hints_last_hint_text

StepQuizHintsFeature.ViewState.HintState.SEE_NEXT_HINT ->
error("Can't evaluate text for state = $state")
}.let(context::getString)
)
}
if (state.hintState == StepQuizHintsFeature.ViewState.HintState.REACT_TO_HINT) {
stepQuizHintReportTextView.setOnClickListener {
handleHintReportClick(context, onNewMessage)
}
}
}
Expand All @@ -111,14 +143,14 @@ class StepQuizHintsDelegate(
onNewMessage: (StepQuizHintsFeature.Message) -> Unit
) =
MaterialAlertDialogBuilder(context)
.setTitle(org.hyperskill.app.R.string.step_quiz_hints_report_alert_title)
.setMessage(org.hyperskill.app.R.string.step_quiz_hints_report_alert_text)
.setPositiveButton(org.hyperskill.app.R.string.yes) { dialog, _ ->
.setTitle(R.string.step_quiz_hints_report_alert_title)
.setMessage(R.string.step_quiz_hints_report_alert_text)
.setPositiveButton(R.string.yes) { dialog, _ ->
dialog.dismiss()
onNewMessage(StepQuizHintsFeature.Message.ReportHintNoticeHiddenEventMessage(true))
onNewMessage(StepQuizHintsFeature.Message.ReportHint)
}
.setNegativeButton(org.hyperskill.app.R.string.no) { dialog, _ ->
.setNegativeButton(R.string.no) { dialog, _ ->
dialog.dismiss()
onNewMessage(
StepQuizHintsFeature.Message.ReportHintNoticeHiddenEventMessage(false)
Expand Down

This file was deleted.

Loading

0 comments on commit c2e8d7c

Please sign in to comment.