Skip to content

Commit

Permalink
Implement input editing
Browse files Browse the repository at this point in the history
  • Loading branch information
XanderZhu committed Oct 18, 2023
1 parent 1517904 commit 6bc815f
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,13 @@ package org.hyperskill.app.android.step_quiz_fill_blanks.delegate

import android.widget.TextView
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.FragmentManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.flexbox.FlexboxLayoutManager
import org.hyperskill.app.android.R
import org.hyperskill.app.android.databinding.LayoutStepQuizFillBlanksBindingBinding
import org.hyperskill.app.android.step_quiz.view.delegate.StepQuizFormDelegate
import org.hyperskill.app.android.step_quiz_fill_blanks.dialog.FillBlanksInputDialogFragment
import org.hyperskill.app.step_quiz.domain.model.submissions.Reply
import org.hyperskill.app.step_quiz.presentation.StepQuizFeature
import org.hyperskill.app.step_quiz_fill_blanks.model.FillBlanksItem
Expand All @@ -15,15 +18,19 @@ import org.hyperskill.app.step_quiz_fill_blanks.presentation.FillBlanksResolver
import ru.nobird.android.ui.adapterdelegates.dsl.adapterDelegate
import ru.nobird.android.ui.adapters.DefaultDelegateAdapter
import ru.nobird.android.view.base.ui.extension.setTextIfChanged
import ru.nobird.android.view.base.ui.extension.showIfNotExists
import ru.nobird.app.core.model.mutate

class FillBlanksStepQuizFormDelegate(
private val binding: LayoutStepQuizFillBlanksBindingBinding
private val binding: LayoutStepQuizFillBlanksBindingBinding,
private val fragmentManager: FragmentManager,
private val onQuizChanged: (Reply) -> Unit
) : StepQuizFormDelegate {

private val fillBlanksAdapter = DefaultDelegateAdapter<FillBlanksItem>().apply {
addDelegate(textAdapterDelegate())
addDelegate(
inputAdapterDelegate { _, _ -> }
inputAdapterDelegate(::onInputItemClick)
)
}

Expand Down Expand Up @@ -76,6 +83,15 @@ class FillBlanksStepQuizFormDelegate(
}
)

fun onInputItemModified(index: Int, text: String) {
fillBlanksAdapter.items = fillBlanksAdapter.items.mutate {
val inputItem = get(index) as FillBlanksItem.Input
set(index, inputItem.copy(inputText = text))
}
fillBlanksAdapter.notifyItemChanged(index)
onQuizChanged(createReply())
}

private fun textAdapterDelegate() =
adapterDelegate<FillBlanksItem, FillBlanksItem.Text>(R.layout.item_step_quiz_fill_blanks_text) {
val textView = itemView as TextView
Expand All @@ -87,14 +103,26 @@ class FillBlanksStepQuizFormDelegate(
}
}

private fun inputAdapterDelegate(onClick: (Int, String) -> Unit) =
private fun inputAdapterDelegate(onClick: (index: Int, String) -> Unit) =
adapterDelegate<FillBlanksItem, FillBlanksItem.Input>(R.layout.item_step_quiz_fill_blanks_input) {
val textView = itemView as TextView
textView.setOnClickListener {
val position = bindingAdapterPosition
if (position != RecyclerView.NO_POSITION) {
onClick(position, textView.text.toString())
}
}
onBind { inputItem ->
textView.setTextIfChanged(inputItem.inputText ?: "")
}
}

private fun onInputItemClick(index: Int, text: String) {
FillBlanksInputDialogFragment
.newInstance(index, text)
.showIfNotExists(fragmentManager, FillBlanksInputDialogFragment.TAG)
}

private enum class ResolveState {
NOT_RESOLVED,
RESOLVE_SUCCEED,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package org.hyperskill.app.android.step_quiz_fill_blanks.dialog

import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.inputmethod.EditorInfo
import android.view.inputmethod.InputMethodManager
import by.kirich1409.viewbindingdelegate.viewBinding
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import org.hyperskill.app.android.R
import org.hyperskill.app.android.databinding.FragmentFillBlanksInputBinding
import ru.nobird.android.view.base.ui.extension.argument

class FillBlanksInputDialogFragment : BottomSheetDialogFragment() {
companion object {
const val TAG: String = "FillBlanksInputDialogFragment"

private const val ARG_INDEX = "INDEX"
private const val ARG_TEXT = "TEXT"

fun newInstance(
index: Int,
text: String
): FillBlanksInputDialogFragment =
FillBlanksInputDialogFragment().apply {
this.index = index
this.text = text
}
}

private var index: Int by argument()
private var text: String by argument()

private val fillBlanksInputBinding: FragmentFillBlanksInputBinding by viewBinding(
FragmentFillBlanksInputBinding::bind
)

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setStyle(STYLE_NO_TITLE, R.style.TopCornersRoundedBottomSheetDialog)
}

override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? =
inflater.inflate(R.layout.fragment_fill_blanks_input, container, false)

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)

if (savedInstanceState != null) {
index = savedInstanceState.getInt(ARG_INDEX)
text = savedInstanceState.getString(ARG_TEXT) ?: return
}
with(fillBlanksInputBinding) {
fillBlanksInputField.append(text)
fillBlanksInputField.setOnEditorActionListener { _, actionId, _ ->
if (actionId == EditorInfo.IME_ACTION_DONE) {
super.dismiss()
}
false
}
fillBlanksInputField.post {
fillBlanksInputField.requestFocus()
val inputMethodManager =
requireContext().getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
inputMethodManager.showSoftInput(fillBlanksInputField, InputMethodManager.SHOW_IMPLICIT)
}
}
}

override fun onPause() {
(parentFragment as? Callback)
?.onSyncInputItemWithParent(
index = index,
text = fillBlanksInputBinding.fillBlanksInputField.text.toString()
)
super.onPause()
}

override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putInt(ARG_INDEX, index)
outState.putString(ARG_TEXT, text)
}

interface Callback {
fun onSyncInputItemWithParent(index: Int, text: String)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,13 @@ import org.hyperskill.app.android.databinding.LayoutStepQuizFillBlanksBindingBin
import org.hyperskill.app.android.step_quiz.view.delegate.StepQuizFormDelegate
import org.hyperskill.app.android.step_quiz.view.fragment.DefaultStepQuizFragment
import org.hyperskill.app.android.step_quiz_fill_blanks.delegate.FillBlanksStepQuizFormDelegate
import org.hyperskill.app.android.step_quiz_fill_blanks.dialog.FillBlanksInputDialogFragment
import org.hyperskill.app.step.domain.model.Step
import org.hyperskill.app.step.domain.model.StepRoute

class FillBlanksQuizFragment : DefaultStepQuizFragment() {
class FillBlanksQuizFragment :
DefaultStepQuizFragment(),
FillBlanksInputDialogFragment.Callback {

companion object {
fun newInstance(
Expand All @@ -28,6 +31,8 @@ class FillBlanksQuizFragment : DefaultStepQuizFragment() {
private val binding: LayoutStepQuizFillBlanksBindingBinding
get() = requireNotNull(_binding)

private var fillBlanksStepQuizFormDelegate: FillBlanksStepQuizFormDelegate? = null

override val quizViews: Array<View>
get() = arrayOf(binding.stepQuizFillBlanksContainer)
override val skeletonView: View
Expand All @@ -42,10 +47,21 @@ class FillBlanksQuizFragment : DefaultStepQuizFragment() {
}

override fun createStepQuizFormDelegate(): StepQuizFormDelegate =
FillBlanksStepQuizFormDelegate(binding)
FillBlanksStepQuizFormDelegate(
binding = binding,
fragmentManager = childFragmentManager,
onQuizChanged = ::syncReplyState
).also {
this.fillBlanksStepQuizFormDelegate = it
}

override fun onDestroyView() {
super.onDestroyView()
_binding = null
fillBlanksStepQuizFormDelegate = null
}

override fun onSyncInputItemWithParent(index: Int, text: String) {
fillBlanksStepQuizFormDelegate?.onInputItemModified(index, text)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<stroke
android:width="1dp"
android:color="@color/color_primary" />
<corners android:radius="@dimen/step_quiz_fill_blanks_input_radius" />
</shape>
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<com.google.android.material.textfield.TextInputEditText
android:id="@+id/fillBlanksInputField"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="@dimen/step_quiz_fill_blanks_input_text_min_height"
app:fontFamily="@font/roboto_medium"
android:textAppearance="?textAppearanceBody1"
android:maxLines="1"
android:lines="1"
android:singleLine="true"
android:imeOptions="actionDone"
android:hint="@string/step_quiz_text_field_hint"
android:background="@drawable/bg_step_quiz_fill_blanks_input_text_field"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingEnd="12dp"
android:paddingTop="12dp"
android:paddingBottom="8dp"
android:layout_margin="20dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
/>

</androidx.constraintlayout.widget.ConstraintLayout>
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
android:lines="1"
android:ellipsize="end"
android:gravity="center"
android:background="@drawable/bg_step_quiz_fill_blanks_input"
android:background="@drawable/bg_step_quiz_fill_blanks_input_item"
android:paddingLeft="@dimen/step_quiz_fill_blanks_padding"
android:paddingRight="@dimen/step_quiz_fill_blanks_padding"
android:layout_marginTop="@dimen/step_quiz_fill_blanks_item_top_margin"
Expand Down
2 changes: 2 additions & 0 deletions androidHyperskillApp/src/main/res/values/dimens.xml
Original file line number Diff line number Diff line change
Expand Up @@ -85,13 +85,15 @@
<!-- Step quiz parsons -->
<dimen name="step_quiz_parsons_line_gap">8dp</dimen>

<!-- Step quiz fill blanks -->
<dimen name="step_quiz_fill_blanks_input_radius">8dp</dimen>
<dimen name="step_quiz_fill_blanks_height">32dp</dimen>
<dimen name="step_quiz_fill_blanks_min_width">48dp</dimen>
<dimen name="step_quiz_fill_blanks_max_width">180dp</dimen>
<dimen name="step_quiz_fill_blanks_padding">8dp</dimen>
<dimen name="step_quiz_fill_blanks_item_top_margin">16dp</dimen>
<dimen name="step_quiz_fill_blanks_input_item_horizontal_margin">8dp</dimen>
<dimen name="step_quiz_fill_blanks_input_text_min_height">56dp</dimen>

<!-- Onboarding -->
<dimen name="onboarding_splash_icon_width">48dp</dimen>
Expand Down

0 comments on commit 6bc815f

Please sign in to comment.