From 4a5813a5711d3c40068dd56b23f6e7133e9f2cf8 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Thu, 8 Aug 2019 02:53:49 +0300 Subject: [PATCH 01/51] add executable code block to syncReply --- .../android/presentation/step_quiz/StepQuizPresenter.kt | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/stepik/android/presentation/step_quiz/StepQuizPresenter.kt b/app/src/main/java/org/stepik/android/presentation/step_quiz/StepQuizPresenter.kt index 848fbdd3dc..9475b81930 100644 --- a/app/src/main/java/org/stepik/android/presentation/step_quiz/StepQuizPresenter.kt +++ b/app/src/main/java/org/stepik/android/presentation/step_quiz/StepQuizPresenter.kt @@ -45,6 +45,9 @@ constructor( } } + fun fetchUponFullScreenReturn(stepWrapper: StepPersistentWrapper, lessonData: LessonData): Unit = + fetchAttempt(stepWrapper, lessonData) + private fun fetchAttempt(stepWrapper: StepPersistentWrapper, lessonData: LessonData) { state = StepQuizView.State.Loading compositeDisposable += stepQuizInteractor @@ -124,7 +127,7 @@ constructor( ) } - fun syncReplyState(reply: Reply) { + fun syncReplyState(reply: Reply, onSync: (() -> Unit)? = null) { val oldState = (state as? StepQuizView.State.AttemptLoaded) ?: return @@ -140,6 +143,6 @@ constructor( .createLocalSubmission(submission) .subscribeOn(backgroundScheduler) .observeOn(mainScheduler) - .subscribeBy(onError = emptyOnErrorStub) + .subscribeBy(onSuccess = { onSync?.invoke() }, onError = emptyOnErrorStub) } } \ No newline at end of file From 0b058990fae44ac103f5cf34c13b4570ffa7437a Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Thu, 8 Aug 2019 02:54:49 +0300 Subject: [PATCH 02/51] executable code parameter in StepQuizDelegate --- .../view/step_quiz/ui/delegate/StepQuizDelegate.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz/ui/delegate/StepQuizDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz/ui/delegate/StepQuizDelegate.kt index 415fedbfb6..1e42ff82ce 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz/ui/delegate/StepQuizDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz/ui/delegate/StepQuizDelegate.kt @@ -10,8 +10,8 @@ import org.stepik.android.presentation.step_quiz.StepQuizPresenter import org.stepik.android.presentation.step_quiz.StepQuizView import org.stepik.android.presentation.step_quiz.model.ReplyResult import org.stepik.android.view.step_quiz.mapper.StepQuizFeedbackMapper -import org.stepik.android.view.step_quiz.resolver.StepQuizFormResolver import org.stepik.android.view.step_quiz.model.StepQuizFeedbackState +import org.stepik.android.view.step_quiz.resolver.StepQuizFormResolver class StepQuizDelegate( private val step: Step, @@ -33,7 +33,7 @@ class StepQuizDelegate( stepQuizActionButton.setOnClickListener { onActionButtonClicked() } } - private fun onActionButtonClicked() { + fun onActionButtonClicked() { val state = currentState ?: return if (StepQuizFormResolver.isSubmissionInTerminalState(state)) { @@ -107,13 +107,13 @@ class StepQuizDelegate( } } - fun syncReplyState() { + fun syncReplyState(onSync: (() -> Unit)? = null) { if (StepQuizFormResolver.isSubmissionInTerminalState(currentState ?: return)) return val reply = (stepQuizFormDelegate.createReply() as? ReplyResult.Success) ?.reply ?: return - stepQuizPresenter.syncReplyState(reply) + stepQuizPresenter.syncReplyState(reply, onSync) } } \ No newline at end of file From 19b6386a776fe56c34f1a928f2d0e1f0edb5903e Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Thu, 8 Aug 2019 02:56:49 +0300 Subject: [PATCH 03/51] string resources --- app/src/main/res/values-ru/strings.xml | 3 +++ app/src/main/res/values/strings.xml | 3 +++ 2 files changed, 6 insertions(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 58f946ff1a..454415f23a 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -740,6 +740,9 @@ Выберите язык Перед отправкой решения выберите язык программирования из списка + Условия + Код + Выберите почтовый клиент diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index fada4bad7a..19fb401e53 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -769,6 +769,9 @@ Choose language Choose programming language before submission + Instruction + Code + Choose email app From 7e3da1c9cd13346c03934edf54c1b5a8ed7b4cad Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Thu, 8 Aug 2019 02:58:16 +0300 Subject: [PATCH 04/51] full screen code activity, adapter and fragments + di --- app/src/main/AndroidManifest.xml | 3 + .../view/injection/step/StepComponent.kt | 5 +- .../CodeStepQuizFullScreenActivity.kt | 128 ++++++++++++ .../adapter/CodeStepQuizFullScreenAdapter.kt | 35 ++++ .../CodeQuizFormFullScreenDelegate.kt | 173 ++++++++++++++++ ...deStepQuizFullScreenInstructionFragment.kt | 86 ++++++++ ...odeStepQuizFullScreenPlaygroundFragment.kt | 192 ++++++++++++++++++ .../activity_step_quiz_code_fullscreen.xml | 84 ++++++++ ..._step_quiz_code_fullscreen_instruction.xml | 62 ++++++ ...t_step_quiz_code_fullscreen_playground.xml | 51 +++++ ..._quiz_code_full_screen_playground_menu.xml | 8 + 11 files changed, 826 insertions(+), 1 deletion(-) create mode 100644 app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt create mode 100644 app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenAdapter.kt create mode 100644 app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/delegate/CodeQuizFormFullScreenDelegate.kt create mode 100644 app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenInstructionFragment.kt create mode 100644 app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenPlaygroundFragment.kt create mode 100644 app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml create mode 100644 app/src/main/res/layout/fragment_step_quiz_code_fullscreen_instruction.xml create mode 100644 app/src/main/res/layout/fragment_step_quiz_code_fullscreen_playground.xml create mode 100644 app/src/main/res/menu/step_quiz_code_full_screen_playground_menu.xml diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 4ccd444aeb..af43044f30 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -369,6 +369,9 @@ + + diff --git a/app/src/main/java/org/stepik/android/view/injection/step/StepComponent.kt b/app/src/main/java/org/stepik/android/view/injection/step/StepComponent.kt index 80db4cb287..d78b9bd1f5 100644 --- a/app/src/main/java/org/stepik/android/view/injection/step/StepComponent.kt +++ b/app/src/main/java/org/stepik/android/view/injection/step/StepComponent.kt @@ -7,8 +7,9 @@ import org.stepik.android.view.injection.step_quiz.StepQuizModule import org.stepik.android.view.injection.step_quiz.StepQuizPresentationModule import org.stepik.android.view.injection.submission.SubmissionDataModule import org.stepik.android.view.step.ui.fragment.StepFragment -import org.stepik.android.view.step_quiz_code.ui.fragment.CodeStepQuizFragment import org.stepik.android.view.step_quiz_choice.ui.fragment.ChoiceStepQuizFragment +import org.stepik.android.view.step_quiz_code.ui.fragment.CodeStepQuizFragment +import org.stepik.android.view.step_quiz_fullscreen_code.ui.fragment.CodeStepQuizFullScreenPlaygroundFragment import org.stepik.android.view.step_quiz_text.ui.fragment.TextStepQuizFragment @Subcomponent(modules = [ @@ -31,4 +32,6 @@ interface StepComponent { fun inject(choiceStepQuizFragment: ChoiceStepQuizFragment) fun inject(codeStepQuizFragment: CodeStepQuizFragment) fun inject(textStepQuizFragment: TextStepQuizFragment) + + fun inject(codeStepQuizFullScreenPlaygroundFragment: CodeStepQuizFullScreenPlaygroundFragment) } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt new file mode 100644 index 0000000000..f4c1e999f1 --- /dev/null +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt @@ -0,0 +1,128 @@ +package org.stepik.android.view.step_quiz_fullscreen_code.ui.activity + +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.support.design.widget.TabLayout +import android.view.MenuItem +import android.view.ViewGroup +import android.widget.TextView +import kotlinx.android.synthetic.main.activity_step_quiz_code_fullscreen.* +import org.stepic.droid.R +import org.stepic.droid.base.FragmentActivityBase +import org.stepic.droid.fonts.FontType +import org.stepic.droid.persistence.model.StepPersistentWrapper +import org.stepic.droid.ui.util.BackButtonHandler +import org.stepic.droid.ui.util.OnBackClickListener +import org.stepik.android.domain.lesson.model.LessonData +import org.stepik.android.view.base.ui.interfaces.KeyboardExtensionContainer +import org.stepik.android.view.step_quiz_fullscreen_code.ui.adapter.CodeStepQuizFullScreenAdapter +import uk.co.chrisjenx.calligraphy.TypefaceUtils +import java.lang.ref.WeakReference + +class CodeStepQuizFullScreenActivity : FragmentActivityBase(), BackButtonHandler, + KeyboardExtensionContainer { + companion object { + private val EXTRA_CURRENT_LANG = "current_lang_key" + private val EXTRA_STEP_WRAPPER = "step_wrapper" + private val EXTRA_LESSON_DATA = "lesson_data" + + fun createIntent(context: Context, lang: String, stepPersistentWrapper: StepPersistentWrapper, lessonData: LessonData): Intent = + Intent(context, CodeStepQuizFullScreenActivity::class.java) + .putExtra(EXTRA_CURRENT_LANG, lang) + .putExtra(EXTRA_STEP_WRAPPER, stepPersistentWrapper) + .putExtra(EXTRA_LESSON_DATA, lessonData) + } + + private var onBackClickListener: WeakReference? = null + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + setContentView(R.layout.activity_step_quiz_code_fullscreen) + + setSupportActionBar(fullScreenCodeToolbar) + val actionBar = this.supportActionBar + ?: throw IllegalStateException("support action bar should be set") + + with(actionBar) { + setDisplayShowTitleEnabled(false) + setDisplayHomeAsUpEnabled(true) + } + + val currentLang: String = intent.getStringExtra(EXTRA_CURRENT_LANG) + ?: throw IllegalStateException("Current lang cannot be null") + + val stepPersistentWrapper: StepPersistentWrapper = intent.getParcelableExtra(EXTRA_STEP_WRAPPER) + ?: throw IllegalStateException("StepPersistentWrapper cannot be null") + + val lessonData: LessonData = intent.getParcelableExtra(EXTRA_LESSON_DATA) + ?: throw IllegalStateException("Lesson data cannot be null") + + fullScreenCodeToolbarTitle.text = lessonData.lesson.title + + initViewPager(currentLang, stepPersistentWrapper, lessonData) + } + + override fun onOptionsItemSelected(item: MenuItem): Boolean = + if (item.itemId == android.R.id.home) { + if (fragmentBackKeyIntercept()) { + true + } else { + finish() + true + } + } else { + false + } + + override fun onBackPressed() { + if (!fragmentBackKeyIntercept()) { + super.onBackPressed() + } + } + + private fun initViewPager(currentLang: String, stepPersistentWrapper: StepPersistentWrapper, lessonData: LessonData) { + val lightFont = TypefaceUtils.load(assets, fontsProvider.provideFontPath(FontType.light)) + val regularFont = TypefaceUtils.load(assets, fontsProvider.provideFontPath(FontType.regular)) + + val codePagerAdapter = CodeStepQuizFullScreenAdapter(this, currentLang, supportFragmentManager, stepPersistentWrapper, lessonData) + + fullScreenCodeViewPager.adapter = codePagerAdapter + fullScreenCodeTabs.setupWithViewPager(fullScreenCodeViewPager) + fullScreenCodeTabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { + override fun onTabReselected(tab: TabLayout.Tab?) {} + override fun onTabUnselected(tab: TabLayout.Tab?) { + (tab?.customView as? TextView)?.let { + it.typeface = lightFont + } + } + override fun onTabSelected(tab: TabLayout.Tab?) { + (tab?.customView as? TextView)?.let { + it.typeface = regularFont + } + } + }) + + for (i in 0 until fullScreenCodeTabs.tabCount) { + val tab = fullScreenCodeTabs.getTabAt(i) + tab?.customView = layoutInflater.inflate(R.layout.view_course_tab, null) + } + + (fullScreenCodeTabs.getTabAt(fullScreenCodeTabs.selectedTabPosition)?.customView as? TextView) + ?.typeface = regularFont + } + + override fun setBackClickListener(onBackClickListener: OnBackClickListener) { + this.onBackClickListener = WeakReference(onBackClickListener) + } + + override fun removeBackClickListener(onBackClickListener: OnBackClickListener) { + this.onBackClickListener = null + } + + private fun fragmentBackKeyIntercept(): Boolean = + onBackClickListener?.get()?.onBackClick() ?: false + + override fun getKeyboardExtensionViewContainer(): ViewGroup = + coordinator +} \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenAdapter.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenAdapter.kt new file mode 100644 index 0000000000..c14565681d --- /dev/null +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenAdapter.kt @@ -0,0 +1,35 @@ +package org.stepik.android.view.step_quiz_fullscreen_code.ui.adapter + +import android.content.Context +import android.support.v4.app.Fragment +import android.support.v4.app.FragmentManager +import android.support.v4.app.FragmentPagerAdapter +import org.stepic.droid.R +import org.stepic.droid.persistence.model.StepPersistentWrapper +import org.stepik.android.domain.lesson.model.LessonData +import org.stepik.android.view.step_quiz_fullscreen_code.ui.fragment.CodeStepQuizFullScreenInstructionFragment +import org.stepik.android.view.step_quiz_fullscreen_code.ui.fragment.CodeStepQuizFullScreenPlaygroundFragment + +class CodeStepQuizFullScreenAdapter( + context: Context, + lang: String, + fragmentManager: FragmentManager, + stepPersistentWrapper: StepPersistentWrapper, + lessonData: LessonData +) : FragmentPagerAdapter(fragmentManager) { + private val fragments = listOf( + { CodeStepQuizFullScreenInstructionFragment.newInstance(stepPersistentWrapper, lang) } + to context.resources.getString(R.string.step_quiz_code_full_screen_instruction_tab), + { CodeStepQuizFullScreenPlaygroundFragment.newInstance(stepPersistentWrapper, lessonData) } + to context.resources.getString(R.string.step_quiz_code_full_screen_code_tab) + ) + + override fun getItem(position: Int): Fragment = + fragments[position].first.invoke() + + override fun getCount(): Int = + fragments.size + + override fun getPageTitle(position: Int): CharSequence = + fragments[position].second +} \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/delegate/CodeQuizFormFullScreenDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/delegate/CodeQuizFormFullScreenDelegate.kt new file mode 100644 index 0000000000..9e86274cf8 --- /dev/null +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/delegate/CodeQuizFormFullScreenDelegate.kt @@ -0,0 +1,173 @@ +package org.stepik.android.view.step_quiz_fullscreen_code.ui.delegate + +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.RecyclerView +import android.view.View +import android.view.ViewGroup +import android.widget.RelativeLayout +import kotlinx.android.synthetic.main.fragment_step_quiz_code_fullscreen_playground.view.* +import kotlinx.android.synthetic.main.layout_step_quiz_code.view.codeStepLayout +import org.stepic.droid.R +import org.stepic.droid.code.util.CodeToolbarUtil +import org.stepic.droid.model.code.extensionForLanguage +import org.stepic.droid.persistence.model.StepPersistentWrapper +import org.stepic.droid.ui.adapters.CodeToolbarAdapter +import org.stepic.droid.ui.util.inflate +import org.stepic.droid.ui.util.setOnKeyboardOpenListener +import org.stepic.droid.util.DpPixelsHelper +import org.stepik.android.model.Reply +import org.stepik.android.presentation.step_quiz.StepQuizView +import org.stepik.android.presentation.step_quiz.model.ReplyResult +import org.stepik.android.view.base.ui.interfaces.KeyboardExtensionContainer +import org.stepik.android.view.step_quiz.resolver.StepQuizFormResolver +import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFormDelegate +import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizDetailsMapper +import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizFormStateMapper +import org.stepik.android.view.step_quiz_code.model.CodeDetail +import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState +import org.stepik.android.view.ui.delegate.ViewStateDelegate +import ru.nobird.android.ui.adapterssupport.DefaultDelegateAdapter + +class CodeQuizFormFullScreenDelegate( + containerView: View, + keyboardExtensionContainer: KeyboardExtensionContainer?, + private val stepWrapper: StepPersistentWrapper, + private val actionsListener: ActionsListener +) : StepQuizFormDelegate { + private var state: CodeStepQuizFormState = CodeStepQuizFormState.Idle + set(value) { + field = value + + viewStateDelegate.switchState(value) + + when (value) { + is CodeStepQuizFormState.Lang -> { + codeLayout.setText(value.code) + codeLayout.lang = extensionForLanguage(value.lang) + codeToolbarAdapter.setLanguage(value.lang) + codeChosenLanguage.setText(value.lang) + } + } + + stepQuizCodeDetailsAdapter.items = + codeStepQuizDetailsMapper.mapToCodeDetails(stepWrapper.step, (value as? CodeStepQuizFormState.Lang)?.lang) + } + + // Flag is necessary, because keyboard listener is constantly invoked (probably global layout listener reacts to view changes) + private var keyboardShown: Boolean = false + + private val viewStateDelegate = ViewStateDelegate() + private val codeStepQuizFormStateMapper = CodeStepQuizFormStateMapper() + + private val codeLayout = containerView.codeStepLayout + private val codeChosenLanguage = containerView.codeChosenLanguage + private val codeSubmitButton = containerView.codeSubmitButton + + private val stepQuizCodeDetailsAdapter = DefaultDelegateAdapter() + private val codeStepQuizDetailsMapper = CodeStepQuizDetailsMapper() + + private val codeOptions = stepWrapper.step.block?.options ?: throw IllegalArgumentException("Code options shouldn't be null") + + private val codeToolbarAdapter = CodeToolbarAdapter(containerView.context) + .apply { + onSymbolClickListener = object : CodeToolbarAdapter.OnSymbolClickListener { + override fun onSymbolClick(symbol: String, offset: Int) { + codeLayout.insertText(CodeToolbarUtil.mapToolbarSymbolToPrintable(symbol, codeLayout.indentSize), offset) + } + } + } + + init { + viewStateDelegate.addState() + viewStateDelegate.addState(codeLayout) + + /** + * Keyboard extension + */ + (containerView as? ViewGroup) + keyboardExtensionContainer + ?.getKeyboardExtensionViewContainer() + ?.let { container -> + val stepQuizCodeKeyboardExtension = + container.inflate(R.layout.layout_step_quiz_code_keyboard_extension) as RecyclerView + stepQuizCodeKeyboardExtension.adapter = codeToolbarAdapter + stepQuizCodeKeyboardExtension.layoutManager = LinearLayoutManager(container.context, LinearLayoutManager.HORIZONTAL, false) + codeLayout.codeToolbarAdapter = codeToolbarAdapter + + container.addView(stepQuizCodeKeyboardExtension) + stepQuizCodeKeyboardExtension.visibility = View.INVISIBLE // Apparently this fixes the offset bug when the current line is under the code toolbar adapter + + setOnKeyboardOpenListener( + container, + onKeyboardHidden = { + if (keyboardShown) { + stepQuizCodeKeyboardExtension.visibility = View.GONE + codeLayout.isNestedScrollingEnabled = true + codeLayout.layoutParams = + (codeLayout.layoutParams as RelativeLayout.LayoutParams) + .apply { + bottomMargin = 0 + } + codeLayout.setPadding(0, 0, 0, DpPixelsHelper.convertDpToPixel(80f).toInt()) + codeSubmitButton.visibility = View.VISIBLE + keyboardShown = false + } + }, + onKeyboardShown = { + if (!keyboardShown) { + stepQuizCodeKeyboardExtension.visibility = View.VISIBLE + codeLayout.isNestedScrollingEnabled = false + codeLayout.layoutParams = + (codeLayout.layoutParams as RelativeLayout.LayoutParams) + .apply { + bottomMargin = stepQuizCodeKeyboardExtension.height + } + codeLayout.setPadding(0, 0, 0, 0) + codeSubmitButton.visibility = View.GONE + keyboardShown = true + } + } + ) + } + + codeChosenLanguage.setOnClickListener { actionsListener.onChangeLanguageClicked() } + codeSubmitButton.setOnClickListener { actionsListener.onSubmitClicked() } + } + + override fun setState(state: StepQuizView.State.AttemptLoaded) { + this.state = codeStepQuizFormStateMapper.mapToFormState(codeOptions, state) + + val isEnabled = StepQuizFormResolver.isQuizEnabled(state) + codeLayout.isEnabled = isEnabled + codeSubmitButton.isEnabled = isEnabled + } + + fun onLanguageSelected(lang: String) { + if (state !is CodeStepQuizFormState.Lang) { + return + } + + state = CodeStepQuizFormState.Lang(lang, codeOptions.codeTemplates[lang] ?: "") + } + + fun onResetCode() { + val oldState = (state as? CodeStepQuizFormState.Lang) + ?: return + + state = oldState.copy(code = codeOptions.codeTemplates[oldState.lang] ?: "") + } + + override fun createReply(): ReplyResult { + val state = state + return if (state is CodeStepQuizFormState.Lang) { + ReplyResult.Success(Reply(code = codeLayout.text.toString(), language = state.lang)) + } else { + ReplyResult.Error(codeLayout.context.getString(R.string.step_quiz_code_empty_lang)) + } + } + + interface ActionsListener { + fun onChangeLanguageClicked() + fun onSubmitClicked() + } +} \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenInstructionFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenInstructionFragment.kt new file mode 100644 index 0000000000..3b3857c4b9 --- /dev/null +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenInstructionFragment.kt @@ -0,0 +1,86 @@ +package org.stepik.android.view.step_quiz_fullscreen_code.ui.fragment + +import android.os.Bundle +import android.support.v4.app.Fragment +import android.support.v7.content.res.AppCompatResources +import android.support.v7.widget.DividerItemDecoration +import android.support.v7.widget.LinearLayoutManager +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import kotlinx.android.synthetic.main.fragment_step_quiz_code_fullscreen_instruction.* +import org.stepic.droid.R +import org.stepic.droid.persistence.model.StepPersistentWrapper +import org.stepic.droid.ui.custom.LatexSupportableEnhancedFrameLayout +import org.stepic.droid.ui.util.changeVisibility +import org.stepic.droid.util.argument +import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizDetailsMapper +import org.stepik.android.view.step_quiz_code.model.CodeDetail +import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeDetailLimitAdapterDelegate +import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeDetailSampleAdapterDelegate +import ru.nobird.android.ui.adapterssupport.DefaultDelegateAdapter + +class CodeStepQuizFullScreenInstructionFragment : Fragment() { + companion object { + fun newInstance(stepPersistentWrapper: StepPersistentWrapper, currentLang: String): Fragment = + CodeStepQuizFullScreenInstructionFragment() + .apply { + this.stepWrapper = stepPersistentWrapper + this.currentLang = currentLang + } + } + + private var stepWrapper: StepPersistentWrapper by argument() + private var latexLayout: LatexSupportableEnhancedFrameLayout? = null + private var currentLang: String by argument() + + private val stepQuizCodeDetailsAdapter = DefaultDelegateAdapter() + private val codeStepQuizDetailsMapper = CodeStepQuizDetailsMapper() + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = + inflater.inflate(R.layout.fragment_step_quiz_code_fullscreen_instruction, container, false) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + if (latexLayout == null) { + latexLayout = stepQuizCodeTextContent as LatexSupportableEnhancedFrameLayout + + val text = stepWrapper + .step + .block + ?.text + ?.takeIf(String::isNotEmpty) + + stepQuizCodeTextContent.changeVisibility(needShow = text != null) + if (text != null) { + stepQuizCodeTextContent.setText(text) + stepQuizCodeTextContent.setTextIsSelectable(true) + } + } + + stepQuizCodeDetailsAdapter += CodeDetailSampleAdapterDelegate() + stepQuizCodeDetailsAdapter += CodeDetailLimitAdapterDelegate() + + with(stepQuizCodeDetailsContent) { + layoutManager = object : LinearLayoutManager(context) { + override fun canScrollVertically(): Boolean = + false + } + adapter = stepQuizCodeDetailsAdapter + + val divider = DividerItemDecoration(context, DividerItemDecoration.VERTICAL) + divider.setDrawable( + AppCompatResources.getDrawable( + context, + R.drawable.bg_step_quiz_code_details_separator + )!! + ) + addItemDecoration(divider) + } + stepQuizCodeDetailsContent.isNestedScrollingEnabled = false + + stepQuizCodeDetailsAdapter.items = + codeStepQuizDetailsMapper.mapToCodeDetails(stepWrapper.step, currentLang) + } +} \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenPlaygroundFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenPlaygroundFragment.kt new file mode 100644 index 0000000000..199b77f9b5 --- /dev/null +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenPlaygroundFragment.kt @@ -0,0 +1,192 @@ +package org.stepik.android.view.step_quiz_fullscreen_code.ui.fragment + +import android.app.Activity +import android.arch.lifecycle.ViewModelProvider +import android.arch.lifecycle.ViewModelProviders +import android.content.Context +import android.content.Intent +import android.os.Bundle +import android.support.design.widget.Snackbar +import android.support.v4.app.Fragment +import android.support.v4.content.ContextCompat +import android.text.SpannableString +import android.text.style.ForegroundColorSpan +import android.view.LayoutInflater +import android.view.Menu +import android.view.MenuInflater +import android.view.MenuItem +import android.view.View +import android.view.ViewGroup +import org.stepic.droid.R +import org.stepic.droid.base.App +import org.stepic.droid.persistence.model.StepPersistentWrapper +import org.stepic.droid.ui.dialogs.ChangeCodeLanguageDialog +import org.stepic.droid.ui.dialogs.ProgrammingLanguageChooserDialogFragment +import org.stepic.droid.ui.dialogs.ResetCodeDialogFragment +import org.stepic.droid.ui.util.BackButtonHandler +import org.stepic.droid.ui.util.OnBackClickListener +import org.stepic.droid.util.ColorUtil +import org.stepic.droid.util.argument +import org.stepic.droid.util.setTextColor +import org.stepik.android.domain.lesson.model.LessonData +import org.stepik.android.presentation.step_quiz.StepQuizPresenter +import org.stepik.android.presentation.step_quiz.StepQuizView +import org.stepik.android.presentation.step_quiz.model.ReplyResult +import org.stepik.android.view.base.ui.extension.parentOfType +import org.stepik.android.view.step_quiz_fullscreen_code.ui.delegate.CodeQuizFormFullScreenDelegate +import javax.inject.Inject + +class CodeStepQuizFullScreenPlaygroundFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog.Callback, ProgrammingLanguageChooserDialogFragment.Callback, ResetCodeDialogFragment.Callback, OnBackClickListener { + companion object { + const val IS_SUBMITTED_CLICKED = "is_submit_clicked" + + fun newInstance(stepPersistentWrapper: StepPersistentWrapper, lessonData: LessonData): Fragment = + CodeStepQuizFullScreenPlaygroundFragment() + .apply { + this.stepWrapper = stepPersistentWrapper + this.lessonData = lessonData + } + } + + private var stepWrapper: StepPersistentWrapper by argument() + private var lessonData: LessonData by argument() + + @Inject + internal lateinit var viewModelFactory: ViewModelProvider.Factory + + private lateinit var presenter: StepQuizPresenter + + private lateinit var codeStepQuizFormFullScreenDelegate: CodeQuizFormFullScreenDelegate + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + injectComponent() + setHasOptionsMenu(true) + presenter = ViewModelProviders.of(this, viewModelFactory).get(StepQuizPresenter::class.java) + presenter.onStepData(stepWrapper, lessonData) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = + inflater.inflate(R.layout.fragment_step_quiz_code_fullscreen_playground, container, false) + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) + + val actionsListener = object : CodeQuizFormFullScreenDelegate.ActionsListener { + override fun onChangeLanguageClicked() { + val dialog = ChangeCodeLanguageDialog.newInstance() + if (!dialog.isAdded) { + dialog.show(childFragmentManager, null) + } + } + + override fun onSubmitClicked() { + syncCodeOnFullScreenExit(true) + } + } + + codeStepQuizFormFullScreenDelegate = CodeQuizFormFullScreenDelegate(view, parentOfType(), stepWrapper, actionsListener) + } + + override fun onAttach(context: Context?) { + super.onAttach(context) + (activity as? BackButtonHandler)?.setBackClickListener(this) + } + + override fun onDetach() { + (activity as? BackButtonHandler)?.removeBackClickListener(this) + super.onDetach() + } + + override fun onStart() { + super.onStart() + presenter.attachView(this) + } + + override fun onStop() { + presenter.detachView(this) + val reply = codeStepQuizFormFullScreenDelegate.createReply() + if (reply is ReplyResult.Success) { + presenter.syncReplyState(reply.reply) + } + super.onStop() + } + + override fun setState(state: StepQuizView.State) { + if (state is StepQuizView.State.AttemptLoaded) { + codeStepQuizFormFullScreenDelegate.setState(state) + } + } + + override fun showNetworkError() { + val view = view ?: return + + Snackbar + .make(view, R.string.no_connection, Snackbar.LENGTH_SHORT) + .setTextColor(ContextCompat.getColor(requireContext(), R.color.white)) + .show() + } + + override fun onBackClick(): Boolean { + syncCodeOnFullScreenExit() + return true + } + + override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { + super.onCreateOptionsMenu(menu, inflater) + inflater.inflate(R.menu.step_quiz_code_full_screen_playground_menu, menu) + val menuItem = menu.findItem(R.id.action_reset_code) + val resetString = SpannableString(getString(R.string.code_quiz_reset)) + resetString.setSpan(ForegroundColorSpan(ColorUtil.getColorArgb(R.color.new_red_color)), 0, resetString.length, 0) + menuItem?.title = resetString + } + + override fun onOptionsItemSelected(item: MenuItem?): Boolean = + when (item?.itemId) { + R.id.action_reset_code -> { + val dialog = ResetCodeDialogFragment.newInstance() + if (!dialog.isAdded) { + dialog.show(childFragmentManager, null) + } + true + } + else -> false + } + + override fun onChangeLanguage() { + val languages = stepWrapper.step.block?.options?.limits?.keys?.sorted()?.toTypedArray() ?: emptyArray() + + val dialog = ProgrammingLanguageChooserDialogFragment.newInstance(languages) + if (!dialog.isAdded) { + dialog.show(childFragmentManager, null) + } + } + + override fun onLanguageChosen(programmingLanguage: String) { + codeStepQuizFormFullScreenDelegate.onLanguageSelected(programmingLanguage) + } + + override fun onReset() { + codeStepQuizFormFullScreenDelegate.onResetCode() + } + + private fun syncCodeOnFullScreenExit(isSubmittedClicked: Boolean = false) { + val reply = codeStepQuizFormFullScreenDelegate.createReply() + if (reply is ReplyResult.Success) { + presenter.syncReplyState(reply.reply) { + (activity as? BackButtonHandler)?.removeBackClickListener(this) + val data = Intent() + data.putExtra(IS_SUBMITTED_CLICKED, isSubmittedClicked) + activity?.setResult(Activity.RESULT_OK, data) + activity?.onBackPressed() + } + } + } + + private fun injectComponent() { + App.component() + .stepComponentBuilder() + .build() + .inject(this) + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml b/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml new file mode 100644 index 0000000000..212bf9c047 --- /dev/null +++ b/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_step_quiz_code_fullscreen_instruction.xml b/app/src/main/res/layout/fragment_step_quiz_code_fullscreen_instruction.xml new file mode 100644 index 0000000000..938c31e1f4 --- /dev/null +++ b/app/src/main/res/layout/fragment_step_quiz_code_fullscreen_instruction.xml @@ -0,0 +1,62 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_step_quiz_code_fullscreen_playground.xml b/app/src/main/res/layout/fragment_step_quiz_code_fullscreen_playground.xml new file mode 100644 index 0000000000..1d08704b38 --- /dev/null +++ b/app/src/main/res/layout/fragment_step_quiz_code_fullscreen_playground.xml @@ -0,0 +1,51 @@ + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/step_quiz_code_full_screen_playground_menu.xml b/app/src/main/res/menu/step_quiz_code_full_screen_playground_menu.xml new file mode 100644 index 0000000000..0a0e3b8f36 --- /dev/null +++ b/app/src/main/res/menu/step_quiz_code_full_screen_playground_menu.xml @@ -0,0 +1,8 @@ + + + + \ No newline at end of file From 6fd73ecb9aa7bcc523c278fa5cb52d1943e1e27d Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Thu, 8 Aug 2019 02:59:08 +0300 Subject: [PATCH 05/51] remove old full screen use in new CodeStepQuiz --- .../ui/delegate/CodeStepQuizFormDelegate.kt | 7 ----- .../ui/fragment/CodeStepQuizFragment.kt | 30 +++++++++---------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt index e156b936c4..772f1e07d5 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt @@ -9,9 +9,6 @@ import android.text.style.ForegroundColorSpan import android.view.View import android.widget.PopupMenu import kotlinx.android.synthetic.main.layout_step_quiz_code.view.* -import kotlinx.android.synthetic.main.layout_step_quiz_code.view.stepQuizCodeDetails -import kotlinx.android.synthetic.main.layout_step_quiz_code.view.stepQuizCodeDetailsArrow -import kotlinx.android.synthetic.main.layout_step_quiz_code.view.stepQuizCodeDetailsContent import org.stepic.droid.R import org.stepic.droid.code.util.CodeToolbarUtil import org.stepic.droid.model.code.extensionForLanguage @@ -223,10 +220,6 @@ class CodeStepQuizFormDelegate( state = CodeStepQuizFormState.Lang(lang, codeOptions.codeTemplates[lang] ?: "") } - fun onResultFromFullscreen(lang: String, code: String) { - state = CodeStepQuizFormState.Lang(lang, code) - } - fun onResetCode() { val oldState = (state as? CodeStepQuizFormState.Lang) ?: return diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt index 8e9a213bc6..b063ccbe9c 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt @@ -19,7 +19,6 @@ import org.stepic.droid.R import org.stepic.droid.base.App import org.stepic.droid.fonts.FontsProvider import org.stepic.droid.persistence.model.StepPersistentWrapper -import org.stepic.droid.ui.activities.CodePlaygroundActivity import org.stepic.droid.ui.dialogs.ChangeCodeLanguageDialog import org.stepic.droid.ui.dialogs.ProgrammingLanguageChooserDialogFragment import org.stepic.droid.ui.dialogs.ResetCodeDialogFragment @@ -32,6 +31,8 @@ import org.stepik.android.view.base.ui.extension.parentOfType import org.stepik.android.view.step_quiz.ui.delegate.StepQuizDelegate import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFeedbackBlocksDelegate import org.stepik.android.view.step_quiz_code.ui.delegate.CodeStepQuizFormDelegate +import org.stepik.android.view.step_quiz_fullscreen_code.ui.activity.CodeStepQuizFullScreenActivity +import org.stepik.android.view.step_quiz_fullscreen_code.ui.fragment.CodeStepQuizFullScreenPlaygroundFragment import org.stepik.android.view.ui.delegate.ViewStateDelegate import javax.inject.Inject @@ -63,7 +64,7 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ResetCodeDialogFragment.C private lateinit var codeStepQuizFormDelegate: CodeStepQuizFormDelegate - private var fullscreenResult: Pair? = null + private var isFullScreenSubmitClicked: Boolean = false override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -106,9 +107,10 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ResetCodeDialogFragment.C } override fun onFullscreenClicked(lang: String, code: String) { - val intent = CodePlaygroundActivity.intentForLaunch(requireActivity(), code, lang, - stepWrapper.step.block?.options ?: throw IllegalStateException("can't find code options in code quiz")) - startActivityForResult(intent, CODE_PLAYGROUND_REQUEST) + stepQuizDelegate.syncReplyState { + val intent = CodeStepQuizFullScreenActivity.createIntent(requireActivity(), lang, stepWrapper, lessonData) + startActivityForResult(intent, CODE_PLAYGROUND_REQUEST) + } } override fun onResetClicked() { @@ -147,9 +149,10 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ResetCodeDialogFragment.C viewStateDelegate.switchState(state) if (state is StepQuizView.State.AttemptLoaded) { stepQuizDelegate.setState(state) - - fullscreenResult?.let { (lang, code) -> codeStepQuizFormDelegate.onResultFromFullscreen(lang, code) } - fullscreenResult = null + if (isFullScreenSubmitClicked && state.submissionState is StepQuizView.SubmissionState.Loaded) { + isFullScreenSubmitClicked = false + stepQuizDelegate.onActionButtonClicked() + } } } @@ -182,13 +185,10 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ResetCodeDialogFragment.C override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { when (requestCode) { CODE_PLAYGROUND_REQUEST -> - data?.takeIf { resultCode == Activity.RESULT_OK } - ?.let { intent -> - val lang = intent.getStringExtra(CodePlaygroundActivity.LANG_KEY) - val code = intent.getStringExtra(CodePlaygroundActivity.CODE_KEY) - fullscreenResult = lang to code // todo: remove after fullscreen code quiz refactor - } - + if (resultCode == Activity.RESULT_OK) { + isFullScreenSubmitClicked = data?.getBooleanExtra(CodeStepQuizFullScreenPlaygroundFragment.IS_SUBMITTED_CLICKED, false) ?: false + presenter.fetchUponFullScreenReturn(stepWrapper, lessonData) + } else -> super.onActivityResult(requestCode, resultCode, data) } From f5f1d04e4715017e7bf75549285295c00d9c9592 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Thu, 8 Aug 2019 12:04:17 +0300 Subject: [PATCH 06/51] change language in options menu --- .../delegate/CodeQuizFormFullScreenDelegate.kt | 5 +---- .../CodeStepQuizFullScreenPlaygroundFragment.kt | 16 ++++++++-------- ...tep_quiz_code_full_screen_playground_menu.xml | 8 -------- 3 files changed, 9 insertions(+), 20 deletions(-) delete mode 100644 app/src/main/res/menu/step_quiz_code_full_screen_playground_menu.xml diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/delegate/CodeQuizFormFullScreenDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/delegate/CodeQuizFormFullScreenDelegate.kt index 9e86274cf8..4d27fa56c0 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/delegate/CodeQuizFormFullScreenDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/delegate/CodeQuizFormFullScreenDelegate.kt @@ -45,7 +45,7 @@ class CodeQuizFormFullScreenDelegate( codeLayout.setText(value.code) codeLayout.lang = extensionForLanguage(value.lang) codeToolbarAdapter.setLanguage(value.lang) - codeChosenLanguage.setText(value.lang) + codeChosenLanguage.text = value.lang } } @@ -129,8 +129,6 @@ class CodeQuizFormFullScreenDelegate( } ) } - - codeChosenLanguage.setOnClickListener { actionsListener.onChangeLanguageClicked() } codeSubmitButton.setOnClickListener { actionsListener.onSubmitClicked() } } @@ -167,7 +165,6 @@ class CodeQuizFormFullScreenDelegate( } interface ActionsListener { - fun onChangeLanguageClicked() fun onSubmitClicked() } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenPlaygroundFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenPlaygroundFragment.kt index 199b77f9b5..f49d930f72 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenPlaygroundFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenPlaygroundFragment.kt @@ -73,13 +73,6 @@ class CodeStepQuizFullScreenPlaygroundFragment : Fragment(), StepQuizView, Chang super.onViewCreated(view, savedInstanceState) val actionsListener = object : CodeQuizFormFullScreenDelegate.ActionsListener { - override fun onChangeLanguageClicked() { - val dialog = ChangeCodeLanguageDialog.newInstance() - if (!dialog.isAdded) { - dialog.show(childFragmentManager, null) - } - } - override fun onSubmitClicked() { syncCodeOnFullScreenExit(true) } @@ -134,7 +127,7 @@ class CodeStepQuizFullScreenPlaygroundFragment : Fragment(), StepQuizView, Chang override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { super.onCreateOptionsMenu(menu, inflater) - inflater.inflate(R.menu.step_quiz_code_full_screen_playground_menu, menu) + inflater.inflate(R.menu.code_playground_menu, menu) val menuItem = menu.findItem(R.id.action_reset_code) val resetString = SpannableString(getString(R.string.code_quiz_reset)) resetString.setSpan(ForegroundColorSpan(ColorUtil.getColorArgb(R.color.new_red_color)), 0, resetString.length, 0) @@ -150,6 +143,13 @@ class CodeStepQuizFullScreenPlaygroundFragment : Fragment(), StepQuizView, Chang } true } + R.id.action_language_code -> { + val dialog = ChangeCodeLanguageDialog.newInstance() + if (!dialog.isAdded) { + dialog.show(childFragmentManager, null) + } + true + } else -> false } diff --git a/app/src/main/res/menu/step_quiz_code_full_screen_playground_menu.xml b/app/src/main/res/menu/step_quiz_code_full_screen_playground_menu.xml deleted file mode 100644 index 0a0e3b8f36..0000000000 --- a/app/src/main/res/menu/step_quiz_code_full_screen_playground_menu.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - \ No newline at end of file From 8c00729db4dd3af995ef62dcf0fae1c556da1c60 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Tue, 13 Aug 2019 18:13:03 +0300 Subject: [PATCH 07/51] try using layouts instead of fragments --- .../CodeStepQuizFullScreenActivity.kt | 39 ++++------------- .../CodeStepQuizFullScreenPagerAdapter.kt | 42 +++++++++++++++++++ 2 files changed, 50 insertions(+), 31 deletions(-) create mode 100644 app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/experiment/CodeStepQuizFullScreenPagerAdapter.kt diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt index f4c1e999f1..031347d7cd 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt @@ -12,16 +12,14 @@ import org.stepic.droid.R import org.stepic.droid.base.FragmentActivityBase import org.stepic.droid.fonts.FontType import org.stepic.droid.persistence.model.StepPersistentWrapper -import org.stepic.droid.ui.util.BackButtonHandler import org.stepic.droid.ui.util.OnBackClickListener import org.stepik.android.domain.lesson.model.LessonData import org.stepik.android.view.base.ui.interfaces.KeyboardExtensionContainer -import org.stepik.android.view.step_quiz_fullscreen_code.ui.adapter.CodeStepQuizFullScreenAdapter +import org.stepik.android.view.step_quiz_fullscreen_code.ui.experiment.CodeStepQuizFullScreenPagerAdapter import uk.co.chrisjenx.calligraphy.TypefaceUtils import java.lang.ref.WeakReference -class CodeStepQuizFullScreenActivity : FragmentActivityBase(), BackButtonHandler, - KeyboardExtensionContainer { +class CodeStepQuizFullScreenActivity : FragmentActivityBase(), KeyboardExtensionContainer { companion object { private val EXTRA_CURRENT_LANG = "current_lang_key" private val EXTRA_STEP_WRAPPER = "step_wrapper" @@ -60,34 +58,24 @@ class CodeStepQuizFullScreenActivity : FragmentActivityBase(), BackButtonHandler fullScreenCodeToolbarTitle.text = lessonData.lesson.title - initViewPager(currentLang, stepPersistentWrapper, lessonData) + initViewPager() } override fun onOptionsItemSelected(item: MenuItem): Boolean = if (item.itemId == android.R.id.home) { - if (fragmentBackKeyIntercept()) { - true - } else { - finish() - true - } + finish() + true } else { false } - override fun onBackPressed() { - if (!fragmentBackKeyIntercept()) { - super.onBackPressed() - } - } - - private fun initViewPager(currentLang: String, stepPersistentWrapper: StepPersistentWrapper, lessonData: LessonData) { + private fun initViewPager() { val lightFont = TypefaceUtils.load(assets, fontsProvider.provideFontPath(FontType.light)) val regularFont = TypefaceUtils.load(assets, fontsProvider.provideFontPath(FontType.regular)) - val codePagerAdapter = CodeStepQuizFullScreenAdapter(this, currentLang, supportFragmentManager, stepPersistentWrapper, lessonData) + val pagerAdapter = CodeStepQuizFullScreenPagerAdapter(this) - fullScreenCodeViewPager.adapter = codePagerAdapter + fullScreenCodeViewPager.adapter = pagerAdapter fullScreenCodeTabs.setupWithViewPager(fullScreenCodeViewPager) fullScreenCodeTabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { override fun onTabReselected(tab: TabLayout.Tab?) {} @@ -112,17 +100,6 @@ class CodeStepQuizFullScreenActivity : FragmentActivityBase(), BackButtonHandler ?.typeface = regularFont } - override fun setBackClickListener(onBackClickListener: OnBackClickListener) { - this.onBackClickListener = WeakReference(onBackClickListener) - } - - override fun removeBackClickListener(onBackClickListener: OnBackClickListener) { - this.onBackClickListener = null - } - - private fun fragmentBackKeyIntercept(): Boolean = - onBackClickListener?.get()?.onBackClick() ?: false - override fun getKeyboardExtensionViewContainer(): ViewGroup = coordinator } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/experiment/CodeStepQuizFullScreenPagerAdapter.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/experiment/CodeStepQuizFullScreenPagerAdapter.kt new file mode 100644 index 0000000000..8439c936e4 --- /dev/null +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/experiment/CodeStepQuizFullScreenPagerAdapter.kt @@ -0,0 +1,42 @@ +package org.stepik.android.view.step_quiz_fullscreen_code.ui.experiment + +import android.content.Context +import android.support.v4.view.PagerAdapter +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import org.stepic.droid.R + +class CodeStepQuizFullScreenPagerAdapter( + context: Context +) : PagerAdapter() { + + private val layouts = listOf( + LayoutInflater.from(context).inflate(R.layout.fragment_step_quiz_code_fullscreen_instruction, null) to "Instruction", + LayoutInflater.from(context).inflate(R.layout.fragment_step_quiz_code_fullscreen_playground, null) to "Playground" + ) + + override fun instantiateItem(container: ViewGroup, position: Int): Any { + val view = layouts[position].first + container.addView(view) + return view + } + + override fun destroyItem(container: ViewGroup, position: Int, view: Any) { + container.removeView(layouts[position].first) + } + + override fun isViewFromObject(p0: View, p1: Any): Boolean { + return p0 == p1 + } + + override fun getPageTitle(position: Int): CharSequence = + layouts[position].second + + override fun getCount(): Int { + return layouts.size + } + + fun getViewAt(position: Int): View = + layouts[position].first +} \ No newline at end of file From 27a236c2f2c6a09ed59d9a23a5d6e35e14d2f81d Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Wed, 14 Aug 2019 01:20:51 +0300 Subject: [PATCH 08/51] make dialog fragments compatible with activity host --- .../stepic/droid/ui/dialogs/ChangeCodeLanguageDialog.kt | 7 ++++++- .../ui/dialogs/ProgrammingLanguageChooserDialogFragment.kt | 7 ++++++- 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/stepic/droid/ui/dialogs/ChangeCodeLanguageDialog.kt b/app/src/main/java/org/stepic/droid/ui/dialogs/ChangeCodeLanguageDialog.kt index 3c84b968ac..7b6c1a20fa 100644 --- a/app/src/main/java/org/stepic/droid/ui/dialogs/ChangeCodeLanguageDialog.kt +++ b/app/src/main/java/org/stepic/droid/ui/dialogs/ChangeCodeLanguageDialog.kt @@ -20,7 +20,12 @@ class ChangeCodeLanguageDialog : DialogFragment() { .setTitle(R.string.reset_code_dialog_title) .setMessage(R.string.change_code_dialog_explanation) .setPositiveButton(R.string.yes) { _, _ -> - (parentFragment as Callback).onChangeLanguage() + val callback = if (parentFragment != null) { + parentFragment as Callback + } else { + activity as Callback + } + callback.onChangeLanguage() } .setNegativeButton(R.string.cancel, null) .create() diff --git a/app/src/main/java/org/stepic/droid/ui/dialogs/ProgrammingLanguageChooserDialogFragment.kt b/app/src/main/java/org/stepic/droid/ui/dialogs/ProgrammingLanguageChooserDialogFragment.kt index 462a37e9c4..941262eb6a 100644 --- a/app/src/main/java/org/stepic/droid/ui/dialogs/ProgrammingLanguageChooserDialogFragment.kt +++ b/app/src/main/java/org/stepic/droid/ui/dialogs/ProgrammingLanguageChooserDialogFragment.kt @@ -36,7 +36,12 @@ class ProgrammingLanguageChooserDialogFragment : DialogFragment() { .positiveText(R.string.choose_action) .negativeText(R.string.cancel) .onPositive { _, _ -> - (parentFragment as Callback).onLanguageChosen(picker.displayedValues[picker.value]) + val callback = if (parentFragment != null) { + parentFragment as Callback + } else { + activity as Callback + } + callback.onLanguageChosen(picker.displayedValues[picker.value]) } .build() } From edd767d8c52db74c30828aa5a9b1fc52161eeb21 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Wed, 14 Aug 2019 01:21:24 +0300 Subject: [PATCH 09/51] make CodeEditor accessible outside of CodeEditorLayout --- app/src/main/java/org/stepic/droid/code/ui/CodeEditorLayout.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/org/stepic/droid/code/ui/CodeEditorLayout.kt b/app/src/main/java/org/stepic/droid/code/ui/CodeEditorLayout.kt index e211cb647c..3dad769a36 100644 --- a/app/src/main/java/org/stepic/droid/code/ui/CodeEditorLayout.kt +++ b/app/src/main/java/org/stepic/droid/code/ui/CodeEditorLayout.kt @@ -1,7 +1,6 @@ package org.stepic.droid.code.ui import android.content.Context -import android.graphics.Typeface import android.support.v4.widget.NestedScrollView import android.util.AttributeSet import android.view.LayoutInflater @@ -15,7 +14,7 @@ class CodeEditorLayout @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) : NestedScrollView(context, attrs, defStyleAttr) { - private val codeEditor: CodeEditor + val codeEditor: CodeEditor var theme: CodeTheme get() = codeEditor.theme From d74f4ad3fe69bec638fdcc831232e34d83ff1aec Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Wed, 14 Aug 2019 01:21:47 +0300 Subject: [PATCH 10/51] replace fragments in full screen with layouts; attempt to reduce code duplication in form delegates --- .../view/injection/step/StepComponent.kt | 4 +- .../ui/delegate/CodeQuizFormBaseDelegate.kt | 124 +++++++++++ .../ui/delegate/CodeStepQuizFormDelegate.kt | 156 +------------- .../CodeStepQuizFullScreenFormDelegate.kt | 107 ++++++++++ .../ui/fragment/CodeStepQuizFragment.kt | 31 +-- .../CodeStepQuizFullScreenActivity.kt | 192 +++++++++++++++--- .../adapter/CodeStepQuizFullScreenAdapter.kt | 35 ---- .../CodeStepQuizFullScreenPagerAdapter.kt | 16 +- .../CodeQuizFormFullScreenDelegate.kt | 170 ---------------- ...deStepQuizFullScreenInstructionFragment.kt | 86 -------- ...odeStepQuizFullScreenPlaygroundFragment.kt | 192 ------------------ .../activity_step_quiz_code_fullscreen.xml | 15 +- .../main/res/layout/layout_step_quiz_code.xml | 29 +-- ...step_quiz_code_fullscreen_instruction.xml} | 3 +- ..._step_quiz_code_fullscreen_playground.xml} | 52 +++-- 15 files changed, 472 insertions(+), 740 deletions(-) create mode 100644 app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizFormBaseDelegate.kt create mode 100644 app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt delete mode 100644 app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenAdapter.kt rename app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/{experiment => adapter}/CodeStepQuizFullScreenPagerAdapter.kt (62%) delete mode 100644 app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/delegate/CodeQuizFormFullScreenDelegate.kt delete mode 100644 app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenInstructionFragment.kt delete mode 100644 app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenPlaygroundFragment.kt rename app/src/main/res/layout/{fragment_step_quiz_code_fullscreen_instruction.xml => layout_step_quiz_code_fullscreen_instruction.xml} (97%) rename app/src/main/res/layout/{fragment_step_quiz_code_fullscreen_playground.xml => layout_step_quiz_code_fullscreen_playground.xml} (52%) diff --git a/app/src/main/java/org/stepik/android/view/injection/step/StepComponent.kt b/app/src/main/java/org/stepik/android/view/injection/step/StepComponent.kt index d78b9bd1f5..8a6a5e859e 100644 --- a/app/src/main/java/org/stepik/android/view/injection/step/StepComponent.kt +++ b/app/src/main/java/org/stepik/android/view/injection/step/StepComponent.kt @@ -9,7 +9,7 @@ import org.stepik.android.view.injection.submission.SubmissionDataModule import org.stepik.android.view.step.ui.fragment.StepFragment import org.stepik.android.view.step_quiz_choice.ui.fragment.ChoiceStepQuizFragment import org.stepik.android.view.step_quiz_code.ui.fragment.CodeStepQuizFragment -import org.stepik.android.view.step_quiz_fullscreen_code.ui.fragment.CodeStepQuizFullScreenPlaygroundFragment +import org.stepik.android.view.step_quiz_fullscreen_code.ui.activity.CodeStepQuizFullScreenActivity import org.stepik.android.view.step_quiz_text.ui.fragment.TextStepQuizFragment @Subcomponent(modules = [ @@ -33,5 +33,5 @@ interface StepComponent { fun inject(codeStepQuizFragment: CodeStepQuizFragment) fun inject(textStepQuizFragment: TextStepQuizFragment) - fun inject(codeStepQuizFullScreenPlaygroundFragment: CodeStepQuizFullScreenPlaygroundFragment) + fun inject(codeStepQuizFullScreenActivity: CodeStepQuizFullScreenActivity) } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizFormBaseDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizFormBaseDelegate.kt new file mode 100644 index 0000000000..9146011b51 --- /dev/null +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizFormBaseDelegate.kt @@ -0,0 +1,124 @@ +package org.stepik.android.view.step_quiz_code.ui.delegate + +import android.support.v7.content.res.AppCompatResources +import android.support.v7.widget.DividerItemDecoration +import android.support.v7.widget.LinearLayoutManager +import android.view.View +import kotlinx.android.synthetic.main.layout_step_quiz_code.view.* +import org.stepic.droid.R +import org.stepic.droid.code.util.CodeToolbarUtil +import org.stepic.droid.model.code.extensionForLanguage +import org.stepic.droid.persistence.model.StepPersistentWrapper +import org.stepic.droid.ui.adapters.CodeToolbarAdapter +import org.stepik.android.model.Reply +import org.stepik.android.presentation.step_quiz.StepQuizView +import org.stepik.android.presentation.step_quiz.model.ReplyResult +import org.stepik.android.view.step_quiz.resolver.StepQuizFormResolver +import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFormDelegate +import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizDetailsMapper +import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizFormStateMapper +import org.stepik.android.view.step_quiz_code.model.CodeDetail +import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState +import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeDetailLimitAdapterDelegate +import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeDetailSampleAdapterDelegate +import org.stepik.android.view.ui.delegate.ViewStateDelegate +import ru.nobird.android.ui.adapterssupport.DefaultDelegateAdapter + +abstract class CodeQuizFormBaseDelegate( + detailsContainerView: View, + codeContainerView: View, + val stepWrapper: StepPersistentWrapper +) : StepQuizFormDelegate { + + var state: CodeStepQuizFormState = CodeStepQuizFormState.Idle + set(value) { + field = value + + viewStateDelegate.switchState(value) + + when (value) { + is CodeStepQuizFormState.Lang -> { + codeLayout.setText(value.code) + codeLayout.lang = extensionForLanguage(value.lang) + stepQuizActionChangeLang.text = value.lang + + codeToolbarAdapter.setLanguage(value.lang) + } + } + + stepQuizCodeDetailsAdapter.items = + codeStepQuizDetailsMapper.mapToCodeDetails(stepWrapper.step, (value as? CodeStepQuizFormState.Lang)?.lang) + } + + protected val viewStateDelegate = ViewStateDelegate() + protected val codeStepQuizFormStateMapper = CodeStepQuizFormStateMapper() + + protected val codeLayout = codeContainerView.codeStepLayout + + protected val stepQuizCodeDetails = detailsContainerView.stepQuizCodeDetails + protected val stepQuizCodeDetailsArrow = detailsContainerView.stepQuizCodeDetailsArrow + protected val stepQuizCodeDetailsContent = detailsContainerView.stepQuizCodeDetailsContent + + protected val stepQuizCodeDetailsAdapter = DefaultDelegateAdapter() + protected val codeStepQuizDetailsMapper = CodeStepQuizDetailsMapper() + + protected val codeToolbarAdapter = CodeToolbarAdapter(codeContainerView.context) + .apply { + onSymbolClickListener = object : CodeToolbarAdapter.OnSymbolClickListener { + override fun onSymbolClick(symbol: String, offset: Int) { + codeLayout.insertText(CodeToolbarUtil.mapToolbarSymbolToPrintable(symbol, codeLayout.indentSize), offset) + } + } + } + + protected val stepQuizActions = codeContainerView.stepQuizActions + protected val stepQuizActionChangeLang = codeContainerView.stepQuizActionChangeLang + + protected val codeOptions = stepWrapper.step.block?.options ?: throw IllegalArgumentException("Code options shouldn't be null") + + protected fun setupCodeDetailContentData() { + stepQuizCodeDetailsAdapter += CodeDetailSampleAdapterDelegate() + stepQuizCodeDetailsAdapter += CodeDetailLimitAdapterDelegate() + + with(stepQuizCodeDetailsContent) { + visibility = View.GONE + layoutManager = LinearLayoutManager(context) + adapter = stepQuizCodeDetailsAdapter + + val divider = DividerItemDecoration(context, DividerItemDecoration.VERTICAL) + divider.setDrawable(AppCompatResources.getDrawable(context, R.drawable.bg_step_quiz_code_details_separator)!!) + addItemDecoration(divider) + } + } + + override fun createReply(): ReplyResult { + val state = state + return if (state is CodeStepQuizFormState.Lang) { + ReplyResult.Success(Reply(code = codeLayout.text.toString(), language = state.lang)) + } else { + ReplyResult.Error(codeLayout.context.getString(R.string.step_quiz_code_empty_lang)) + } + } + + override fun setState(state: StepQuizView.State.AttemptLoaded) { + this.state = codeStepQuizFormStateMapper.mapToFormState(codeOptions, state) + + val isEnabled = StepQuizFormResolver.isQuizEnabled(state) + codeLayout.isEnabled = isEnabled + stepQuizActionChangeLang.isEnabled = isEnabled + } + + fun onLanguageSelected(lang: String) { + if (state !is CodeStepQuizFormState.Lang) { + return + } + state = CodeStepQuizFormState.Lang(lang, codeOptions.codeTemplates[lang] ?: "") + } + + fun onResetCode() { + val oldState = (state as? CodeStepQuizFormState.Lang) + ?: return + + state = oldState.copy(code = codeOptions.codeTemplates[oldState.lang] ?: "") + } +} \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt index 772f1e07d5..f60483f603 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt @@ -1,98 +1,31 @@ package org.stepik.android.view.step_quiz_code.ui.delegate -import android.support.v7.content.res.AppCompatResources -import android.support.v7.widget.DividerItemDecoration import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.RecyclerView -import android.text.SpannableString -import android.text.style.ForegroundColorSpan import android.view.View -import android.widget.PopupMenu import kotlinx.android.synthetic.main.layout_step_quiz_code.view.* import org.stepic.droid.R -import org.stepic.droid.code.util.CodeToolbarUtil -import org.stepic.droid.model.code.extensionForLanguage import org.stepic.droid.persistence.model.StepPersistentWrapper -import org.stepic.droid.ui.adapters.CodeToolbarAdapter import org.stepic.droid.ui.util.StepikAnimUtils import org.stepic.droid.ui.util.inflate import org.stepic.droid.ui.util.setCompoundDrawables import org.stepic.droid.ui.util.setOnKeyboardOpenListener -import org.stepic.droid.util.ColorUtil -import org.stepik.android.model.Reply -import org.stepik.android.presentation.step_quiz.StepQuizView -import org.stepik.android.presentation.step_quiz.model.ReplyResult import org.stepik.android.view.base.ui.interfaces.KeyboardExtensionContainer -import org.stepik.android.view.step_quiz.resolver.StepQuizFormResolver -import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFormDelegate -import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizDetailsMapper -import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizFormStateMapper -import org.stepik.android.view.step_quiz_code.model.CodeDetail import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState -import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeDetailLimitAdapterDelegate -import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeDetailSampleAdapterDelegate import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeLangAdapterDelegate -import org.stepik.android.view.ui.delegate.ViewStateDelegate import ru.nobird.android.ui.adapterssupport.DefaultDelegateAdapter class CodeStepQuizFormDelegate( containerView: View, keyboardExtensionContainer: KeyboardExtensionContainer?, - private val stepWrapper: StepPersistentWrapper, + stepWrapper: StepPersistentWrapper, private val actionsListener: ActionsListener -) : StepQuizFormDelegate { - private var state: CodeStepQuizFormState = CodeStepQuizFormState.Idle - set(value) { - field = value - - viewStateDelegate.switchState(value) - - when (value) { - is CodeStepQuizFormState.Lang -> { - codeLayout.setText(value.code) - codeLayout.lang = extensionForLanguage(value.lang) - stepQuizActionChangeLang.text = value.lang - - codeToolbarAdapter.setLanguage(value.lang) - } - } - - stepQuizCodeDetailsAdapter.items = - codeStepQuizDetailsMapper.mapToCodeDetails(stepWrapper.step, (value as? CodeStepQuizFormState.Lang)?.lang) - } - - private val viewStateDelegate = ViewStateDelegate() - private val codeStepQuizFormStateMapper = CodeStepQuizFormStateMapper() - - private val codeLayout = containerView.codeStepLayout - - private val stepQuizCodeDetails = containerView.stepQuizCodeDetails - private val stepQuizCodeDetailsArrow = containerView.stepQuizCodeDetailsArrow - private val stepQuizCodeDetailsContent = containerView.stepQuizCodeDetailsContent - - private val stepQuizCodeDetailsAdapter = DefaultDelegateAdapter() - private val codeStepQuizDetailsMapper = CodeStepQuizDetailsMapper() - - private val codeToolbarAdapter = CodeToolbarAdapter(containerView.context) - .apply { - onSymbolClickListener = object : CodeToolbarAdapter.OnSymbolClickListener { - override fun onSymbolClick(symbol: String, offset: Int) { - codeLayout.insertText(CodeToolbarUtil.mapToolbarSymbolToPrintable(symbol, codeLayout.indentSize), offset) - } - } - } +) : CodeQuizFormBaseDelegate(containerView, containerView, stepWrapper) { private val stepQuizCodeLangChooserTitle = containerView.stepQuizCodeLangChooserTitle private val stepQuizCodeLangChooser = containerView.stepQuizCodeLangChooser private val stepQuizCodeLangChooserAdapter = DefaultDelegateAdapter() - private val stepQuizActions = containerView.stepQuizActions - private val stepQuizActionChangeLang = containerView.stepQuizActionChangeLang - private val stepQuizActionFullscreen = containerView.stepQuizActionFullscreen - private val stepQuizActionMore = containerView.stepQuizActionMore - - private val codeOptions = stepWrapper.step.block?.options ?: throw IllegalArgumentException("Code options shouldn't be null") - init { viewStateDelegate.addState() viewStateDelegate.addState(stepQuizCodeLangChooserTitle, stepQuizCodeLangChooser) @@ -109,23 +42,8 @@ class CodeStepQuizFormDelegate( StepikAnimUtils.collapse(stepQuizCodeDetailsContent) } } + setupCodeDetailContentData() - stepQuizCodeDetailsAdapter += CodeDetailSampleAdapterDelegate() - stepQuizCodeDetailsAdapter += CodeDetailLimitAdapterDelegate() - - with(stepQuizCodeDetailsContent) { - visibility = View.GONE - layoutManager = LinearLayoutManager(context) - adapter = stepQuizCodeDetailsAdapter - - val divider = DividerItemDecoration(context, DividerItemDecoration.VERTICAL) - divider.setDrawable(AppCompatResources.getDrawable(context, R.drawable.bg_step_quiz_code_details_separator)!!) - addItemDecoration(divider) - } - - /** - * Keyboard extension - */ keyboardExtensionContainer ?.getKeyboardExtensionViewContainer() ?.let { container -> @@ -163,73 +81,15 @@ class CodeStepQuizFormDelegate( stepQuizActionChangeLang.setCompoundDrawables(end = R.drawable.ic_arrow_bottom) stepQuizActionChangeLang.setOnClickListener { actionsListener.onChangeLanguageClicked() } - stepQuizActionFullscreen.setOnClickListener { - val state = (state as? CodeStepQuizFormState.Lang) ?: return@setOnClickListener - actionsListener.onFullscreenClicked(state.lang, codeLayout.text.toString()) - } - stepQuizActionMore.setOnClickListener { showMoreActions() } - } - - private fun showMoreActions() { - val context = stepQuizActionMore.context - val popupMenu = PopupMenu(context, stepQuizActionMore) - popupMenu.inflate(R.menu.code_playground_menu) - - val menu = popupMenu.menu - val resetMenuItem = menu?.findItem(R.id.action_reset_code) - val resetString = SpannableString(context.getString(R.string.code_quiz_reset)) - resetString.setSpan(ForegroundColorSpan(ColorUtil.getColorArgb(R.color.new_red_color)), 0, resetString.length, 0) - resetMenuItem?.title = resetString - - menu?.findItem(R.id.action_language_code)?.isVisible = false - - popupMenu.setOnMenuItemClickListener { item -> - when (item.itemId) { - R.id.action_reset_code -> - actionsListener.onResetClicked() - } - true - } - popupMenu.show() - } - - override fun createReply(): ReplyResult { - val state = state - return if (state is CodeStepQuizFormState.Lang) { - ReplyResult.Success(Reply(code = codeLayout.text.toString(), language = state.lang)) - } else { - ReplyResult.Error(codeLayout.context.getString(R.string.step_quiz_code_empty_lang)) + codeLayout.codeEditor.isFocusable = false + codeLayout.codeEditor.setOnClickListener { + if (state !is CodeStepQuizFormState.Lang) return@setOnClickListener + actionsListener.onFullscreenClicked() } } - override fun setState(state: StepQuizView.State.AttemptLoaded) { - this.state = codeStepQuizFormStateMapper.mapToFormState(codeOptions, state) - - val isEnabled = StepQuizFormResolver.isQuizEnabled(state) - codeLayout.isEnabled = isEnabled - stepQuizActionChangeLang.isEnabled = isEnabled - stepQuizActionFullscreen.isEnabled = isEnabled - stepQuizActionMore.isEnabled = isEnabled - } - - fun onLanguageSelected(lang: String) { - if (state !is CodeStepQuizFormState.Lang) { - return - } - - state = CodeStepQuizFormState.Lang(lang, codeOptions.codeTemplates[lang] ?: "") - } - - fun onResetCode() { - val oldState = (state as? CodeStepQuizFormState.Lang) - ?: return - - state = oldState.copy(code = codeOptions.codeTemplates[oldState.lang] ?: "") - } - interface ActionsListener { fun onChangeLanguageClicked() - fun onFullscreenClicked(lang: String, code: String) - fun onResetClicked() + fun onFullscreenClicked() } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt new file mode 100644 index 0000000000..3a6bccb3c5 --- /dev/null +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt @@ -0,0 +1,107 @@ +package org.stepik.android.view.step_quiz_code.ui.delegate + +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.RecyclerView +import android.view.View +import android.view.ViewGroup +import android.widget.RelativeLayout +import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_instruction.view.* +import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.view.* +import org.stepic.droid.R +import org.stepic.droid.persistence.model.StepPersistentWrapper +import org.stepic.droid.ui.custom.LatexSupportableEnhancedFrameLayout +import org.stepic.droid.ui.util.inflate +import org.stepic.droid.ui.util.setCompoundDrawables +import org.stepic.droid.ui.util.setOnKeyboardOpenListener +import org.stepic.droid.util.DpPixelsHelper +import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState + +class CodeStepQuizFullScreenFormDelegate( + instructionContainerView: View, + codeContainerView: View, + keyboardExtensionContainer: ViewGroup?, + stepWrapper: StepPersistentWrapper, + actionsListener: ActionsListener +) : CodeQuizFormBaseDelegate(instructionContainerView, codeContainerView, stepWrapper) { + + // Flag is necessary, because keyboard listener is constantly invoked (probably global layout listener reacts to view changes) + private var keyboardShown: Boolean = false + private val codeSubmitButton = codeContainerView.codeSubmitButton + private var latexLayout: LatexSupportableEnhancedFrameLayout? = null + + init { + viewStateDelegate.addState() + viewStateDelegate.addState(codeLayout) + + if (latexLayout == null) { + latexLayout = instructionContainerView.stepQuizCodeTextContent as LatexSupportableEnhancedFrameLayout + + val text = stepWrapper + .step + .block + ?.text + ?.takeIf(String::isNotEmpty) + + if (text != null) { + instructionContainerView.stepQuizCodeTextContent.setText(text) + instructionContainerView.stepQuizCodeTextContent.setTextIsSelectable(true) + } + } + setupCodeDetailContentData() + instructionContainerView.stepQuizCodeDetailsContent.visibility = View.VISIBLE + instructionContainerView.stepQuizCodeDetailsContent.isNestedScrollingEnabled = false + /** + * Keyboard extension + */ + keyboardExtensionContainer.let { container -> + val stepQuizCodeKeyboardExtension = + container?.inflate(R.layout.layout_step_quiz_code_keyboard_extension) as RecyclerView + stepQuizCodeKeyboardExtension.adapter = codeToolbarAdapter + stepQuizCodeKeyboardExtension.layoutManager = LinearLayoutManager(container.context, LinearLayoutManager.HORIZONTAL, false) + codeLayout.codeToolbarAdapter = codeToolbarAdapter + + container.addView(stepQuizCodeKeyboardExtension) + stepQuizCodeKeyboardExtension.visibility = View.INVISIBLE // Apparently this fixes the offset bug when the current line is under the code toolbar adapter + + setOnKeyboardOpenListener( + container, + onKeyboardHidden = { + if (keyboardShown) { + stepQuizCodeKeyboardExtension.visibility = View.GONE + codeLayout.isNestedScrollingEnabled = true + codeLayout.layoutParams = + (codeLayout.layoutParams as RelativeLayout.LayoutParams) + .apply { + bottomMargin = 0 + } + codeLayout.setPadding(0, 0, 0, DpPixelsHelper.convertDpToPixel(80f).toInt()) + codeSubmitButton.visibility = View.VISIBLE + keyboardShown = false + } + }, + onKeyboardShown = { + if (!keyboardShown) { + stepQuizCodeKeyboardExtension.visibility = View.VISIBLE + codeLayout.isNestedScrollingEnabled = false + codeLayout.layoutParams = + (codeLayout.layoutParams as RelativeLayout.LayoutParams) + .apply { + bottomMargin = stepQuizCodeKeyboardExtension.height + } + codeLayout.setPadding(0, 0, 0, 0) + codeSubmitButton.visibility = View.GONE + keyboardShown = true + } + } + ) + } + stepQuizActionChangeLang.setCompoundDrawables(end = R.drawable.ic_arrow_bottom) + stepQuizActionChangeLang.setOnClickListener { actionsListener.onChangeLanguageClicked() } + codeSubmitButton.setOnClickListener { actionsListener.onSubmitClicked() } + } + + interface ActionsListener { + fun onChangeLanguageClicked() + fun onSubmitClicked() + } +} \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt index b063ccbe9c..e920573283 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt @@ -21,7 +21,6 @@ import org.stepic.droid.fonts.FontsProvider import org.stepic.droid.persistence.model.StepPersistentWrapper import org.stepic.droid.ui.dialogs.ChangeCodeLanguageDialog import org.stepic.droid.ui.dialogs.ProgrammingLanguageChooserDialogFragment -import org.stepic.droid.ui.dialogs.ResetCodeDialogFragment import org.stepic.droid.util.argument import org.stepic.droid.util.setTextColor import org.stepik.android.domain.lesson.model.LessonData @@ -30,13 +29,12 @@ import org.stepik.android.presentation.step_quiz.StepQuizView import org.stepik.android.view.base.ui.extension.parentOfType import org.stepik.android.view.step_quiz.ui.delegate.StepQuizDelegate import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFeedbackBlocksDelegate -import org.stepik.android.view.step_quiz_code.ui.delegate.CodeStepQuizFormDelegate import org.stepik.android.view.step_quiz_fullscreen_code.ui.activity.CodeStepQuizFullScreenActivity -import org.stepik.android.view.step_quiz_fullscreen_code.ui.fragment.CodeStepQuizFullScreenPlaygroundFragment +import org.stepik.android.view.step_quiz_code.ui.delegate.CodeStepQuizFormDelegate import org.stepik.android.view.ui.delegate.ViewStateDelegate import javax.inject.Inject -class CodeStepQuizFragment : Fragment(), StepQuizView, ResetCodeDialogFragment.Callback, ChangeCodeLanguageDialog.Callback, ProgrammingLanguageChooserDialogFragment.Callback { +class CodeStepQuizFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog.Callback, ProgrammingLanguageChooserDialogFragment.Callback { companion object { private const val CODE_PLAYGROUND_REQUEST = 153 @@ -62,7 +60,7 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ResetCodeDialogFragment.C private lateinit var viewStateDelegate: ViewStateDelegate private lateinit var stepQuizDelegate: StepQuizDelegate - private lateinit var codeStepQuizFormDelegate: CodeStepQuizFormDelegate + private lateinit var codeStepQuizFormDelegateNew: CodeStepQuizFormDelegate private var isFullScreenSubmitClicked: Boolean = false @@ -106,27 +104,20 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ResetCodeDialogFragment.C } } - override fun onFullscreenClicked(lang: String, code: String) { + override fun onFullscreenClicked() { stepQuizDelegate.syncReplyState { - val intent = CodeStepQuizFullScreenActivity.createIntent(requireActivity(), lang, stepWrapper, lessonData) + val intent = CodeStepQuizFullScreenActivity.createIntent(requireActivity(), stepWrapper, lessonData) startActivityForResult(intent, CODE_PLAYGROUND_REQUEST) } } - - override fun onResetClicked() { - val dialog = ResetCodeDialogFragment.newInstance() - if (!dialog.isAdded) { - dialog.show(childFragmentManager, null) - } - } } - codeStepQuizFormDelegate = CodeStepQuizFormDelegate(view, parentOfType(), stepWrapper, actionsListener) + codeStepQuizFormDelegateNew = CodeStepQuizFormDelegate(view, parentOfType(), stepWrapper, actionsListener) stepQuizDelegate = StepQuizDelegate( step = stepWrapper.step, - stepQuizFormDelegate = codeStepQuizFormDelegate, + stepQuizFormDelegate = codeStepQuizFormDelegateNew, stepQuizFeedbackBlocksDelegate = StepQuizFeedbackBlocksDelegate(stepQuizFeedbackBlocks, fontsProvider), stepQuizActionButton = stepQuizAction, stepQuizDiscountingPolicy = stepQuizDiscountingPolicy, @@ -165,10 +156,6 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ResetCodeDialogFragment.C .show() } - override fun onReset() { - codeStepQuizFormDelegate.onResetCode() - } - override fun onChangeLanguage() { val languages = stepWrapper.step.block?.options?.limits?.keys?.sorted()?.toTypedArray() ?: emptyArray() @@ -179,14 +166,14 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ResetCodeDialogFragment.C } override fun onLanguageChosen(programmingLanguage: String) { - codeStepQuizFormDelegate.onLanguageSelected(programmingLanguage) + codeStepQuizFormDelegateNew.onLanguageSelected(programmingLanguage) } override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { when (requestCode) { CODE_PLAYGROUND_REQUEST -> if (resultCode == Activity.RESULT_OK) { - isFullScreenSubmitClicked = data?.getBooleanExtra(CodeStepQuizFullScreenPlaygroundFragment.IS_SUBMITTED_CLICKED, false) ?: false + isFullScreenSubmitClicked = data?.getBooleanExtra(CodeStepQuizFullScreenActivity.IS_SUBMITTED_CLICKED, false) ?: false presenter.fetchUponFullScreenReturn(stepWrapper, lessonData) } else -> diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt index 031347d7cd..1cf8932c2d 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt @@ -1,43 +1,74 @@ package org.stepik.android.view.step_quiz_fullscreen_code.ui.activity +import android.app.Activity +import android.arch.lifecycle.ViewModelProvider +import android.arch.lifecycle.ViewModelProviders import android.content.Context import android.content.Intent import android.os.Bundle +import android.support.design.widget.Snackbar import android.support.design.widget.TabLayout +import android.support.v4.content.ContextCompat +import android.text.SpannableString +import android.text.style.ForegroundColorSpan +import android.view.Menu import android.view.MenuItem -import android.view.ViewGroup +import android.view.View import android.widget.TextView +import kotlinx.android.synthetic.main.activity_profile_edit_info.* import kotlinx.android.synthetic.main.activity_step_quiz_code_fullscreen.* import org.stepic.droid.R +import org.stepic.droid.base.App import org.stepic.droid.base.FragmentActivityBase import org.stepic.droid.fonts.FontType import org.stepic.droid.persistence.model.StepPersistentWrapper -import org.stepic.droid.ui.util.OnBackClickListener +import org.stepic.droid.ui.dialogs.ChangeCodeLanguageDialog +import org.stepic.droid.ui.dialogs.ProgrammingLanguageChooserDialogFragment +import org.stepic.droid.ui.dialogs.ResetCodeDialogFragment +import org.stepic.droid.util.ColorUtil +import org.stepic.droid.util.setTextColor import org.stepik.android.domain.lesson.model.LessonData -import org.stepik.android.view.base.ui.interfaces.KeyboardExtensionContainer -import org.stepik.android.view.step_quiz_fullscreen_code.ui.experiment.CodeStepQuizFullScreenPagerAdapter +import org.stepik.android.presentation.step_quiz.StepQuizPresenter +import org.stepik.android.presentation.step_quiz.StepQuizView +import org.stepik.android.presentation.step_quiz.model.ReplyResult +import org.stepik.android.view.step_quiz_code.ui.delegate.CodeStepQuizFullScreenFormDelegate +import org.stepik.android.view.step_quiz_fullscreen_code.ui.adapter.CodeStepQuizFullScreenPagerAdapter +import org.stepik.android.view.ui.delegate.ViewStateDelegate import uk.co.chrisjenx.calligraphy.TypefaceUtils -import java.lang.ref.WeakReference +import javax.inject.Inject -class CodeStepQuizFullScreenActivity : FragmentActivityBase(), KeyboardExtensionContainer { +class CodeStepQuizFullScreenActivity : FragmentActivityBase(), StepQuizView, ChangeCodeLanguageDialog.Callback, ProgrammingLanguageChooserDialogFragment.Callback, ResetCodeDialogFragment.Callback { companion object { - private val EXTRA_CURRENT_LANG = "current_lang_key" - private val EXTRA_STEP_WRAPPER = "step_wrapper" - private val EXTRA_LESSON_DATA = "lesson_data" + const val IS_SUBMITTED_CLICKED = "is_submit_clicked" + private const val EXTRA_STEP_WRAPPER = "step_wrapper" + private const val EXTRA_LESSON_DATA = "lesson_data" - fun createIntent(context: Context, lang: String, stepPersistentWrapper: StepPersistentWrapper, lessonData: LessonData): Intent = + fun createIntent(context: Context, stepPersistentWrapper: StepPersistentWrapper, lessonData: LessonData): Intent = Intent(context, CodeStepQuizFullScreenActivity::class.java) - .putExtra(EXTRA_CURRENT_LANG, lang) .putExtra(EXTRA_STEP_WRAPPER, stepPersistentWrapper) .putExtra(EXTRA_LESSON_DATA, lessonData) } - private var onBackClickListener: WeakReference? = null + private lateinit var stepPersistentWrapper: StepPersistentWrapper + private lateinit var lessonData: LessonData + + private lateinit var viewStateDelegate: ViewStateDelegate + + @Inject + internal lateinit var viewModelFactory: ViewModelProvider.Factory + + private lateinit var presenter: StepQuizPresenter + + private lateinit var codeStepQuizFormFullScreenDelegate: CodeStepQuizFullScreenFormDelegate + + private lateinit var instructionsLayout: View + private lateinit var playgroundLayout: View override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_step_quiz_code_fullscreen) + injectComponent() setSupportActionBar(fullScreenCodeToolbar) val actionBar = this.supportActionBar ?: throw IllegalStateException("support action bar should be set") @@ -47,28 +78,85 @@ class CodeStepQuizFullScreenActivity : FragmentActivityBase(), KeyboardExtension setDisplayHomeAsUpEnabled(true) } - val currentLang: String = intent.getStringExtra(EXTRA_CURRENT_LANG) - ?: throw IllegalStateException("Current lang cannot be null") - - val stepPersistentWrapper: StepPersistentWrapper = intent.getParcelableExtra(EXTRA_STEP_WRAPPER) + stepPersistentWrapper = intent.getParcelableExtra(EXTRA_STEP_WRAPPER) ?: throw IllegalStateException("StepPersistentWrapper cannot be null") - val lessonData: LessonData = intent.getParcelableExtra(EXTRA_LESSON_DATA) + lessonData = intent.getParcelableExtra(EXTRA_LESSON_DATA) ?: throw IllegalStateException("Lesson data cannot be null") fullScreenCodeToolbarTitle.text = lessonData.lesson.title initViewPager() + + presenter = ViewModelProviders.of(this, viewModelFactory).get(StepQuizPresenter::class.java) + presenter.onStepData(stepPersistentWrapper, lessonData) + + viewStateDelegate = ViewStateDelegate() + viewStateDelegate.addState() + viewStateDelegate.addState(stepQuizProgress) + viewStateDelegate.addState(fullScreenCodeViewPager) + + val actionsListenerNew = object : CodeStepQuizFullScreenFormDelegate.ActionsListener { + override fun onSubmitClicked() { + syncCodeOnFullScreenExit(true) + } + + override fun onChangeLanguageClicked() { + val dialog = ChangeCodeLanguageDialog.newInstance() + if (!dialog.isAdded) { + dialog.show(supportFragmentManager, null) + } + } + } + codeStepQuizFormFullScreenDelegate = CodeStepQuizFullScreenFormDelegate(instructionsLayout, playgroundLayout, coordinator, stepPersistentWrapper, actionsListenerNew) + } + + override fun onStart() { + super.onStart() + presenter.attachView(this) + } + + override fun onStop() { + presenter.detachView(this) + val reply = codeStepQuizFormFullScreenDelegate.createReply() + if (reply is ReplyResult.Success) { + presenter.syncReplyState(reply.reply) + } + super.onStop() } - override fun onOptionsItemSelected(item: MenuItem): Boolean = - if (item.itemId == android.R.id.home) { - finish() - true - } else { - false + override fun onOptionsItemSelected(item: MenuItem?): Boolean = + when (item?.itemId) { + android.R.id.home -> { + syncCodeOnFullScreenExit(false) + true + } + R.id.action_reset_code -> { + val dialog = ResetCodeDialogFragment.newInstance() + if (!dialog.isAdded) { + dialog.show(supportFragmentManager, null) + } + true + } + R.id.action_language_code -> { + val dialog = ChangeCodeLanguageDialog.newInstance() + if (!dialog.isAdded) { + dialog.show(supportFragmentManager, null) + } + true + } + else -> false } + override fun onCreateOptionsMenu(menu: Menu?): Boolean { + menuInflater.inflate(R.menu.code_playground_menu, menu) + val menuItem = menu?.findItem(R.id.action_reset_code) + val resetString = SpannableString(getString(R.string.code_quiz_reset)) + resetString.setSpan(ForegroundColorSpan(ColorUtil.getColorArgb(R.color.new_red_color)), 0, resetString.length, 0) + menuItem?.title = resetString + return super.onCreateOptionsMenu(menu) + } + private fun initViewPager() { val lightFont = TypefaceUtils.load(assets, fontsProvider.provideFontPath(FontType.light)) val regularFont = TypefaceUtils.load(assets, fontsProvider.provideFontPath(FontType.regular)) @@ -98,8 +186,62 @@ class CodeStepQuizFullScreenActivity : FragmentActivityBase(), KeyboardExtension (fullScreenCodeTabs.getTabAt(fullScreenCodeTabs.selectedTabPosition)?.customView as? TextView) ?.typeface = regularFont + + instructionsLayout = pagerAdapter.getViewAt(0) + playgroundLayout = pagerAdapter.getViewAt(1) + } + + override fun setState(state: StepQuizView.State) { + viewStateDelegate.switchState(state) + if (state is StepQuizView.State.AttemptLoaded) { + codeStepQuizFormFullScreenDelegate.setState(state) + } } - override fun getKeyboardExtensionViewContainer(): ViewGroup = - coordinator + override fun onBackPressed() { + syncCodeOnFullScreenExit(false) + } + + override fun showNetworkError() { + Snackbar + .make(root, R.string.no_connection, Snackbar.LENGTH_SHORT) + .setTextColor(ContextCompat.getColor(this, R.color.white)) + .show() + } + + override fun onChangeLanguage() { + val languages = stepPersistentWrapper.step.block?.options?.limits?.keys?.sorted()?.toTypedArray() ?: emptyArray() + + val dialog = ProgrammingLanguageChooserDialogFragment.newInstance(languages) + if (!dialog.isAdded) { + dialog.show(supportFragmentManager, null) + } + } + + override fun onLanguageChosen(programmingLanguage: String) { + codeStepQuizFormFullScreenDelegate.onLanguageSelected(programmingLanguage) + } + + override fun onReset() { + codeStepQuizFormFullScreenDelegate.onResetCode() + } + + private fun syncCodeOnFullScreenExit(isSubmittedClicked: Boolean = false) { + val reply = codeStepQuizFormFullScreenDelegate.createReply() + if (reply is ReplyResult.Success) { + presenter.syncReplyState(reply.reply) { + val data = Intent() + data.putExtra(IS_SUBMITTED_CLICKED, isSubmittedClicked) + setResult(Activity.RESULT_OK, data) + finish() + } + } + } + + private fun injectComponent() { + App.component() + .stepComponentBuilder() + .build() + .inject(this) + } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenAdapter.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenAdapter.kt deleted file mode 100644 index c14565681d..0000000000 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenAdapter.kt +++ /dev/null @@ -1,35 +0,0 @@ -package org.stepik.android.view.step_quiz_fullscreen_code.ui.adapter - -import android.content.Context -import android.support.v4.app.Fragment -import android.support.v4.app.FragmentManager -import android.support.v4.app.FragmentPagerAdapter -import org.stepic.droid.R -import org.stepic.droid.persistence.model.StepPersistentWrapper -import org.stepik.android.domain.lesson.model.LessonData -import org.stepik.android.view.step_quiz_fullscreen_code.ui.fragment.CodeStepQuizFullScreenInstructionFragment -import org.stepik.android.view.step_quiz_fullscreen_code.ui.fragment.CodeStepQuizFullScreenPlaygroundFragment - -class CodeStepQuizFullScreenAdapter( - context: Context, - lang: String, - fragmentManager: FragmentManager, - stepPersistentWrapper: StepPersistentWrapper, - lessonData: LessonData -) : FragmentPagerAdapter(fragmentManager) { - private val fragments = listOf( - { CodeStepQuizFullScreenInstructionFragment.newInstance(stepPersistentWrapper, lang) } - to context.resources.getString(R.string.step_quiz_code_full_screen_instruction_tab), - { CodeStepQuizFullScreenPlaygroundFragment.newInstance(stepPersistentWrapper, lessonData) } - to context.resources.getString(R.string.step_quiz_code_full_screen_code_tab) - ) - - override fun getItem(position: Int): Fragment = - fragments[position].first.invoke() - - override fun getCount(): Int = - fragments.size - - override fun getPageTitle(position: Int): CharSequence = - fragments[position].second -} \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/experiment/CodeStepQuizFullScreenPagerAdapter.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenPagerAdapter.kt similarity index 62% rename from app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/experiment/CodeStepQuizFullScreenPagerAdapter.kt rename to app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenPagerAdapter.kt index 8439c936e4..f24a311b9d 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/experiment/CodeStepQuizFullScreenPagerAdapter.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenPagerAdapter.kt @@ -1,4 +1,4 @@ -package org.stepik.android.view.step_quiz_fullscreen_code.ui.experiment +package org.stepik.android.view.step_quiz_fullscreen_code.ui.adapter import android.content.Context import android.support.v4.view.PagerAdapter @@ -12,8 +12,8 @@ class CodeStepQuizFullScreenPagerAdapter( ) : PagerAdapter() { private val layouts = listOf( - LayoutInflater.from(context).inflate(R.layout.fragment_step_quiz_code_fullscreen_instruction, null) to "Instruction", - LayoutInflater.from(context).inflate(R.layout.fragment_step_quiz_code_fullscreen_playground, null) to "Playground" + LayoutInflater.from(context).inflate(R.layout.layout_step_quiz_code_fullscreen_instruction, null) to "Instruction", + LayoutInflater.from(context).inflate(R.layout.layout_step_quiz_code_fullscreen_playground, null) to "Playground" ) override fun instantiateItem(container: ViewGroup, position: Int): Any { @@ -26,16 +26,14 @@ class CodeStepQuizFullScreenPagerAdapter( container.removeView(layouts[position].first) } - override fun isViewFromObject(p0: View, p1: Any): Boolean { - return p0 == p1 - } + override fun isViewFromObject(p0: View, p1: Any): Boolean = + p0 == p1 override fun getPageTitle(position: Int): CharSequence = layouts[position].second - override fun getCount(): Int { - return layouts.size - } + override fun getCount(): Int = + layouts.size fun getViewAt(position: Int): View = layouts[position].first diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/delegate/CodeQuizFormFullScreenDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/delegate/CodeQuizFormFullScreenDelegate.kt deleted file mode 100644 index 4d27fa56c0..0000000000 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/delegate/CodeQuizFormFullScreenDelegate.kt +++ /dev/null @@ -1,170 +0,0 @@ -package org.stepik.android.view.step_quiz_fullscreen_code.ui.delegate - -import android.support.v7.widget.LinearLayoutManager -import android.support.v7.widget.RecyclerView -import android.view.View -import android.view.ViewGroup -import android.widget.RelativeLayout -import kotlinx.android.synthetic.main.fragment_step_quiz_code_fullscreen_playground.view.* -import kotlinx.android.synthetic.main.layout_step_quiz_code.view.codeStepLayout -import org.stepic.droid.R -import org.stepic.droid.code.util.CodeToolbarUtil -import org.stepic.droid.model.code.extensionForLanguage -import org.stepic.droid.persistence.model.StepPersistentWrapper -import org.stepic.droid.ui.adapters.CodeToolbarAdapter -import org.stepic.droid.ui.util.inflate -import org.stepic.droid.ui.util.setOnKeyboardOpenListener -import org.stepic.droid.util.DpPixelsHelper -import org.stepik.android.model.Reply -import org.stepik.android.presentation.step_quiz.StepQuizView -import org.stepik.android.presentation.step_quiz.model.ReplyResult -import org.stepik.android.view.base.ui.interfaces.KeyboardExtensionContainer -import org.stepik.android.view.step_quiz.resolver.StepQuizFormResolver -import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFormDelegate -import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizDetailsMapper -import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizFormStateMapper -import org.stepik.android.view.step_quiz_code.model.CodeDetail -import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState -import org.stepik.android.view.ui.delegate.ViewStateDelegate -import ru.nobird.android.ui.adapterssupport.DefaultDelegateAdapter - -class CodeQuizFormFullScreenDelegate( - containerView: View, - keyboardExtensionContainer: KeyboardExtensionContainer?, - private val stepWrapper: StepPersistentWrapper, - private val actionsListener: ActionsListener -) : StepQuizFormDelegate { - private var state: CodeStepQuizFormState = CodeStepQuizFormState.Idle - set(value) { - field = value - - viewStateDelegate.switchState(value) - - when (value) { - is CodeStepQuizFormState.Lang -> { - codeLayout.setText(value.code) - codeLayout.lang = extensionForLanguage(value.lang) - codeToolbarAdapter.setLanguage(value.lang) - codeChosenLanguage.text = value.lang - } - } - - stepQuizCodeDetailsAdapter.items = - codeStepQuizDetailsMapper.mapToCodeDetails(stepWrapper.step, (value as? CodeStepQuizFormState.Lang)?.lang) - } - - // Flag is necessary, because keyboard listener is constantly invoked (probably global layout listener reacts to view changes) - private var keyboardShown: Boolean = false - - private val viewStateDelegate = ViewStateDelegate() - private val codeStepQuizFormStateMapper = CodeStepQuizFormStateMapper() - - private val codeLayout = containerView.codeStepLayout - private val codeChosenLanguage = containerView.codeChosenLanguage - private val codeSubmitButton = containerView.codeSubmitButton - - private val stepQuizCodeDetailsAdapter = DefaultDelegateAdapter() - private val codeStepQuizDetailsMapper = CodeStepQuizDetailsMapper() - - private val codeOptions = stepWrapper.step.block?.options ?: throw IllegalArgumentException("Code options shouldn't be null") - - private val codeToolbarAdapter = CodeToolbarAdapter(containerView.context) - .apply { - onSymbolClickListener = object : CodeToolbarAdapter.OnSymbolClickListener { - override fun onSymbolClick(symbol: String, offset: Int) { - codeLayout.insertText(CodeToolbarUtil.mapToolbarSymbolToPrintable(symbol, codeLayout.indentSize), offset) - } - } - } - - init { - viewStateDelegate.addState() - viewStateDelegate.addState(codeLayout) - - /** - * Keyboard extension - */ - (containerView as? ViewGroup) - keyboardExtensionContainer - ?.getKeyboardExtensionViewContainer() - ?.let { container -> - val stepQuizCodeKeyboardExtension = - container.inflate(R.layout.layout_step_quiz_code_keyboard_extension) as RecyclerView - stepQuizCodeKeyboardExtension.adapter = codeToolbarAdapter - stepQuizCodeKeyboardExtension.layoutManager = LinearLayoutManager(container.context, LinearLayoutManager.HORIZONTAL, false) - codeLayout.codeToolbarAdapter = codeToolbarAdapter - - container.addView(stepQuizCodeKeyboardExtension) - stepQuizCodeKeyboardExtension.visibility = View.INVISIBLE // Apparently this fixes the offset bug when the current line is under the code toolbar adapter - - setOnKeyboardOpenListener( - container, - onKeyboardHidden = { - if (keyboardShown) { - stepQuizCodeKeyboardExtension.visibility = View.GONE - codeLayout.isNestedScrollingEnabled = true - codeLayout.layoutParams = - (codeLayout.layoutParams as RelativeLayout.LayoutParams) - .apply { - bottomMargin = 0 - } - codeLayout.setPadding(0, 0, 0, DpPixelsHelper.convertDpToPixel(80f).toInt()) - codeSubmitButton.visibility = View.VISIBLE - keyboardShown = false - } - }, - onKeyboardShown = { - if (!keyboardShown) { - stepQuizCodeKeyboardExtension.visibility = View.VISIBLE - codeLayout.isNestedScrollingEnabled = false - codeLayout.layoutParams = - (codeLayout.layoutParams as RelativeLayout.LayoutParams) - .apply { - bottomMargin = stepQuizCodeKeyboardExtension.height - } - codeLayout.setPadding(0, 0, 0, 0) - codeSubmitButton.visibility = View.GONE - keyboardShown = true - } - } - ) - } - codeSubmitButton.setOnClickListener { actionsListener.onSubmitClicked() } - } - - override fun setState(state: StepQuizView.State.AttemptLoaded) { - this.state = codeStepQuizFormStateMapper.mapToFormState(codeOptions, state) - - val isEnabled = StepQuizFormResolver.isQuizEnabled(state) - codeLayout.isEnabled = isEnabled - codeSubmitButton.isEnabled = isEnabled - } - - fun onLanguageSelected(lang: String) { - if (state !is CodeStepQuizFormState.Lang) { - return - } - - state = CodeStepQuizFormState.Lang(lang, codeOptions.codeTemplates[lang] ?: "") - } - - fun onResetCode() { - val oldState = (state as? CodeStepQuizFormState.Lang) - ?: return - - state = oldState.copy(code = codeOptions.codeTemplates[oldState.lang] ?: "") - } - - override fun createReply(): ReplyResult { - val state = state - return if (state is CodeStepQuizFormState.Lang) { - ReplyResult.Success(Reply(code = codeLayout.text.toString(), language = state.lang)) - } else { - ReplyResult.Error(codeLayout.context.getString(R.string.step_quiz_code_empty_lang)) - } - } - - interface ActionsListener { - fun onSubmitClicked() - } -} \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenInstructionFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenInstructionFragment.kt deleted file mode 100644 index 3b3857c4b9..0000000000 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenInstructionFragment.kt +++ /dev/null @@ -1,86 +0,0 @@ -package org.stepik.android.view.step_quiz_fullscreen_code.ui.fragment - -import android.os.Bundle -import android.support.v4.app.Fragment -import android.support.v7.content.res.AppCompatResources -import android.support.v7.widget.DividerItemDecoration -import android.support.v7.widget.LinearLayoutManager -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import kotlinx.android.synthetic.main.fragment_step_quiz_code_fullscreen_instruction.* -import org.stepic.droid.R -import org.stepic.droid.persistence.model.StepPersistentWrapper -import org.stepic.droid.ui.custom.LatexSupportableEnhancedFrameLayout -import org.stepic.droid.ui.util.changeVisibility -import org.stepic.droid.util.argument -import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizDetailsMapper -import org.stepik.android.view.step_quiz_code.model.CodeDetail -import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeDetailLimitAdapterDelegate -import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeDetailSampleAdapterDelegate -import ru.nobird.android.ui.adapterssupport.DefaultDelegateAdapter - -class CodeStepQuizFullScreenInstructionFragment : Fragment() { - companion object { - fun newInstance(stepPersistentWrapper: StepPersistentWrapper, currentLang: String): Fragment = - CodeStepQuizFullScreenInstructionFragment() - .apply { - this.stepWrapper = stepPersistentWrapper - this.currentLang = currentLang - } - } - - private var stepWrapper: StepPersistentWrapper by argument() - private var latexLayout: LatexSupportableEnhancedFrameLayout? = null - private var currentLang: String by argument() - - private val stepQuizCodeDetailsAdapter = DefaultDelegateAdapter() - private val codeStepQuizDetailsMapper = CodeStepQuizDetailsMapper() - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = - inflater.inflate(R.layout.fragment_step_quiz_code_fullscreen_instruction, container, false) - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - if (latexLayout == null) { - latexLayout = stepQuizCodeTextContent as LatexSupportableEnhancedFrameLayout - - val text = stepWrapper - .step - .block - ?.text - ?.takeIf(String::isNotEmpty) - - stepQuizCodeTextContent.changeVisibility(needShow = text != null) - if (text != null) { - stepQuizCodeTextContent.setText(text) - stepQuizCodeTextContent.setTextIsSelectable(true) - } - } - - stepQuizCodeDetailsAdapter += CodeDetailSampleAdapterDelegate() - stepQuizCodeDetailsAdapter += CodeDetailLimitAdapterDelegate() - - with(stepQuizCodeDetailsContent) { - layoutManager = object : LinearLayoutManager(context) { - override fun canScrollVertically(): Boolean = - false - } - adapter = stepQuizCodeDetailsAdapter - - val divider = DividerItemDecoration(context, DividerItemDecoration.VERTICAL) - divider.setDrawable( - AppCompatResources.getDrawable( - context, - R.drawable.bg_step_quiz_code_details_separator - )!! - ) - addItemDecoration(divider) - } - stepQuizCodeDetailsContent.isNestedScrollingEnabled = false - - stepQuizCodeDetailsAdapter.items = - codeStepQuizDetailsMapper.mapToCodeDetails(stepWrapper.step, currentLang) - } -} \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenPlaygroundFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenPlaygroundFragment.kt deleted file mode 100644 index f49d930f72..0000000000 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/fragment/CodeStepQuizFullScreenPlaygroundFragment.kt +++ /dev/null @@ -1,192 +0,0 @@ -package org.stepik.android.view.step_quiz_fullscreen_code.ui.fragment - -import android.app.Activity -import android.arch.lifecycle.ViewModelProvider -import android.arch.lifecycle.ViewModelProviders -import android.content.Context -import android.content.Intent -import android.os.Bundle -import android.support.design.widget.Snackbar -import android.support.v4.app.Fragment -import android.support.v4.content.ContextCompat -import android.text.SpannableString -import android.text.style.ForegroundColorSpan -import android.view.LayoutInflater -import android.view.Menu -import android.view.MenuInflater -import android.view.MenuItem -import android.view.View -import android.view.ViewGroup -import org.stepic.droid.R -import org.stepic.droid.base.App -import org.stepic.droid.persistence.model.StepPersistentWrapper -import org.stepic.droid.ui.dialogs.ChangeCodeLanguageDialog -import org.stepic.droid.ui.dialogs.ProgrammingLanguageChooserDialogFragment -import org.stepic.droid.ui.dialogs.ResetCodeDialogFragment -import org.stepic.droid.ui.util.BackButtonHandler -import org.stepic.droid.ui.util.OnBackClickListener -import org.stepic.droid.util.ColorUtil -import org.stepic.droid.util.argument -import org.stepic.droid.util.setTextColor -import org.stepik.android.domain.lesson.model.LessonData -import org.stepik.android.presentation.step_quiz.StepQuizPresenter -import org.stepik.android.presentation.step_quiz.StepQuizView -import org.stepik.android.presentation.step_quiz.model.ReplyResult -import org.stepik.android.view.base.ui.extension.parentOfType -import org.stepik.android.view.step_quiz_fullscreen_code.ui.delegate.CodeQuizFormFullScreenDelegate -import javax.inject.Inject - -class CodeStepQuizFullScreenPlaygroundFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog.Callback, ProgrammingLanguageChooserDialogFragment.Callback, ResetCodeDialogFragment.Callback, OnBackClickListener { - companion object { - const val IS_SUBMITTED_CLICKED = "is_submit_clicked" - - fun newInstance(stepPersistentWrapper: StepPersistentWrapper, lessonData: LessonData): Fragment = - CodeStepQuizFullScreenPlaygroundFragment() - .apply { - this.stepWrapper = stepPersistentWrapper - this.lessonData = lessonData - } - } - - private var stepWrapper: StepPersistentWrapper by argument() - private var lessonData: LessonData by argument() - - @Inject - internal lateinit var viewModelFactory: ViewModelProvider.Factory - - private lateinit var presenter: StepQuizPresenter - - private lateinit var codeStepQuizFormFullScreenDelegate: CodeQuizFormFullScreenDelegate - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - injectComponent() - setHasOptionsMenu(true) - presenter = ViewModelProviders.of(this, viewModelFactory).get(StepQuizPresenter::class.java) - presenter.onStepData(stepWrapper, lessonData) - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = - inflater.inflate(R.layout.fragment_step_quiz_code_fullscreen_playground, container, false) - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - - val actionsListener = object : CodeQuizFormFullScreenDelegate.ActionsListener { - override fun onSubmitClicked() { - syncCodeOnFullScreenExit(true) - } - } - - codeStepQuizFormFullScreenDelegate = CodeQuizFormFullScreenDelegate(view, parentOfType(), stepWrapper, actionsListener) - } - - override fun onAttach(context: Context?) { - super.onAttach(context) - (activity as? BackButtonHandler)?.setBackClickListener(this) - } - - override fun onDetach() { - (activity as? BackButtonHandler)?.removeBackClickListener(this) - super.onDetach() - } - - override fun onStart() { - super.onStart() - presenter.attachView(this) - } - - override fun onStop() { - presenter.detachView(this) - val reply = codeStepQuizFormFullScreenDelegate.createReply() - if (reply is ReplyResult.Success) { - presenter.syncReplyState(reply.reply) - } - super.onStop() - } - - override fun setState(state: StepQuizView.State) { - if (state is StepQuizView.State.AttemptLoaded) { - codeStepQuizFormFullScreenDelegate.setState(state) - } - } - - override fun showNetworkError() { - val view = view ?: return - - Snackbar - .make(view, R.string.no_connection, Snackbar.LENGTH_SHORT) - .setTextColor(ContextCompat.getColor(requireContext(), R.color.white)) - .show() - } - - override fun onBackClick(): Boolean { - syncCodeOnFullScreenExit() - return true - } - - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - super.onCreateOptionsMenu(menu, inflater) - inflater.inflate(R.menu.code_playground_menu, menu) - val menuItem = menu.findItem(R.id.action_reset_code) - val resetString = SpannableString(getString(R.string.code_quiz_reset)) - resetString.setSpan(ForegroundColorSpan(ColorUtil.getColorArgb(R.color.new_red_color)), 0, resetString.length, 0) - menuItem?.title = resetString - } - - override fun onOptionsItemSelected(item: MenuItem?): Boolean = - when (item?.itemId) { - R.id.action_reset_code -> { - val dialog = ResetCodeDialogFragment.newInstance() - if (!dialog.isAdded) { - dialog.show(childFragmentManager, null) - } - true - } - R.id.action_language_code -> { - val dialog = ChangeCodeLanguageDialog.newInstance() - if (!dialog.isAdded) { - dialog.show(childFragmentManager, null) - } - true - } - else -> false - } - - override fun onChangeLanguage() { - val languages = stepWrapper.step.block?.options?.limits?.keys?.sorted()?.toTypedArray() ?: emptyArray() - - val dialog = ProgrammingLanguageChooserDialogFragment.newInstance(languages) - if (!dialog.isAdded) { - dialog.show(childFragmentManager, null) - } - } - - override fun onLanguageChosen(programmingLanguage: String) { - codeStepQuizFormFullScreenDelegate.onLanguageSelected(programmingLanguage) - } - - override fun onReset() { - codeStepQuizFormFullScreenDelegate.onResetCode() - } - - private fun syncCodeOnFullScreenExit(isSubmittedClicked: Boolean = false) { - val reply = codeStepQuizFormFullScreenDelegate.createReply() - if (reply is ReplyResult.Success) { - presenter.syncReplyState(reply.reply) { - (activity as? BackButtonHandler)?.removeBackClickListener(this) - val data = Intent() - data.putExtra(IS_SUBMITTED_CLICKED, isSubmittedClicked) - activity?.setResult(Activity.RESULT_OK, data) - activity?.onBackPressed() - } - } - } - - private fun injectComponent() { - App.component() - .stepComponentBuilder() - .build() - .inject(this) - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml b/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml index 212bf9c047..389f88f55d 100644 --- a/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml +++ b/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml @@ -16,8 +16,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="start" - android:gravity="start" - app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"> + android:gravity="start"> + app:tabPaddingEnd="24dp" /> + + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_step_quiz_code.xml b/app/src/main/res/layout/layout_step_quiz_code.xml index bceb06dc6b..6179e09832 100644 --- a/app/src/main/res/layout/layout_step_quiz_code.xml +++ b/app/src/main/res/layout/layout_step_quiz_code.xml @@ -125,33 +125,6 @@ tools:text="python3 dasjdlkas dadlj aldj akjsdlakj lkjasdkl jkdas" /> - - - - + + + android:padding="16dp" /> + + + + + + - - Date: Fri, 23 Aug 2019 19:47:59 +0300 Subject: [PATCH 11/51] add custom layout behavior to viewpager --- .../CodeStepQuizFullScreenFormDelegate.kt | 12 +++---- .../behavior/FullScreenCoordinatorBehavior.kt | 30 +++++++++++++++++ .../activity_step_quiz_code_fullscreen.xml | 8 +++-- ...t_step_quiz_code_fullscreen_playground.xml | 32 +++++++++++-------- 4 files changed, 59 insertions(+), 23 deletions(-) create mode 100644 app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/behavior/FullScreenCoordinatorBehavior.kt diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt index 3a6bccb3c5..d248199750 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt @@ -1,10 +1,10 @@ package org.stepik.android.view.step_quiz_code.ui.delegate +import android.support.constraint.ConstraintLayout import android.support.v7.widget.LinearLayoutManager import android.support.v7.widget.RecyclerView import android.view.View import android.view.ViewGroup -import android.widget.RelativeLayout import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_instruction.view.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.view.* import org.stepic.droid.R @@ -13,7 +13,6 @@ import org.stepic.droid.ui.custom.LatexSupportableEnhancedFrameLayout import org.stepic.droid.ui.util.inflate import org.stepic.droid.ui.util.setCompoundDrawables import org.stepic.droid.ui.util.setOnKeyboardOpenListener -import org.stepic.droid.util.DpPixelsHelper import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState class CodeStepQuizFullScreenFormDelegate( @@ -26,6 +25,7 @@ class CodeStepQuizFullScreenFormDelegate( // Flag is necessary, because keyboard listener is constantly invoked (probably global layout listener reacts to view changes) private var keyboardShown: Boolean = false + private val submitButtonSeparator = codeContainerView.submitButtonSeparator private val codeSubmitButton = codeContainerView.codeSubmitButton private var latexLayout: LatexSupportableEnhancedFrameLayout? = null @@ -70,11 +70,11 @@ class CodeStepQuizFullScreenFormDelegate( stepQuizCodeKeyboardExtension.visibility = View.GONE codeLayout.isNestedScrollingEnabled = true codeLayout.layoutParams = - (codeLayout.layoutParams as RelativeLayout.LayoutParams) + (codeLayout.layoutParams as ConstraintLayout.LayoutParams) .apply { bottomMargin = 0 } - codeLayout.setPadding(0, 0, 0, DpPixelsHelper.convertDpToPixel(80f).toInt()) + submitButtonSeparator.visibility = View.VISIBLE codeSubmitButton.visibility = View.VISIBLE keyboardShown = false } @@ -84,11 +84,11 @@ class CodeStepQuizFullScreenFormDelegate( stepQuizCodeKeyboardExtension.visibility = View.VISIBLE codeLayout.isNestedScrollingEnabled = false codeLayout.layoutParams = - (codeLayout.layoutParams as RelativeLayout.LayoutParams) + (codeLayout.layoutParams as ConstraintLayout.LayoutParams) .apply { bottomMargin = stepQuizCodeKeyboardExtension.height } - codeLayout.setPadding(0, 0, 0, 0) + submitButtonSeparator.visibility = View.GONE codeSubmitButton.visibility = View.GONE keyboardShown = true } diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/behavior/FullScreenCoordinatorBehavior.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/behavior/FullScreenCoordinatorBehavior.kt new file mode 100644 index 0000000000..945635a4fc --- /dev/null +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/behavior/FullScreenCoordinatorBehavior.kt @@ -0,0 +1,30 @@ +package org.stepik.android.view.step_quiz_fullscreen_code.ui.behavior + +import android.content.Context +import android.support.design.widget.AppBarLayout +import android.support.design.widget.CoordinatorLayout +import android.util.AttributeSet +import android.view.View +import android.view.ViewGroup + +class FullScreenCoordinatorBehavior(context: Context, attributeSet: AttributeSet) : CoordinatorLayout.Behavior(context, attributeSet) { + + private var startHeight: Int? = null + + override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean = + dependency is AppBarLayout + + override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean { + if (dependency is AppBarLayout) { + if (startHeight == null) { + startHeight = child.height + } + child.y = dependency.y + dependency.height + child.layoutParams = (child.layoutParams as ViewGroup.MarginLayoutParams) + .apply { + bottomMargin = (dependency.height + dependency.y).toInt() + } + } + return false + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml b/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml index 389f88f55d..ebe8073669 100644 --- a/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml +++ b/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml @@ -16,7 +16,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="start" - android:gravity="start"> + android:gravity="start" + app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed"> + app:tabPaddingEnd="24dp" + app:layout_scrollFlags="scroll|enterAlways|enterAlwaysCollapsed" /> + app:layout_behavior="org.stepik.android.view.step_quiz_fullscreen_code.ui.behavior.FullScreenCoordinatorBehavior" /> \ No newline at end of file diff --git a/app/src/main/res/layout/layout_step_quiz_code_fullscreen_playground.xml b/app/src/main/res/layout/layout_step_quiz_code_fullscreen_playground.xml index 2b3b625626..8529c825e3 100644 --- a/app/src/main/res/layout/layout_step_quiz_code_fullscreen_playground.xml +++ b/app/src/main/res/layout/layout_step_quiz_code_fullscreen_playground.xml @@ -1,5 +1,5 @@ - + + - - + app:layout_constraintBottom_toBottomOf="parent" + android:layout_marginBottom="16dp" + android:layout_marginEnd="16dp" + android:layout_marginStart="16dp"/> - \ No newline at end of file + \ No newline at end of file From 7efc2a09ba7b34145c9f52051a4953a157a17994 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Wed, 28 Aug 2019 22:10:19 +0300 Subject: [PATCH 12/51] update code editor behaviour --- app/src/main/AndroidManifest.xml | 3 +- .../CodeStepQuizFullScreenFormDelegate.kt | 35 ++++++--- .../CodeStepQuizFullScreenActivity.kt | 13 ++++ .../behavior/FullScreenCoordinatorBehavior.kt | 30 -------- .../activity_step_quiz_code_fullscreen.xml | 76 ++++++++----------- ...t_step_quiz_code_fullscreen_playground.xml | 33 ++++---- 6 files changed, 85 insertions(+), 105 deletions(-) delete mode 100644 app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/behavior/FullScreenCoordinatorBehavior.kt diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index af43044f30..b3f07d4cc8 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -369,8 +369,7 @@ - + () @@ -55,13 +60,17 @@ class CodeStepQuizFullScreenFormDelegate( */ keyboardExtensionContainer.let { container -> val stepQuizCodeKeyboardExtension = - container?.inflate(R.layout.layout_step_quiz_code_keyboard_extension) as RecyclerView + container.inflate(R.layout.layout_step_quiz_code_keyboard_extension) as RecyclerView stepQuizCodeKeyboardExtension.adapter = codeToolbarAdapter stepQuizCodeKeyboardExtension.layoutManager = LinearLayoutManager(container.context, LinearLayoutManager.HORIZONTAL, false) codeLayout.codeToolbarAdapter = codeToolbarAdapter container.addView(stepQuizCodeKeyboardExtension) stepQuizCodeKeyboardExtension.visibility = View.INVISIBLE // Apparently this fixes the offset bug when the current line is under the code toolbar adapter + stepQuizCodeKeyboardExtension.layoutParams = (stepQuizCodeKeyboardExtension.layoutParams as RelativeLayout.LayoutParams) + .apply { + addRule(RelativeLayout.ALIGN_PARENT_BOTTOM) + } setOnKeyboardOpenListener( container, @@ -70,12 +79,12 @@ class CodeStepQuizFullScreenFormDelegate( stepQuizCodeKeyboardExtension.visibility = View.GONE codeLayout.isNestedScrollingEnabled = true codeLayout.layoutParams = - (codeLayout.layoutParams as ConstraintLayout.LayoutParams) + (codeLayout.layoutParams as RelativeLayout.LayoutParams) .apply { bottomMargin = 0 } - submitButtonSeparator.visibility = View.VISIBLE - codeSubmitButton.visibility = View.VISIBLE + codeLayout.setPadding(0, 0, 0, DpPixelsHelper.convertDpToPixel(80f).toInt()) + setViewsVisibility(View.VISIBLE) keyboardShown = false } }, @@ -84,12 +93,12 @@ class CodeStepQuizFullScreenFormDelegate( stepQuizCodeKeyboardExtension.visibility = View.VISIBLE codeLayout.isNestedScrollingEnabled = false codeLayout.layoutParams = - (codeLayout.layoutParams as ConstraintLayout.LayoutParams) + (codeLayout.layoutParams as RelativeLayout.LayoutParams) .apply { bottomMargin = stepQuizCodeKeyboardExtension.height } - submitButtonSeparator.visibility = View.GONE - codeSubmitButton.visibility = View.GONE + codeLayout.setPadding(0, 0, 0, 0) + setViewsVisibility(View.GONE) keyboardShown = true } } @@ -100,6 +109,14 @@ class CodeStepQuizFullScreenFormDelegate( codeSubmitButton.setOnClickListener { actionsListener.onSubmitClicked() } } + private fun setViewsVisibility(visibility: Int) { + submitButtonSeparator.visibility = visibility + codeSubmitButton.visibility = visibility + fullScreenCodeToolbar.visibility = visibility + fullScreenCodeTabs.visibility = visibility + fullScreenCodeSeparator.visibility = visibility + } + interface ActionsListener { fun onChangeLanguageClicked() fun onSubmitClicked() diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt index 1cf8932c2d..fd2dd4779e 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt @@ -9,11 +9,13 @@ import android.os.Bundle import android.support.design.widget.Snackbar import android.support.design.widget.TabLayout import android.support.v4.content.ContextCompat +import android.support.v4.view.ViewPager import android.text.SpannableString import android.text.style.ForegroundColorSpan import android.view.Menu import android.view.MenuItem import android.view.View +import android.view.inputmethod.InputMethodManager import android.widget.TextView import kotlinx.android.synthetic.main.activity_profile_edit_info.* import kotlinx.android.synthetic.main.activity_step_quiz_code_fullscreen.* @@ -49,6 +51,8 @@ class CodeStepQuizFullScreenActivity : FragmentActivityBase(), StepQuizView, Cha .putExtra(EXTRA_LESSON_DATA, lessonData) } + private val inputMethodService = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + private lateinit var stepPersistentWrapper: StepPersistentWrapper private lateinit var lessonData: LessonData @@ -165,6 +169,15 @@ class CodeStepQuizFullScreenActivity : FragmentActivityBase(), StepQuizView, Cha fullScreenCodeViewPager.adapter = pagerAdapter fullScreenCodeTabs.setupWithViewPager(fullScreenCodeViewPager) + fullScreenCodeViewPager.addOnPageChangeListener(object : ViewPager.OnPageChangeListener { + override fun onPageScrollStateChanged(p0: Int) {} + override fun onPageScrolled(p0: Int, p1: Float, p2: Int) {} + override fun onPageSelected(p0: Int) { + if (p0 == 0) { + this@CodeStepQuizFullScreenActivity.currentFocus?.let { inputMethodService.hideSoftInputFromWindow(it.windowToken, 0) } + } + } + }) fullScreenCodeTabs.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { override fun onTabReselected(tab: TabLayout.Tab?) {} override fun onTabUnselected(tab: TabLayout.Tab?) { diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/behavior/FullScreenCoordinatorBehavior.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/behavior/FullScreenCoordinatorBehavior.kt deleted file mode 100644 index 945635a4fc..0000000000 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/behavior/FullScreenCoordinatorBehavior.kt +++ /dev/null @@ -1,30 +0,0 @@ -package org.stepik.android.view.step_quiz_fullscreen_code.ui.behavior - -import android.content.Context -import android.support.design.widget.AppBarLayout -import android.support.design.widget.CoordinatorLayout -import android.util.AttributeSet -import android.view.View -import android.view.ViewGroup - -class FullScreenCoordinatorBehavior(context: Context, attributeSet: AttributeSet) : CoordinatorLayout.Behavior(context, attributeSet) { - - private var startHeight: Int? = null - - override fun layoutDependsOn(parent: CoordinatorLayout, child: View, dependency: View): Boolean = - dependency is AppBarLayout - - override fun onDependentViewChanged(parent: CoordinatorLayout, child: View, dependency: View): Boolean { - if (dependency is AppBarLayout) { - if (startHeight == null) { - startHeight = child.height - } - child.y = dependency.y + dependency.height - child.layoutParams = (child.layoutParams as ViewGroup.MarginLayoutParams) - .apply { - bottomMargin = (dependency.height + dependency.y).toInt() - } - } - return false - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml b/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml index ebe8073669..e47abb45a6 100644 --- a/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml +++ b/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml @@ -1,57 +1,40 @@ - - - - - - - + - - - - + android:ellipsize="end" + android:maxLines="1" + android:textAppearance="@style/StepikToolbarTextAppearance"/> - - + - + android:layout_height="wrap_content" /> - \ No newline at end of file + \ No newline at end of file diff --git a/app/src/main/res/layout/layout_step_quiz_code_fullscreen_playground.xml b/app/src/main/res/layout/layout_step_quiz_code_fullscreen_playground.xml index 8529c825e3..e502fce892 100644 --- a/app/src/main/res/layout/layout_step_quiz_code_fullscreen_playground.xml +++ b/app/src/main/res/layout/layout_step_quiz_code_fullscreen_playground.xml @@ -1,18 +1,16 @@ - - - + android:layout_margin="16dp" + android:layout_alignParentBottom="true"/> + + - \ No newline at end of file + \ No newline at end of file From 6ce623ece0efb36095c975942b729326b4e3af1b Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Thu, 29 Aug 2019 00:00:22 +0300 Subject: [PATCH 13/51] sql challenge draft --- .../util/resolvers/StepTypeResolverImpl.java | 6 +- .../interactor/StepQuizInteractor.kt | 1 + .../view/injection/step/StepComponent.kt | 2 + .../ui/factory/StepQuizFragmentFactoryImpl.kt | 8 +- .../ui/delegate/SqlStepQuizFormDelegate.kt | 66 ++++++++ .../ui/fragment/SqlStepQuizFragment.kt | 143 ++++++++++++++++++ .../main/res/layout/layout_step_quiz_sql.xml | 72 +++++++++ 7 files changed, 293 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/org/stepik/android/view/step_quiz_sql/ui/delegate/SqlStepQuizFormDelegate.kt create mode 100644 app/src/main/java/org/stepik/android/view/step_quiz_sql/ui/fragment/SqlStepQuizFragment.kt create mode 100644 app/src/main/res/layout/layout_step_quiz_sql.xml diff --git a/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolverImpl.java b/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolverImpl.java index 03707b1753..84abfc27b1 100644 --- a/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolverImpl.java +++ b/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolverImpl.java @@ -8,7 +8,6 @@ import org.stepic.droid.base.StepBaseFragment; import org.stepic.droid.di.AppSingleton; import org.stepic.droid.ui.fragments.PyCharmStepFragment; -import org.stepic.droid.ui.fragments.SqlStepFragment; import org.stepic.droid.ui.quiz.ChoiceQuizDelegate; import org.stepic.droid.ui.quiz.NotSupportedQuizDelegate; import org.stepic.droid.ui.quiz.NumberQuizDelegate; @@ -99,8 +98,8 @@ public StepBaseFragment getFragment(Step step) { switch (type) { case AppConstants.TYPE_PYCHARM: return new PyCharmStepFragment(); - case AppConstants.TYPE_SQL: - return SqlStepFragment.Companion.newInstance(); +// case AppConstants.TYPE_SQL: +// return SqlStepFragment.Companion.newInstance(); default: return null; } @@ -149,6 +148,7 @@ public boolean isNeedUseOldStepContainer(@NotNull Step step) { case AppConstants.TYPE_SORTING: case AppConstants.TYPE_MATCHING: + case AppConstants.TYPE_SQL: return false; default: return true; diff --git a/app/src/main/java/org/stepik/android/domain/step_quiz/interactor/StepQuizInteractor.kt b/app/src/main/java/org/stepik/android/domain/step_quiz/interactor/StepQuizInteractor.kt index d58f34ec0b..db783c20bb 100644 --- a/app/src/main/java/org/stepik/android/domain/step_quiz/interactor/StepQuizInteractor.kt +++ b/app/src/main/java/org/stepik/android/domain/step_quiz/interactor/StepQuizInteractor.kt @@ -120,6 +120,7 @@ constructor( AppConstants.TYPE_SORTING, AppConstants.TYPE_MATCHING -> + // TODO Check if we need to recreate SQL quiz false else -> diff --git a/app/src/main/java/org/stepik/android/view/injection/step/StepComponent.kt b/app/src/main/java/org/stepik/android/view/injection/step/StepComponent.kt index 92bff27b00..32451a2b5e 100644 --- a/app/src/main/java/org/stepik/android/view/injection/step/StepComponent.kt +++ b/app/src/main/java/org/stepik/android/view/injection/step/StepComponent.kt @@ -9,6 +9,7 @@ import org.stepik.android.view.injection.submission.SubmissionDataModule import org.stepik.android.view.step.ui.fragment.StepFragment import org.stepik.android.view.step_quiz.ui.fragment.DefaultStepQuizFragment import org.stepik.android.view.step_quiz_code.ui.fragment.CodeStepQuizFragment +import org.stepik.android.view.step_quiz_sql.ui.fragment.SqlStepQuizFragment import org.stepik.android.view.step_quiz_unsupported.ui.fragment.UnsupportedStepQuizFragment @Subcomponent(modules = [ @@ -31,4 +32,5 @@ interface StepComponent { fun inject(codeStepQuizFragment: CodeStepQuizFragment) fun inject(defaultStepQuizFragment: DefaultStepQuizFragment) fun inject(unsupportedStepQuizFragment: UnsupportedStepQuizFragment) + fun inject(sqlStepQuizFragment: SqlStepQuizFragment) } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz/ui/factory/StepQuizFragmentFactoryImpl.kt b/app/src/main/java/org/stepik/android/view/step_quiz/ui/factory/StepQuizFragmentFactoryImpl.kt index 42f116a8c6..b25319a38e 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz/ui/factory/StepQuizFragmentFactoryImpl.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz/ui/factory/StepQuizFragmentFactoryImpl.kt @@ -4,11 +4,12 @@ import android.support.v4.app.Fragment import org.stepic.droid.persistence.model.StepPersistentWrapper import org.stepic.droid.util.AppConstants import org.stepik.android.domain.lesson.model.LessonData -import org.stepik.android.view.step_quiz_code.ui.fragment.CodeStepQuizFragment -import org.stepik.android.view.step_quiz_text.ui.fragment.TextStepQuizFragment import org.stepik.android.view.step_quiz_choice.ui.fragment.ChoiceStepQuizFragment +import org.stepik.android.view.step_quiz_code.ui.fragment.CodeStepQuizFragment import org.stepik.android.view.step_quiz_matching.ui.fragment.MatchingStepQuizFragment import org.stepik.android.view.step_quiz_sorting.ui.fragment.SortingStepQuizFragment +import org.stepik.android.view.step_quiz_sql.ui.fragment.SqlStepQuizFragment +import org.stepik.android.view.step_quiz_text.ui.fragment.TextStepQuizFragment import org.stepik.android.view.step_quiz_unsupported.ui.fragment.UnsupportedStepQuizFragment import javax.inject.Inject @@ -34,6 +35,9 @@ constructor() : StepQuizFragmentFactory { AppConstants.TYPE_MATCHING -> MatchingStepQuizFragment.newInstance(stepPersistentWrapper, lessonData) + AppConstants.TYPE_SQL -> + SqlStepQuizFragment.newInstance(stepPersistentWrapper, lessonData) + else -> UnsupportedStepQuizFragment.newInstance(stepPersistentWrapper) } diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_sql/ui/delegate/SqlStepQuizFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_sql/ui/delegate/SqlStepQuizFormDelegate.kt new file mode 100644 index 0000000000..6a1042cfdb --- /dev/null +++ b/app/src/main/java/org/stepik/android/view/step_quiz_sql/ui/delegate/SqlStepQuizFormDelegate.kt @@ -0,0 +1,66 @@ +package org.stepik.android.view.step_quiz_sql.ui.delegate + +import android.view.View +import kotlinx.android.synthetic.main.layout_step_quiz_code.view.* +import org.stepic.droid.R +import org.stepic.droid.model.code.extensionForLanguage +import org.stepic.droid.persistence.model.StepPersistentWrapper +import org.stepik.android.model.Reply +import org.stepik.android.presentation.step_quiz.StepQuizView +import org.stepik.android.presentation.step_quiz.model.ReplyResult +import org.stepik.android.view.step_quiz.resolver.StepQuizFormResolver +import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFormDelegate +import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState +import org.stepik.android.view.ui.delegate.ViewStateDelegate + +class SqlStepQuizFormDelegate( + containerView: View, + private val stepWrapper: StepPersistentWrapper +) : StepQuizFormDelegate { + companion object { + private const val SQL_LANG = "sql" + } + private var state: CodeStepQuizFormState = CodeStepQuizFormState.Idle + set(value) { + field = value + + viewStateDelegate.switchState(value) + + when (value) { + is CodeStepQuizFormState.Lang -> { + codeLayout.setText(value.code) + codeLayout.lang = extensionForLanguage(value.lang) + } + } + } + + private val viewStateDelegate = ViewStateDelegate() + + private val stepQuizActions = containerView.stepQuizActions + private val codeLayout = containerView.codeStepLayout + + init { + viewStateDelegate.addState() + viewStateDelegate.addState(codeLayout, stepQuizActions) + } + + override fun createReply(): ReplyResult { + val state = state + return if (state is CodeStepQuizFormState.Lang) { + ReplyResult.Success(Reply(solveSql = codeLayout.text.toString())) + } else { + ReplyResult.Error(codeLayout.context.getString(R.string.step_quiz_code_empty_lang)) + } + } + + override fun setState(state: StepQuizView.State.AttemptLoaded) { + val submission = (state.submissionState as? StepQuizView.SubmissionState.Loaded) + ?.submission + this.state = CodeStepQuizFormState.Lang(SQL_LANG, submission?.reply?.solveSql ?: "") + + val isEnabled = StepQuizFormResolver.isQuizEnabled(state) + // codeLayout.isEnabled = isEnabled + } + + +} \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_sql/ui/fragment/SqlStepQuizFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_sql/ui/fragment/SqlStepQuizFragment.kt new file mode 100644 index 0000000000..80b7c22946 --- /dev/null +++ b/app/src/main/java/org/stepik/android/view/step_quiz_sql/ui/fragment/SqlStepQuizFragment.kt @@ -0,0 +1,143 @@ +package org.stepik.android.view.step_quiz_sql.ui.fragment + +import android.arch.lifecycle.ViewModelProvider +import android.arch.lifecycle.ViewModelProviders +import android.os.Bundle +import android.support.design.widget.Snackbar +import android.support.v4.app.Fragment +import android.support.v4.content.ContextCompat +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import kotlinx.android.synthetic.main.error_no_connection_with_button_small.view.* +import kotlinx.android.synthetic.main.fragment_step_quiz.* +import kotlinx.android.synthetic.main.layout_step_quiz_code.* +import kotlinx.android.synthetic.main.view_step_quiz_submit_button.* +import org.stepic.droid.R +import org.stepic.droid.base.App +import org.stepic.droid.core.ScreenManager +import org.stepic.droid.fonts.FontsProvider +import org.stepic.droid.persistence.model.StepPersistentWrapper +import org.stepic.droid.ui.listeners.NextMoveable +import org.stepic.droid.util.argument +import org.stepic.droid.util.setTextColor +import org.stepik.android.domain.lesson.model.LessonData +import org.stepik.android.presentation.step_quiz.StepQuizPresenter +import org.stepik.android.presentation.step_quiz.StepQuizView +import org.stepik.android.view.step_quiz.ui.delegate.StepQuizDelegate +import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFeedbackBlocksDelegate +import org.stepik.android.view.step_quiz_sql.ui.delegate.SqlStepQuizFormDelegate +import org.stepik.android.view.ui.delegate.ViewStateDelegate +import javax.inject.Inject + +class SqlStepQuizFragment : Fragment(), StepQuizView { + companion object { + fun newInstance(stepPersistentWrapper: StepPersistentWrapper, lessonData: LessonData): Fragment = + SqlStepQuizFragment() + .apply { + this.stepWrapper = stepPersistentWrapper + this.lessonData = lessonData + } + } + + @Inject + internal lateinit var viewModelFactory: ViewModelProvider.Factory + + @Inject + internal lateinit var fontsProvider: FontsProvider + + @Inject + internal lateinit var screenManager: ScreenManager + + private lateinit var presenter: StepQuizPresenter + + private var lessonData: LessonData by argument() + private var stepWrapper: StepPersistentWrapper by argument() + + private lateinit var viewStateDelegate: ViewStateDelegate + private lateinit var stepQuizDelegate: StepQuizDelegate + + private lateinit var sqlStepQuizFormDelegate: SqlStepQuizFormDelegate + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + injectComponent() + + presenter = ViewModelProviders.of(this, viewModelFactory).get(StepQuizPresenter::class.java) + presenter.onStepData(stepWrapper, lessonData) + } + + private fun injectComponent() { + App.component() + .stepComponentBuilder() + .build() + .inject(this) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = + (inflater.inflate(R.layout.fragment_step_quiz, container, false) as ViewGroup) + .apply { + addView(inflater.inflate(R.layout.layout_step_quiz_sql, this, false)) + } + + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + stepQuizDescription.visibility = View.GONE + + viewStateDelegate = ViewStateDelegate() + viewStateDelegate.addState() + viewStateDelegate.addState(stepQuizProgress) + viewStateDelegate.addState(stepQuizDiscountingPolicy, stepQuizFeedbackBlocks, stepQuizCodeContainer, stepQuizActionContainer) + viewStateDelegate.addState(stepQuizNetworkError) + + stepQuizNetworkError.tryAgain.setOnClickListener { presenter.onStepData(stepWrapper, lessonData, forceUpdate = true) } + + sqlStepQuizFormDelegate = SqlStepQuizFormDelegate(view, stepWrapper) + + stepQuizDelegate = + StepQuizDelegate( + step = stepWrapper.step, + lessonData = lessonData, + stepQuizFormDelegate = sqlStepQuizFormDelegate, + stepQuizFeedbackBlocksDelegate = StepQuizFeedbackBlocksDelegate( + stepQuizFeedbackBlocks, + fontsProvider, + stepWrapper.step.actions?.doReview != null, + { screenManager.openStepInWeb(requireContext(), stepWrapper.step) } + ), + stepQuizActionButton = stepQuizAction, + stepRetryButton = stepQuizRetry, + stepQuizDiscountingPolicy = stepQuizDiscountingPolicy, + stepQuizPresenter = presenter + ) { + (parentFragment as? NextMoveable)?.moveNext() + } + } + + + override fun onStart() { + super.onStart() + presenter.attachView(this) + } + + override fun onStop() { + presenter.detachView(this) + stepQuizDelegate.syncReplyState() + super.onStop() + } + + override fun setState(state: StepQuizView.State) { + viewStateDelegate.switchState(state) + if (state is StepQuizView.State.AttemptLoaded) { + stepQuizDelegate.setState(state) + } + } + + override fun showNetworkError() { + val view = view ?: return + + Snackbar + .make(view, R.string.no_connection, Snackbar.LENGTH_SHORT) + .setTextColor(ContextCompat.getColor(requireContext(), R.color.white)) + .show() + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/layout_step_quiz_sql.xml b/app/src/main/res/layout/layout_step_quiz_sql.xml new file mode 100644 index 0000000000..3bcbacd0b0 --- /dev/null +++ b/app/src/main/res/layout/layout_step_quiz_sql.xml @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + \ No newline at end of file From fc87c36fb373a4a15830fbb70fea8b337fb018e8 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Thu, 29 Aug 2019 00:12:30 +0300 Subject: [PATCH 14/51] init input method manager in onCreate --- .../ui/activity/CodeStepQuizFullScreenActivity.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt index fd2dd4779e..34dc36f191 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt @@ -51,7 +51,7 @@ class CodeStepQuizFullScreenActivity : FragmentActivityBase(), StepQuizView, Cha .putExtra(EXTRA_LESSON_DATA, lessonData) } - private val inputMethodService = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + private lateinit var inputMethodManager: InputMethodManager private lateinit var stepPersistentWrapper: StepPersistentWrapper private lateinit var lessonData: LessonData @@ -82,6 +82,8 @@ class CodeStepQuizFullScreenActivity : FragmentActivityBase(), StepQuizView, Cha setDisplayHomeAsUpEnabled(true) } + inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + stepPersistentWrapper = intent.getParcelableExtra(EXTRA_STEP_WRAPPER) ?: throw IllegalStateException("StepPersistentWrapper cannot be null") @@ -174,7 +176,7 @@ class CodeStepQuizFullScreenActivity : FragmentActivityBase(), StepQuizView, Cha override fun onPageScrolled(p0: Int, p1: Float, p2: Int) {} override fun onPageSelected(p0: Int) { if (p0 == 0) { - this@CodeStepQuizFullScreenActivity.currentFocus?.let { inputMethodService.hideSoftInputFromWindow(it.windowToken, 0) } + this@CodeStepQuizFullScreenActivity.currentFocus?.let { inputMethodManager.hideSoftInputFromWindow(it.windowToken, 0) } } } }) From de930e47aebb8bdb6891a4bfb7e501c1a00bc8d7 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Thu, 29 Aug 2019 00:14:09 +0300 Subject: [PATCH 15/51] remove keyboard extension from small code form --- .../ui/delegate/CodeStepQuizFormDelegate.kt | 23 ------------------- .../ui/fragment/CodeStepQuizFragment.kt | 5 ++-- 2 files changed, 2 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt index f60483f603..ba7cc967c0 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt @@ -1,23 +1,18 @@ package org.stepik.android.view.step_quiz_code.ui.delegate import android.support.v7.widget.LinearLayoutManager -import android.support.v7.widget.RecyclerView import android.view.View import kotlinx.android.synthetic.main.layout_step_quiz_code.view.* import org.stepic.droid.R import org.stepic.droid.persistence.model.StepPersistentWrapper import org.stepic.droid.ui.util.StepikAnimUtils -import org.stepic.droid.ui.util.inflate import org.stepic.droid.ui.util.setCompoundDrawables -import org.stepic.droid.ui.util.setOnKeyboardOpenListener -import org.stepik.android.view.base.ui.interfaces.KeyboardExtensionContainer import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeLangAdapterDelegate import ru.nobird.android.ui.adapterssupport.DefaultDelegateAdapter class CodeStepQuizFormDelegate( containerView: View, - keyboardExtensionContainer: KeyboardExtensionContainer?, stepWrapper: StepPersistentWrapper, private val actionsListener: ActionsListener ) : CodeQuizFormBaseDelegate(containerView, containerView, stepWrapper) { @@ -44,24 +39,6 @@ class CodeStepQuizFormDelegate( } setupCodeDetailContentData() - keyboardExtensionContainer - ?.getKeyboardExtensionViewContainer() - ?.let { container -> - val stepQuizCodeKeyboardExtension = - container.inflate(R.layout.layout_step_quiz_code_keyboard_extension) as RecyclerView - stepQuizCodeKeyboardExtension.adapter = codeToolbarAdapter - stepQuizCodeKeyboardExtension.layoutManager = LinearLayoutManager(container.context, LinearLayoutManager.HORIZONTAL, false) - codeLayout.codeToolbarAdapter = codeToolbarAdapter - - container.addView(stepQuizCodeKeyboardExtension) - - setOnKeyboardOpenListener( - container, - onKeyboardHidden = { stepQuizCodeKeyboardExtension.visibility = View.GONE }, - onKeyboardShown = { stepQuizCodeKeyboardExtension.visibility = View.VISIBLE } - ) - } - /** * Lang chooser */ diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt index e920573283..7bd21e17b1 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt @@ -26,11 +26,10 @@ import org.stepic.droid.util.setTextColor import org.stepik.android.domain.lesson.model.LessonData import org.stepik.android.presentation.step_quiz.StepQuizPresenter import org.stepik.android.presentation.step_quiz.StepQuizView -import org.stepik.android.view.base.ui.extension.parentOfType import org.stepik.android.view.step_quiz.ui.delegate.StepQuizDelegate import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFeedbackBlocksDelegate -import org.stepik.android.view.step_quiz_fullscreen_code.ui.activity.CodeStepQuizFullScreenActivity import org.stepik.android.view.step_quiz_code.ui.delegate.CodeStepQuizFormDelegate +import org.stepik.android.view.step_quiz_fullscreen_code.ui.activity.CodeStepQuizFullScreenActivity import org.stepik.android.view.ui.delegate.ViewStateDelegate import javax.inject.Inject @@ -112,7 +111,7 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog. } } - codeStepQuizFormDelegateNew = CodeStepQuizFormDelegate(view, parentOfType(), stepWrapper, actionsListener) + codeStepQuizFormDelegateNew = CodeStepQuizFormDelegate(view, stepWrapper, actionsListener) stepQuizDelegate = StepQuizDelegate( From 005ae3da6b2fb9952c8c00832bdc2a4d7aae37e2 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Fri, 30 Aug 2019 23:56:49 +0300 Subject: [PATCH 16/51] update classDirectories path with java + kotlin classes --- code_quality_tools/jacoco.gradle | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/code_quality_tools/jacoco.gradle b/code_quality_tools/jacoco.gradle index 94a95ebae0..7ef1670d5c 100644 --- a/code_quality_tools/jacoco.gradle +++ b/code_quality_tools/jacoco.gradle @@ -32,9 +32,7 @@ project.afterEvaluate { group = 'Reporting' description = "Generate Jacoco coverage reports for the ${sourceName.capitalize()} build." - classDirectories = fileTree( - dir: "${project.buildDir}/intermediates/classes/${sourcePath}", - excludes: ['**/R.class', + def excludes = ['**/R.class', '**/R$*.class', '**/*$ViewInjector*.*', '**/*$ViewBinder*.*', @@ -46,6 +44,13 @@ project.afterEvaluate { '**/*Dagger*.*', // Dagger auto-generated code. '**/*MembersInjector*.*', // Dagger auto-generated code. '**/*_Provide*Factory*.*'] // Dagger auto-generated code. + + classDirectories = fileTree( + dir: "${project.buildDir}/intermediates/javac/${sourcePath}", + excludes: excludes + ) + fileTree( + dir: "${project.buildDir}/tmp/kotlin-classes/${sourcePath}", + excludes: excludes ) def coverageSourceDirs = [ From 51f55d2e173c599b91b8ea67b86157b50079e1db Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 2 Sep 2019 17:01:27 +0300 Subject: [PATCH 17/51] transfer fullscreen from activity to dialog fragment --- .../step_quiz/StepQuizPresenter.kt | 7 +- .../view/injection/step/StepComponent.kt | 4 +- .../step_quiz/ui/delegate/StepQuizDelegate.kt | 4 +- .../ui/delegate/CodeQuizFormBaseDelegate.kt | 10 - .../ui/delegate/CodeStepQuizFormDelegate.kt | 21 +- .../CodeStepQuizFullScreenFormDelegate.kt | 6 + .../ui/fragment/CodeStepQuizFragment.kt | 48 ++-- .../CodeStepQuizFullScreenDialogFragment.kt} | 259 ++++++++++-------- 8 files changed, 189 insertions(+), 170 deletions(-) rename app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/{activity/CodeStepQuizFullScreenActivity.kt => dialog/CodeStepQuizFullScreenDialogFragment.kt} (52%) diff --git a/app/src/main/java/org/stepik/android/presentation/step_quiz/StepQuizPresenter.kt b/app/src/main/java/org/stepik/android/presentation/step_quiz/StepQuizPresenter.kt index 9475b81930..848fbdd3dc 100644 --- a/app/src/main/java/org/stepik/android/presentation/step_quiz/StepQuizPresenter.kt +++ b/app/src/main/java/org/stepik/android/presentation/step_quiz/StepQuizPresenter.kt @@ -45,9 +45,6 @@ constructor( } } - fun fetchUponFullScreenReturn(stepWrapper: StepPersistentWrapper, lessonData: LessonData): Unit = - fetchAttempt(stepWrapper, lessonData) - private fun fetchAttempt(stepWrapper: StepPersistentWrapper, lessonData: LessonData) { state = StepQuizView.State.Loading compositeDisposable += stepQuizInteractor @@ -127,7 +124,7 @@ constructor( ) } - fun syncReplyState(reply: Reply, onSync: (() -> Unit)? = null) { + fun syncReplyState(reply: Reply) { val oldState = (state as? StepQuizView.State.AttemptLoaded) ?: return @@ -143,6 +140,6 @@ constructor( .createLocalSubmission(submission) .subscribeOn(backgroundScheduler) .observeOn(mainScheduler) - .subscribeBy(onSuccess = { onSync?.invoke() }, onError = emptyOnErrorStub) + .subscribeBy(onError = emptyOnErrorStub) } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/injection/step/StepComponent.kt b/app/src/main/java/org/stepik/android/view/injection/step/StepComponent.kt index 8a6a5e859e..416f63dd2e 100644 --- a/app/src/main/java/org/stepik/android/view/injection/step/StepComponent.kt +++ b/app/src/main/java/org/stepik/android/view/injection/step/StepComponent.kt @@ -9,7 +9,7 @@ import org.stepik.android.view.injection.submission.SubmissionDataModule import org.stepik.android.view.step.ui.fragment.StepFragment import org.stepik.android.view.step_quiz_choice.ui.fragment.ChoiceStepQuizFragment import org.stepik.android.view.step_quiz_code.ui.fragment.CodeStepQuizFragment -import org.stepik.android.view.step_quiz_fullscreen_code.ui.activity.CodeStepQuizFullScreenActivity +import org.stepik.android.view.step_quiz_fullscreen_code.ui.dialog.CodeStepQuizFullScreenDialogFragment import org.stepik.android.view.step_quiz_text.ui.fragment.TextStepQuizFragment @Subcomponent(modules = [ @@ -33,5 +33,5 @@ interface StepComponent { fun inject(codeStepQuizFragment: CodeStepQuizFragment) fun inject(textStepQuizFragment: TextStepQuizFragment) - fun inject(codeStepQuizFullScreenActivity: CodeStepQuizFullScreenActivity) + fun inject(codeStepQuizFullScreenDialogFragment: CodeStepQuizFullScreenDialogFragment) } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz/ui/delegate/StepQuizDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz/ui/delegate/StepQuizDelegate.kt index 1e42ff82ce..8558b8e4a7 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz/ui/delegate/StepQuizDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz/ui/delegate/StepQuizDelegate.kt @@ -107,13 +107,13 @@ class StepQuizDelegate( } } - fun syncReplyState(onSync: (() -> Unit)? = null) { + fun syncReplyState() { if (StepQuizFormResolver.isSubmissionInTerminalState(currentState ?: return)) return val reply = (stepQuizFormDelegate.createReply() as? ReplyResult.Success) ?.reply ?: return - stepQuizPresenter.syncReplyState(reply, onSync) + stepQuizPresenter.syncReplyState(reply) } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizFormBaseDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizFormBaseDelegate.kt index 9146011b51..c7d818afae 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizFormBaseDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizFormBaseDelegate.kt @@ -11,9 +11,7 @@ import org.stepic.droid.model.code.extensionForLanguage import org.stepic.droid.persistence.model.StepPersistentWrapper import org.stepic.droid.ui.adapters.CodeToolbarAdapter import org.stepik.android.model.Reply -import org.stepik.android.presentation.step_quiz.StepQuizView import org.stepik.android.presentation.step_quiz.model.ReplyResult -import org.stepik.android.view.step_quiz.resolver.StepQuizFormResolver import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFormDelegate import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizDetailsMapper import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizFormStateMapper @@ -100,14 +98,6 @@ abstract class CodeQuizFormBaseDelegate( } } - override fun setState(state: StepQuizView.State.AttemptLoaded) { - this.state = codeStepQuizFormStateMapper.mapToFormState(codeOptions, state) - - val isEnabled = StepQuizFormResolver.isQuizEnabled(state) - codeLayout.isEnabled = isEnabled - stepQuizActionChangeLang.isEnabled = isEnabled - } - fun onLanguageSelected(lang: String) { if (state !is CodeStepQuizFormState.Lang) { return diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt index ba7cc967c0..7ccfa31d1f 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt @@ -7,6 +7,8 @@ import org.stepic.droid.R import org.stepic.droid.persistence.model.StepPersistentWrapper import org.stepic.droid.ui.util.StepikAnimUtils import org.stepic.droid.ui.util.setCompoundDrawables +import org.stepik.android.presentation.step_quiz.StepQuizView +import org.stepik.android.view.step_quiz.resolver.StepQuizFormResolver import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeLangAdapterDelegate import ru.nobird.android.ui.adapterssupport.DefaultDelegateAdapter @@ -60,13 +62,26 @@ class CodeStepQuizFormDelegate( codeLayout.codeEditor.isFocusable = false codeLayout.codeEditor.setOnClickListener { - if (state !is CodeStepQuizFormState.Lang) return@setOnClickListener - actionsListener.onFullscreenClicked() + val oldState = (state as? CodeStepQuizFormState.Lang) + ?: return@setOnClickListener + actionsListener.onFullscreenClicked(oldState.lang, oldState.code) } } + override fun setState(state: StepQuizView.State.AttemptLoaded) { + this.state = codeStepQuizFormStateMapper.mapToFormState(codeOptions, state) + + val isEnabled = StepQuizFormResolver.isQuizEnabled(state) + codeLayout.isEnabled = isEnabled + stepQuizActionChangeLang.isEnabled = isEnabled + } + + fun updateCodeLayout(lang: String, code: String) { + state = CodeStepQuizFormState.Lang(lang, code) + } + interface ActionsListener { fun onChangeLanguageClicked() - fun onFullscreenClicked() + fun onFullscreenClicked(lang: String, code: String) } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt index 6aad8af628..5dbe440311 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt @@ -15,6 +15,7 @@ import org.stepic.droid.ui.util.inflate import org.stepic.droid.ui.util.setCompoundDrawables import org.stepic.droid.ui.util.setOnKeyboardOpenListener import org.stepic.droid.util.DpPixelsHelper +import org.stepik.android.presentation.step_quiz.StepQuizView import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState class CodeStepQuizFullScreenFormDelegate( @@ -70,6 +71,7 @@ class CodeStepQuizFullScreenFormDelegate( stepQuizCodeKeyboardExtension.layoutParams = (stepQuizCodeKeyboardExtension.layoutParams as RelativeLayout.LayoutParams) .apply { addRule(RelativeLayout.ALIGN_PARENT_BOTTOM) +// addRule(RelativeLayout.ALIGN_BOTTOM, R.id.codeStepLayout) } setOnKeyboardOpenListener( @@ -109,6 +111,10 @@ class CodeStepQuizFullScreenFormDelegate( codeSubmitButton.setOnClickListener { actionsListener.onSubmitClicked() } } + override fun setState(state: StepQuizView.State.AttemptLoaded) { + this.state = codeStepQuizFormStateMapper.mapToFormState(codeOptions, state) + } + private fun setViewsVisibility(visibility: Int) { submitButtonSeparator.visibility = visibility codeSubmitButton.visibility = visibility diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt index 7bd21e17b1..3082afb4e0 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt @@ -1,9 +1,7 @@ package org.stepik.android.view.step_quiz_code.ui.fragment -import android.app.Activity import android.arch.lifecycle.ViewModelProvider import android.arch.lifecycle.ViewModelProviders -import android.content.Intent import android.os.Bundle import android.support.design.widget.Snackbar import android.support.v4.app.Fragment @@ -29,14 +27,12 @@ import org.stepik.android.presentation.step_quiz.StepQuizView import org.stepik.android.view.step_quiz.ui.delegate.StepQuizDelegate import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFeedbackBlocksDelegate import org.stepik.android.view.step_quiz_code.ui.delegate.CodeStepQuizFormDelegate -import org.stepik.android.view.step_quiz_fullscreen_code.ui.activity.CodeStepQuizFullScreenActivity +import org.stepik.android.view.step_quiz_fullscreen_code.ui.dialog.CodeStepQuizFullScreenDialogFragment import org.stepik.android.view.ui.delegate.ViewStateDelegate import javax.inject.Inject -class CodeStepQuizFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog.Callback, ProgrammingLanguageChooserDialogFragment.Callback { +class CodeStepQuizFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog.Callback, ProgrammingLanguageChooserDialogFragment.Callback, CodeStepQuizFullScreenDialogFragment.Callback { companion object { - private const val CODE_PLAYGROUND_REQUEST = 153 - fun newInstance(stepPersistentWrapper: StepPersistentWrapper, lessonData: LessonData): Fragment = CodeStepQuizFragment() .apply { @@ -59,9 +55,7 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog. private lateinit var viewStateDelegate: ViewStateDelegate private lateinit var stepQuizDelegate: StepQuizDelegate - private lateinit var codeStepQuizFormDelegateNew: CodeStepQuizFormDelegate - - private var isFullScreenSubmitClicked: Boolean = false + private lateinit var codeStepQuizFormDelegate: CodeStepQuizFormDelegate override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -103,20 +97,23 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog. } } - override fun onFullscreenClicked() { - stepQuizDelegate.syncReplyState { - val intent = CodeStepQuizFullScreenActivity.createIntent(requireActivity(), stepWrapper, lessonData) - startActivityForResult(intent, CODE_PLAYGROUND_REQUEST) - } + override fun onFullscreenClicked(lang: String, code: String) { + val supportFragmentManager = fragmentManager + ?.takeIf { it.findFragmentByTag(CodeStepQuizFullScreenDialogFragment.TAG) == null } + ?: return + + val dialog = CodeStepQuizFullScreenDialogFragment.newInstance(lang, code, stepWrapper, lessonData) + dialog.setTargetFragment(this@CodeStepQuizFragment, CodeStepQuizFullScreenDialogFragment.CODE_PLAYGROUND_REQUEST) + dialog.show(supportFragmentManager, CodeStepQuizFullScreenDialogFragment.TAG) } } - codeStepQuizFormDelegateNew = CodeStepQuizFormDelegate(view, stepWrapper, actionsListener) + codeStepQuizFormDelegate = CodeStepQuizFormDelegate(view, stepWrapper, actionsListener) stepQuizDelegate = StepQuizDelegate( step = stepWrapper.step, - stepQuizFormDelegate = codeStepQuizFormDelegateNew, + stepQuizFormDelegate = codeStepQuizFormDelegate, stepQuizFeedbackBlocksDelegate = StepQuizFeedbackBlocksDelegate(stepQuizFeedbackBlocks, fontsProvider), stepQuizActionButton = stepQuizAction, stepQuizDiscountingPolicy = stepQuizDiscountingPolicy, @@ -139,10 +136,6 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog. viewStateDelegate.switchState(state) if (state is StepQuizView.State.AttemptLoaded) { stepQuizDelegate.setState(state) - if (isFullScreenSubmitClicked && state.submissionState is StepQuizView.SubmissionState.Loaded) { - isFullScreenSubmitClicked = false - stepQuizDelegate.onActionButtonClicked() - } } } @@ -165,18 +158,13 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog. } override fun onLanguageChosen(programmingLanguage: String) { - codeStepQuizFormDelegateNew.onLanguageSelected(programmingLanguage) + codeStepQuizFormDelegate.onLanguageSelected(programmingLanguage) } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - when (requestCode) { - CODE_PLAYGROUND_REQUEST -> - if (resultCode == Activity.RESULT_OK) { - isFullScreenSubmitClicked = data?.getBooleanExtra(CodeStepQuizFullScreenActivity.IS_SUBMITTED_CLICKED, false) ?: false - presenter.fetchUponFullScreenReturn(stepWrapper, lessonData) - } - else -> - super.onActivityResult(requestCode, resultCode, data) + override fun onSyncCodeStateWithParent(lang: String, code: String, onSubmitClicked: Boolean) { + codeStepQuizFormDelegate.updateCodeLayout(lang, code) + if (onSubmitClicked) { + stepQuizDelegate.onActionButtonClicked() } } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt similarity index 52% rename from app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt rename to app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt index 34dc36f191..960a577d1a 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/activity/CodeStepQuizFullScreenActivity.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt @@ -1,63 +1,72 @@ -package org.stepik.android.view.step_quiz_fullscreen_code.ui.activity +package org.stepik.android.view.step_quiz_fullscreen_code.ui.dialog -import android.app.Activity +import android.app.Dialog import android.arch.lifecycle.ViewModelProvider import android.arch.lifecycle.ViewModelProviders -import android.content.Context -import android.content.Intent import android.os.Bundle import android.support.design.widget.Snackbar import android.support.design.widget.TabLayout +import android.support.v4.app.DialogFragment import android.support.v4.content.ContextCompat +import android.support.v4.content.ContextCompat.getSystemService import android.support.v4.view.ViewPager -import android.text.SpannableString -import android.text.style.ForegroundColorSpan -import android.view.Menu -import android.view.MenuItem +import android.view.LayoutInflater import android.view.View +import android.view.ViewGroup +import android.view.Window import android.view.inputmethod.InputMethodManager import android.widget.TextView -import kotlinx.android.synthetic.main.activity_profile_edit_info.* import kotlinx.android.synthetic.main.activity_step_quiz_code_fullscreen.* +import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.* import org.stepic.droid.R import org.stepic.droid.base.App -import org.stepic.droid.base.FragmentActivityBase import org.stepic.droid.fonts.FontType +import org.stepic.droid.fonts.FontsProvider import org.stepic.droid.persistence.model.StepPersistentWrapper import org.stepic.droid.ui.dialogs.ChangeCodeLanguageDialog import org.stepic.droid.ui.dialogs.ProgrammingLanguageChooserDialogFragment import org.stepic.droid.ui.dialogs.ResetCodeDialogFragment -import org.stepic.droid.util.ColorUtil +import org.stepic.droid.util.argument import org.stepic.droid.util.setTextColor import org.stepik.android.domain.lesson.model.LessonData import org.stepik.android.presentation.step_quiz.StepQuizPresenter import org.stepik.android.presentation.step_quiz.StepQuizView import org.stepik.android.presentation.step_quiz.model.ReplyResult +import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState import org.stepik.android.view.step_quiz_code.ui.delegate.CodeStepQuizFullScreenFormDelegate import org.stepik.android.view.step_quiz_fullscreen_code.ui.adapter.CodeStepQuizFullScreenPagerAdapter import org.stepik.android.view.ui.delegate.ViewStateDelegate import uk.co.chrisjenx.calligraphy.TypefaceUtils import javax.inject.Inject -class CodeStepQuizFullScreenActivity : FragmentActivityBase(), StepQuizView, ChangeCodeLanguageDialog.Callback, ProgrammingLanguageChooserDialogFragment.Callback, ResetCodeDialogFragment.Callback { +class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, ChangeCodeLanguageDialog.Callback, ProgrammingLanguageChooserDialogFragment.Callback, ResetCodeDialogFragment.Callback { companion object { - const val IS_SUBMITTED_CLICKED = "is_submit_clicked" - private const val EXTRA_STEP_WRAPPER = "step_wrapper" - private const val EXTRA_LESSON_DATA = "lesson_data" - - fun createIntent(context: Context, stepPersistentWrapper: StepPersistentWrapper, lessonData: LessonData): Intent = - Intent(context, CodeStepQuizFullScreenActivity::class.java) - .putExtra(EXTRA_STEP_WRAPPER, stepPersistentWrapper) - .putExtra(EXTRA_LESSON_DATA, lessonData) + const val TAG = "CodeStepQuizFullScreenDialogFragment" + const val CODE_PLAYGROUND_REQUEST = 153 + + fun newInstance(lang: String, code: String, stepPersistentWrapper: StepPersistentWrapper, lessonData: LessonData): DialogFragment = + CodeStepQuizFullScreenDialogFragment() + .apply { + this.lang = lang + this.code = code + this.stepWrapper = stepPersistentWrapper + this.lessonData = lessonData + } + } + + interface Callback { + fun onSyncCodeStateWithParent(lang: String, code: String, onSubmitClicked: Boolean = false) } - private lateinit var inputMethodManager: InputMethodManager + private lateinit var callback: Callback - private lateinit var stepPersistentWrapper: StepPersistentWrapper - private lateinit var lessonData: LessonData + private var inputMethodManager: InputMethodManager? = null private lateinit var viewStateDelegate: ViewStateDelegate + @Inject + internal lateinit var fontsProvider: FontsProvider + @Inject internal lateinit var viewModelFactory: ViewModelProvider.Factory @@ -68,106 +77,118 @@ class CodeStepQuizFullScreenActivity : FragmentActivityBase(), StepQuizView, Cha private lateinit var instructionsLayout: View private lateinit var playgroundLayout: View + private var lang: String by argument() + private var code: String by argument() + private var lessonData: LessonData by argument() + private var stepWrapper: StepPersistentWrapper by argument() + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val dialog = super.onCreateDialog(savedInstanceState) + + dialog.setCanceledOnTouchOutside(false) + dialog.setCancelable(false) + dialog.requestWindowFeature(Window.FEATURE_NO_TITLE) + + return dialog + } + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_step_quiz_code_fullscreen) + setStyle(STYLE_NO_TITLE, R.style.AppTheme_FullScreenDialog) injectComponent() - setSupportActionBar(fullScreenCodeToolbar) - val actionBar = this.supportActionBar - ?: throw IllegalStateException("support action bar should be set") + } - with(actionBar) { - setDisplayShowTitleEnabled(false) - setDisplayHomeAsUpEnabled(true) + override fun setState(state: StepQuizView.State) { + viewStateDelegate.switchState(state) + if (state is StepQuizView.State.AttemptLoaded) { + codeStepQuizFormFullScreenDelegate.setState(state) } + } + + private fun injectComponent() { + App.component() + .stepComponentBuilder() + .build() + .inject(this) + } + + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = + inflater.inflate(R.layout.activity_step_quiz_code_fullscreen, container, false) - inputMethodManager = getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { + super.onViewCreated(view, savedInstanceState) - stepPersistentWrapper = intent.getParcelableExtra(EXTRA_STEP_WRAPPER) - ?: throw IllegalStateException("StepPersistentWrapper cannot be null") + callback = targetFragment as Callback - lessonData = intent.getParcelableExtra(EXTRA_LESSON_DATA) - ?: throw IllegalStateException("Lesson data cannot be null") + inputMethodManager = getSystemService(App.getAppContext(), InputMethodManager::class.java) fullScreenCodeToolbarTitle.text = lessonData.lesson.title + fullScreenCodeToolbar.inflateMenu(R.menu.code_playground_menu) + fullScreenCodeToolbar.setNavigationOnClickListener { dismiss() } + fullScreenCodeToolbar.setNavigationIcon(R.drawable.ic_close_dark) + fullScreenCodeToolbar.setOnMenuItemClickListener { item -> + when (item?.itemId) { + android.R.id.home -> { + true + } + R.id.action_reset_code -> { + val dialog = ResetCodeDialogFragment.newInstance() + if (!dialog.isAdded) { + dialog.show(childFragmentManager, null) + } + true + } + R.id.action_language_code -> { + val dialog = ChangeCodeLanguageDialog.newInstance() + if (!dialog.isAdded) { + dialog.show(childFragmentManager, null) + } + true + } + else -> false + } + } initViewPager() presenter = ViewModelProviders.of(this, viewModelFactory).get(StepQuizPresenter::class.java) - presenter.onStepData(stepPersistentWrapper, lessonData) viewStateDelegate = ViewStateDelegate() - viewStateDelegate.addState() + viewStateDelegate.addState(fullScreenCodeViewPager) viewStateDelegate.addState(stepQuizProgress) viewStateDelegate.addState(fullScreenCodeViewPager) val actionsListenerNew = object : CodeStepQuizFullScreenFormDelegate.ActionsListener { override fun onSubmitClicked() { - syncCodeOnFullScreenExit(true) + callback.onSyncCodeStateWithParent((codeStepQuizFormFullScreenDelegate.state as CodeStepQuizFormState.Lang).lang, codeStepLayout.text.toString(), true) + dismiss() } override fun onChangeLanguageClicked() { val dialog = ChangeCodeLanguageDialog.newInstance() if (!dialog.isAdded) { - dialog.show(supportFragmentManager, null) + dialog.show(childFragmentManager, null) } } } - codeStepQuizFormFullScreenDelegate = CodeStepQuizFullScreenFormDelegate(instructionsLayout, playgroundLayout, coordinator, stepPersistentWrapper, actionsListenerNew) - } - - override fun onStart() { - super.onStart() - presenter.attachView(this) - } + codeStepQuizFormFullScreenDelegate = CodeStepQuizFullScreenFormDelegate(instructionsLayout, playgroundLayout, coordinator, stepWrapper, actionsListenerNew) - override fun onStop() { - presenter.detachView(this) - val reply = codeStepQuizFormFullScreenDelegate.createReply() - if (reply is ReplyResult.Success) { - presenter.syncReplyState(reply.reply) + if (savedInstanceState == null) { + codeStepQuizFormFullScreenDelegate.state = CodeStepQuizFormState.Lang(lang, code) + } else { + presenter.onStepData(stepWrapper, lessonData) } - super.onStop() - } - - override fun onOptionsItemSelected(item: MenuItem?): Boolean = - when (item?.itemId) { - android.R.id.home -> { - syncCodeOnFullScreenExit(false) - true - } - R.id.action_reset_code -> { - val dialog = ResetCodeDialogFragment.newInstance() - if (!dialog.isAdded) { - dialog.show(supportFragmentManager, null) - } - true - } - R.id.action_language_code -> { - val dialog = ChangeCodeLanguageDialog.newInstance() - if (!dialog.isAdded) { - dialog.show(supportFragmentManager, null) - } - true - } - else -> false - } - - override fun onCreateOptionsMenu(menu: Menu?): Boolean { - menuInflater.inflate(R.menu.code_playground_menu, menu) - val menuItem = menu?.findItem(R.id.action_reset_code) - val resetString = SpannableString(getString(R.string.code_quiz_reset)) - resetString.setSpan(ForegroundColorSpan(ColorUtil.getColorArgb(R.color.new_red_color)), 0, resetString.length, 0) - menuItem?.title = resetString - return super.onCreateOptionsMenu(menu) } private fun initViewPager() { - val lightFont = TypefaceUtils.load(assets, fontsProvider.provideFontPath(FontType.light)) - val regularFont = TypefaceUtils.load(assets, fontsProvider.provideFontPath(FontType.regular)) + val activity = activity + ?: return - val pagerAdapter = CodeStepQuizFullScreenPagerAdapter(this) + val lightFont = TypefaceUtils.load(activity.assets, fontsProvider.provideFontPath(FontType.light)) + val regularFont = TypefaceUtils.load(activity.assets, fontsProvider.provideFontPath(FontType.regular)) + + val pagerAdapter = CodeStepQuizFullScreenPagerAdapter(activity) fullScreenCodeViewPager.adapter = pagerAdapter fullScreenCodeTabs.setupWithViewPager(fullScreenCodeViewPager) @@ -176,7 +197,10 @@ class CodeStepQuizFullScreenActivity : FragmentActivityBase(), StepQuizView, Cha override fun onPageScrolled(p0: Int, p1: Float, p2: Int) {} override fun onPageSelected(p0: Int) { if (p0 == 0) { - this@CodeStepQuizFullScreenActivity.currentFocus?.let { inputMethodManager.hideSoftInputFromWindow(it.windowToken, 0) } + this@CodeStepQuizFullScreenDialogFragment + .activity + ?.currentFocus + ?.let { inputMethodManager?.hideSoftInputFromWindow(it.windowToken, 0) } } } }) @@ -206,30 +230,48 @@ class CodeStepQuizFullScreenActivity : FragmentActivityBase(), StepQuizView, Cha playgroundLayout = pagerAdapter.getViewAt(1) } - override fun setState(state: StepQuizView.State) { - viewStateDelegate.switchState(state) - if (state is StepQuizView.State.AttemptLoaded) { - codeStepQuizFormFullScreenDelegate.setState(state) - } + override fun onStart() { + super.onStart() + dialog + ?.window + ?.let { window -> + window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) + window.setWindowAnimations(R.style.AppTheme_FullScreenDialog) + } + + presenter.attachView(this) } - override fun onBackPressed() { - syncCodeOnFullScreenExit(false) + override fun onPause() { + callback.onSyncCodeStateWithParent((codeStepQuizFormFullScreenDelegate.state as CodeStepQuizFormState.Lang).lang, codeStepLayout.text.toString()) + super.onPause() + } + + override fun onStop() { + presenter.detachView(this) + val reply = codeStepQuizFormFullScreenDelegate.createReply() + if (reply is ReplyResult.Success) { + presenter.syncReplyState(reply.reply) + } + super.onStop() } override fun showNetworkError() { + val view = view + ?: return + Snackbar - .make(root, R.string.no_connection, Snackbar.LENGTH_SHORT) - .setTextColor(ContextCompat.getColor(this, R.color.white)) + .make(view, R.string.connectionProblems, Snackbar.LENGTH_SHORT) + .setTextColor(ContextCompat.getColor(view.context, R.color.white)) .show() } override fun onChangeLanguage() { - val languages = stepPersistentWrapper.step.block?.options?.limits?.keys?.sorted()?.toTypedArray() ?: emptyArray() + val languages = stepWrapper.step.block?.options?.limits?.keys?.sorted()?.toTypedArray() ?: emptyArray() val dialog = ProgrammingLanguageChooserDialogFragment.newInstance(languages) if (!dialog.isAdded) { - dialog.show(supportFragmentManager, null) + dialog.show(childFragmentManager, null) } } @@ -240,23 +282,4 @@ class CodeStepQuizFullScreenActivity : FragmentActivityBase(), StepQuizView, Cha override fun onReset() { codeStepQuizFormFullScreenDelegate.onResetCode() } - - private fun syncCodeOnFullScreenExit(isSubmittedClicked: Boolean = false) { - val reply = codeStepQuizFormFullScreenDelegate.createReply() - if (reply is ReplyResult.Success) { - presenter.syncReplyState(reply.reply) { - val data = Intent() - data.putExtra(IS_SUBMITTED_CLICKED, isSubmittedClicked) - setResult(Activity.RESULT_OK, data) - finish() - } - } - } - - private fun injectComponent() { - App.component() - .stepComponentBuilder() - .build() - .inject(this) - } } \ No newline at end of file From 76a832cfffb98466a39af8f6bb7e815a08e49f96 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 2 Sep 2019 17:19:27 +0300 Subject: [PATCH 18/51] fix codetoolbar positioning --- .../ui/delegate/CodeStepQuizFullScreenFormDelegate.kt | 1 - .../ui/dialog/CodeStepQuizFullScreenDialogFragment.kt | 8 ++++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt index 5dbe440311..551028dc19 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt @@ -71,7 +71,6 @@ class CodeStepQuizFullScreenFormDelegate( stepQuizCodeKeyboardExtension.layoutParams = (stepQuizCodeKeyboardExtension.layoutParams as RelativeLayout.LayoutParams) .apply { addRule(RelativeLayout.ALIGN_PARENT_BOTTOM) -// addRule(RelativeLayout.ALIGN_BOTTOM, R.id.codeStepLayout) } setOnKeyboardOpenListener( diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt index 960a577d1a..31ec1b6413 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt @@ -14,6 +14,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.Window +import android.view.WindowManager import android.view.inputmethod.InputMethodManager import android.widget.TextView import kotlinx.android.synthetic.main.activity_step_quiz_code_fullscreen.* @@ -113,8 +114,11 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, Cha .inject(this) } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = - inflater.inflate(R.layout.activity_step_quiz_code_fullscreen, container, false) + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { + dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) + return inflater.inflate(R.layout.activity_step_quiz_code_fullscreen, container, false) + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) From 323e676b32df155777c757d99d295efe1af97fef Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 2 Sep 2019 17:33:58 +0300 Subject: [PATCH 19/51] remove old code step --- .../droid/core/presenters/CodePresenter.kt | 36 -- .../presenters/PreparingCodeStepPresenter.kt | 57 --- .../org/stepic/droid/di/step/StepComponent.kt | 3 - .../droid/di/step/code/CodeComponent.kt | 15 - .../stepic/droid/di/step/code/CodeScope.kt | 7 - .../ui/activities/CodePlaygroundActivity.kt | 81 ---- .../ui/fragments/CodePlaygroundFragment.kt | 190 -------- .../droid/ui/fragments/CodeStepFragment.kt | 456 ------------------ .../util/resolvers/StepTypeResolverImpl.java | 3 - .../CodeStepQuizFullScreenDialogFragment.kt | 7 - .../main/res/menu/code_playground_menu.xml | 5 - 11 files changed, 860 deletions(-) delete mode 100644 app/src/main/java/org/stepic/droid/core/presenters/CodePresenter.kt delete mode 100644 app/src/main/java/org/stepic/droid/core/presenters/PreparingCodeStepPresenter.kt delete mode 100644 app/src/main/java/org/stepic/droid/di/step/code/CodeComponent.kt delete mode 100644 app/src/main/java/org/stepic/droid/di/step/code/CodeScope.kt delete mode 100644 app/src/main/java/org/stepic/droid/ui/activities/CodePlaygroundActivity.kt delete mode 100644 app/src/main/java/org/stepic/droid/ui/fragments/CodePlaygroundFragment.kt delete mode 100644 app/src/main/java/org/stepic/droid/ui/fragments/CodeStepFragment.kt diff --git a/app/src/main/java/org/stepic/droid/core/presenters/CodePresenter.kt b/app/src/main/java/org/stepic/droid/core/presenters/CodePresenter.kt deleted file mode 100644 index 3b86db58c5..0000000000 --- a/app/src/main/java/org/stepic/droid/core/presenters/CodePresenter.kt +++ /dev/null @@ -1,36 +0,0 @@ -package org.stepic.droid.core.presenters - -import org.stepic.droid.concurrency.MainHandler -import org.stepic.droid.core.presenters.contracts.CodeView -import org.stepic.droid.di.step.code.CodeScope -import org.stepic.droid.storage.operations.DatabaseFacade -import java.util.concurrent.ThreadPoolExecutor -import javax.inject.Inject - -@CodeScope -class CodePresenter -@Inject constructor( - private val mainHandler: MainHandler, - private val threadPoolExecutor: ThreadPoolExecutor, - private val databaseFacade: DatabaseFacade -) : PresenterBase() { - - fun onShowAttempt(attemptId: Long, stepId: Long) { - //if we have code for attemptId in database -> show - //otherwise -> get by stepId and remove all -> show from block - threadPoolExecutor.execute { - val codeSubmission = databaseFacade.getCodeSubmission(attemptId) - if (codeSubmission == null) { - mainHandler.post { - view?.onAttemptIsNotStored() - } - databaseFacade.removeCodeSubmissionsOfStep(stepId) - } else { - mainHandler.post { - view?.onShowStored(codeSubmission.language, codeSubmission.code) - } - } - - } - } -} diff --git a/app/src/main/java/org/stepic/droid/core/presenters/PreparingCodeStepPresenter.kt b/app/src/main/java/org/stepic/droid/core/presenters/PreparingCodeStepPresenter.kt deleted file mode 100644 index a48d659274..0000000000 --- a/app/src/main/java/org/stepic/droid/core/presenters/PreparingCodeStepPresenter.kt +++ /dev/null @@ -1,57 +0,0 @@ -package org.stepic.droid.core.presenters - -import io.reactivex.Scheduler -import io.reactivex.disposables.CompositeDisposable -import org.stepic.droid.core.presenters.contracts.PreparingCodeStepView -import org.stepic.droid.di.qualifiers.BackgroundScheduler -import org.stepic.droid.di.qualifiers.MainScheduler -import org.stepic.droid.di.step.code.CodeScope -import org.stepik.android.model.Step -import org.stepic.droid.util.isCodeStepReady -import org.stepic.droid.web.Api -import javax.inject.Inject - -@CodeScope -class PreparingCodeStepPresenter -@Inject -constructor( - private val api: Api, - @BackgroundScheduler - private val scheduler: Scheduler, - @MainScheduler - private val mainScheduler: Scheduler) : PresenterBase() { - - private val compositeDisposable = CompositeDisposable() - - fun prepareStep(step: Step) { - if (step.isCodeStepReady()) { - view?.onStepPrepared(step) - return - } - - view?.onStepPreparing() - val disposable = api.getStepsReactive(longArrayOf(step.id)) - .map { - val internetStep = it.steps?.first() - when (internetStep?.isCodeStepReady()) { - true -> internetStep - else -> throw StepNotPrepared() - } - } - .subscribeOn(scheduler) - .observeOn(mainScheduler) - .subscribe({ newStep -> - view?.onStepPrepared(newStep) - }, { - view?.onStepNotPrepared() - }) - compositeDisposable.add(disposable) - } - - override fun detachView(view: PreparingCodeStepView) { - super.detachView(view) - compositeDisposable.clear() - } - - private class StepNotPrepared : Throwable("Step is not prepared") -} diff --git a/app/src/main/java/org/stepic/droid/di/step/StepComponent.kt b/app/src/main/java/org/stepic/droid/di/step/StepComponent.kt index c82e6a9bd9..84b7cc444d 100644 --- a/app/src/main/java/org/stepic/droid/di/step/StepComponent.kt +++ b/app/src/main/java/org/stepic/droid/di/step/StepComponent.kt @@ -3,7 +3,6 @@ package org.stepic.droid.di.step import dagger.Subcomponent import org.stepic.droid.base.StepBaseFragment import org.stepic.droid.di.comment.CommentsComponent -import org.stepic.droid.di.step.code.CodeComponent import org.stepic.droid.di.streak.StreakModule import org.stepic.droid.ui.fragments.StepAttemptFragment import org.stepik.android.view.injection.feedback.FeedbackDataModule @@ -18,8 +17,6 @@ interface StepComponent { fun commentsComponentBuilder(): CommentsComponent.Builder - fun codeComponentBuilder(): CodeComponent.Builder - fun inject(stepFragment: StepBaseFragment) fun inject(stepAttemptFragment: StepAttemptFragment) diff --git a/app/src/main/java/org/stepic/droid/di/step/code/CodeComponent.kt b/app/src/main/java/org/stepic/droid/di/step/code/CodeComponent.kt deleted file mode 100644 index 6453a4f61d..0000000000 --- a/app/src/main/java/org/stepic/droid/di/step/code/CodeComponent.kt +++ /dev/null @@ -1,15 +0,0 @@ -package org.stepic.droid.di.step.code - -import dagger.Subcomponent -import org.stepic.droid.ui.fragments.CodeStepFragment - -@CodeScope -@Subcomponent -interface CodeComponent { - @Subcomponent.Builder - interface Builder { - fun build(): CodeComponent - } - - fun inject(codeStepFragment: CodeStepFragment) -} diff --git a/app/src/main/java/org/stepic/droid/di/step/code/CodeScope.kt b/app/src/main/java/org/stepic/droid/di/step/code/CodeScope.kt deleted file mode 100644 index 7d29706174..0000000000 --- a/app/src/main/java/org/stepic/droid/di/step/code/CodeScope.kt +++ /dev/null @@ -1,7 +0,0 @@ -package org.stepic.droid.di.step.code - -import javax.inject.Scope - -@Scope -@Retention(AnnotationRetention.RUNTIME) -annotation class CodeScope diff --git a/app/src/main/java/org/stepic/droid/ui/activities/CodePlaygroundActivity.kt b/app/src/main/java/org/stepic/droid/ui/activities/CodePlaygroundActivity.kt deleted file mode 100644 index 4a6805b236..0000000000 --- a/app/src/main/java/org/stepic/droid/ui/activities/CodePlaygroundActivity.kt +++ /dev/null @@ -1,81 +0,0 @@ -package org.stepic.droid.ui.activities - -import android.app.Activity -import android.content.Intent -import android.support.v4.app.Fragment -import android.view.MenuItem -import org.stepic.droid.base.SingleFragmentActivity -import org.stepik.android.model.code.CodeOptions -import org.stepic.droid.ui.fragments.CodePlaygroundFragment -import org.stepic.droid.ui.util.BackButtonHandler -import org.stepic.droid.ui.util.OnBackClickListener -import java.lang.ref.WeakReference - -class CodePlaygroundActivity : SingleFragmentActivity(), BackButtonHandler { - - companion object { - const val CODE_KEY = "code_key" - const val LANG_KEY = "lang_key" - const val WAS_RESET = "WAS_RESET" - private const val QUIZ_INFO_KEY = "quiz_info_key" - - fun intentForLaunch(callingActivity: Activity, code: String, lang: String, codeOptions: CodeOptions): Intent { - val intent = Intent(callingActivity, CodePlaygroundActivity::class.java) - intent.putExtra(CODE_KEY, code) - intent.putExtra(LANG_KEY, lang) - intent.putExtra(QUIZ_INFO_KEY, codeOptions) - return intent - } - } - - private var onBackClickListener: WeakReference? = null - - override fun createFragment(): Fragment = - CodePlaygroundFragment.newInstance( - intent.getStringExtra(CODE_KEY), - intent.getStringExtra(LANG_KEY), - intent.getParcelableExtra(QUIZ_INFO_KEY) - ) - - override fun applyTransitionPrev() { - //no-op - } - - - override fun setBackClickListener(onBackClickListener: OnBackClickListener) { - this.onBackClickListener = WeakReference(onBackClickListener) - } - - override fun removeBackClickListener(onBackClickListener: OnBackClickListener) { - this.onBackClickListener = null - } - - override fun finish() { - hideSoftKeypad() - super.finish() - } - - override fun onOptionsItemSelected(item: MenuItem?): Boolean { - when (item?.itemId) { - android.R.id.home -> { - if (fragmentBackKeyIntercept()) { - return true - } else { - finish() - return true - } - } - } - return super.onOptionsItemSelected(item) - } - - - override fun onBackPressed() { - if (!fragmentBackKeyIntercept()) { - super.onBackPressed() - } - } - - private fun fragmentBackKeyIntercept(): Boolean = - onBackClickListener?.get()?.onBackClick() ?: false -} diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/CodePlaygroundFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/CodePlaygroundFragment.kt deleted file mode 100644 index 60f11cf936..0000000000 --- a/app/src/main/java/org/stepic/droid/ui/fragments/CodePlaygroundFragment.kt +++ /dev/null @@ -1,190 +0,0 @@ -package org.stepic.droid.ui.fragments - -import android.app.Activity -import android.content.Context -import android.content.Intent -import android.os.Bundle -import android.support.v4.app.Fragment -import android.support.v7.widget.LinearLayoutManager -import android.text.SpannableString -import android.text.style.ForegroundColorSpan -import android.view.* -import kotlinx.android.synthetic.main.fragment_code_playground.* -import kotlinx.android.synthetic.main.view_code_editor_layout.* -import kotlinx.android.synthetic.main.view_code_toolbar.codeToolbarView -import org.stepic.droid.R -import org.stepic.droid.analytic.Analytic -import org.stepic.droid.base.FragmentBase -import org.stepic.droid.code.util.CodeToolbarUtil -import org.stepik.android.model.code.CodeOptions -import org.stepic.droid.model.code.extensionForLanguage -import org.stepic.droid.ui.activities.CodePlaygroundActivity -import org.stepic.droid.ui.adapters.CodeToolbarAdapter -import org.stepic.droid.ui.dialogs.ChangeCodeLanguageDialog -import org.stepic.droid.ui.dialogs.ProgrammingLanguageChooserDialogFragment -import org.stepic.droid.ui.dialogs.ResetCodeDialogFragment -import org.stepic.droid.ui.util.* -import org.stepic.droid.util.AppConstants -import org.stepic.droid.util.ColorUtil -import org.stepic.droid.util.argument - -class CodePlaygroundFragment : FragmentBase(), - OnBackClickListener, - ProgrammingLanguageChooserDialogFragment.Callback, - ResetCodeDialogFragment.Callback, - ChangeCodeLanguageDialog.Callback, - CodeToolbarAdapter.OnSymbolClickListener { - companion object { - private const val ANALYTIC_SCREEN_TYPE: String = "fullscreen" - - fun newInstance(code: String, lang: String, codeOptions: CodeOptions): Fragment = - CodePlaygroundFragment().also { - it.code = code - it.lang = lang - it.codeOptions = codeOptions - } - } - - private var codeToolbarAdapter: CodeToolbarAdapter? = null - private var onGlobalLayoutListener: ViewTreeObserver.OnGlobalLayoutListener? = null - private var wasReset: Boolean = false - - private var code: String by argument() - private var lang: String by argument() - private var codeOptions: CodeOptions by argument() - - override fun onAttach(context: Context?) { - super.onAttach(context) - (activity as? BackButtonHandler)?.setBackClickListener(this) - } - - override fun onDetach() { - (activity as? BackButtonHandler)?.removeBackClickListener(this) - super.onDetach() - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - codeToolbarAdapter = CodeToolbarAdapter(requireContext()) - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = - inflater.inflate(R.layout.fragment_code_playground, container, false) - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - initCenteredToolbar(R.string.code_playground_title, true) - - codeToolbarView.adapter = codeToolbarAdapter - codeToolbarAdapter?.onSymbolClickListener = this - codeToolbarView.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) - codeToolbarAdapter?.setLanguage(lang) - codeEditor.codeToolbarAdapter = codeToolbarAdapter - - if (savedInstanceState == null) { - codeEditor.setText(code) - } - codeEditor.lang = extensionForLanguage(lang) - setHasOptionsMenu(true) - } - - override fun onStart() { - super.onStart() - onGlobalLayoutListener = listenKeyboardChanges( - codePlaygroundRootView, - onKeyboardShown = { - codeToolbarView?.visibility = View.VISIBLE - }, - onKeyboardHidden = { - codeToolbarView?.visibility = View.GONE - } - ) - } - - override fun onStop() { - super.onStop() - stopListenKeyboardChanges(codePlaygroundRootView, onGlobalLayoutListener) - onGlobalLayoutListener = null - } - - override fun onDestroyView() { - super.onDestroyView() - codeToolbarAdapter?.onSymbolClickListener = null - } - - override fun onDestroy() { - super.onDestroy() - codeToolbarAdapter = null - } - - override fun onCreateOptionsMenu(menu: Menu?, inflater: MenuInflater?) { - super.onCreateOptionsMenu(menu, inflater) - inflater?.inflate(R.menu.code_playground_menu, menu) - - val menuItem = menu?.findItem(R.id.action_reset_code) - val resetString = SpannableString(getString(R.string.code_quiz_reset)) - resetString.setSpan(ForegroundColorSpan(ColorUtil.getColorArgb(R.color.new_red_color)), 0, resetString.length, 0) - menuItem?.title = resetString - } - - override fun onOptionsItemSelected(item: MenuItem?): Boolean = when (item?.itemId) { - R.id.action_reset_code -> { - analytic.reportEvent(Analytic.Code.CODE_RESET_PRESSED, - Bundle().apply { putString(AppConstants.ANALYTIC_CODE_SCREEN_KEY, ANALYTIC_SCREEN_TYPE) } - ) - val dialog = ResetCodeDialogFragment.newInstance() - if (!dialog.isAdded) { - dialog.show(childFragmentManager, null) - } - true - } - R.id.action_language_code -> { - val dialog = ChangeCodeLanguageDialog.newInstance() - if (!dialog.isAdded) { - dialog.show(childFragmentManager, null) - } - true - } - else -> false - } - - override fun onReset() { - wasReset = true - codeEditor.setText(codeOptions.codeTemplates[lang]) - } - - override fun onLanguageChosen(programmingLanguage: String) { - wasReset = true - lang = programmingLanguage - codeToolbarAdapter?.setLanguage(programmingLanguage) - codeEditor.setText(codeOptions.codeTemplates[programmingLanguage]) - codeEditor.lang = extensionForLanguage(programmingLanguage) - } - - override fun onBackClick(): Boolean { - val resultIntent = Intent() - resultIntent.putExtra(CodePlaygroundActivity.WAS_RESET, wasReset) - resultIntent.putExtra(CodePlaygroundActivity.LANG_KEY, lang) - resultIntent.putExtra(CodePlaygroundActivity.CODE_KEY, codeEditor.text.toString()) - activity?.setResult(Activity.RESULT_OK, resultIntent) - return false - } - - override fun onSymbolClick(symbol: String, offset: Int) { - CodeToolbarUtil.reportSelectedSymbol(analytic, lang, symbol) - codeEditor.insertText(CodeToolbarUtil.mapToolbarSymbolToPrintable(symbol, codeEditor.indentSize), offset) - } - - override fun onChangeLanguage() { - showLanguageChoosingDialog() - } - - private fun showLanguageChoosingDialog() { - val languages = codeOptions.limits.keys.sorted().toTypedArray() - - val dialog = ProgrammingLanguageChooserDialogFragment.newInstance(languages) - if (!dialog.isAdded) { - dialog.show(childFragmentManager, null) - } - } -} diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/CodeStepFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/CodeStepFragment.kt deleted file mode 100644 index d36787f91c..0000000000 --- a/app/src/main/java/org/stepic/droid/ui/fragments/CodeStepFragment.kt +++ /dev/null @@ -1,456 +0,0 @@ -package org.stepic.droid.ui.fragments - -import android.app.Activity -import android.content.Intent -import android.os.Bundle -import android.support.v7.widget.LinearLayoutManager -import android.view.View -import android.view.ViewGroup -import android.view.ViewTreeObserver -import kotlinx.android.synthetic.main.fragment_step_attempt.* -import kotlinx.android.synthetic.main.view_code_editor_layout.* -import kotlinx.android.synthetic.main.view_code_quiz.* -import kotlinx.android.synthetic.main.view_code_toolbar.* -import kotlinx.android.synthetic.main.view_step_preparing.* -import org.stepic.droid.R -import org.stepic.droid.analytic.Analytic -import org.stepic.droid.base.App -import org.stepic.droid.code.util.CodeToolbarUtil -import org.stepic.droid.core.presenters.CodePresenter -import org.stepic.droid.core.presenters.PreparingCodeStepPresenter -import org.stepic.droid.core.presenters.contracts.CodeView -import org.stepic.droid.core.presenters.contracts.PreparingCodeStepView -import org.stepik.android.model.Step -import org.stepik.android.model.Submission -import org.stepic.droid.model.code.extensionForLanguage -import org.stepic.droid.ui.activities.CodePlaygroundActivity -import org.stepic.droid.ui.adapters.CodeToolbarAdapter -import org.stepic.droid.ui.dialogs.ChangeCodeLanguageDialog -import org.stepic.droid.ui.dialogs.ResetCodeDialogFragment -import org.stepic.droid.ui.util.initForCodeLanguages -import org.stepic.droid.ui.util.listenKeyboardChanges -import org.stepic.droid.ui.util.stopListenKeyboardChanges -import org.stepic.droid.util.AppConstants -import org.stepic.droid.util.ProgressHelper -import org.stepik.android.model.attempts.Attempt -import org.stepik.android.model.Reply -import javax.inject.Inject - -class CodeStepFragment : StepAttemptFragment(), - CodeView, - PreparingCodeStepView, - ResetCodeDialogFragment.Callback, - ChangeCodeLanguageDialog.Callback, CodeToolbarAdapter.OnSymbolClickListener { - companion object { - private const val ANALYTIC_SCREEN_TYPE = "standard" - private const val CHOSEN_POSITION_KEY: String = "chosenPositionKey" - private const val CODE_PLAYGROUND_REQUEST = 153 - fun newInstance(): CodeStepFragment = CodeStepFragment() - } - - @Inject - lateinit var codePresenter: CodePresenter - - @Inject - lateinit var preparingCodeStepPresenter: PreparingCodeStepPresenter - - private var codeToolbarAdapter: CodeToolbarAdapter? = null - private var onGlobalLayoutListener: ViewTreeObserver.OnGlobalLayoutListener? = null - - private var activityResultActivated = false - - override fun injectComponent() { - App - .componentManager() - .stepComponent(step.id) - .codeComponentBuilder() - .build() - .inject(this) - } - - private var chosenProgrammingLanguageName: String? = null - set(value) { - field = value - if (value != null) codeEditor?.let { it.lang = extensionForLanguage(value) } - } - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - codeToolbarAdapter = CodeToolbarAdapter(requireContext()) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - val viewGroup = layoutInflater.inflate(R.layout.view_code_quiz, attemptContainer, false) as ViewGroup - attemptContainer.addView(viewGroup) - - codeToolbarView.adapter = codeToolbarAdapter - codeToolbarAdapter?.onSymbolClickListener = this - codeToolbarView.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) - codeEditor.codeToolbarAdapter = codeToolbarAdapter - - codePresenter.attachView(this) - preparingCodeStepPresenter.attachView(this) - preparingCodeStepPresenter.prepareStep(step) - } - - override fun onStepPrepared(newStep: Step) { - //here code options should be prepared - step = newStep - - initLanguageChooser() - - codeQuizChooseLangAction.setOnClickListener { - val programmingLanguageServerName = codeQuizLanguagePicker?.displayedValues?.get(codeQuizLanguagePicker.value) - if (programmingLanguageServerName == null) { - analytic.reportEventWithName(Analytic.Code.CHOOSE_NULL, "${step?.lesson} ${step?.id}") - return@setOnClickListener - } - - chosenProgrammingLanguageName = programmingLanguageServerName - - codeEditor.setText(step.block?.options?.codeTemplates?.get(programmingLanguageServerName)) - showLanguageChoosingView(false) - showCodeQuizEditor() - } - - codeQuizFullscreenAction.setOnClickListener { - chosenProgrammingLanguageName?.let { lang -> - if (submission?.status != Submission.Status.CORRECT) { - val intent = CodePlaygroundActivity.intentForLaunch( - requireActivity(), - codeEditor.text.toString(), - lang, - step?.block?.options ?: throw IllegalStateException("can't find code options in code quiz")) - - analytic.reportEvent(Analytic.Code.CODE_FULLSCREEN_PRESSED) - startActivityForResult(intent, CODE_PLAYGROUND_REQUEST) - } - } - } - - codeQuizResetAction.setOnClickListener { - analytic.reportEvent(Analytic.Code.CODE_RESET_PRESSED, - Bundle().apply { putString(AppConstants.ANALYTIC_CODE_SCREEN_KEY, ANALYTIC_SCREEN_TYPE) } - ) - - if (submission?.status == Submission.Status.CORRECT) { - tryAgain() - } else { - val dialog = ResetCodeDialogFragment.newInstance() - if (!dialog.isAdded) { - dialog.show(childFragmentManager, null) - } - } - - } - - codeQuizCurrentLanguage.setOnClickListener { - if (isOneLanguageAvailable()) { - //we shouldn't change it - return@setOnClickListener - } - - if (checkForResetDialog()) { - val dialog = ChangeCodeLanguageDialog.newInstance() - if (!dialog.isAdded) { - dialog.show(childFragmentManager, null) - } - } else if (submission?.status != Submission.Status.CORRECT) { - onChangeLanguage() - } - } - - initSamples() - - ProgressHelper.dismiss(progressBar) - stepPreparingView.visibility = View.GONE - codePreparedContainer.visibility = View.VISIBLE - if (chosenProgrammingLanguageName == null) { - showCodeQuizEditor(false) - showLanguageChoosingView(true) - } else { - showCodeQuizEditor(true) - showLanguageChoosingView(false) - } - activityResultActivated = false - } - - override fun onStepNotPrepared() { - showCodeQuizEditor(false) - showLanguageChoosingView(false) - ProgressHelper.dismiss(progressBar) - codePreparedContainer.visibility = View.GONE - - stepPreparingView.visibility = View.VISIBLE - stepPreparingView.setOnClickListener { - stepPreparingView.visibility = View.GONE - preparingCodeStepPresenter.prepareStep(step) - } - } - - override fun onStepPreparing() { - //note: on 1st load this progress bar can be hidden by attempt is loading - //if we introduce progress bar for step loading, then we will have 2 progress bar on screen - //todo sync dismissing of progressbar in future - ProgressHelper.activate(progressBar) - stepAttemptSubmitButton.visibility = View.GONE - } - - override fun onStart() { - super.onStart() - onGlobalLayoutListener = listenKeyboardChanges( - rootFrameLayoutInStepAttempt, - onKeyboardShown = { - codeToolbarView.visibility = View.VISIBLE - codeToolbarSpaceInContainer.visibility = View.VISIBLE - }, - onKeyboardHidden = { - codeToolbarView.visibility = View.GONE - codeToolbarSpaceInContainer.visibility = View.GONE - } - ) - } - - override fun onStop() { - super.onStop() - stopListenKeyboardChanges(rootFrameLayoutInStepAttempt, onGlobalLayoutListener) - onGlobalLayoutListener = null - } - - private fun initSamples() { - val newLine = "
" - val stringBuilder = StringBuilder() - step?.block?.options?.samples?.forEachIndexed { index, parcelableStringList -> - if (index != 0) { - stringBuilder.append(newLine) - stringBuilder.append(newLine) - } - stringBuilder.append(getString(R.string.sample_input, index + 1)) - stringBuilder.append(newLine) - stringBuilder.append(parcelableStringList[0].replace("\n", newLine)) - stringBuilder.append(newLine) - stringBuilder.append(getString(R.string.sample_output, index + 1)) - stringBuilder.append(newLine) - stringBuilder.append(parcelableStringList[1].replace("\n", newLine)) - } - val samplesString = textResolver.fromHtml(stringBuilder.toString()) - codeQuizSamples.text = samplesString - } - - override fun onDestroyView() { - super.onDestroyView() - preparingCodeStepPresenter.detachView(this) - codePresenter.detachView(this) - codeToolbarAdapter?.onSymbolClickListener = null - } - - override fun onDestroy() { - super.onDestroy() - codeToolbarAdapter = null - } - - override fun showAttempt(attempt: Attempt) { - codePresenter.onShowAttempt(attemptId = attempt.id, stepId = step.id) - } - - override fun onSaveInstanceState(outState: Bundle) { - super.onSaveInstanceState(outState) - outState.putInt(CHOSEN_POSITION_KEY, codeQuizLanguagePicker.value) - } - - override fun onViewStateRestored(savedInstanceState: Bundle?) { - super.onViewStateRestored(savedInstanceState) - savedInstanceState?.let { - codeQuizLanguagePicker.value = it.getInt(CHOSEN_POSITION_KEY) - } - } - - private fun toVisibility(needShow: Boolean): Int { - return if (needShow) { - View.VISIBLE - } else { - View.GONE - } - } - - override fun generateReply(): Reply = Reply( - language = chosenProgrammingLanguageName, - code = codeEditor.text.toString() - ) - - - override fun blockUIBeforeSubmit(needBlock: Boolean) { - codeEditor.isEnabled = !needBlock - } - - override fun onRestoreSubmission() { - if (submission?.reply == null) { - if (chosenProgrammingLanguageName == null) { - //we haven't submission from the server and stored submission - showLanguageChoosingView(false) - showCodeQuizEditor() - } - } else { - if (submission.status == Submission.Status.WRONG) { - actionButton.setText(R.string.send) - blockUIBeforeSubmit(false) - if (submission.reply?.code != codeEditor.text.toString()) { - hideWrongStatus() - resetBackgroundOfAttempt() - hideHint() - } - submission = null - } else { - if (activityResultActivated) return - codeEditor.setText(submission.reply?.code) - chosenProgrammingLanguageName = submission.reply?.language - showLanguageChoosingView(false) - showCodeQuizEditor() - } - } - } - - override fun onAttemptIsNotStored() { - if (codeEditor.visibility == View.VISIBLE) { - return - } - - if (isOneLanguageAvailable()) { - val langTemplate = step?.block?.options?.codeTemplates?.entries?.singleOrNull() - if (langTemplate == null) { - analytic.reportEvent(Analytic.Error.TEMPLATE_WAS_NULL, step.id.toString()) - return - } - chosenProgrammingLanguageName = langTemplate.key - codeEditor.setText(langTemplate.value) - - showLanguageChoosingView(false) - showCodeQuizEditor() - } else { - showCodeQuizEditor(false) - showLanguageChoosingView() - } - } - - override fun onShowStored(language: String, code: String) { - if (activityResultActivated) return - chosenProgrammingLanguageName = language - codeEditor.setText(code) - showLanguageChoosingView(false) - showCodeQuizEditor() - } - - private fun initLanguageChooser() { - step.block?.options?.limits - ?.keys - ?.sorted() - ?.toTypedArray() - ?.let { - codeQuizLanguagePicker.initForCodeLanguages(it) - } - } - - private fun showCodeQuizEditor(needShow: Boolean = true) { - val visibility = toVisibility(needShow) - if (needShow) { - chosenProgrammingLanguageName?.let { chosenLanguage -> - codeToolbarAdapter?.setLanguage(chosenLanguage) - codeQuizCurrentLanguage.text = chosenLanguage - step?.block?.options?.limits?.get(chosenLanguage)?.let { codeLimit -> - val stringFromResources = getString(R.string.code_quiz_limits, - resources.getQuantityString(R.plurals.time_seconds, codeLimit.time, codeLimit.time), - codeLimit.memory.toString()) - val spanned = textResolver.fromHtml(stringFromResources) - codeQuizLimits.text = spanned - } - } - } - - if (codePreparedContainer.visibility != View.VISIBLE) { - return - } - - codeEditor.visibility = visibility - stepAttemptSubmitButton.visibility = visibility - codeQuizCurrentLanguage.visibility = visibility - codeQuizDelimiter.visibility = visibility - codeQuizFullscreenAction.visibility = visibility - codeQuizResetAction.visibility = visibility - codeQuizLimits.visibility = visibility - } - - private fun showLanguageChoosingView(needShow: Boolean = true) { - val visibility = toVisibility(needShow) - - if (needShow) { - chosenProgrammingLanguageName = null - } - if (codePreparedContainer.visibility != View.VISIBLE) { - return - } - - codeQuizChooseLangAction.visibility = visibility - codeQuizLanguagePicker.visibility = visibility - codeQuizChooseLangTitle.visibility = visibility - } - - override fun onReset() { - chosenProgrammingLanguageName?.let { - val template = step?.block?.options?.codeTemplates?.get(it) - codeEditor.setText(template) - resetBackgroundOfAttempt() - hideHint() - hideWrongStatus() - } - } - - override fun onChangeLanguage() { - if (isOneLanguageAvailable()) { - //we shouldn't do anything - return - } - showCodeQuizEditor(false) - showLanguageChoosingView() - resetBackgroundOfAttempt() - hideHint() - hideWrongStatus() - } - - private fun checkForResetDialog(): Boolean { - chosenProgrammingLanguageName?.let { - val template = step.block?.options?.codeTemplates?.get(it) - val needDialog = template != null && - template != codeEditor.text.toString() && - submission?.status != Submission.Status.CORRECT - return needDialog - } - return false - } - - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - - if (requestCode == CODE_PLAYGROUND_REQUEST && resultCode == Activity.RESULT_OK) { - activityResultActivated = true - chosenProgrammingLanguageName = data?.getStringExtra(CodePlaygroundActivity.LANG_KEY) - val newCode = data?.getStringExtra(CodePlaygroundActivity.CODE_KEY) - codeEditor.setText(newCode) - showCodeQuizEditor() - if (data?.getBooleanExtra(CodePlaygroundActivity.WAS_RESET, false) == true) { - resetBackgroundOfAttempt() - hideHint() - hideWrongStatus() - } - } - } - - private fun isOneLanguageAvailable(): Boolean = - step?.block?.options?.codeTemplates?.size == 1 - - override fun onSymbolClick(symbol: String, offset: Int) { - CodeToolbarUtil.reportSelectedSymbol(analytic, chosenProgrammingLanguageName, symbol) - codeEditor.insertText(CodeToolbarUtil.mapToolbarSymbolToPrintable(symbol, codeEditor.indentSize), offset) - } - -} diff --git a/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolverImpl.java b/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolverImpl.java index 9cf6c2aa31..9c2b43277f 100644 --- a/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolverImpl.java +++ b/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolverImpl.java @@ -7,7 +7,6 @@ import org.stepic.droid.base.StepBaseFragment; import org.stepic.droid.di.AppSingleton; import org.stepic.droid.ui.fragments.ChoiceStepFragment; -import org.stepic.droid.ui.fragments.CodeStepFragment; import org.stepic.droid.ui.fragments.MatchingStepFragment; import org.stepic.droid.ui.fragments.NotSupportedYetStepFragment; import org.stepic.droid.ui.fragments.PyCharmStepFragment; @@ -114,8 +113,6 @@ public StepBaseFragment getFragment(Step step) { return new MatchingStepFragment(); case AppConstants.TYPE_TABLE: return TableChoiceStepFragment.Companion.newInstance(); - case AppConstants.TYPE_CODE: - return CodeStepFragment.Companion.newInstance(); case AppConstants.TYPE_SQL: return SqlStepFragment.Companion.newInstance(); default: diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt index 31ec1b6413..d14a9bcbcf 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt @@ -143,13 +143,6 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, Cha } true } - R.id.action_language_code -> { - val dialog = ChangeCodeLanguageDialog.newInstance() - if (!dialog.isAdded) { - dialog.show(childFragmentManager, null) - } - true - } else -> false } } diff --git a/app/src/main/res/menu/code_playground_menu.xml b/app/src/main/res/menu/code_playground_menu.xml index 877fc82c04..e5b99c7332 100644 --- a/app/src/main/res/menu/code_playground_menu.xml +++ b/app/src/main/res/menu/code_playground_menu.xml @@ -5,9 +5,4 @@ android:id="@+id/action_reset_code" android:title="@string/code_quiz_reset" app:showAsAction="never"/> - - \ No newline at end of file From 270d5d0c0fbb388d838f04722d9442789fdc9d8e Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 2 Sep 2019 17:39:11 +0300 Subject: [PATCH 20/51] hide keyboard when opening instructions --- .../ui/dialog/CodeStepQuizFullScreenDialogFragment.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt index d14a9bcbcf..7f056cbf3a 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt @@ -119,7 +119,6 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, Cha return inflater.inflate(R.layout.activity_step_quiz_code_fullscreen, container, false) } - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -194,10 +193,11 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, Cha override fun onPageScrolled(p0: Int, p1: Float, p2: Int) {} override fun onPageSelected(p0: Int) { if (p0 == 0) { - this@CodeStepQuizFullScreenDialogFragment - .activity - ?.currentFocus - ?.let { inputMethodManager?.hideSoftInputFromWindow(it.windowToken, 0) } + inputMethodManager?.let { + if (it.isActive) { + it.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS) + } + } } } }) From c9c3216ca8f8b1741d4d8890a46ce0eb4c124742 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 2 Sep 2019 20:30:34 +0300 Subject: [PATCH 21/51] code review fixes --- .../CodeStepQuizFullScreenFormDelegate.kt | 21 +++---------- .../ui/fragment/CodeStepQuizFragment.kt | 1 - .../CodeStepQuizFullScreenDialogFragment.kt | 30 +++++++++++++------ ...t_step_quiz_code_fullscreen_playground.xml | 2 +- app/src/main/res/values/dimens.xml | 3 ++ 5 files changed, 29 insertions(+), 28 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt index 551028dc19..d473a84418 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt @@ -8,13 +8,12 @@ import android.widget.RelativeLayout import kotlinx.android.synthetic.main.activity_step_quiz_code_fullscreen.view.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_instruction.view.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.view.* +import kotlinx.android.synthetic.main.view_step_quiz_submit_button.view.* import org.stepic.droid.R import org.stepic.droid.persistence.model.StepPersistentWrapper -import org.stepic.droid.ui.custom.LatexSupportableEnhancedFrameLayout import org.stepic.droid.ui.util.inflate import org.stepic.droid.ui.util.setCompoundDrawables import org.stepic.droid.ui.util.setOnKeyboardOpenListener -import org.stepic.droid.util.DpPixelsHelper import org.stepik.android.presentation.step_quiz.StepQuizView import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState @@ -30,7 +29,7 @@ class CodeStepQuizFullScreenFormDelegate( private var keyboardShown: Boolean = false private val submitButtonSeparator = codeContainerView.submitButtonSeparator private val codeSubmitButton = codeContainerView.codeSubmitButton - private var latexLayout: LatexSupportableEnhancedFrameLayout? = null + private val retryButton = codeSubmitButton.stepQuizRetry private val fullScreenCodeToolbar = keyboardExtensionContainer.fullScreenCodeToolbar private val fullScreenCodeTabs = keyboardExtensionContainer.fullScreenCodeTabs private val fullScreenCodeSeparator = keyboardExtensionContainer.fullScreenCodeSeparator @@ -39,20 +38,8 @@ class CodeStepQuizFullScreenFormDelegate( viewStateDelegate.addState() viewStateDelegate.addState(codeLayout) - if (latexLayout == null) { - latexLayout = instructionContainerView.stepQuizCodeTextContent as LatexSupportableEnhancedFrameLayout + retryButton.visibility = View.GONE - val text = stepWrapper - .step - .block - ?.text - ?.takeIf(String::isNotEmpty) - - if (text != null) { - instructionContainerView.stepQuizCodeTextContent.setText(text) - instructionContainerView.stepQuizCodeTextContent.setTextIsSelectable(true) - } - } setupCodeDetailContentData() instructionContainerView.stepQuizCodeDetailsContent.visibility = View.VISIBLE instructionContainerView.stepQuizCodeDetailsContent.isNestedScrollingEnabled = false @@ -84,7 +71,7 @@ class CodeStepQuizFullScreenFormDelegate( .apply { bottomMargin = 0 } - codeLayout.setPadding(0, 0, 0, DpPixelsHelper.convertDpToPixel(80f).toInt()) + codeLayout.setPadding(0, 0, 0, container.context.resources.getDimensionPixelSize(R.dimen.step_quiz_fullscreen_code_layout_bottom_padding)) setViewsVisibility(View.VISIBLE) keyboardShown = false } diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt index 40475f9f34..398c3ee87a 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt @@ -20,7 +20,6 @@ import org.stepic.droid.fonts.FontsProvider import org.stepic.droid.persistence.model.StepPersistentWrapper import org.stepic.droid.ui.dialogs.ChangeCodeLanguageDialog import org.stepic.droid.ui.dialogs.ProgrammingLanguageChooserDialogFragment -import org.stepic.droid.ui.dialogs.ResetCodeDialogFragment import org.stepic.droid.ui.listeners.NextMoveable import org.stepic.droid.util.argument import org.stepic.droid.util.setTextColor diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt index 7f056cbf3a..064074e86f 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt @@ -18,6 +18,7 @@ import android.view.WindowManager import android.view.inputmethod.InputMethodManager import android.widget.TextView import kotlinx.android.synthetic.main.activity_step_quiz_code_fullscreen.* +import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_instruction.view.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.* import org.stepic.droid.R import org.stepic.droid.base.App @@ -100,13 +101,6 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, Cha injectComponent() } - override fun setState(state: StepQuizView.State) { - viewStateDelegate.switchState(state) - if (state is StepQuizView.State.AttemptLoaded) { - codeStepQuizFormFullScreenDelegate.setState(state) - } - } - private fun injectComponent() { App.component() .stepComponentBuilder() @@ -150,12 +144,23 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, Cha presenter = ViewModelProviders.of(this, viewModelFactory).get(StepQuizPresenter::class.java) + val text = stepWrapper + .step + .block + ?.text + ?.takeIf(String::isNotEmpty) + + if (text != null) { + instructionsLayout.stepQuizCodeTextContent.setText(text) + instructionsLayout.stepQuizCodeTextContent.setTextIsSelectable(true) + } + viewStateDelegate = ViewStateDelegate() viewStateDelegate.addState(fullScreenCodeViewPager) viewStateDelegate.addState(stepQuizProgress) viewStateDelegate.addState(fullScreenCodeViewPager) - val actionsListenerNew = object : CodeStepQuizFullScreenFormDelegate.ActionsListener { + val actionsListener = object : CodeStepQuizFullScreenFormDelegate.ActionsListener { override fun onSubmitClicked() { callback.onSyncCodeStateWithParent((codeStepQuizFormFullScreenDelegate.state as CodeStepQuizFormState.Lang).lang, codeStepLayout.text.toString(), true) dismiss() @@ -168,7 +173,7 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, Cha } } } - codeStepQuizFormFullScreenDelegate = CodeStepQuizFullScreenFormDelegate(instructionsLayout, playgroundLayout, coordinator, stepWrapper, actionsListenerNew) + codeStepQuizFormFullScreenDelegate = CodeStepQuizFullScreenFormDelegate(instructionsLayout, playgroundLayout, coordinator, stepWrapper, actionsListener) if (savedInstanceState == null) { codeStepQuizFormFullScreenDelegate.state = CodeStepQuizFormState.Lang(lang, code) @@ -253,6 +258,13 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, Cha super.onStop() } + override fun setState(state: StepQuizView.State) { + viewStateDelegate.switchState(state) + if (state is StepQuizView.State.AttemptLoaded) { + codeStepQuizFormFullScreenDelegate.setState(state) + } + } + override fun showNetworkError() { val view = view ?: return diff --git a/app/src/main/res/layout/layout_step_quiz_code_fullscreen_playground.xml b/app/src/main/res/layout/layout_step_quiz_code_fullscreen_playground.xml index e502fce892..124bc618eb 100644 --- a/app/src/main/res/layout/layout_step_quiz_code_fullscreen_playground.xml +++ b/app/src/main/res/layout/layout_step_quiz_code_fullscreen_playground.xml @@ -46,7 +46,7 @@ android:layout_below="@id/stepQuizActions" android:layout_width="match_parent" android:layout_height="match_parent" - android:paddingBottom="80dp" + android:paddingBottom="@dimen/step_quiz_fullscreen_code_layout_bottom_padding" android:fillViewport="true" /> 64dp + + + 80dp From 4a4a6f73b96f42d6510376bcf9f8a9c44b6635b9 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 2 Sep 2019 21:53:52 +0300 Subject: [PATCH 22/51] decompose code into code instruction delegate --- .../ui/delegate/CodeQuizFormBaseDelegate.kt | 35 ++--------- .../delegate/CodeQuizInstructionDelegate.kt | 58 +++++++++++++++++++ .../ui/delegate/CodeStepQuizFormDelegate.kt | 19 +----- .../CodeStepQuizFullScreenFormDelegate.kt | 10 +--- .../ui/fragment/CodeStepQuizFragment.kt | 3 +- .../CodeStepQuizFullScreenDialogFragment.kt | 10 ++-- 6 files changed, 75 insertions(+), 60 deletions(-) create mode 100644 app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizInstructionDelegate.kt diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizFormBaseDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizFormBaseDelegate.kt index c7d818afae..7c52399485 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizFormBaseDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizFormBaseDelegate.kt @@ -1,8 +1,5 @@ package org.stepik.android.view.step_quiz_code.ui.delegate -import android.support.v7.content.res.AppCompatResources -import android.support.v7.widget.DividerItemDecoration -import android.support.v7.widget.LinearLayoutManager import android.view.View import kotlinx.android.synthetic.main.layout_step_quiz_code.view.* import org.stepic.droid.R @@ -15,17 +12,13 @@ import org.stepik.android.presentation.step_quiz.model.ReplyResult import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFormDelegate import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizDetailsMapper import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizFormStateMapper -import org.stepik.android.view.step_quiz_code.model.CodeDetail import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState -import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeDetailLimitAdapterDelegate -import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeDetailSampleAdapterDelegate import org.stepik.android.view.ui.delegate.ViewStateDelegate -import ru.nobird.android.ui.adapterssupport.DefaultDelegateAdapter abstract class CodeQuizFormBaseDelegate( - detailsContainerView: View, codeContainerView: View, - val stepWrapper: StepPersistentWrapper + val stepWrapper: StepPersistentWrapper, + private val codeQuizInstructionDelegate: CodeQuizInstructionDelegate ) : StepQuizFormDelegate { var state: CodeStepQuizFormState = CodeStepQuizFormState.Idle @@ -44,20 +37,13 @@ abstract class CodeQuizFormBaseDelegate( } } - stepQuizCodeDetailsAdapter.items = - codeStepQuizDetailsMapper.mapToCodeDetails(stepWrapper.step, (value as? CodeStepQuizFormState.Lang)?.lang) + codeQuizInstructionDelegate.setCodeDetailsData(codeStepQuizDetailsMapper.mapToCodeDetails(stepWrapper.step, (value as? CodeStepQuizFormState.Lang)?.lang)) } protected val viewStateDelegate = ViewStateDelegate() protected val codeStepQuizFormStateMapper = CodeStepQuizFormStateMapper() protected val codeLayout = codeContainerView.codeStepLayout - - protected val stepQuizCodeDetails = detailsContainerView.stepQuizCodeDetails - protected val stepQuizCodeDetailsArrow = detailsContainerView.stepQuizCodeDetailsArrow - protected val stepQuizCodeDetailsContent = detailsContainerView.stepQuizCodeDetailsContent - - protected val stepQuizCodeDetailsAdapter = DefaultDelegateAdapter() protected val codeStepQuizDetailsMapper = CodeStepQuizDetailsMapper() protected val codeToolbarAdapter = CodeToolbarAdapter(codeContainerView.context) @@ -74,19 +60,8 @@ abstract class CodeQuizFormBaseDelegate( protected val codeOptions = stepWrapper.step.block?.options ?: throw IllegalArgumentException("Code options shouldn't be null") - protected fun setupCodeDetailContentData() { - stepQuizCodeDetailsAdapter += CodeDetailSampleAdapterDelegate() - stepQuizCodeDetailsAdapter += CodeDetailLimitAdapterDelegate() - - with(stepQuizCodeDetailsContent) { - visibility = View.GONE - layoutManager = LinearLayoutManager(context) - adapter = stepQuizCodeDetailsAdapter - - val divider = DividerItemDecoration(context, DividerItemDecoration.VERTICAL) - divider.setDrawable(AppCompatResources.getDrawable(context, R.drawable.bg_step_quiz_code_details_separator)!!) - addItemDecoration(divider) - } + init { + codeQuizInstructionDelegate.setupCodeDetailView() } override fun createReply(): ReplyResult { diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizInstructionDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizInstructionDelegate.kt new file mode 100644 index 0000000000..f1794b594e --- /dev/null +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizInstructionDelegate.kt @@ -0,0 +1,58 @@ +package org.stepik.android.view.step_quiz_code.ui.delegate + +import android.support.v7.content.res.AppCompatResources +import android.support.v7.widget.DividerItemDecoration +import android.support.v7.widget.LinearLayoutManager +import android.view.View +import kotlinx.android.synthetic.main.layout_step_quiz_code.view.* +import org.stepic.droid.R +import org.stepic.droid.ui.util.StepikAnimUtils +import org.stepik.android.view.step_quiz_code.model.CodeDetail +import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeDetailLimitAdapterDelegate +import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeDetailSampleAdapterDelegate +import ru.nobird.android.ui.adapterssupport.DefaultDelegateAdapter + +class CodeQuizInstructionDelegate( + detailsContainerView: View, + private val isCollapseable: Boolean +) { + + val stepQuizCodeDetails = detailsContainerView.stepQuizCodeDetails + val stepQuizCodeDetailsArrow = detailsContainerView.stepQuizCodeDetailsArrow + val stepQuizCodeDetailsContent = detailsContainerView.stepQuizCodeDetailsContent + + val stepQuizCodeDetailsAdapter = DefaultDelegateAdapter() + + fun setCodeDetailsData(codeDetails: List) { + stepQuizCodeDetailsAdapter.items = codeDetails + } + + fun setupCodeDetailView() { + stepQuizCodeDetailsAdapter += CodeDetailSampleAdapterDelegate() + stepQuizCodeDetailsAdapter += CodeDetailLimitAdapterDelegate() + + with(stepQuizCodeDetailsContent) { + visibility = View.GONE + layoutManager = LinearLayoutManager(context) + adapter = stepQuizCodeDetailsAdapter + + val divider = DividerItemDecoration(context, DividerItemDecoration.VERTICAL) + divider.setDrawable(AppCompatResources.getDrawable(context, R.drawable.bg_step_quiz_code_details_separator)!!) + addItemDecoration(divider) + } + + if (isCollapseable) { + stepQuizCodeDetails.setOnClickListener { + stepQuizCodeDetailsArrow.changeState() + if (stepQuizCodeDetailsArrow.isExpanded()) { + StepikAnimUtils.expand(stepQuizCodeDetailsContent) + } else { + StepikAnimUtils.collapse(stepQuizCodeDetailsContent) + } + } + } else { + stepQuizCodeDetailsContent.visibility = View.VISIBLE + stepQuizCodeDetailsContent.isNestedScrollingEnabled = false + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt index 7ccfa31d1f..450ccc0c1f 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt @@ -5,7 +5,6 @@ import android.view.View import kotlinx.android.synthetic.main.layout_step_quiz_code.view.* import org.stepic.droid.R import org.stepic.droid.persistence.model.StepPersistentWrapper -import org.stepic.droid.ui.util.StepikAnimUtils import org.stepic.droid.ui.util.setCompoundDrawables import org.stepik.android.presentation.step_quiz.StepQuizView import org.stepik.android.view.step_quiz.resolver.StepQuizFormResolver @@ -16,8 +15,9 @@ import ru.nobird.android.ui.adapterssupport.DefaultDelegateAdapter class CodeStepQuizFormDelegate( containerView: View, stepWrapper: StepPersistentWrapper, - private val actionsListener: ActionsListener -) : CodeQuizFormBaseDelegate(containerView, containerView, stepWrapper) { + private val actionsListener: ActionsListener, + codeQuizInstructionDelegate: CodeQuizInstructionDelegate +) : CodeQuizFormBaseDelegate(containerView, stepWrapper, codeQuizInstructionDelegate) { private val stepQuizCodeLangChooserTitle = containerView.stepQuizCodeLangChooserTitle private val stepQuizCodeLangChooser = containerView.stepQuizCodeLangChooser @@ -28,19 +28,6 @@ class CodeStepQuizFormDelegate( viewStateDelegate.addState(stepQuizCodeLangChooserTitle, stepQuizCodeLangChooser) viewStateDelegate.addState(codeLayout, stepQuizActions) - /** - * Details - */ - stepQuizCodeDetails.setOnClickListener { - stepQuizCodeDetailsArrow.changeState() - if (stepQuizCodeDetailsArrow.isExpanded()) { - StepikAnimUtils.expand(stepQuizCodeDetailsContent) - } else { - StepikAnimUtils.collapse(stepQuizCodeDetailsContent) - } - } - setupCodeDetailContentData() - /** * Lang chooser */ diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt index d473a84418..e486ac64be 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt @@ -6,7 +6,6 @@ import android.view.View import android.view.ViewGroup import android.widget.RelativeLayout import kotlinx.android.synthetic.main.activity_step_quiz_code_fullscreen.view.* -import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_instruction.view.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.view.* import kotlinx.android.synthetic.main.view_step_quiz_submit_button.view.* import org.stepic.droid.R @@ -18,12 +17,12 @@ import org.stepik.android.presentation.step_quiz.StepQuizView import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState class CodeStepQuizFullScreenFormDelegate( - instructionContainerView: View, codeContainerView: View, keyboardExtensionContainer: ViewGroup, stepWrapper: StepPersistentWrapper, - actionsListener: ActionsListener -) : CodeQuizFormBaseDelegate(instructionContainerView, codeContainerView, stepWrapper) { + actionsListener: ActionsListener, + codeQuizInstructionDelegate: CodeQuizInstructionDelegate +) : CodeQuizFormBaseDelegate(codeContainerView, stepWrapper, codeQuizInstructionDelegate) { // Flag is necessary, because keyboard listener is constantly invoked (probably global layout listener reacts to view changes) private var keyboardShown: Boolean = false @@ -40,9 +39,6 @@ class CodeStepQuizFullScreenFormDelegate( retryButton.visibility = View.GONE - setupCodeDetailContentData() - instructionContainerView.stepQuizCodeDetailsContent.visibility = View.VISIBLE - instructionContainerView.stepQuizCodeDetailsContent.isNestedScrollingEnabled = false /** * Keyboard extension */ diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt index 398c3ee87a..850b81f976 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt @@ -28,6 +28,7 @@ import org.stepik.android.presentation.step_quiz.StepQuizPresenter import org.stepik.android.presentation.step_quiz.StepQuizView import org.stepik.android.view.step_quiz.ui.delegate.StepQuizDelegate import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFeedbackBlocksDelegate +import org.stepik.android.view.step_quiz_code.ui.delegate.CodeQuizInstructionDelegate import org.stepik.android.view.step_quiz_code.ui.delegate.CodeStepQuizFormDelegate import org.stepik.android.view.step_quiz_fullscreen_code.ui.dialog.CodeStepQuizFullScreenDialogFragment import org.stepik.android.view.ui.delegate.ViewStateDelegate @@ -113,7 +114,7 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog. } } - codeStepQuizFormDelegate = CodeStepQuizFormDelegate(view, stepWrapper, actionsListener) + codeStepQuizFormDelegate = CodeStepQuizFormDelegate(view, stepWrapper, actionsListener, CodeQuizInstructionDelegate(view, isCollapseable = true)) stepQuizDelegate = StepQuizDelegate( diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt index 064074e86f..cb6a3a8b37 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt @@ -35,6 +35,7 @@ import org.stepik.android.presentation.step_quiz.StepQuizPresenter import org.stepik.android.presentation.step_quiz.StepQuizView import org.stepik.android.presentation.step_quiz.model.ReplyResult import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState +import org.stepik.android.view.step_quiz_code.ui.delegate.CodeQuizInstructionDelegate import org.stepik.android.view.step_quiz_code.ui.delegate.CodeStepQuizFullScreenFormDelegate import org.stepik.android.view.step_quiz_fullscreen_code.ui.adapter.CodeStepQuizFullScreenPagerAdapter import org.stepik.android.view.ui.delegate.ViewStateDelegate @@ -152,6 +153,7 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, Cha if (text != null) { instructionsLayout.stepQuizCodeTextContent.setText(text) + instructionsLayout.stepQuizCodeTextContent.setTextSize(16f) instructionsLayout.stepQuizCodeTextContent.setTextIsSelectable(true) } @@ -173,7 +175,7 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, Cha } } } - codeStepQuizFormFullScreenDelegate = CodeStepQuizFullScreenFormDelegate(instructionsLayout, playgroundLayout, coordinator, stepWrapper, actionsListener) + codeStepQuizFormFullScreenDelegate = CodeStepQuizFullScreenFormDelegate(playgroundLayout, coordinator, stepWrapper, actionsListener, CodeQuizInstructionDelegate(instructionsLayout, false)) if (savedInstanceState == null) { codeStepQuizFormFullScreenDelegate.state = CodeStepQuizFormState.Lang(lang, code) @@ -198,11 +200,7 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, Cha override fun onPageScrolled(p0: Int, p1: Float, p2: Int) {} override fun onPageSelected(p0: Int) { if (p0 == 0) { - inputMethodManager?.let { - if (it.isActive) { - it.toggleSoftInput(0, InputMethodManager.HIDE_NOT_ALWAYS) - } - } + inputMethodManager?.hideSoftInputFromWindow(playgroundLayout.windowToken, 0) } } }) From 34ed5d2b6617b05a44f3a3a3ceb937625d5a6c6f Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Wed, 4 Sep 2019 15:09:10 +0300 Subject: [PATCH 23/51] change margins --- app/src/main/res/values/dimens.xml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index 1c5783d349..5b88fbbc99 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -98,11 +98,11 @@ 20dp 8dp - 4dp - 12dp + 8dp + 8dp - 16dp - 14dp + 12dp + 10dp 40dp 20dp @@ -143,7 +143,7 @@ 14sp 150dp - 16dp + 12dp 7dp From 116659e6d3c658b195347bf5005f842da1f52f90 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Wed, 4 Sep 2019 21:30:04 +0300 Subject: [PATCH 24/51] attempt to break down fullscreen delegate into a reusable delegate --- .../ui/delegate/CodeQuizFormBaseDelegate.kt | 89 --------------- .../delegate/CodeQuizInstructionDelegate.kt | 15 ++- .../ui/delegate/CodeStepQuizFormDelegate.kt | 68 ++++++++---- ...ormDelegate.kt => CoreCodeStepDelegate.kt} | 105 +++++++++++++----- .../ui/fragment/CodeStepQuizFragment.kt | 20 +++- .../CodeStepQuizFullScreenDialogFragment.kt | 105 +++++++----------- 6 files changed, 187 insertions(+), 215 deletions(-) delete mode 100644 app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizFormBaseDelegate.kt rename app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/{CodeStepQuizFullScreenFormDelegate.kt => CoreCodeStepDelegate.kt} (54%) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizFormBaseDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizFormBaseDelegate.kt deleted file mode 100644 index 7c52399485..0000000000 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizFormBaseDelegate.kt +++ /dev/null @@ -1,89 +0,0 @@ -package org.stepik.android.view.step_quiz_code.ui.delegate - -import android.view.View -import kotlinx.android.synthetic.main.layout_step_quiz_code.view.* -import org.stepic.droid.R -import org.stepic.droid.code.util.CodeToolbarUtil -import org.stepic.droid.model.code.extensionForLanguage -import org.stepic.droid.persistence.model.StepPersistentWrapper -import org.stepic.droid.ui.adapters.CodeToolbarAdapter -import org.stepik.android.model.Reply -import org.stepik.android.presentation.step_quiz.model.ReplyResult -import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFormDelegate -import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizDetailsMapper -import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizFormStateMapper -import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState -import org.stepik.android.view.ui.delegate.ViewStateDelegate - -abstract class CodeQuizFormBaseDelegate( - codeContainerView: View, - val stepWrapper: StepPersistentWrapper, - private val codeQuizInstructionDelegate: CodeQuizInstructionDelegate -) : StepQuizFormDelegate { - - var state: CodeStepQuizFormState = CodeStepQuizFormState.Idle - set(value) { - field = value - - viewStateDelegate.switchState(value) - - when (value) { - is CodeStepQuizFormState.Lang -> { - codeLayout.setText(value.code) - codeLayout.lang = extensionForLanguage(value.lang) - stepQuizActionChangeLang.text = value.lang - - codeToolbarAdapter.setLanguage(value.lang) - } - } - - codeQuizInstructionDelegate.setCodeDetailsData(codeStepQuizDetailsMapper.mapToCodeDetails(stepWrapper.step, (value as? CodeStepQuizFormState.Lang)?.lang)) - } - - protected val viewStateDelegate = ViewStateDelegate() - protected val codeStepQuizFormStateMapper = CodeStepQuizFormStateMapper() - - protected val codeLayout = codeContainerView.codeStepLayout - protected val codeStepQuizDetailsMapper = CodeStepQuizDetailsMapper() - - protected val codeToolbarAdapter = CodeToolbarAdapter(codeContainerView.context) - .apply { - onSymbolClickListener = object : CodeToolbarAdapter.OnSymbolClickListener { - override fun onSymbolClick(symbol: String, offset: Int) { - codeLayout.insertText(CodeToolbarUtil.mapToolbarSymbolToPrintable(symbol, codeLayout.indentSize), offset) - } - } - } - - protected val stepQuizActions = codeContainerView.stepQuizActions - protected val stepQuizActionChangeLang = codeContainerView.stepQuizActionChangeLang - - protected val codeOptions = stepWrapper.step.block?.options ?: throw IllegalArgumentException("Code options shouldn't be null") - - init { - codeQuizInstructionDelegate.setupCodeDetailView() - } - - override fun createReply(): ReplyResult { - val state = state - return if (state is CodeStepQuizFormState.Lang) { - ReplyResult.Success(Reply(code = codeLayout.text.toString(), language = state.lang)) - } else { - ReplyResult.Error(codeLayout.context.getString(R.string.step_quiz_code_empty_lang)) - } - } - - fun onLanguageSelected(lang: String) { - if (state !is CodeStepQuizFormState.Lang) { - return - } - state = CodeStepQuizFormState.Lang(lang, codeOptions.codeTemplates[lang] ?: "") - } - - fun onResetCode() { - val oldState = (state as? CodeStepQuizFormState.Lang) - ?: return - - state = oldState.copy(code = codeOptions.codeTemplates[oldState.lang] ?: "") - } -} \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizInstructionDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizInstructionDelegate.kt index f1794b594e..baa3cdf71b 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizInstructionDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizInstructionDelegate.kt @@ -7,6 +7,8 @@ import android.view.View import kotlinx.android.synthetic.main.layout_step_quiz_code.view.* import org.stepic.droid.R import org.stepic.droid.ui.util.StepikAnimUtils +import org.stepik.android.model.Step +import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizDetailsMapper import org.stepik.android.view.step_quiz_code.model.CodeDetail import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeDetailLimitAdapterDelegate import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeDetailSampleAdapterDelegate @@ -17,14 +19,15 @@ class CodeQuizInstructionDelegate( private val isCollapseable: Boolean ) { - val stepQuizCodeDetails = detailsContainerView.stepQuizCodeDetails - val stepQuizCodeDetailsArrow = detailsContainerView.stepQuizCodeDetailsArrow - val stepQuizCodeDetailsContent = detailsContainerView.stepQuizCodeDetailsContent + private val stepQuizCodeDetails = detailsContainerView.stepQuizCodeDetails + private val stepQuizCodeDetailsArrow = detailsContainerView.stepQuizCodeDetailsArrow + private val stepQuizCodeDetailsContent = detailsContainerView.stepQuizCodeDetailsContent - val stepQuizCodeDetailsAdapter = DefaultDelegateAdapter() + private val stepQuizCodeDetailsAdapter = DefaultDelegateAdapter() + private val codeStepQuizDetailsMapper = CodeStepQuizDetailsMapper() - fun setCodeDetailsData(codeDetails: List) { - stepQuizCodeDetailsAdapter.items = codeDetails + fun setCodeDetailsData(step: Step, lang: String?) { + stepQuizCodeDetailsAdapter.items = codeStepQuizDetailsMapper.mapToCodeDetails(step, lang) } fun setupCodeDetailView() { diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt index 450ccc0c1f..f897165943 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt @@ -3,21 +3,41 @@ package org.stepik.android.view.step_quiz_code.ui.delegate import android.support.v7.widget.LinearLayoutManager import android.view.View import kotlinx.android.synthetic.main.layout_step_quiz_code.view.* +import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.view.codeStepLayout +import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.view.stepQuizActions import org.stepic.droid.R -import org.stepic.droid.persistence.model.StepPersistentWrapper import org.stepic.droid.ui.util.setCompoundDrawables +import org.stepik.android.model.Reply import org.stepik.android.presentation.step_quiz.StepQuizView +import org.stepik.android.presentation.step_quiz.model.ReplyResult import org.stepik.android.view.step_quiz.resolver.StepQuizFormResolver +import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFormDelegate import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeLangAdapterDelegate +import org.stepik.android.view.ui.delegate.ViewStateDelegate import ru.nobird.android.ui.adapterssupport.DefaultDelegateAdapter class CodeStepQuizFormDelegate( containerView: View, - stepWrapper: StepPersistentWrapper, - private val actionsListener: ActionsListener, - codeQuizInstructionDelegate: CodeQuizInstructionDelegate -) : CodeQuizFormBaseDelegate(containerView, stepWrapper, codeQuizInstructionDelegate) { + private val coreCodeStepDelegate: CoreCodeStepDelegate +) : StepQuizFormDelegate { + var state: CodeStepQuizFormState = CodeStepQuizFormState.Idle + set(value) { + field = value + + viewStateDelegate.switchState(value) + + when (value) { + is CodeStepQuizFormState.Lang -> + coreCodeStepDelegate.setLanguage(value) + } + coreCodeStepDelegate.setDetailsContentData((value as? CodeStepQuizFormState.Lang)?.lang) + } + + val viewStateDelegate = ViewStateDelegate() + + private val codeLayout = containerView.codeStepLayout + private val stepQuizActions = containerView.stepQuizActions private val stepQuizCodeLangChooserTitle = containerView.stepQuizCodeLangChooserTitle private val stepQuizCodeLangChooser = containerView.stepQuizCodeLangChooser @@ -31,9 +51,9 @@ class CodeStepQuizFormDelegate( /** * Lang chooser */ - stepQuizCodeLangChooserAdapter += CodeLangAdapterDelegate { state = CodeStepQuizFormState.Lang(it, codeOptions.codeTemplates[it] ?: "") } + stepQuizCodeLangChooserAdapter += CodeLangAdapterDelegate { state = CodeStepQuizFormState.Lang(it, coreCodeStepDelegate.codeOptions.codeTemplates[it] ?: "") } stepQuizCodeLangChooserAdapter.items = - codeOptions.codeTemplates.keys.toList().sorted() + coreCodeStepDelegate.codeOptions.codeTemplates.keys.toList().sorted() stepQuizCodeLangChooserTitle.setCompoundDrawables(start = R.drawable.ic_step_quiz_code_lang) with(stepQuizCodeLangChooser) { @@ -41,34 +61,38 @@ class CodeStepQuizFormDelegate( adapter = stepQuizCodeLangChooserAdapter } - /** - * Actions - */ - stepQuizActionChangeLang.setCompoundDrawables(end = R.drawable.ic_arrow_bottom) - stepQuizActionChangeLang.setOnClickListener { actionsListener.onChangeLanguageClicked() } - codeLayout.codeEditor.isFocusable = false codeLayout.codeEditor.setOnClickListener { val oldState = (state as? CodeStepQuizFormState.Lang) ?: return@setOnClickListener - actionsListener.onFullscreenClicked(oldState.lang, oldState.code) + coreCodeStepDelegate.onFullscreenClicked(oldState.lang, oldState.code) + } + } + + override fun createReply(): ReplyResult { + val state = state + return if (state is CodeStepQuizFormState.Lang) { + ReplyResult.Success(Reply(code = state.code, language = state.lang)) + } else { + ReplyResult.Error(codeLayout.context.getString(R.string.step_quiz_code_empty_lang)) } } override fun setState(state: StepQuizView.State.AttemptLoaded) { - this.state = codeStepQuizFormStateMapper.mapToFormState(codeOptions, state) + this.state = coreCodeStepDelegate.codeStepQuizFormStateMapper.mapToFormState(coreCodeStepDelegate.codeOptions, state) val isEnabled = StepQuizFormResolver.isQuizEnabled(state) - codeLayout.isEnabled = isEnabled - stepQuizActionChangeLang.isEnabled = isEnabled + coreCodeStepDelegate.setEnabled(isEnabled) } - fun updateCodeLayout(lang: String, code: String) { - state = CodeStepQuizFormState.Lang(lang, code) + fun onLanguageSelected(lang: String) { + if (state !is CodeStepQuizFormState.Lang) { + return + } + state = coreCodeStepDelegate.onLanguageSelected(lang) } - interface ActionsListener { - fun onChangeLanguageClicked() - fun onFullscreenClicked(lang: String, code: String) + fun updateCodeLayoutFromDialog(lang: String, code: String) { + state = CodeStepQuizFormState.Lang(lang, code) } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt similarity index 54% rename from app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt rename to app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt index e486ac64be..adc408658e 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFullScreenFormDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt @@ -9,40 +9,65 @@ import kotlinx.android.synthetic.main.activity_step_quiz_code_fullscreen.view.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.view.* import kotlinx.android.synthetic.main.view_step_quiz_submit_button.view.* import org.stepic.droid.R +import org.stepic.droid.code.util.CodeToolbarUtil +import org.stepic.droid.model.code.extensionForLanguage import org.stepic.droid.persistence.model.StepPersistentWrapper +import org.stepic.droid.ui.adapters.CodeToolbarAdapter import org.stepic.droid.ui.util.inflate import org.stepic.droid.ui.util.setCompoundDrawables import org.stepic.droid.ui.util.setOnKeyboardOpenListener -import org.stepik.android.presentation.step_quiz.StepQuizView +import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizFormStateMapper import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState -class CodeStepQuizFullScreenFormDelegate( +class CoreCodeStepDelegate( codeContainerView: View, - keyboardExtensionContainer: ViewGroup, - stepWrapper: StepPersistentWrapper, - actionsListener: ActionsListener, - codeQuizInstructionDelegate: CodeQuizInstructionDelegate -) : CodeQuizFormBaseDelegate(codeContainerView, stepWrapper, codeQuizInstructionDelegate) { - + keyboardExtensionContainer: ViewGroup?, + private val stepWrapper: StepPersistentWrapper, + private val codeQuizInstructionDelegate: CodeQuizInstructionDelegate, + private val actionsListener: ActionsListener +) { // Flag is necessary, because keyboard listener is constantly invoked (probably global layout listener reacts to view changes) private var keyboardShown: Boolean = false - private val submitButtonSeparator = codeContainerView.submitButtonSeparator + private val submitButtonSeparator = keyboardExtensionContainer?.submitButtonSeparator private val codeSubmitButton = codeContainerView.codeSubmitButton - private val retryButton = codeSubmitButton.stepQuizRetry - private val fullScreenCodeToolbar = keyboardExtensionContainer.fullScreenCodeToolbar - private val fullScreenCodeTabs = keyboardExtensionContainer.fullScreenCodeTabs - private val fullScreenCodeSeparator = keyboardExtensionContainer.fullScreenCodeSeparator + private val retryButton = codeSubmitButton?.stepQuizRetry + private val fullScreenCodeToolbar = keyboardExtensionContainer?.fullScreenCodeToolbar + private val fullScreenCodeTabs = keyboardExtensionContainer?.fullScreenCodeTabs + private val fullScreenCodeSeparator = keyboardExtensionContainer?.fullScreenCodeSeparator + private val codeLayout = codeContainerView.codeStepLayout + private val stepQuizActionChangeLang = codeContainerView.stepQuizActionChangeLang + + val codeStepQuizFormStateMapper = CodeStepQuizFormStateMapper() + + val codeOptions = stepWrapper.step.block?.options ?: throw IllegalArgumentException("Code options shouldn't be null") + + private val codeToolbarAdapter = CodeToolbarAdapter(codeContainerView.context) + .apply { + onSymbolClickListener = object : CodeToolbarAdapter.OnSymbolClickListener { + override fun onSymbolClick(symbol: String, offset: Int) { + codeLayout.insertText(CodeToolbarUtil.mapToolbarSymbolToPrintable(symbol, codeLayout.indentSize), offset) + } + } + } init { - viewStateDelegate.addState() - viewStateDelegate.addState(codeLayout) + /** + * Initialize code details + */ + codeQuizInstructionDelegate.setupCodeDetailView() - retryButton.visibility = View.GONE + /** + * Actions + */ + stepQuizActionChangeLang.setOnClickListener { actionsListener.onChangeLanguageClicked() } + stepQuizActionChangeLang.setCompoundDrawables(end = R.drawable.ic_arrow_bottom) + codeSubmitButton?.setOnClickListener { actionsListener.onSubmitClicked() } + retryButton?.visibility = View.GONE /** * Keyboard extension */ - keyboardExtensionContainer.let { container -> + keyboardExtensionContainer?.let { container -> val stepQuizCodeKeyboardExtension = container.inflate(R.layout.layout_step_quiz_code_keyboard_extension) as RecyclerView stepQuizCodeKeyboardExtension.adapter = codeToolbarAdapter @@ -67,7 +92,8 @@ class CodeStepQuizFullScreenFormDelegate( .apply { bottomMargin = 0 } - codeLayout.setPadding(0, 0, 0, container.context.resources.getDimensionPixelSize(R.dimen.step_quiz_fullscreen_code_layout_bottom_padding)) + codeLayout.setPadding(0, 0, 0, container.context.resources.getDimensionPixelSize( + R.dimen.step_quiz_fullscreen_code_layout_bottom_padding)) setViewsVisibility(View.VISIBLE) keyboardShown = false } @@ -88,25 +114,48 @@ class CodeStepQuizFullScreenFormDelegate( } ) } - stepQuizActionChangeLang.setCompoundDrawables(end = R.drawable.ic_arrow_bottom) - stepQuizActionChangeLang.setOnClickListener { actionsListener.onChangeLanguageClicked() } - codeSubmitButton.setOnClickListener { actionsListener.onSubmitClicked() } } - override fun setState(state: StepQuizView.State.AttemptLoaded) { - this.state = codeStepQuizFormStateMapper.mapToFormState(codeOptions, state) + fun setLanguage(codeStepQuizFormState: CodeStepQuizFormState.Lang) { + codeLayout.setText(codeStepQuizFormState.code) + codeLayout.lang = extensionForLanguage(codeStepQuizFormState.lang) + stepQuizActionChangeLang.text = codeStepQuizFormState.lang + codeToolbarAdapter.setLanguage(codeStepQuizFormState.lang) + } + + fun setDetailsContentData(lang: String?) { + codeQuizInstructionDelegate.setCodeDetailsData(stepWrapper.step, lang) + } + + fun onFullscreenClicked(lang: String, code: String) { + actionsListener.onFullscreenClicked(lang, code) + } + + fun onLanguageSelected(lang: String): CodeStepQuizFormState.Lang = + CodeStepQuizFormState.Lang(lang, codeOptions.codeTemplates[lang] ?: "") + + fun onResetCode(): String = + codeOptions.codeTemplates[codeLayout.lang] ?: "" + + fun setEnabled(isEnabled: Boolean) { + codeLayout.isEnabled = isEnabled + stepQuizActionChangeLang.isEnabled = isEnabled } + /** + * Hiding views upon opening keyboard + */ private fun setViewsVisibility(visibility: Int) { - submitButtonSeparator.visibility = visibility - codeSubmitButton.visibility = visibility - fullScreenCodeToolbar.visibility = visibility - fullScreenCodeTabs.visibility = visibility - fullScreenCodeSeparator.visibility = visibility + submitButtonSeparator?.visibility = visibility + codeSubmitButton?.visibility = visibility + fullScreenCodeToolbar?.visibility = visibility + fullScreenCodeTabs?.visibility = visibility + fullScreenCodeSeparator?.visibility = visibility } interface ActionsListener { fun onChangeLanguageClicked() + fun onFullscreenClicked(lang: String, code: String) fun onSubmitClicked() } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt index 850b81f976..9d9bd21e28 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt @@ -30,6 +30,7 @@ import org.stepik.android.view.step_quiz.ui.delegate.StepQuizDelegate import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFeedbackBlocksDelegate import org.stepik.android.view.step_quiz_code.ui.delegate.CodeQuizInstructionDelegate import org.stepik.android.view.step_quiz_code.ui.delegate.CodeStepQuizFormDelegate +import org.stepik.android.view.step_quiz_code.ui.delegate.CoreCodeStepDelegate import org.stepik.android.view.step_quiz_fullscreen_code.ui.dialog.CodeStepQuizFullScreenDialogFragment import org.stepik.android.view.ui.delegate.ViewStateDelegate import javax.inject.Inject @@ -95,7 +96,7 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog. stepQuizNetworkError.tryAgain.setOnClickListener { presenter.onStepData(stepWrapper, lessonData, forceUpdate = true) } - val actionsListener = object : CodeStepQuizFormDelegate.ActionsListener { + val actionsListener = object : CoreCodeStepDelegate.ActionsListener { override fun onChangeLanguageClicked() { val dialog = ChangeCodeLanguageDialog.newInstance() if (!dialog.isAdded) { @@ -112,9 +113,20 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog. dialog.setTargetFragment(this@CodeStepQuizFragment, CodeStepQuizFullScreenDialogFragment.CODE_PLAYGROUND_REQUEST) dialog.show(supportFragmentManager, CodeStepQuizFullScreenDialogFragment.TAG) } - } - codeStepQuizFormDelegate = CodeStepQuizFormDelegate(view, stepWrapper, actionsListener, CodeQuizInstructionDelegate(view, isCollapseable = true)) + override fun onSubmitClicked() {} + } + + codeStepQuizFormDelegate = CodeStepQuizFormDelegate( + containerView = view, + coreCodeStepDelegate = CoreCodeStepDelegate( + codeContainerView = view, + keyboardExtensionContainer = null, + stepWrapper = stepWrapper, + codeQuizInstructionDelegate = CodeQuizInstructionDelegate(view, true), + actionsListener = actionsListener + ) + ) stepQuizDelegate = StepQuizDelegate( @@ -177,7 +189,7 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog. } override fun onSyncCodeStateWithParent(lang: String, code: String, onSubmitClicked: Boolean) { - codeStepQuizFormDelegate.updateCodeLayout(lang, code) + codeStepQuizFormDelegate.updateCodeLayoutFromDialog(lang, code) if (onSubmitClicked) { stepQuizDelegate.onActionButtonClicked() } diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt index cb6a3a8b37..9e7f0c425f 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt @@ -1,13 +1,9 @@ package org.stepik.android.view.step_quiz_fullscreen_code.ui.dialog import android.app.Dialog -import android.arch.lifecycle.ViewModelProvider -import android.arch.lifecycle.ViewModelProviders import android.os.Bundle -import android.support.design.widget.Snackbar import android.support.design.widget.TabLayout import android.support.v4.app.DialogFragment -import android.support.v4.content.ContextCompat import android.support.v4.content.ContextCompat.getSystemService import android.support.v4.view.ViewPager import android.view.LayoutInflater @@ -20,6 +16,7 @@ import android.widget.TextView import kotlinx.android.synthetic.main.activity_step_quiz_code_fullscreen.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_instruction.view.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.* +import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.view.* import org.stepic.droid.R import org.stepic.droid.base.App import org.stepic.droid.fonts.FontType @@ -29,24 +26,22 @@ import org.stepic.droid.ui.dialogs.ChangeCodeLanguageDialog import org.stepic.droid.ui.dialogs.ProgrammingLanguageChooserDialogFragment import org.stepic.droid.ui.dialogs.ResetCodeDialogFragment import org.stepic.droid.util.argument -import org.stepic.droid.util.setTextColor import org.stepik.android.domain.lesson.model.LessonData -import org.stepik.android.presentation.step_quiz.StepQuizPresenter -import org.stepik.android.presentation.step_quiz.StepQuizView -import org.stepik.android.presentation.step_quiz.model.ReplyResult import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState import org.stepik.android.view.step_quiz_code.ui.delegate.CodeQuizInstructionDelegate -import org.stepik.android.view.step_quiz_code.ui.delegate.CodeStepQuizFullScreenFormDelegate +import org.stepik.android.view.step_quiz_code.ui.delegate.CoreCodeStepDelegate import org.stepik.android.view.step_quiz_fullscreen_code.ui.adapter.CodeStepQuizFullScreenPagerAdapter -import org.stepik.android.view.ui.delegate.ViewStateDelegate import uk.co.chrisjenx.calligraphy.TypefaceUtils import javax.inject.Inject -class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, ChangeCodeLanguageDialog.Callback, ProgrammingLanguageChooserDialogFragment.Callback, ResetCodeDialogFragment.Callback { +class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguageDialog.Callback, ProgrammingLanguageChooserDialogFragment.Callback, ResetCodeDialogFragment.Callback { companion object { const val TAG = "CodeStepQuizFullScreenDialogFragment" const val CODE_PLAYGROUND_REQUEST = 153 + private const val LANG = "LANG" + private const val CODE = "CODE" + fun newInstance(lang: String, code: String, stepPersistentWrapper: StepPersistentWrapper, lessonData: LessonData): DialogFragment = CodeStepQuizFullScreenDialogFragment() .apply { @@ -65,17 +60,10 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, Cha private var inputMethodManager: InputMethodManager? = null - private lateinit var viewStateDelegate: ViewStateDelegate - @Inject internal lateinit var fontsProvider: FontsProvider - @Inject - internal lateinit var viewModelFactory: ViewModelProvider.Factory - - private lateinit var presenter: StepQuizPresenter - - private lateinit var codeStepQuizFormFullScreenDelegate: CodeStepQuizFullScreenFormDelegate + private lateinit var coreCodeStepDelegate: CoreCodeStepDelegate private lateinit var instructionsLayout: View private lateinit var playgroundLayout: View @@ -98,7 +86,6 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, Cha override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setStyle(STYLE_NO_TITLE, R.style.AppTheme_FullScreenDialog) - injectComponent() } @@ -143,8 +130,6 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, Cha initViewPager() - presenter = ViewModelProviders.of(this, viewModelFactory).get(StepQuizPresenter::class.java) - val text = stepWrapper .step .block @@ -157,14 +142,9 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, Cha instructionsLayout.stepQuizCodeTextContent.setTextIsSelectable(true) } - viewStateDelegate = ViewStateDelegate() - viewStateDelegate.addState(fullScreenCodeViewPager) - viewStateDelegate.addState(stepQuizProgress) - viewStateDelegate.addState(fullScreenCodeViewPager) - - val actionsListener = object : CodeStepQuizFullScreenFormDelegate.ActionsListener { + val actionsListener = object : CoreCodeStepDelegate.ActionsListener { override fun onSubmitClicked() { - callback.onSyncCodeStateWithParent((codeStepQuizFormFullScreenDelegate.state as CodeStepQuizFormState.Lang).lang, codeStepLayout.text.toString(), true) + callback.onSyncCodeStateWithParent(lang, codeStepLayout.text.toString(), true) dismiss() } @@ -174,14 +154,30 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, Cha dialog.show(childFragmentManager, null) } } - } - codeStepQuizFormFullScreenDelegate = CodeStepQuizFullScreenFormDelegate(playgroundLayout, coordinator, stepWrapper, actionsListener, CodeQuizInstructionDelegate(instructionsLayout, false)) - if (savedInstanceState == null) { - codeStepQuizFormFullScreenDelegate.state = CodeStepQuizFormState.Lang(lang, code) - } else { - presenter.onStepData(stepWrapper, lessonData) + override fun onFullscreenClicked(lang: String, code: String) {} } + coreCodeStepDelegate = CoreCodeStepDelegate( + codeContainerView = playgroundLayout, + keyboardExtensionContainer = coordinator, + stepWrapper = stepWrapper, + codeQuizInstructionDelegate = CodeQuizInstructionDelegate(instructionsLayout, false), + actionsListener = actionsListener + ) + + if (savedInstanceState != null) { + lang = savedInstanceState.getString(LANG) ?: return + code = savedInstanceState.getString(CODE) ?: return + } + coreCodeStepDelegate.setLanguage(CodeStepQuizFormState.Lang(lang, code)) + coreCodeStepDelegate.setDetailsContentData(lang) + fullScreenCodeViewPager.setCurrentItem(1, false) + } + + override fun onSaveInstanceState(outState: Bundle) { + super.onSaveInstanceState(outState) + outState.putString(LANG, lang) + outState.putString(CODE, codeStepLayout.text.toString()) } private fun initViewPager() { @@ -238,41 +234,13 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, Cha window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) window.setWindowAnimations(R.style.AppTheme_FullScreenDialog) } - - presenter.attachView(this) } override fun onPause() { - callback.onSyncCodeStateWithParent((codeStepQuizFormFullScreenDelegate.state as CodeStepQuizFormState.Lang).lang, codeStepLayout.text.toString()) + callback.onSyncCodeStateWithParent(lang, codeStepLayout.text.toString()) super.onPause() } - override fun onStop() { - presenter.detachView(this) - val reply = codeStepQuizFormFullScreenDelegate.createReply() - if (reply is ReplyResult.Success) { - presenter.syncReplyState(reply.reply) - } - super.onStop() - } - - override fun setState(state: StepQuizView.State) { - viewStateDelegate.switchState(state) - if (state is StepQuizView.State.AttemptLoaded) { - codeStepQuizFormFullScreenDelegate.setState(state) - } - } - - override fun showNetworkError() { - val view = view - ?: return - - Snackbar - .make(view, R.string.connectionProblems, Snackbar.LENGTH_SHORT) - .setTextColor(ContextCompat.getColor(view.context, R.color.white)) - .show() - } - override fun onChangeLanguage() { val languages = stepWrapper.step.block?.options?.limits?.keys?.sorted()?.toTypedArray() ?: emptyArray() @@ -283,10 +251,15 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), StepQuizView, Cha } override fun onLanguageChosen(programmingLanguage: String) { - codeStepQuizFormFullScreenDelegate.onLanguageSelected(programmingLanguage) + lang = programmingLanguage + coreCodeStepDelegate.setLanguage(coreCodeStepDelegate.onLanguageSelected(programmingLanguage)) + coreCodeStepDelegate.setDetailsContentData(programmingLanguage) } override fun onReset() { - codeStepQuizFormFullScreenDelegate.onResetCode() + coreCodeStepDelegate.onResetCode().let { codeTemplate -> + code = codeTemplate + playgroundLayout.codeStepLayout.setText(codeTemplate) + } } } \ No newline at end of file From de800877c5c118993a896a4defa64b7749cc70d4 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Wed, 4 Sep 2019 21:33:36 +0300 Subject: [PATCH 25/51] add icons --- app/src/main/res/drawable-hdpi/ic_fullscreen.png | Bin 0 -> 262 bytes .../main/res/drawable-hdpi/ic_fullscreen_exit.png | Bin 0 -> 228 bytes app/src/main/res/drawable-mdpi/ic_fullscreen.png | Bin 0 -> 195 bytes .../main/res/drawable-mdpi/ic_fullscreen_exit.png | Bin 0 -> 201 bytes app/src/main/res/drawable-xhdpi/ic_fullscreen.png | Bin 0 -> 224 bytes .../res/drawable-xhdpi/ic_fullscreen_exit.png | Bin 0 -> 222 bytes .../main/res/drawable-xxhdpi/ic_fullscreen.png | Bin 0 -> 420 bytes .../res/drawable-xxhdpi/ic_fullscreen_exit.png | Bin 0 -> 413 bytes .../main/res/drawable-xxxhdpi/ic_fullscreen.png | Bin 0 -> 282 bytes .../res/drawable-xxxhdpi/ic_fullscreen_exit.png | Bin 0 -> 289 bytes 10 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 app/src/main/res/drawable-hdpi/ic_fullscreen.png create mode 100644 app/src/main/res/drawable-hdpi/ic_fullscreen_exit.png create mode 100644 app/src/main/res/drawable-mdpi/ic_fullscreen.png create mode 100644 app/src/main/res/drawable-mdpi/ic_fullscreen_exit.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_fullscreen.png create mode 100644 app/src/main/res/drawable-xhdpi/ic_fullscreen_exit.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_fullscreen.png create mode 100644 app/src/main/res/drawable-xxhdpi/ic_fullscreen_exit.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_fullscreen.png create mode 100644 app/src/main/res/drawable-xxxhdpi/ic_fullscreen_exit.png diff --git a/app/src/main/res/drawable-hdpi/ic_fullscreen.png b/app/src/main/res/drawable-hdpi/ic_fullscreen.png new file mode 100644 index 0000000000000000000000000000000000000000..f2d9f70e2f4e48b5b49b0e7b66a86b87eb33d7e2 GIT binary patch literal 262 zcmV+h0r~!kP) M07*qoM6N<$f{N{Kod5s; literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-hdpi/ic_fullscreen_exit.png b/app/src/main/res/drawable-hdpi/ic_fullscreen_exit.png new file mode 100644 index 0000000000000000000000000000000000000000..243a9b1611b32be5bab42399e48fe74b19cb06a4 GIT binary patch literal 228 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjt36#DLp(a)PP67ZY#`vmYW5>Z zGbExlc*m*OORGX&3ok90sJvGsas$Wipa8*+4+ly%|8`hCzqqS`yFmQ>frKYD(>_PJ zi3(V5VVpeCJ5q0MgINQQN!^c&3^%6Q-8;#r@iMw$*$?3ZI=(vh8!j@enR@FeBeQ|% z8Z+?&5i3LaU#z@$UcR_4jR| cO>?X+h(C5*%j6R^0pte;Pgg&ebxsLQ0NYMoiU0rr literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_fullscreen.png b/app/src/main/res/drawable-mdpi/ic_fullscreen.png new file mode 100644 index 0000000000000000000000000000000000000000..4ab1665c4759197e2e4ddd6a10b65c33f4bed531 GIT binary patch literal 195 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`U7jwEAr`%NCmV7#7znU@c5~FJ zX^B{RQO#`M(L+w$+^21Fa{M@+YjTM_I^>v;->z-Ox1!O}x4_FG`Awxd|Jn?Ou;hF% zM(zixUd#b1|8f}j@Xh615y#4+5S1R!P;~N3x$*vKCONEK>@$6g?wVI^U`{jCQn0tI s{_f5_;nl_TPY0GfyI`=u_}eYsWaeJx=T`qt0$s)6>FVdQ&MBb@0KhRrlK=n! literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-mdpi/ic_fullscreen_exit.png b/app/src/main/res/drawable-mdpi/ic_fullscreen_exit.png new file mode 100644 index 0000000000000000000000000000000000000000..73499bf8b3e245fc10bf5a6715aee6f0bdd4bc21 GIT binary patch literal 201 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`6FglULo9lqPFCb=ao};S-r{?L zBd_s^!0H1HPHSBf!W1?tTi$Taan0Pt;@I>+J^t_X`R9Dxk8o5l8eixT{%}p_=NTta z`?ZeKOjobhy|7XHYsI1jqZ-93z4eQkR=YN^Ma;E#JSb3b_x|sSNhOCjeHJLFJ+O7U zO)^u~*OEmKvVUB1HvhxQE_y&HSK>m}HtA~SQ@?smU!LT=4|E%Yr>mdKI;Vst0Kx}P AZ2$lO literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_fullscreen.png b/app/src/main/res/drawable-xhdpi/ic_fullscreen.png new file mode 100644 index 0000000000000000000000000000000000000000..844f401e21107187cd19ce216b7e974653849ab2 GIT binary patch literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJ<(@8%ArY-_rz`Tc7>Kx3Pc~g~ zHCsT#?;x)QuZBvWvfj3QR#D!@Z_{~~wAi0i5q {gw~!2PUb7-ok<(JZFSUY@d)N z#K6P(Ig0fL(}n|k9tSd9U_Telc|eBSQtQEL2CfOJ4xB#o7Kgv(Zz!A^I)CcYpp|(l z)A-CQ-ua(-6&4vP=D(3i!=a4fTJD`qOQw}KeqIzMcgeWUZ921vgLcW5!;GPa_I&3z YTDIV%tPSTGppzLqUHx3vIVCg!0Djj`@Bjb+ literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xhdpi/ic_fullscreen_exit.png b/app/src/main/res/drawable-xhdpi/ic_fullscreen_exit.png new file mode 100644 index 0000000000000000000000000000000000000000..114fe0dce57bfcf3ba9b6d40e031ef17c33b1f11 GIT binary patch literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJrJgR1ArY-_r)}hIF%V#hy`s+I zvL)fAYn#kR){Bg+PRwW6|1s$Nd{-f;P^g{zEY`Q^TAKn#hr|A2<-Pw?<6PCUBv?mFnXQ}`Spa2S>0Nnv3?xws?z@`TPv3tSAe1{BR2rM0G-Z6q5wgZ5v%Tml20Z;eN zr&6g@DwRrgS7E!vA-2(!_X3#pAm136m*fk9QFff(W4mN|AAxlb03zV4Bws>Bcluxb z&?tZcD1ZVeK~Nvj&M0fYOa;Nl*iEWx{WpXIj+=Y1*ib4uMK)rZV|Uo9^~EEm zy6WwaPXQFb17PPaNPGYy0YHd75=-muamVQa5CD?~_U;k`qlR?@;NcHMlM_1SKb{-_ O00004%P)L3akWqA&^w$?SNSy08`+^Z+!wALEbx% zSLB_6g#svm0w{n23lV>)(Z-5+FI`k6&zK1!wxAy5a`3zhK0Jz%gxB5wd zpa94!f?U-#fU8cxQ~?yABY@O4B5?++1ppCnyrb@+02l!)U?cPzcoP6jfcTEOG4R~B zu1cj+sZ=V}zY=Ck9Ad^>i6dYlsQYT~mDUY`aWPIOnAu$7BM=J!B0CaG>!#>8u>vT- zH^2_FxN36FaEq;rLqB`$OYCFThKn0s))ed--~xO&^fL#Z+7$eo%UuOf00mG01sDn- zz>MAHUp)t8<8+7_iOYF=VBQCSPyNrp)>~p=T$2~j;)MMIm8upyTdi{R00000NkvXX Hu0mjf3Q()7 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_fullscreen.png b/app/src/main/res/drawable-xxxhdpi/ic_fullscreen.png new file mode 100644 index 0000000000000000000000000000000000000000..cf21fe256ee88f35e6898f8452e25d61814db4f3 GIT binary patch literal 282 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=4?SHRLn`LHy|t0A$$-K2;=lj< zB_HKE%Wyno=HPy2dEh`oSFW5wMgFC;H@@lITBaDlF)447)aQ<4Uv14I;WVbWXa#XI8!RCBxKP z!L?tcIy)fX#RikThhGanF1hah*)%@Ozwqb7{rg2&QMB8cor|AgoWri+%Rc+g&$aza zy?0$H{y7Pv#)8{n>7V;I)c)DS>_F~>yrOufaE=0{an^LB{Ts5YA9)U literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_fullscreen_exit.png b/app/src/main/res/drawable-xxxhdpi/ic_fullscreen_exit.png new file mode 100644 index 0000000000000000000000000000000000000000..cf7e8b09a306b2d236527ea4878454a4849378af GIT binary patch literal 289 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=FFaiwLn`LHy|t06*+9fC@&13t zS9+}T4{Tq##d|`~lF1hTWH(u;s@&^X`TW4#_fKz6G2wlx`cmyAYnsWOuN`k*ttne7 zb5;9J){gAXH&P%DE6`9l*vfpO{>GQi&sKsBr+4hXt5-0Q)l!yo!ethyin@aunWppB zD;|h>uy6U*S{En?iT(8cgV^JlyzhUD?8v{Px8sk0AOn{USknr&1(Quw{CM7aG?X9v z`+cwb-}A~V&n$*p31mE2#ISaWra{{K4^QqJww1m8y Date: Wed, 4 Sep 2019 21:44:29 +0300 Subject: [PATCH 26/51] add full screen icon to player layout --- .../res/layout/exo_playback_control_view.xml | 54 +++++++++++++------ 1 file changed, 38 insertions(+), 16 deletions(-) diff --git a/app/src/main/res/layout/exo_playback_control_view.xml b/app/src/main/res/layout/exo_playback_control_view.xml index 7c4be16663..6eb9d8f090 100644 --- a/app/src/main/res/layout/exo_playback_control_view.xml +++ b/app/src/main/res/layout/exo_playback_control_view.xml @@ -1,10 +1,10 @@ - @@ -119,7 +119,7 @@ android:src="@drawable/ic_forward_10_white_48dp"/> - - + + + + + From 9ab7ca1445bd8f3e08b722d776f2af3e52c0ce7d Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Thu, 5 Sep 2019 00:24:36 +0300 Subject: [PATCH 27/51] handle full screen button click --- .../video_player/VideoPlayerPresenter.kt | 27 +++------- .../video_player/VideoPlayerView.kt | 2 +- .../ui/activity/VideoPlayerActivity.kt | 54 +++++++++++-------- .../res/layout/exo_simple_player_view.xml | 5 ++ app/src/main/res/menu/video_more_menu.xml | 5 -- 5 files changed, 44 insertions(+), 49 deletions(-) diff --git a/app/src/main/java/org/stepik/android/presentation/video_player/VideoPlayerPresenter.kt b/app/src/main/java/org/stepik/android/presentation/video_player/VideoPlayerPresenter.kt index 1799ebdb60..e74d8b98b6 100644 --- a/app/src/main/java/org/stepik/android/presentation/video_player/VideoPlayerPresenter.kt +++ b/app/src/main/java/org/stepik/android/presentation/video_player/VideoPlayerPresenter.kt @@ -30,6 +30,7 @@ constructor( ) : PresenterBase() { companion object { private const val VIDEO_PLAYER_DATA = "video_player_data" + private const val FULLSCREEN_DATA = "fullscreen_data" private const val TIMESTAMP_EPS = 1000L } @@ -41,29 +42,18 @@ constructor( view?.setVideoPlayerData(value) } } - - private var isRotateVideo: Boolean? = null + private var isLandscapeVideo: Boolean = false set(value) { field = value - view?.setIsRotateVideo(value ?: false) + view?.setIsLandscapeVideo(value) } private var isLoading = false - init { - compositeDisposable += videoPlayerSettingsInteractor - .isRotateVideo() - .subscribeOn(backgroundScheduler) - .observeOn(mainScheduler) - .subscribe { isRotate -> - isRotateVideo = isRotate - } - } - override fun attachView(view: VideoPlayerView) { super.attachView(view) videoPlayerData?.let(view::setVideoPlayerData) - view.setIsRotateVideo(isRotateVideo ?: false) + view.setIsLandscapeVideo(isLandscapeVideo) } /** @@ -73,6 +63,7 @@ constructor( if (videoPlayerData == null) { videoPlayerData = savedInstanceState.getParcelable(VIDEO_PLAYER_DATA) } + isLandscapeVideo = savedInstanceState.getBoolean(FULLSCREEN_DATA) } fun onMediaData(mediaData: VideoPlayerMediaData) { @@ -144,12 +135,7 @@ constructor( } fun changeVideoRotation(isRotateVideo: Boolean) { - this.isRotateVideo = isRotateVideo - - compositeDisposable += videoPlayerSettingsInteractor - .setRotateVideo(isRotateVideo) - .subscribeOn(backgroundScheduler) - .subscribe() + this.isLandscapeVideo = isRotateVideo } fun syncVideoTimestamp(currentPosition: Long, duration: Long) { @@ -171,5 +157,6 @@ constructor( override fun onSaveInstanceState(outState: Bundle) { outState.putParcelable(VIDEO_PLAYER_DATA, videoPlayerData) + outState.putBoolean(FULLSCREEN_DATA, isLandscapeVideo) } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/presentation/video_player/VideoPlayerView.kt b/app/src/main/java/org/stepik/android/presentation/video_player/VideoPlayerView.kt index 1eb6a62925..df4f920e16 100644 --- a/app/src/main/java/org/stepik/android/presentation/video_player/VideoPlayerView.kt +++ b/app/src/main/java/org/stepik/android/presentation/video_player/VideoPlayerView.kt @@ -4,6 +4,6 @@ import org.stepik.android.view.video_player.model.VideoPlayerData interface VideoPlayerView { fun setVideoPlayerData(videoPlayerData: VideoPlayerData) - fun setIsRotateVideo(isRotateVideo: Boolean) + fun setIsLandscapeVideo(isLandScapeVideo: Boolean) fun showPlayInBackgroundPopup() } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/video_player/ui/activity/VideoPlayerActivity.kt b/app/src/main/java/org/stepik/android/view/video_player/ui/activity/VideoPlayerActivity.kt index 4ffbbdc919..53a8466138 100644 --- a/app/src/main/java/org/stepik/android/view/video_player/ui/activity/VideoPlayerActivity.kt +++ b/app/src/main/java/org/stepik/android/view/video_player/ui/activity/VideoPlayerActivity.kt @@ -10,6 +10,7 @@ import android.content.pm.ActivityInfo import android.os.Bundle import android.os.IBinder import android.support.v7.app.AppCompatActivity +import android.support.v7.content.res.AppCompatResources import android.support.v7.widget.PopupMenu import android.view.Gravity import android.view.View @@ -22,6 +23,8 @@ import com.google.android.exoplayer2.upstream.HttpDataSource import com.google.android.exoplayer2.util.Util import kotlinx.android.synthetic.main.activity_video_player.* import kotlinx.android.synthetic.main.exo_playback_control_view.* +import kotlinx.android.synthetic.main.exo_playback_control_view.view.* +import kotlinx.android.synthetic.main.exo_simple_player_view.view.* import org.stepic.droid.R import org.stepic.droid.analytic.AmplitudeAnalytic import org.stepic.droid.analytic.Analytic @@ -98,8 +101,7 @@ class VideoPlayerActivity : AppCompatActivity(), VideoPlayerView, VideoQualityDi playerView?.player = value } - - private var isRotateVideo = false + private var isLandscapeVideo = false private lateinit var videoPlayerPresenter: VideoPlayerPresenter @@ -137,6 +139,8 @@ class VideoPlayerActivity : AppCompatActivity(), VideoPlayerView, VideoQualityDi playerView.setFastForwardIncrementMs(JUMP_TIME_MILLIS) playerView.setRewindIncrementMs(JUMP_TIME_MILLIS) + playerView.exo_controller.exo_fullscreen_icon.setOnClickListener { changeVideoRotation() } + playerView.setControllerVisibilityListener { visibility -> if (visibility == View.VISIBLE) { NavigationBarUtil.hideNavigationBar(false, this) @@ -161,7 +165,6 @@ class VideoPlayerActivity : AppCompatActivity(), VideoPlayerView, VideoQualityDi override fun onStop() { playerInBackroundPopup?.dismiss() - exoPlayer?.let { player -> videoPlayerPresenter.syncVideoTimestamp(player.currentPosition, player.duration) } @@ -208,20 +211,8 @@ class VideoPlayerActivity : AppCompatActivity(), VideoPlayerView, VideoQualityDi val morePopupMenu = PopupMenu(this, view) morePopupMenu.inflate(R.menu.video_more_menu) - val menuItem = morePopupMenu.menu.findItem(R.id.orientation_flag) - menuItem.isChecked = isRotateVideo - morePopupMenu.setOnMenuItemClickListener { when (it.itemId) { - R.id.orientation_flag -> { - val oldValue = it.isChecked - val newValue = !oldValue - it.isChecked = newValue - - videoPlayerPresenter.changeVideoRotation(newValue) - - true - } R.id.video_quality -> { val cachedVideo: Video? = videoPlayerData.mediaData.cachedVideo val externalVideo: Video? = videoPlayerData.mediaData.externalVideo @@ -245,14 +236,13 @@ class VideoPlayerActivity : AppCompatActivity(), VideoPlayerView, VideoQualityDi playerView.showController() } - override fun setIsRotateVideo(isRotateVideo: Boolean) { - this.isRotateVideo = isRotateVideo - requestedOrientation = - if (isRotateVideo) { - ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR - } else { - ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED - } + override fun setIsLandscapeVideo(isLandScapeVideo: Boolean) { + this.isLandscapeVideo = isLandScapeVideo + if (isLandscapeVideo) { + playerView.exo_controller.exo_fullscreen_icon.setImageDrawable(AppCompatResources.getDrawable(this, R.drawable.ic_fullscreen_exit)) + } else { + playerView.exo_controller.exo_fullscreen_icon.setImageDrawable(AppCompatResources.getDrawable(this, R.drawable.ic_fullscreen)) + } } override fun showPlayInBackgroundPopup() { @@ -285,4 +275,22 @@ class VideoPlayerActivity : AppCompatActivity(), VideoPlayerView, VideoQualityDi analytic.reportAmplitudeEvent(AmplitudeAnalytic.Video.PLAY_IN_BACKGROUND) } } + + override fun onBackPressed() { + if (isLandscapeVideo) { + changeVideoRotation() + } else { + super.onBackPressed() + } + } + + private fun changeVideoRotation() { + isLandscapeVideo = !isLandscapeVideo + requestedOrientation = if (isLandscapeVideo) { + ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE + } else { + ActivityInfo.SCREEN_ORIENTATION_PORTRAIT + } + videoPlayerPresenter.changeVideoRotation(isLandscapeVideo) + } } \ No newline at end of file diff --git a/app/src/main/res/layout/exo_simple_player_view.xml b/app/src/main/res/layout/exo_simple_player_view.xml index 66e6b13509..c7691cbaa8 100644 --- a/app/src/main/res/layout/exo_simple_player_view.xml +++ b/app/src/main/res/layout/exo_simple_player_view.xml @@ -42,6 +42,11 @@ + + diff --git a/app/src/main/res/menu/video_more_menu.xml b/app/src/main/res/menu/video_more_menu.xml index 765bc50621..d05af36aef 100644 --- a/app/src/main/res/menu/video_more_menu.xml +++ b/app/src/main/res/menu/video_more_menu.xml @@ -1,10 +1,5 @@ - - From 7af278e7321cc39c134416ee1478a9ade6233203 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Thu, 5 Sep 2019 00:25:17 +0300 Subject: [PATCH 28/51] remove redundant methods from interactor --- .../interactor/VideoPlayerSettingsInteractor.kt | 8 -------- 1 file changed, 8 deletions(-) diff --git a/app/src/main/java/org/stepik/android/domain/video_player/interactor/VideoPlayerSettingsInteractor.kt b/app/src/main/java/org/stepik/android/domain/video_player/interactor/VideoPlayerSettingsInteractor.kt index 16bccaa433..b065f19679 100644 --- a/app/src/main/java/org/stepik/android/domain/video_player/interactor/VideoPlayerSettingsInteractor.kt +++ b/app/src/main/java/org/stepik/android/domain/video_player/interactor/VideoPlayerSettingsInteractor.kt @@ -34,14 +34,6 @@ constructor( ) } - fun isRotateVideo(): Single = - Single.fromCallable(userPreferences::isRotateVideo) - - fun setRotateVideo(isRotateVideo: Boolean): Completable = - Completable.fromAction { - userPreferences.isRotateVideo = isRotateVideo - } - private fun getVideoUrl(videoUrls: List): Single = Single .fromCallable(userPreferences::getQualityVideoForPlaying) From 69cbfb060185fe515e6470688ef623ad9ba40ec2 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Thu, 5 Sep 2019 01:41:42 +0300 Subject: [PATCH 29/51] perform background fetch if reviews are obtained from cache --- .../course_reviews/CourseReviewsPresenter.kt | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/app/src/main/java/org/stepik/android/presentation/course_reviews/CourseReviewsPresenter.kt b/app/src/main/java/org/stepik/android/presentation/course_reviews/CourseReviewsPresenter.kt index d6eb8f3cdc..ffc4a91672 100644 --- a/app/src/main/java/org/stepik/android/presentation/course_reviews/CourseReviewsPresenter.kt +++ b/app/src/main/java/org/stepik/android/presentation/course_reviews/CourseReviewsPresenter.kt @@ -83,7 +83,12 @@ constructor( .subscribeOn(backgroundScheduler) .observeOn(mainScheduler) .subscribeBy( - onSuccess = { state = it }, + onSuccess = { + state = it + if (state is CourseReviewsView.State.CourseReviewsCache) { + fetchNextPageFromRemote(backgroundLoading = true) + } + }, onError = { state = CourseReviewsView.State.NetworkError } ) } @@ -114,7 +119,7 @@ constructor( /** * Pagination handling */ - fun fetchNextPageFromRemote() { + fun fetchNextPageFromRemote(backgroundLoading: Boolean = false) { val oldState = state val oldItems = (oldState as? CourseReviewsView.State.CourseReviewsRemote)?.courseReviewItems @@ -146,7 +151,7 @@ constructor( .subscribeBy( onSuccess = { state = CourseReviewsView.State.CourseReviewsRemote(currentItems.concatWithPagedList(it)) - if (oldState is CourseReviewsView.State.CourseReviewsCache) { + if (oldState is CourseReviewsView.State.CourseReviewsCache && !backgroundLoading) { fetchNextPageFromRemote() // load 2 page from remote after going online } }, From 26788cbdbd7f2fda300e336290686fed13f4f86e Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Thu, 5 Sep 2019 20:44:40 +0300 Subject: [PATCH 30/51] refactor activity --- .../ui/activity/VideoPlayerActivity.kt | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/video_player/ui/activity/VideoPlayerActivity.kt b/app/src/main/java/org/stepik/android/view/video_player/ui/activity/VideoPlayerActivity.kt index 53a8466138..b8e88d388d 100644 --- a/app/src/main/java/org/stepik/android/view/video_player/ui/activity/VideoPlayerActivity.kt +++ b/app/src/main/java/org/stepik/android/view/video_player/ui/activity/VideoPlayerActivity.kt @@ -9,8 +9,8 @@ import android.content.ServiceConnection import android.content.pm.ActivityInfo import android.os.Bundle import android.os.IBinder +import android.support.annotation.DrawableRes import android.support.v7.app.AppCompatActivity -import android.support.v7.content.res.AppCompatResources import android.support.v7.widget.PopupMenu import android.view.Gravity import android.view.View @@ -23,8 +23,6 @@ import com.google.android.exoplayer2.upstream.HttpDataSource import com.google.android.exoplayer2.util.Util import kotlinx.android.synthetic.main.activity_video_player.* import kotlinx.android.synthetic.main.exo_playback_control_view.* -import kotlinx.android.synthetic.main.exo_playback_control_view.view.* -import kotlinx.android.synthetic.main.exo_simple_player_view.view.* import org.stepic.droid.R import org.stepic.droid.analytic.AmplitudeAnalytic import org.stepic.droid.analytic.Analytic @@ -139,7 +137,7 @@ class VideoPlayerActivity : AppCompatActivity(), VideoPlayerView, VideoQualityDi playerView.setFastForwardIncrementMs(JUMP_TIME_MILLIS) playerView.setRewindIncrementMs(JUMP_TIME_MILLIS) - playerView.exo_controller.exo_fullscreen_icon.setOnClickListener { changeVideoRotation() } + exo_fullscreen_icon.setOnClickListener { changeVideoRotation() } playerView.setControllerVisibilityListener { visibility -> if (visibility == View.VISIBLE) { @@ -238,11 +236,16 @@ class VideoPlayerActivity : AppCompatActivity(), VideoPlayerView, VideoQualityDi override fun setIsLandscapeVideo(isLandScapeVideo: Boolean) { this.isLandscapeVideo = isLandScapeVideo - if (isLandscapeVideo) { - playerView.exo_controller.exo_fullscreen_icon.setImageDrawable(AppCompatResources.getDrawable(this, R.drawable.ic_fullscreen_exit)) - } else { - playerView.exo_controller.exo_fullscreen_icon.setImageDrawable(AppCompatResources.getDrawable(this, R.drawable.ic_fullscreen)) - } + + @DrawableRes + val fullScreenIconRes = + if (isLandScapeVideo) { + R.drawable.ic_fullscreen_exit + } else { + R.drawable.ic_fullscreen + } + + exo_fullscreen_icon.setImageResource(fullScreenIconRes) } override fun showPlayInBackgroundPopup() { From a61adb689f0079949469ca6b8f4f816a33fae8ae Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Thu, 5 Sep 2019 21:19:54 +0300 Subject: [PATCH 31/51] replace icons with vector resources --- app/src/main/res/drawable-hdpi/ic_fullscreen.png | Bin 262 -> 0 bytes .../main/res/drawable-hdpi/ic_fullscreen_exit.png | Bin 228 -> 0 bytes app/src/main/res/drawable-mdpi/ic_fullscreen.png | Bin 195 -> 0 bytes .../main/res/drawable-mdpi/ic_fullscreen_exit.png | Bin 201 -> 0 bytes app/src/main/res/drawable-xhdpi/ic_fullscreen.png | Bin 224 -> 0 bytes .../res/drawable-xhdpi/ic_fullscreen_exit.png | Bin 222 -> 0 bytes .../main/res/drawable-xxhdpi/ic_fullscreen.png | Bin 420 -> 0 bytes .../res/drawable-xxhdpi/ic_fullscreen_exit.png | Bin 413 -> 0 bytes .../main/res/drawable-xxxhdpi/ic_fullscreen.png | Bin 282 -> 0 bytes .../res/drawable-xxxhdpi/ic_fullscreen_exit.png | Bin 289 -> 0 bytes app/src/main/res/drawable/ic_fullscreen.xml | 11 +++++++++++ app/src/main/res/drawable/ic_fullscreen_exit.xml | 11 +++++++++++ 12 files changed, 22 insertions(+) delete mode 100644 app/src/main/res/drawable-hdpi/ic_fullscreen.png delete mode 100644 app/src/main/res/drawable-hdpi/ic_fullscreen_exit.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_fullscreen.png delete mode 100644 app/src/main/res/drawable-mdpi/ic_fullscreen_exit.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_fullscreen.png delete mode 100644 app/src/main/res/drawable-xhdpi/ic_fullscreen_exit.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_fullscreen.png delete mode 100644 app/src/main/res/drawable-xxhdpi/ic_fullscreen_exit.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_fullscreen.png delete mode 100644 app/src/main/res/drawable-xxxhdpi/ic_fullscreen_exit.png create mode 100644 app/src/main/res/drawable/ic_fullscreen.xml create mode 100644 app/src/main/res/drawable/ic_fullscreen_exit.xml diff --git a/app/src/main/res/drawable-hdpi/ic_fullscreen.png b/app/src/main/res/drawable-hdpi/ic_fullscreen.png deleted file mode 100644 index f2d9f70e2f4e48b5b49b0e7b66a86b87eb33d7e2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 262 zcmV+h0r~!kP) M07*qoM6N<$f{N{Kod5s; diff --git a/app/src/main/res/drawable-hdpi/ic_fullscreen_exit.png b/app/src/main/res/drawable-hdpi/ic_fullscreen_exit.png deleted file mode 100644 index 243a9b1611b32be5bab42399e48fe74b19cb06a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 228 zcmeAS@N?(olHy`uVBq!ia0vp^5+KaM1|%Pp+x`Gjt36#DLp(a)PP67ZY#`vmYW5>Z zGbExlc*m*OORGX&3ok90sJvGsas$Wipa8*+4+ly%|8`hCzqqS`yFmQ>frKYD(>_PJ zi3(V5VVpeCJ5q0MgINQQN!^c&3^%6Q-8;#r@iMw$*$?3ZI=(vh8!j@enR@FeBeQ|% z8Z+?&5i3LaU#z@$UcR_4jR| cO>?X+h(C5*%j6R^0pte;Pgg&ebxsLQ0NYMoiU0rr diff --git a/app/src/main/res/drawable-mdpi/ic_fullscreen.png b/app/src/main/res/drawable-mdpi/ic_fullscreen.png deleted file mode 100644 index 4ab1665c4759197e2e4ddd6a10b65c33f4bed531..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 195 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`U7jwEAr`%NCmV7#7znU@c5~FJ zX^B{RQO#`M(L+w$+^21Fa{M@+YjTM_I^>v;->z-Ox1!O}x4_FG`Awxd|Jn?Ou;hF% zM(zixUd#b1|8f}j@Xh615y#4+5S1R!P;~N3x$*vKCONEK>@$6g?wVI^U`{jCQn0tI s{_f5_;nl_TPY0GfyI`=u_}eYsWaeJx=T`qt0$s)6>FVdQ&MBb@0KhRrlK=n! diff --git a/app/src/main/res/drawable-mdpi/ic_fullscreen_exit.png b/app/src/main/res/drawable-mdpi/ic_fullscreen_exit.png deleted file mode 100644 index 73499bf8b3e245fc10bf5a6715aee6f0bdd4bc21..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 201 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`6FglULo9lqPFCb=ao};S-r{?L zBd_s^!0H1HPHSBf!W1?tTi$Taan0Pt;@I>+J^t_X`R9Dxk8o5l8eixT{%}p_=NTta z`?ZeKOjobhy|7XHYsI1jqZ-93z4eQkR=YN^Ma;E#JSb3b_x|sSNhOCjeHJLFJ+O7U zO)^u~*OEmKvVUB1HvhxQE_y&HSK>m}HtA~SQ@?smU!LT=4|E%Yr>mdKI;Vst0Kx}P AZ2$lO diff --git a/app/src/main/res/drawable-xhdpi/ic_fullscreen.png b/app/src/main/res/drawable-xhdpi/ic_fullscreen.png deleted file mode 100644 index 844f401e21107187cd19ce216b7e974653849ab2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 224 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJ<(@8%ArY-_rz`Tc7>Kx3Pc~g~ zHCsT#?;x)QuZBvWvfj3QR#D!@Z_{~~wAi0i5q {gw~!2PUb7-ok<(JZFSUY@d)N z#K6P(Ig0fL(}n|k9tSd9U_Telc|eBSQtQEL2CfOJ4xB#o7Kgv(Zz!A^I)CcYpp|(l z)A-CQ-ua(-6&4vP=D(3i!=a4fTJD`qOQw}KeqIzMcgeWUZ921vgLcW5!;GPa_I&3z YTDIV%tPSTGppzLqUHx3vIVCg!0Djj`@Bjb+ diff --git a/app/src/main/res/drawable-xhdpi/ic_fullscreen_exit.png b/app/src/main/res/drawable-xhdpi/ic_fullscreen_exit.png deleted file mode 100644 index 114fe0dce57bfcf3ba9b6d40e031ef17c33b1f11..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 222 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=ffJrJgR1ArY-_r)}hIF%V#hy`s+I zvL)fAYn#kR){Bg+PRwW6|1s$Nd{-f;P^g{zEY`Q^TAKn#hr|A2<-Pw?<6PCUBv?mFnXQ}`Spa2S>0Nnv3?xws?z@`TPv3tSAe1{BR2rM0G-Z6q5wgZ5v%Tml20Z;eN zr&6g@DwRrgS7E!vA-2(!_X3#pAm136m*fk9QFff(W4mN|AAxlb03zV4Bws>Bcluxb z&?tZcD1ZVeK~Nvj&M0fYOa;Nl*iEWx{WpXIj+=Y1*ib4uMK)rZV|Uo9^~EEm zy6WwaPXQFb17PPaNPGYy0YHd75=-muamVQa5CD?~_U;k`qlR?@;NcHMlM_1SKb{-_ O00004%P)L3akWqA&^w$?SNSy08`+^Z+!wALEbx% zSLB_6g#svm0w{n23lV>)(Z-5+FI`k6&zK1!wxAy5a`3zhK0Jz%gxB5wd zpa94!f?U-#fU8cxQ~?yABY@O4B5?++1ppCnyrb@+02l!)U?cPzcoP6jfcTEOG4R~B zu1cj+sZ=V}zY=Ck9Ad^>i6dYlsQYT~mDUY`aWPIOnAu$7BM=J!B0CaG>!#>8u>vT- zH^2_FxN36FaEq;rLqB`$OYCFThKn0s))ed--~xO&^fL#Z+7$eo%UuOf00mG01sDn- zz>MAHUp)t8<8+7_iOYF=VBQCSPyNrp)>~p=T$2~j;)MMIm8upyTdi{R00000NkvXX Hu0mjf3Q()7 diff --git a/app/src/main/res/drawable-xxxhdpi/ic_fullscreen.png b/app/src/main/res/drawable-xxxhdpi/ic_fullscreen.png deleted file mode 100644 index cf21fe256ee88f35e6898f8452e25d61814db4f3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 282 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=4?SHRLn`LHy|t0A$$-K2;=lj< zB_HKE%Wyno=HPy2dEh`oSFW5wMgFC;H@@lITBaDlF)447)aQ<4Uv14I;WVbWXa#XI8!RCBxKP z!L?tcIy)fX#RikThhGanF1hah*)%@Ozwqb7{rg2&QMB8cor|AgoWri+%Rc+g&$aza zy?0$H{y7Pv#)8{n>7V;I)c)DS>_F~>yrOufaE=0{an^LB{Ts5YA9)U diff --git a/app/src/main/res/drawable-xxxhdpi/ic_fullscreen_exit.png b/app/src/main/res/drawable-xxxhdpi/ic_fullscreen_exit.png deleted file mode 100644 index cf7e8b09a306b2d236527ea4878454a4849378af..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 289 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0I1|(Ny7TyC=FFaiwLn`LHy|t06*+9fC@&13t zS9+}T4{Tq##d|`~lF1hTWH(u;s@&^X`TW4#_fKz6G2wlx`cmyAYnsWOuN`k*ttne7 zb5;9J){gAXH&P%DE6`9l*vfpO{>GQi&sKsBr+4hXt5-0Q)l!yo!ethyin@aunWppB zD;|h>uy6U*S{En?iT(8cgV^JlyzhUD?8v{Px8sk0AOn{USknr&1(Quw{CM7aG?X9v z`+cwb-}A~V&n$*p31mE2#ISaWra{{K4^QqJww1m8y + + + + diff --git a/app/src/main/res/drawable/ic_fullscreen_exit.xml b/app/src/main/res/drawable/ic_fullscreen_exit.xml new file mode 100644 index 0000000000..8dc641eb9d --- /dev/null +++ b/app/src/main/res/drawable/ic_fullscreen_exit.xml @@ -0,0 +1,11 @@ + + + + + From 593e9c99aa5bf02640524dd1d3fda6491abc462b Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Thu, 5 Sep 2019 21:42:29 +0300 Subject: [PATCH 32/51] add ripple to landscape button --- .../ui/activity/VideoPlayerActivity.kt | 2 +- .../res/layout/exo_playback_control_view.xml | 26 ++++++++++++------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/video_player/ui/activity/VideoPlayerActivity.kt b/app/src/main/java/org/stepik/android/view/video_player/ui/activity/VideoPlayerActivity.kt index b8e88d388d..978f1e5399 100644 --- a/app/src/main/java/org/stepik/android/view/video_player/ui/activity/VideoPlayerActivity.kt +++ b/app/src/main/java/org/stepik/android/view/video_player/ui/activity/VideoPlayerActivity.kt @@ -137,7 +137,7 @@ class VideoPlayerActivity : AppCompatActivity(), VideoPlayerView, VideoQualityDi playerView.setFastForwardIncrementMs(JUMP_TIME_MILLIS) playerView.setRewindIncrementMs(JUMP_TIME_MILLIS) - exo_fullscreen_icon.setOnClickListener { changeVideoRotation() } + exo_fullscreen_icon_container.setOnClickListener { changeVideoRotation() } playerView.setControllerVisibilityListener { visibility -> if (visibility == View.VISIBLE) { diff --git a/app/src/main/res/layout/exo_playback_control_view.xml b/app/src/main/res/layout/exo_playback_control_view.xml index 6eb9d8f090..04b39aa8b8 100644 --- a/app/src/main/res/layout/exo_playback_control_view.xml +++ b/app/src/main/res/layout/exo_playback_control_view.xml @@ -179,24 +179,30 @@ android:layout_height="wrap_content" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintTop_toTopOf="parent" - app:layout_constraintRight_toLeftOf="@id/exo_fullscreen_icon" + app:layout_constraintRight_toLeftOf="@id/exo_fullscreen_icon_container" android:layout_marginRight="@dimen/seekbar_video_margin" android:layout_marginEnd="@dimen/seekbar_video_margin" tools:text="03:35"/> - - + android:background="?selectableItemBackgroundBorderless"> + + + From 033a0672bfa2e0246ed966048d1c260bef65f284 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Thu, 5 Sep 2019 22:15:29 +0300 Subject: [PATCH 33/51] fetch new reviews upon opening screen --- .../course_reviews/CourseReviewsPresenter.kt | 11 +++-------- .../ui/fragment/CourseReviewsFragment.kt | 11 +++++++++-- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/app/src/main/java/org/stepik/android/presentation/course_reviews/CourseReviewsPresenter.kt b/app/src/main/java/org/stepik/android/presentation/course_reviews/CourseReviewsPresenter.kt index ffc4a91672..d6eb8f3cdc 100644 --- a/app/src/main/java/org/stepik/android/presentation/course_reviews/CourseReviewsPresenter.kt +++ b/app/src/main/java/org/stepik/android/presentation/course_reviews/CourseReviewsPresenter.kt @@ -83,12 +83,7 @@ constructor( .subscribeOn(backgroundScheduler) .observeOn(mainScheduler) .subscribeBy( - onSuccess = { - state = it - if (state is CourseReviewsView.State.CourseReviewsCache) { - fetchNextPageFromRemote(backgroundLoading = true) - } - }, + onSuccess = { state = it }, onError = { state = CourseReviewsView.State.NetworkError } ) } @@ -119,7 +114,7 @@ constructor( /** * Pagination handling */ - fun fetchNextPageFromRemote(backgroundLoading: Boolean = false) { + fun fetchNextPageFromRemote() { val oldState = state val oldItems = (oldState as? CourseReviewsView.State.CourseReviewsRemote)?.courseReviewItems @@ -151,7 +146,7 @@ constructor( .subscribeBy( onSuccess = { state = CourseReviewsView.State.CourseReviewsRemote(currentItems.concatWithPagedList(it)) - if (oldState is CourseReviewsView.State.CourseReviewsCache && !backgroundLoading) { + if (oldState is CourseReviewsView.State.CourseReviewsCache) { fetchNextPageFromRemote() // load 2 page from remote after going online } }, diff --git a/app/src/main/java/org/stepik/android/view/course_reviews/ui/fragment/CourseReviewsFragment.kt b/app/src/main/java/org/stepik/android/view/course_reviews/ui/fragment/CourseReviewsFragment.kt index 4d3ed85a4d..4e0bf7ee2a 100644 --- a/app/src/main/java/org/stepik/android/view/course_reviews/ui/fragment/CourseReviewsFragment.kt +++ b/app/src/main/java/org/stepik/android/view/course_reviews/ui/fragment/CourseReviewsFragment.kt @@ -14,8 +14,8 @@ import android.support.v7.widget.RecyclerView import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import kotlinx.android.synthetic.main.empty_default.report_empty -import kotlinx.android.synthetic.main.empty_default.view.placeholderMessage +import kotlinx.android.synthetic.main.empty_default.* +import kotlinx.android.synthetic.main.empty_default.view.* import kotlinx.android.synthetic.main.error_no_connection.* import kotlinx.android.synthetic.main.fragment_course_reviews.* import org.stepic.droid.R @@ -136,6 +136,7 @@ class CourseReviewsFragment : Fragment(), CourseReviewsView { super.setUserVisibleHint(isVisibleToUser) this.isVisibleToUser = isVisibleToUser reportIsVisibleToUser() + fetchNewReviews() } private fun reportIsVisibleToUser() { @@ -148,6 +149,12 @@ class CourseReviewsFragment : Fragment(), CourseReviewsView { } } + private fun fetchNewReviews() { + if (isVisibleToUser && this::courseReviewsPresenter.isInitialized) { + courseReviewsPresenter.fetchNextPageFromRemote() + } + } + override fun onStart() { super.onStart() courseReviewsPresenter.attachView(this) From 6d47c1d3b6d337019fd14a880be8f45809629bfd Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Fri, 6 Sep 2019 12:29:45 +0300 Subject: [PATCH 34/51] code review fixes --- .../ui/delegate/CodeStepQuizFormDelegate.kt | 9 ++- .../ui/delegate/CoreCodeStepDelegate.kt | 30 +------- .../ui/fragment/CodeStepQuizFragment.kt | 5 +- .../CodeStepQuizFullScreenDialogFragment.kt | 75 ++++++++++++------- .../activity_step_quiz_code_fullscreen.xml | 33 +------- 5 files changed, 64 insertions(+), 88 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt index f897165943..ed6a9b8f3d 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt @@ -12,6 +12,7 @@ import org.stepik.android.presentation.step_quiz.StepQuizView import org.stepik.android.presentation.step_quiz.model.ReplyResult import org.stepik.android.view.step_quiz.resolver.StepQuizFormResolver import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFormDelegate +import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizFormStateMapper import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState import org.stepik.android.view.step_quiz_code.ui.adapter.delegate.CodeLangAdapterDelegate import org.stepik.android.view.ui.delegate.ViewStateDelegate @@ -21,7 +22,7 @@ class CodeStepQuizFormDelegate( containerView: View, private val coreCodeStepDelegate: CoreCodeStepDelegate ) : StepQuizFormDelegate { - var state: CodeStepQuizFormState = CodeStepQuizFormState.Idle + private var state: CodeStepQuizFormState = CodeStepQuizFormState.Idle set(value) { field = value @@ -34,7 +35,7 @@ class CodeStepQuizFormDelegate( coreCodeStepDelegate.setDetailsContentData((value as? CodeStepQuizFormState.Lang)?.lang) } - val viewStateDelegate = ViewStateDelegate() + private val viewStateDelegate = ViewStateDelegate() private val codeLayout = containerView.codeStepLayout private val stepQuizActions = containerView.stepQuizActions @@ -43,6 +44,8 @@ class CodeStepQuizFormDelegate( private val stepQuizCodeLangChooser = containerView.stepQuizCodeLangChooser private val stepQuizCodeLangChooserAdapter = DefaultDelegateAdapter() + private val codeStepQuizFormStateMapper = CodeStepQuizFormStateMapper() + init { viewStateDelegate.addState() viewStateDelegate.addState(stepQuizCodeLangChooserTitle, stepQuizCodeLangChooser) @@ -79,7 +82,7 @@ class CodeStepQuizFormDelegate( } override fun setState(state: StepQuizView.State.AttemptLoaded) { - this.state = coreCodeStepDelegate.codeStepQuizFormStateMapper.mapToFormState(coreCodeStepDelegate.codeOptions, state) + this.state = codeStepQuizFormStateMapper.mapToFormState(coreCodeStepDelegate.codeOptions, state) val isEnabled = StepQuizFormResolver.isQuizEnabled(state) coreCodeStepDelegate.setEnabled(isEnabled) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt index adc408658e..2bf0250237 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt @@ -5,9 +5,7 @@ import android.support.v7.widget.RecyclerView import android.view.View import android.view.ViewGroup import android.widget.RelativeLayout -import kotlinx.android.synthetic.main.activity_step_quiz_code_fullscreen.view.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.view.* -import kotlinx.android.synthetic.main.view_step_quiz_submit_button.view.* import org.stepic.droid.R import org.stepic.droid.code.util.CodeToolbarUtil import org.stepic.droid.model.code.extensionForLanguage @@ -16,7 +14,6 @@ import org.stepic.droid.ui.adapters.CodeToolbarAdapter import org.stepic.droid.ui.util.inflate import org.stepic.droid.ui.util.setCompoundDrawables import org.stepic.droid.ui.util.setOnKeyboardOpenListener -import org.stepik.android.view.step_quiz_code.mapper.CodeStepQuizFormStateMapper import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState class CoreCodeStepDelegate( @@ -28,17 +25,9 @@ class CoreCodeStepDelegate( ) { // Flag is necessary, because keyboard listener is constantly invoked (probably global layout listener reacts to view changes) private var keyboardShown: Boolean = false - private val submitButtonSeparator = keyboardExtensionContainer?.submitButtonSeparator - private val codeSubmitButton = codeContainerView.codeSubmitButton - private val retryButton = codeSubmitButton?.stepQuizRetry - private val fullScreenCodeToolbar = keyboardExtensionContainer?.fullScreenCodeToolbar - private val fullScreenCodeTabs = keyboardExtensionContainer?.fullScreenCodeTabs - private val fullScreenCodeSeparator = keyboardExtensionContainer?.fullScreenCodeSeparator private val codeLayout = codeContainerView.codeStepLayout private val stepQuizActionChangeLang = codeContainerView.stepQuizActionChangeLang - val codeStepQuizFormStateMapper = CodeStepQuizFormStateMapper() - val codeOptions = stepWrapper.step.block?.options ?: throw IllegalArgumentException("Code options shouldn't be null") private val codeToolbarAdapter = CodeToolbarAdapter(codeContainerView.context) @@ -61,8 +50,6 @@ class CoreCodeStepDelegate( */ stepQuizActionChangeLang.setOnClickListener { actionsListener.onChangeLanguageClicked() } stepQuizActionChangeLang.setCompoundDrawables(end = R.drawable.ic_arrow_bottom) - codeSubmitButton?.setOnClickListener { actionsListener.onSubmitClicked() } - retryButton?.visibility = View.GONE /** * Keyboard extension @@ -94,7 +81,7 @@ class CoreCodeStepDelegate( } codeLayout.setPadding(0, 0, 0, container.context.resources.getDimensionPixelSize( R.dimen.step_quiz_fullscreen_code_layout_bottom_padding)) - setViewsVisibility(View.VISIBLE) + actionsListener.keyboardShown(true) keyboardShown = false } }, @@ -108,7 +95,7 @@ class CoreCodeStepDelegate( bottomMargin = stepQuizCodeKeyboardExtension.height } codeLayout.setPadding(0, 0, 0, 0) - setViewsVisibility(View.GONE) + actionsListener.keyboardShown(false) keyboardShown = true } } @@ -142,20 +129,9 @@ class CoreCodeStepDelegate( stepQuizActionChangeLang.isEnabled = isEnabled } - /** - * Hiding views upon opening keyboard - */ - private fun setViewsVisibility(visibility: Int) { - submitButtonSeparator?.visibility = visibility - codeSubmitButton?.visibility = visibility - fullScreenCodeToolbar?.visibility = visibility - fullScreenCodeTabs?.visibility = visibility - fullScreenCodeSeparator?.visibility = visibility - } - interface ActionsListener { fun onChangeLanguageClicked() fun onFullscreenClicked(lang: String, code: String) - fun onSubmitClicked() + fun keyboardShown(needShow: Boolean) } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt index 9d9bd21e28..8f28d87f20 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt @@ -113,10 +113,9 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog. dialog.setTargetFragment(this@CodeStepQuizFragment, CodeStepQuizFullScreenDialogFragment.CODE_PLAYGROUND_REQUEST) dialog.show(supportFragmentManager, CodeStepQuizFullScreenDialogFragment.TAG) } - - override fun onSubmitClicked() {} + override fun keyboardShown(needShow: Boolean) {} } - + codeStepQuizFormDelegate = CodeStepQuizFormDelegate( containerView = view, coreCodeStepDelegate = CoreCodeStepDelegate( diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt index 9e7f0c425f..0961a54d59 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt @@ -4,19 +4,20 @@ import android.app.Dialog import android.os.Bundle import android.support.design.widget.TabLayout import android.support.v4.app.DialogFragment -import android.support.v4.content.ContextCompat.getSystemService +import android.support.v4.content.ContextCompat import android.support.v4.view.ViewPager import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.Window import android.view.WindowManager -import android.view.inputmethod.InputMethodManager import android.widget.TextView import kotlinx.android.synthetic.main.activity_step_quiz_code_fullscreen.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_instruction.view.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.view.* +import kotlinx.android.synthetic.main.view_centered_toolbar.* +import kotlinx.android.synthetic.main.view_step_quiz_submit_button.view.* import org.stepic.droid.R import org.stepic.droid.base.App import org.stepic.droid.fonts.FontType @@ -25,6 +26,8 @@ import org.stepic.droid.persistence.model.StepPersistentWrapper import org.stepic.droid.ui.dialogs.ChangeCodeLanguageDialog import org.stepic.droid.ui.dialogs.ProgrammingLanguageChooserDialogFragment import org.stepic.droid.ui.dialogs.ResetCodeDialogFragment +import org.stepic.droid.ui.util.changeVisibility +import org.stepic.droid.ui.util.hideKeyboard import org.stepic.droid.util.argument import org.stepik.android.domain.lesson.model.LessonData import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState @@ -52,22 +55,20 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag } } - interface Callback { - fun onSyncCodeStateWithParent(lang: String, code: String, onSubmitClicked: Boolean = false) - } - - private lateinit var callback: Callback - - private var inputMethodManager: InputMethodManager? = null - @Inject internal lateinit var fontsProvider: FontsProvider + private lateinit var callback: Callback + private lateinit var coreCodeStepDelegate: CoreCodeStepDelegate private lateinit var instructionsLayout: View private lateinit var playgroundLayout: View + private lateinit var submitButtonSeparator: View + private lateinit var codeSubmitButton: View + private lateinit var retryButton: View + private var lang: String by argument() private var code: String by argument() private var lessonData: LessonData by argument() @@ -96,23 +97,20 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag .inject(this) } - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { - dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) - return inflater.inflate(R.layout.activity_step_quiz_code_fullscreen, container, false) - } + override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = + inflater.inflate(R.layout.activity_step_quiz_code_fullscreen, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) callback = targetFragment as Callback - inputMethodManager = getSystemService(App.getAppContext(), InputMethodManager::class.java) - - fullScreenCodeToolbarTitle.text = lessonData.lesson.title - fullScreenCodeToolbar.inflateMenu(R.menu.code_playground_menu) - fullScreenCodeToolbar.setNavigationOnClickListener { dismiss() } - fullScreenCodeToolbar.setNavigationIcon(R.drawable.ic_close_dark) - fullScreenCodeToolbar.setOnMenuItemClickListener { item -> + centeredToolbarTitle.text = lessonData.lesson.title + centeredToolbar.inflateMenu(R.menu.code_playground_menu) + centeredToolbar.setNavigationOnClickListener { dismiss() } + centeredToolbar.setNavigationIcon(R.drawable.ic_close_dark) + centeredToolbar.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.new_primary_color)) + centeredToolbar.setOnMenuItemClickListener { item -> when (item?.itemId) { android.R.id.home -> { true @@ -143,9 +141,8 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag } val actionsListener = object : CoreCodeStepDelegate.ActionsListener { - override fun onSubmitClicked() { - callback.onSyncCodeStateWithParent(lang, codeStepLayout.text.toString(), true) - dismiss() + override fun keyboardShown(needShow: Boolean) { + setViewsVisibility(needShow) } override fun onChangeLanguageClicked() { @@ -157,6 +154,7 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag override fun onFullscreenClicked(lang: String, code: String) {} } + coreCodeStepDelegate = CoreCodeStepDelegate( codeContainerView = playgroundLayout, keyboardExtensionContainer = coordinator, @@ -169,9 +167,20 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag lang = savedInstanceState.getString(LANG) ?: return code = savedInstanceState.getString(CODE) ?: return } + coreCodeStepDelegate.setLanguage(CodeStepQuizFormState.Lang(lang, code)) coreCodeStepDelegate.setDetailsContentData(lang) fullScreenCodeViewPager.setCurrentItem(1, false) + + submitButtonSeparator = playgroundLayout.submitButtonSeparator + codeSubmitButton = playgroundLayout.codeSubmitButton + retryButton = playgroundLayout.stepQuizRetry + + codeSubmitButton.setOnClickListener { + callback.onSyncCodeStateWithParent(lang, codeStepLayout.text.toString(), true) + dismiss() + } + retryButton.changeVisibility(false) } override fun onSaveInstanceState(outState: Bundle) { @@ -196,7 +205,7 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag override fun onPageScrolled(p0: Int, p1: Float, p2: Int) {} override fun onPageSelected(p0: Int) { if (p0 == 0) { - inputMethodManager?.hideSoftInputFromWindow(playgroundLayout.windowToken, 0) + playgroundLayout.hideKeyboard() } } }) @@ -234,6 +243,7 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT) window.setWindowAnimations(R.style.AppTheme_FullScreenDialog) } + dialog?.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) } override fun onPause() { @@ -262,4 +272,19 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag playgroundLayout.codeStepLayout.setText(codeTemplate) } } + + /** + * Hiding views upon opening keyboard + */ + private fun setViewsVisibility(needShow: Boolean) { + submitButtonSeparator.changeVisibility(needShow) + codeSubmitButton.changeVisibility(needShow) + centeredToolbar.changeVisibility(needShow) + fullScreenCodeTabs.changeVisibility(needShow) + fullScreenCodeSeparator.changeVisibility(needShow) + } + + interface Callback { + fun onSyncCodeStateWithParent(lang: String, code: String, onSubmitClicked: Boolean = false) + } } \ No newline at end of file diff --git a/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml b/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml index e47abb45a6..00fb601a57 100644 --- a/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml +++ b/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml @@ -6,35 +6,8 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - - - + Date: Fri, 6 Sep 2019 17:36:15 +0300 Subject: [PATCH 35/51] remove redundant code from core code step delegate --- .../ui/delegate/CoreCodeStepDelegate.kt | 68 ++---------------- .../ui/fragment/CodeStepQuizFragment.kt | 2 - .../CodeStepQuizFullScreenDialogFragment.kt | 70 +++++++++++++++++-- 3 files changed, 69 insertions(+), 71 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt index 2bf0250237..ba6557a189 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt @@ -1,36 +1,26 @@ package org.stepik.android.view.step_quiz_code.ui.delegate -import android.support.v7.widget.LinearLayoutManager -import android.support.v7.widget.RecyclerView import android.view.View -import android.view.ViewGroup -import android.widget.RelativeLayout import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.view.* import org.stepic.droid.R import org.stepic.droid.code.util.CodeToolbarUtil import org.stepic.droid.model.code.extensionForLanguage import org.stepic.droid.persistence.model.StepPersistentWrapper import org.stepic.droid.ui.adapters.CodeToolbarAdapter -import org.stepic.droid.ui.util.inflate import org.stepic.droid.ui.util.setCompoundDrawables -import org.stepic.droid.ui.util.setOnKeyboardOpenListener import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState class CoreCodeStepDelegate( codeContainerView: View, - keyboardExtensionContainer: ViewGroup?, private val stepWrapper: StepPersistentWrapper, private val codeQuizInstructionDelegate: CodeQuizInstructionDelegate, private val actionsListener: ActionsListener ) { - // Flag is necessary, because keyboard listener is constantly invoked (probably global layout listener reacts to view changes) - private var keyboardShown: Boolean = false + private val codeLayout = codeContainerView.codeStepLayout private val stepQuizActionChangeLang = codeContainerView.stepQuizActionChangeLang - val codeOptions = stepWrapper.step.block?.options ?: throw IllegalArgumentException("Code options shouldn't be null") - - private val codeToolbarAdapter = CodeToolbarAdapter(codeContainerView.context) + val codeToolbarAdapter = CodeToolbarAdapter(codeContainerView.context) .apply { onSymbolClickListener = object : CodeToolbarAdapter.OnSymbolClickListener { override fun onSymbolClick(symbol: String, offset: Int) { @@ -39,6 +29,8 @@ class CoreCodeStepDelegate( } } + val codeOptions = stepWrapper.step.block?.options ?: throw IllegalArgumentException("Code options shouldn't be null") + init { /** * Initialize code details @@ -50,57 +42,6 @@ class CoreCodeStepDelegate( */ stepQuizActionChangeLang.setOnClickListener { actionsListener.onChangeLanguageClicked() } stepQuizActionChangeLang.setCompoundDrawables(end = R.drawable.ic_arrow_bottom) - - /** - * Keyboard extension - */ - keyboardExtensionContainer?.let { container -> - val stepQuizCodeKeyboardExtension = - container.inflate(R.layout.layout_step_quiz_code_keyboard_extension) as RecyclerView - stepQuizCodeKeyboardExtension.adapter = codeToolbarAdapter - stepQuizCodeKeyboardExtension.layoutManager = LinearLayoutManager(container.context, LinearLayoutManager.HORIZONTAL, false) - codeLayout.codeToolbarAdapter = codeToolbarAdapter - - container.addView(stepQuizCodeKeyboardExtension) - stepQuizCodeKeyboardExtension.visibility = View.INVISIBLE // Apparently this fixes the offset bug when the current line is under the code toolbar adapter - stepQuizCodeKeyboardExtension.layoutParams = (stepQuizCodeKeyboardExtension.layoutParams as RelativeLayout.LayoutParams) - .apply { - addRule(RelativeLayout.ALIGN_PARENT_BOTTOM) - } - - setOnKeyboardOpenListener( - container, - onKeyboardHidden = { - if (keyboardShown) { - stepQuizCodeKeyboardExtension.visibility = View.GONE - codeLayout.isNestedScrollingEnabled = true - codeLayout.layoutParams = - (codeLayout.layoutParams as RelativeLayout.LayoutParams) - .apply { - bottomMargin = 0 - } - codeLayout.setPadding(0, 0, 0, container.context.resources.getDimensionPixelSize( - R.dimen.step_quiz_fullscreen_code_layout_bottom_padding)) - actionsListener.keyboardShown(true) - keyboardShown = false - } - }, - onKeyboardShown = { - if (!keyboardShown) { - stepQuizCodeKeyboardExtension.visibility = View.VISIBLE - codeLayout.isNestedScrollingEnabled = false - codeLayout.layoutParams = - (codeLayout.layoutParams as RelativeLayout.LayoutParams) - .apply { - bottomMargin = stepQuizCodeKeyboardExtension.height - } - codeLayout.setPadding(0, 0, 0, 0) - actionsListener.keyboardShown(false) - keyboardShown = true - } - } - ) - } } fun setLanguage(codeStepQuizFormState: CodeStepQuizFormState.Lang) { @@ -132,6 +73,5 @@ class CoreCodeStepDelegate( interface ActionsListener { fun onChangeLanguageClicked() fun onFullscreenClicked(lang: String, code: String) - fun keyboardShown(needShow: Boolean) } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt index 8f28d87f20..14a704a364 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt @@ -113,14 +113,12 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog. dialog.setTargetFragment(this@CodeStepQuizFragment, CodeStepQuizFullScreenDialogFragment.CODE_PLAYGROUND_REQUEST) dialog.show(supportFragmentManager, CodeStepQuizFullScreenDialogFragment.TAG) } - override fun keyboardShown(needShow: Boolean) {} } codeStepQuizFormDelegate = CodeStepQuizFormDelegate( containerView = view, coreCodeStepDelegate = CoreCodeStepDelegate( codeContainerView = view, - keyboardExtensionContainer = null, stepWrapper = stepWrapper, codeQuizInstructionDelegate = CodeQuizInstructionDelegate(view, true), actionsListener = actionsListener diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt index 0961a54d59..94064440da 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt @@ -6,11 +6,14 @@ import android.support.design.widget.TabLayout import android.support.v4.app.DialogFragment import android.support.v4.content.ContextCompat import android.support.v4.view.ViewPager +import android.support.v7.widget.LinearLayoutManager +import android.support.v7.widget.RecyclerView import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.view.Window import android.view.WindowManager +import android.widget.RelativeLayout import android.widget.TextView import kotlinx.android.synthetic.main.activity_step_quiz_code_fullscreen.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_instruction.view.* @@ -20,6 +23,7 @@ import kotlinx.android.synthetic.main.view_centered_toolbar.* import kotlinx.android.synthetic.main.view_step_quiz_submit_button.view.* import org.stepic.droid.R import org.stepic.droid.base.App +import org.stepic.droid.code.ui.CodeEditorLayout import org.stepic.droid.fonts.FontType import org.stepic.droid.fonts.FontsProvider import org.stepic.droid.persistence.model.StepPersistentWrapper @@ -28,6 +32,8 @@ import org.stepic.droid.ui.dialogs.ProgrammingLanguageChooserDialogFragment import org.stepic.droid.ui.dialogs.ResetCodeDialogFragment import org.stepic.droid.ui.util.changeVisibility import org.stepic.droid.ui.util.hideKeyboard +import org.stepic.droid.ui.util.inflate +import org.stepic.droid.ui.util.setOnKeyboardOpenListener import org.stepic.droid.util.argument import org.stepik.android.domain.lesson.model.LessonData import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState @@ -65,10 +71,14 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag private lateinit var instructionsLayout: View private lateinit var playgroundLayout: View + private lateinit var codeLayout: CodeEditorLayout private lateinit var submitButtonSeparator: View private lateinit var codeSubmitButton: View private lateinit var retryButton: View + // Flag is necessary, because keyboard listener is constantly invoked (probably global layout listener reacts to view changes) + private var keyboardShown: Boolean = false + private var lang: String by argument() private var code: String by argument() private var lessonData: LessonData by argument() @@ -141,10 +151,6 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag } val actionsListener = object : CoreCodeStepDelegate.ActionsListener { - override fun keyboardShown(needShow: Boolean) { - setViewsVisibility(needShow) - } - override fun onChangeLanguageClicked() { val dialog = ChangeCodeLanguageDialog.newInstance() if (!dialog.isAdded) { @@ -157,7 +163,6 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag coreCodeStepDelegate = CoreCodeStepDelegate( codeContainerView = playgroundLayout, - keyboardExtensionContainer = coordinator, stepWrapper = stepWrapper, codeQuizInstructionDelegate = CodeQuizInstructionDelegate(instructionsLayout, false), actionsListener = actionsListener @@ -175,12 +180,14 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag submitButtonSeparator = playgroundLayout.submitButtonSeparator codeSubmitButton = playgroundLayout.codeSubmitButton retryButton = playgroundLayout.stepQuizRetry + codeLayout = playgroundLayout.codeStepLayout codeSubmitButton.setOnClickListener { callback.onSyncCodeStateWithParent(lang, codeStepLayout.text.toString(), true) dismiss() } retryButton.changeVisibility(false) + setupKeyboardExtensions() } override fun onSaveInstanceState(outState: Bundle) { @@ -273,6 +280,59 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag } } + private fun setupKeyboardExtensions() { + /** + * Keyboard extension + */ + coordinator.let { container -> + val stepQuizCodeKeyboardExtension = + container.inflate(R.layout.layout_step_quiz_code_keyboard_extension) as RecyclerView + stepQuizCodeKeyboardExtension.adapter = coreCodeStepDelegate.codeToolbarAdapter + stepQuizCodeKeyboardExtension.layoutManager = LinearLayoutManager(container.context, LinearLayoutManager.HORIZONTAL, false) + codeLayout.codeToolbarAdapter = coreCodeStepDelegate.codeToolbarAdapter + + container.addView(stepQuizCodeKeyboardExtension) + stepQuizCodeKeyboardExtension.visibility = View.INVISIBLE // Apparently this fixes the offset bug when the current line is under the code toolbar adapter + stepQuizCodeKeyboardExtension.layoutParams = (stepQuizCodeKeyboardExtension.layoutParams as RelativeLayout.LayoutParams) + .apply { + addRule(RelativeLayout.ALIGN_PARENT_BOTTOM) + } + + setOnKeyboardOpenListener( + container, + onKeyboardHidden = { + if (keyboardShown) { + stepQuizCodeKeyboardExtension.visibility = View.GONE + codeLayout.isNestedScrollingEnabled = true + codeLayout.layoutParams = + (codeLayout.layoutParams as RelativeLayout.LayoutParams) + .apply { + bottomMargin = 0 + } + codeLayout.setPadding(0, 0, 0, container.context.resources.getDimensionPixelSize( + R.dimen.step_quiz_fullscreen_code_layout_bottom_padding)) + setViewsVisibility(needShow = true) + keyboardShown = false + } + }, + onKeyboardShown = { + if (!keyboardShown) { + stepQuizCodeKeyboardExtension.visibility = View.VISIBLE + codeLayout.isNestedScrollingEnabled = false + codeLayout.layoutParams = + (codeLayout.layoutParams as RelativeLayout.LayoutParams) + .apply { + bottomMargin = stepQuizCodeKeyboardExtension.height + } + codeLayout.setPadding(0, 0, 0, 0) + setViewsVisibility(needShow = false) + keyboardShown = true + } + } + ) + } + } + /** * Hiding views upon opening keyboard */ From 0b401423e7e4bd3ae3264de8c4578137d289960e Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 9 Sep 2019 12:32:38 +0300 Subject: [PATCH 36/51] add keyboard extension to fullscreen layout --- .../CodeStepQuizFullScreenDialogFragment.kt | 82 ++++++++----------- .../activity_step_quiz_code_fullscreen.xml | 58 +++++++------ 2 files changed, 67 insertions(+), 73 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt index 94064440da..ba448e799d 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt @@ -7,7 +7,6 @@ import android.support.v4.app.DialogFragment import android.support.v4.content.ContextCompat import android.support.v4.view.ViewPager import android.support.v7.widget.LinearLayoutManager -import android.support.v7.widget.RecyclerView import android.view.LayoutInflater import android.view.View import android.view.ViewGroup @@ -19,6 +18,7 @@ import kotlinx.android.synthetic.main.activity_step_quiz_code_fullscreen.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_instruction.view.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.view.* +import kotlinx.android.synthetic.main.layout_step_quiz_code_keyboard_extension.* import kotlinx.android.synthetic.main.view_centered_toolbar.* import kotlinx.android.synthetic.main.view_step_quiz_submit_button.view.* import org.stepic.droid.R @@ -32,7 +32,6 @@ import org.stepic.droid.ui.dialogs.ProgrammingLanguageChooserDialogFragment import org.stepic.droid.ui.dialogs.ResetCodeDialogFragment import org.stepic.droid.ui.util.changeVisibility import org.stepic.droid.ui.util.hideKeyboard -import org.stepic.droid.ui.util.inflate import org.stepic.droid.ui.util.setOnKeyboardOpenListener import org.stepic.droid.util.argument import org.stepik.android.domain.lesson.model.LessonData @@ -284,53 +283,42 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag /** * Keyboard extension */ - coordinator.let { container -> - val stepQuizCodeKeyboardExtension = - container.inflate(R.layout.layout_step_quiz_code_keyboard_extension) as RecyclerView - stepQuizCodeKeyboardExtension.adapter = coreCodeStepDelegate.codeToolbarAdapter - stepQuizCodeKeyboardExtension.layoutManager = LinearLayoutManager(container.context, LinearLayoutManager.HORIZONTAL, false) - codeLayout.codeToolbarAdapter = coreCodeStepDelegate.codeToolbarAdapter - - container.addView(stepQuizCodeKeyboardExtension) - stepQuizCodeKeyboardExtension.visibility = View.INVISIBLE // Apparently this fixes the offset bug when the current line is under the code toolbar adapter - stepQuizCodeKeyboardExtension.layoutParams = (stepQuizCodeKeyboardExtension.layoutParams as RelativeLayout.LayoutParams) - .apply { - addRule(RelativeLayout.ALIGN_PARENT_BOTTOM) + stepQuizCodeKeyboardExtension.adapter = coreCodeStepDelegate.codeToolbarAdapter + stepQuizCodeKeyboardExtension.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false) + codeLayout.codeToolbarAdapter = coreCodeStepDelegate.codeToolbarAdapter + + setOnKeyboardOpenListener( + coordinator, + onKeyboardHidden = { + if (keyboardShown) { + stepQuizCodeKeyboardExtension.visibility = View.GONE + codeLayout.isNestedScrollingEnabled = true + codeLayout.layoutParams = + (codeLayout.layoutParams as RelativeLayout.LayoutParams) + .apply { + bottomMargin = 0 + } + codeLayout.setPadding(0, 0, 0, requireContext().resources.getDimensionPixelSize( + R.dimen.step_quiz_fullscreen_code_layout_bottom_padding)) + setViewsVisibility(needShow = true) + keyboardShown = false } - - setOnKeyboardOpenListener( - container, - onKeyboardHidden = { - if (keyboardShown) { - stepQuizCodeKeyboardExtension.visibility = View.GONE - codeLayout.isNestedScrollingEnabled = true - codeLayout.layoutParams = - (codeLayout.layoutParams as RelativeLayout.LayoutParams) - .apply { - bottomMargin = 0 - } - codeLayout.setPadding(0, 0, 0, container.context.resources.getDimensionPixelSize( - R.dimen.step_quiz_fullscreen_code_layout_bottom_padding)) - setViewsVisibility(needShow = true) - keyboardShown = false - } - }, - onKeyboardShown = { - if (!keyboardShown) { - stepQuizCodeKeyboardExtension.visibility = View.VISIBLE - codeLayout.isNestedScrollingEnabled = false - codeLayout.layoutParams = - (codeLayout.layoutParams as RelativeLayout.LayoutParams) - .apply { - bottomMargin = stepQuizCodeKeyboardExtension.height - } - codeLayout.setPadding(0, 0, 0, 0) - setViewsVisibility(needShow = false) - keyboardShown = true - } + }, + onKeyboardShown = { + if (!keyboardShown) { + stepQuizCodeKeyboardExtension.visibility = View.VISIBLE + codeLayout.isNestedScrollingEnabled = false + codeLayout.layoutParams = + (codeLayout.layoutParams as RelativeLayout.LayoutParams) + .apply { + bottomMargin = stepQuizCodeKeyboardExtension.height + } + codeLayout.setPadding(0, 0, 0, 0) + setViewsVisibility(needShow = false) + keyboardShown = true } - ) - } + } + ) } /** diff --git a/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml b/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml index 00fb601a57..99a6e41482 100644 --- a/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml +++ b/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml @@ -6,32 +6,31 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - - - - - + + + + + + + + \ No newline at end of file From 3fe7cdbe0f4c1e5ccb6376f7ce46ba93726940c2 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 9 Sep 2019 13:00:06 +0300 Subject: [PATCH 37/51] fix function name --- .../ui/dialog/CodeStepQuizFullScreenDialogFragment.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt index ba448e799d..5e2da98156 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt @@ -186,7 +186,7 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag dismiss() } retryButton.changeVisibility(false) - setupKeyboardExtensions() + setupKeyboardExtension() } override fun onSaveInstanceState(outState: Bundle) { @@ -279,10 +279,10 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag } } - private fun setupKeyboardExtensions() { - /** - * Keyboard extension - */ + /** + * Keyboard extension + */ + private fun setupKeyboardExtension() { stepQuizCodeKeyboardExtension.adapter = coreCodeStepDelegate.codeToolbarAdapter stepQuizCodeKeyboardExtension.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false) codeLayout.codeToolbarAdapter = coreCodeStepDelegate.codeToolbarAdapter From 5c35c4a18624576bcde7dfb755645a4356c73233 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 9 Sep 2019 14:19:55 +0300 Subject: [PATCH 38/51] break down inflating into a function --- .../ui/adapter/CodeStepQuizFullScreenPagerAdapter.kt | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenPagerAdapter.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenPagerAdapter.kt index f24a311b9d..2b9bd7d2da 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenPagerAdapter.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenPagerAdapter.kt @@ -1,19 +1,20 @@ package org.stepik.android.view.step_quiz_fullscreen_code.ui.adapter import android.content.Context +import android.support.annotation.LayoutRes +import android.support.annotation.StringRes import android.support.v4.view.PagerAdapter -import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import org.stepic.droid.R class CodeStepQuizFullScreenPagerAdapter( - context: Context + val context: Context ) : PagerAdapter() { private val layouts = listOf( - LayoutInflater.from(context).inflate(R.layout.layout_step_quiz_code_fullscreen_instruction, null) to "Instruction", - LayoutInflater.from(context).inflate(R.layout.layout_step_quiz_code_fullscreen_playground, null) to "Playground" + inflateLayout(R.layout.layout_step_quiz_code_fullscreen_instruction, R.string.step_quiz_code_full_screen_instruction_tab), + inflateLayout(R.layout.layout_step_quiz_code_fullscreen_playground, R.string.step_quiz_code_full_screen_code_tab) ) override fun instantiateItem(container: ViewGroup, position: Int): Any { @@ -37,4 +38,7 @@ class CodeStepQuizFullScreenPagerAdapter( fun getViewAt(position: Int): View = layouts[position].first + + private fun inflateLayout(@LayoutRes layoutId: Int, @StringRes stringId: Int): Pair = + View.inflate(context, layoutId, null) to context.resources.getString(stringId) } \ No newline at end of file From 888a0fc277c1e455345a272e80e803a379b782b8 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 9 Sep 2019 17:57:11 +0300 Subject: [PATCH 39/51] code review fixes --- .../ui/dialogs/ChangeCodeLanguageDialog.kt | 7 +- ...rogrammingLanguageChooserDialogFragment.kt | 7 +- .../ui/fragment/DefaultStepQuizFragment.kt | 4 + .../delegate/CodeQuizInstructionDelegate.kt | 14 +- .../ui/delegate/CoreCodeStepDelegate.kt | 20 +-- .../ui/fragment/CodeStepQuizFragment.kt | 128 ++---------------- .../CodeStepQuizFullScreenPagerAdapter.kt | 2 +- .../CodeStepQuizFullScreenDialogFragment.kt | 45 ++++-- 8 files changed, 60 insertions(+), 167 deletions(-) diff --git a/app/src/main/java/org/stepic/droid/ui/dialogs/ChangeCodeLanguageDialog.kt b/app/src/main/java/org/stepic/droid/ui/dialogs/ChangeCodeLanguageDialog.kt index 7b6c1a20fa..3c84b968ac 100644 --- a/app/src/main/java/org/stepic/droid/ui/dialogs/ChangeCodeLanguageDialog.kt +++ b/app/src/main/java/org/stepic/droid/ui/dialogs/ChangeCodeLanguageDialog.kt @@ -20,12 +20,7 @@ class ChangeCodeLanguageDialog : DialogFragment() { .setTitle(R.string.reset_code_dialog_title) .setMessage(R.string.change_code_dialog_explanation) .setPositiveButton(R.string.yes) { _, _ -> - val callback = if (parentFragment != null) { - parentFragment as Callback - } else { - activity as Callback - } - callback.onChangeLanguage() + (parentFragment as Callback).onChangeLanguage() } .setNegativeButton(R.string.cancel, null) .create() diff --git a/app/src/main/java/org/stepic/droid/ui/dialogs/ProgrammingLanguageChooserDialogFragment.kt b/app/src/main/java/org/stepic/droid/ui/dialogs/ProgrammingLanguageChooserDialogFragment.kt index 941262eb6a..462a37e9c4 100644 --- a/app/src/main/java/org/stepic/droid/ui/dialogs/ProgrammingLanguageChooserDialogFragment.kt +++ b/app/src/main/java/org/stepic/droid/ui/dialogs/ProgrammingLanguageChooserDialogFragment.kt @@ -36,12 +36,7 @@ class ProgrammingLanguageChooserDialogFragment : DialogFragment() { .positiveText(R.string.choose_action) .negativeText(R.string.cancel) .onPositive { _, _ -> - val callback = if (parentFragment != null) { - parentFragment as Callback - } else { - activity as Callback - } - callback.onLanguageChosen(picker.displayedValues[picker.value]) + (parentFragment as Callback).onLanguageChosen(picker.displayedValues[picker.value]) } .build() } diff --git a/app/src/main/java/org/stepik/android/view/step_quiz/ui/fragment/DefaultStepQuizFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz/ui/fragment/DefaultStepQuizFragment.kt index 8c5ce5acfb..d58ea4268d 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz/ui/fragment/DefaultStepQuizFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz/ui/fragment/DefaultStepQuizFragment.kt @@ -108,6 +108,10 @@ abstract class DefaultStepQuizFragment : Fragment(), StepQuizView { protected abstract fun createStepQuizFormDelegate(view: View): StepQuizFormDelegate + protected fun onActionButtonClicked() { + stepQuizDelegate.onActionButtonClicked() + } + override fun onStart() { super.onStart() presenter.attachView(this) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizInstructionDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizInstructionDelegate.kt index baa3cdf71b..7522f43c81 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizInstructionDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizInstructionDelegate.kt @@ -16,7 +16,7 @@ import ru.nobird.android.ui.adapterssupport.DefaultDelegateAdapter class CodeQuizInstructionDelegate( detailsContainerView: View, - private val isCollapseable: Boolean + isCollapseable: Boolean ) { private val stepQuizCodeDetails = detailsContainerView.stepQuizCodeDetails @@ -26,11 +26,7 @@ class CodeQuizInstructionDelegate( private val stepQuizCodeDetailsAdapter = DefaultDelegateAdapter() private val codeStepQuizDetailsMapper = CodeStepQuizDetailsMapper() - fun setCodeDetailsData(step: Step, lang: String?) { - stepQuizCodeDetailsAdapter.items = codeStepQuizDetailsMapper.mapToCodeDetails(step, lang) - } - - fun setupCodeDetailView() { + init { stepQuizCodeDetailsAdapter += CodeDetailSampleAdapterDelegate() stepQuizCodeDetailsAdapter += CodeDetailLimitAdapterDelegate() @@ -38,6 +34,7 @@ class CodeQuizInstructionDelegate( visibility = View.GONE layoutManager = LinearLayoutManager(context) adapter = stepQuizCodeDetailsAdapter + isNestedScrollingEnabled = false val divider = DividerItemDecoration(context, DividerItemDecoration.VERTICAL) divider.setDrawable(AppCompatResources.getDrawable(context, R.drawable.bg_step_quiz_code_details_separator)!!) @@ -55,7 +52,10 @@ class CodeQuizInstructionDelegate( } } else { stepQuizCodeDetailsContent.visibility = View.VISIBLE - stepQuizCodeDetailsContent.isNestedScrollingEnabled = false } } + + fun setCodeDetailsData(step: Step, lang: String?) { + stepQuizCodeDetailsAdapter.items = codeStepQuizDetailsMapper.mapToCodeDetails(step, lang) + } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt index ba6557a189..f87aa40b8b 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt @@ -3,7 +3,6 @@ package org.stepik.android.view.step_quiz_code.ui.delegate import android.view.View import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.view.* import org.stepic.droid.R -import org.stepic.droid.code.util.CodeToolbarUtil import org.stepic.droid.model.code.extensionForLanguage import org.stepic.droid.persistence.model.StepPersistentWrapper import org.stepic.droid.ui.adapters.CodeToolbarAdapter @@ -14,29 +13,16 @@ class CoreCodeStepDelegate( codeContainerView: View, private val stepWrapper: StepPersistentWrapper, private val codeQuizInstructionDelegate: CodeQuizInstructionDelegate, - private val actionsListener: ActionsListener + private val actionsListener: ActionsListener, + private var codeToolbarAdapter: CodeToolbarAdapter? ) { private val codeLayout = codeContainerView.codeStepLayout private val stepQuizActionChangeLang = codeContainerView.stepQuizActionChangeLang - val codeToolbarAdapter = CodeToolbarAdapter(codeContainerView.context) - .apply { - onSymbolClickListener = object : CodeToolbarAdapter.OnSymbolClickListener { - override fun onSymbolClick(symbol: String, offset: Int) { - codeLayout.insertText(CodeToolbarUtil.mapToolbarSymbolToPrintable(symbol, codeLayout.indentSize), offset) - } - } - } - val codeOptions = stepWrapper.step.block?.options ?: throw IllegalArgumentException("Code options shouldn't be null") init { - /** - * Initialize code details - */ - codeQuizInstructionDelegate.setupCodeDetailView() - /** * Actions */ @@ -48,7 +34,7 @@ class CoreCodeStepDelegate( codeLayout.setText(codeStepQuizFormState.code) codeLayout.lang = extensionForLanguage(codeStepQuizFormState.lang) stepQuizActionChangeLang.text = codeStepQuizFormState.lang - codeToolbarAdapter.setLanguage(codeStepQuizFormState.lang) + codeToolbarAdapter?.setLanguage(codeStepQuizFormState.lang) } fun setDetailsContentData(lang: String?) { diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt index 14a704a364..21b970ff09 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt @@ -1,41 +1,22 @@ package org.stepik.android.view.step_quiz_code.ui.fragment -import android.arch.lifecycle.ViewModelProvider -import android.arch.lifecycle.ViewModelProviders -import android.os.Bundle -import android.support.design.widget.Snackbar import android.support.v4.app.Fragment -import android.support.v4.content.ContextCompat -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup -import kotlinx.android.synthetic.main.error_no_connection_with_button_small.view.* -import kotlinx.android.synthetic.main.fragment_step_quiz.* import kotlinx.android.synthetic.main.layout_step_quiz_code.* -import kotlinx.android.synthetic.main.view_step_quiz_submit_button.* import org.stepic.droid.R -import org.stepic.droid.base.App -import org.stepic.droid.core.ScreenManager -import org.stepic.droid.fonts.FontsProvider import org.stepic.droid.persistence.model.StepPersistentWrapper import org.stepic.droid.ui.dialogs.ChangeCodeLanguageDialog import org.stepic.droid.ui.dialogs.ProgrammingLanguageChooserDialogFragment -import org.stepic.droid.ui.listeners.NextMoveable -import org.stepic.droid.util.argument -import org.stepic.droid.util.setTextColor import org.stepik.android.domain.lesson.model.LessonData -import org.stepik.android.presentation.step_quiz.StepQuizPresenter import org.stepik.android.presentation.step_quiz.StepQuizView -import org.stepik.android.view.step_quiz.ui.delegate.StepQuizDelegate -import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFeedbackBlocksDelegate +import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFormDelegate +import org.stepik.android.view.step_quiz.ui.fragment.DefaultStepQuizFragment import org.stepik.android.view.step_quiz_code.ui.delegate.CodeQuizInstructionDelegate import org.stepik.android.view.step_quiz_code.ui.delegate.CodeStepQuizFormDelegate import org.stepik.android.view.step_quiz_code.ui.delegate.CoreCodeStepDelegate import org.stepik.android.view.step_quiz_fullscreen_code.ui.dialog.CodeStepQuizFullScreenDialogFragment -import org.stepik.android.view.ui.delegate.ViewStateDelegate -import javax.inject.Inject -class CodeStepQuizFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog.Callback, ProgrammingLanguageChooserDialogFragment.Callback, CodeStepQuizFullScreenDialogFragment.Callback { +class CodeStepQuizFragment : DefaultStepQuizFragment(), StepQuizView, ChangeCodeLanguageDialog.Callback, ProgrammingLanguageChooserDialogFragment.Callback, CodeStepQuizFullScreenDialogFragment.Callback { companion object { fun newInstance(stepPersistentWrapper: StepPersistentWrapper, lessonData: LessonData): Fragment = CodeStepQuizFragment() @@ -45,57 +26,15 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog. } } - @Inject - internal lateinit var viewModelFactory: ViewModelProvider.Factory - - @Inject - internal lateinit var fontsProvider: FontsProvider - - @Inject - internal lateinit var screenManager: ScreenManager - - private lateinit var presenter: StepQuizPresenter - - private var lessonData: LessonData by argument() - private var stepWrapper: StepPersistentWrapper by argument() - - private lateinit var viewStateDelegate: ViewStateDelegate - private lateinit var stepQuizDelegate: StepQuizDelegate - private lateinit var codeStepQuizFormDelegate: CodeStepQuizFormDelegate - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - injectComponent() - - presenter = ViewModelProviders.of(this, viewModelFactory).get(StepQuizPresenter::class.java) - presenter.onStepData(stepWrapper, lessonData) - } - - private fun injectComponent() { - App.component() - .stepComponentBuilder() - .build() - .inject(this) - } - - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = - (inflater.inflate(R.layout.fragment_step_quiz, container, false) as ViewGroup) - .apply { - addView(inflater.inflate(R.layout.layout_step_quiz_code, this, false)) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - stepQuizDescription.visibility = View.GONE + override val quizLayoutRes: Int = + R.layout.layout_step_quiz_code - viewStateDelegate = ViewStateDelegate() - viewStateDelegate.addState() - viewStateDelegate.addState(stepQuizProgress) - viewStateDelegate.addState(stepQuizDiscountingPolicy, stepQuizFeedbackBlocks, stepQuizCodeContainer, stepQuizActionContainer) - viewStateDelegate.addState(stepQuizNetworkError) - - stepQuizNetworkError.tryAgain.setOnClickListener { presenter.onStepData(stepWrapper, lessonData, forceUpdate = true) } + override val quizViews: Array + get() = arrayOf(stepQuizCodeContainer) + override fun createStepQuizFormDelegate(view: View): StepQuizFormDelegate { val actionsListener = object : CoreCodeStepDelegate.ActionsListener { override fun onChangeLanguageClicked() { val dialog = ChangeCodeLanguageDialog.newInstance() @@ -121,55 +60,12 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog. codeContainerView = view, stepWrapper = stepWrapper, codeQuizInstructionDelegate = CodeQuizInstructionDelegate(view, true), - actionsListener = actionsListener + actionsListener = actionsListener, + codeToolbarAdapter = null ) ) - stepQuizDelegate = - StepQuizDelegate( - step = stepWrapper.step, - lessonData = lessonData, - stepQuizFormDelegate = codeStepQuizFormDelegate, - stepQuizFeedbackBlocksDelegate = StepQuizFeedbackBlocksDelegate( - stepQuizFeedbackBlocks, - fontsProvider, - stepWrapper.step.actions?.doReview != null, - { screenManager.openStepInWeb(requireContext(), stepWrapper.step) } - ), - stepQuizActionButton = stepQuizAction, - stepRetryButton = stepQuizRetry, - stepQuizDiscountingPolicy = stepQuizDiscountingPolicy, - stepQuizPresenter = presenter - ) { - (parentFragment as? NextMoveable)?.moveNext() - } - } - - override fun onStart() { - super.onStart() - presenter.attachView(this) - } - - override fun onStop() { - presenter.detachView(this) - stepQuizDelegate.syncReplyState() - super.onStop() - } - - override fun setState(state: StepQuizView.State) { - viewStateDelegate.switchState(state) - if (state is StepQuizView.State.AttemptLoaded) { - stepQuizDelegate.setState(state) - } - } - - override fun showNetworkError() { - val view = view ?: return - - Snackbar - .make(view, R.string.no_connection, Snackbar.LENGTH_SHORT) - .setTextColor(ContextCompat.getColor(requireContext(), R.color.white)) - .show() + return codeStepQuizFormDelegate } override fun onChangeLanguage() { @@ -188,7 +84,7 @@ class CodeStepQuizFragment : Fragment(), StepQuizView, ChangeCodeLanguageDialog. override fun onSyncCodeStateWithParent(lang: String, code: String, onSubmitClicked: Boolean) { codeStepQuizFormDelegate.updateCodeLayoutFromDialog(lang, code) if (onSubmitClicked) { - stepQuizDelegate.onActionButtonClicked() + onActionButtonClicked() } } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenPagerAdapter.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenPagerAdapter.kt index 2b9bd7d2da..12056281e9 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenPagerAdapter.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/adapter/CodeStepQuizFullScreenPagerAdapter.kt @@ -9,7 +9,7 @@ import android.view.ViewGroup import org.stepic.droid.R class CodeStepQuizFullScreenPagerAdapter( - val context: Context + private val context: Context ) : PagerAdapter() { private val layouts = listOf( diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt index 5e2da98156..0c9447b815 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt @@ -24,9 +24,11 @@ import kotlinx.android.synthetic.main.view_step_quiz_submit_button.view.* import org.stepic.droid.R import org.stepic.droid.base.App import org.stepic.droid.code.ui.CodeEditorLayout +import org.stepic.droid.code.util.CodeToolbarUtil import org.stepic.droid.fonts.FontType import org.stepic.droid.fonts.FontsProvider import org.stepic.droid.persistence.model.StepPersistentWrapper +import org.stepic.droid.ui.adapters.CodeToolbarAdapter import org.stepic.droid.ui.dialogs.ChangeCodeLanguageDialog import org.stepic.droid.ui.dialogs.ProgrammingLanguageChooserDialogFragment import org.stepic.droid.ui.dialogs.ResetCodeDialogFragment @@ -75,6 +77,8 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag private lateinit var codeSubmitButton: View private lateinit var retryButton: View + private lateinit var codeToolbarAdapter: CodeToolbarAdapter + // Flag is necessary, because keyboard listener is constantly invoked (probably global layout listener reacts to view changes) private var keyboardShown: Boolean = false @@ -160,33 +164,35 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag override fun onFullscreenClicked(lang: String, code: String) {} } - coreCodeStepDelegate = CoreCodeStepDelegate( - codeContainerView = playgroundLayout, - stepWrapper = stepWrapper, - codeQuizInstructionDelegate = CodeQuizInstructionDelegate(instructionsLayout, false), - actionsListener = actionsListener - ) - if (savedInstanceState != null) { lang = savedInstanceState.getString(LANG) ?: return code = savedInstanceState.getString(CODE) ?: return } - coreCodeStepDelegate.setLanguage(CodeStepQuizFormState.Lang(lang, code)) - coreCodeStepDelegate.setDetailsContentData(lang) - fullScreenCodeViewPager.setCurrentItem(1, false) - submitButtonSeparator = playgroundLayout.submitButtonSeparator codeSubmitButton = playgroundLayout.codeSubmitButton retryButton = playgroundLayout.stepQuizRetry codeLayout = playgroundLayout.codeStepLayout codeSubmitButton.setOnClickListener { - callback.onSyncCodeStateWithParent(lang, codeStepLayout.text.toString(), true) + callback.onSyncCodeStateWithParent(lang, codeStepLayout.text.toString(), onSubmitClicked = true) dismiss() } retryButton.changeVisibility(false) + setupCodeToolAdapter() setupKeyboardExtension() + + coreCodeStepDelegate = CoreCodeStepDelegate( + codeContainerView = playgroundLayout, + stepWrapper = stepWrapper, + codeQuizInstructionDelegate = CodeQuizInstructionDelegate(instructionsLayout, false), + actionsListener = actionsListener, + codeToolbarAdapter = codeToolbarAdapter + ) + + coreCodeStepDelegate.setLanguage(CodeStepQuizFormState.Lang(lang, code)) + coreCodeStepDelegate.setDetailsContentData(lang) + fullScreenCodeViewPager.setCurrentItem(1, false) } override fun onSaveInstanceState(outState: Bundle) { @@ -279,13 +285,24 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag } } + private fun setupCodeToolAdapter() { + codeToolbarAdapter = CodeToolbarAdapter(requireContext()) + .apply { + onSymbolClickListener = object : CodeToolbarAdapter.OnSymbolClickListener { + override fun onSymbolClick(symbol: String, offset: Int) { + codeLayout.insertText(CodeToolbarUtil.mapToolbarSymbolToPrintable(symbol, codeLayout.indentSize), offset) + } + } + } + } + /** * Keyboard extension */ private fun setupKeyboardExtension() { - stepQuizCodeKeyboardExtension.adapter = coreCodeStepDelegate.codeToolbarAdapter + stepQuizCodeKeyboardExtension.adapter = codeToolbarAdapter stepQuizCodeKeyboardExtension.layoutManager = LinearLayoutManager(requireContext(), LinearLayoutManager.HORIZONTAL, false) - codeLayout.codeToolbarAdapter = coreCodeStepDelegate.codeToolbarAdapter + codeLayout.codeToolbarAdapter = codeToolbarAdapter setOnKeyboardOpenListener( coordinator, From 41981dd2aac8b867a60ae2b893c3ab9dbc7d03c9 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 9 Sep 2019 20:33:27 +0300 Subject: [PATCH 40/51] fix reset code --- .../ui/delegate/CodeStepQuizFormDelegate.kt | 2 +- .../ui/delegate/CoreCodeStepDelegate.kt | 17 +++++++------ .../CodeStepQuizFullScreenDialogFragment.kt | 24 +++++++++---------- 3 files changed, 22 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt index ed6a9b8f3d..67d720878b 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt @@ -30,7 +30,7 @@ class CodeStepQuizFormDelegate( when (value) { is CodeStepQuizFormState.Lang -> - coreCodeStepDelegate.setLanguage(value) + coreCodeStepDelegate.setLanguage(value.lang, value.code) } coreCodeStepDelegate.setDetailsContentData((value as? CodeStepQuizFormState.Lang)?.lang) } diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt index f87aa40b8b..a1502103d3 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt @@ -30,11 +30,14 @@ class CoreCodeStepDelegate( stepQuizActionChangeLang.setCompoundDrawables(end = R.drawable.ic_arrow_bottom) } - fun setLanguage(codeStepQuizFormState: CodeStepQuizFormState.Lang) { - codeLayout.setText(codeStepQuizFormState.code) - codeLayout.lang = extensionForLanguage(codeStepQuizFormState.lang) - stepQuizActionChangeLang.text = codeStepQuizFormState.lang - codeToolbarAdapter?.setLanguage(codeStepQuizFormState.lang) + /** + * if [code] is null then default code template for [lang] will be used + */ + fun setLanguage(lang: String, code: String? = null) { + codeLayout.lang = extensionForLanguage(lang) + stepQuizActionChangeLang.text = lang + codeLayout.setText(code ?: resetCode(lang)) + codeToolbarAdapter?.setLanguage(lang) } fun setDetailsContentData(lang: String?) { @@ -48,8 +51,8 @@ class CoreCodeStepDelegate( fun onLanguageSelected(lang: String): CodeStepQuizFormState.Lang = CodeStepQuizFormState.Lang(lang, codeOptions.codeTemplates[lang] ?: "") - fun onResetCode(): String = - codeOptions.codeTemplates[codeLayout.lang] ?: "" + fun resetCode(lang: String): String = + codeOptions.codeTemplates[lang] ?: "" fun setEnabled(isEnabled: Boolean) { codeLayout.isEnabled = isEnabled diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt index 0c9447b815..6e194856d8 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt @@ -16,7 +16,6 @@ import android.widget.RelativeLayout import android.widget.TextView import kotlinx.android.synthetic.main.activity_step_quiz_code_fullscreen.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_instruction.view.* -import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.view.* import kotlinx.android.synthetic.main.layout_step_quiz_code_keyboard_extension.* import kotlinx.android.synthetic.main.view_centered_toolbar.* @@ -37,7 +36,6 @@ import org.stepic.droid.ui.util.hideKeyboard import org.stepic.droid.ui.util.setOnKeyboardOpenListener import org.stepic.droid.util.argument import org.stepik.android.domain.lesson.model.LessonData -import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState import org.stepik.android.view.step_quiz_code.ui.delegate.CodeQuizInstructionDelegate import org.stepik.android.view.step_quiz_code.ui.delegate.CoreCodeStepDelegate import org.stepik.android.view.step_quiz_fullscreen_code.ui.adapter.CodeStepQuizFullScreenPagerAdapter @@ -174,10 +172,6 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag retryButton = playgroundLayout.stepQuizRetry codeLayout = playgroundLayout.codeStepLayout - codeSubmitButton.setOnClickListener { - callback.onSyncCodeStateWithParent(lang, codeStepLayout.text.toString(), onSubmitClicked = true) - dismiss() - } retryButton.changeVisibility(false) setupCodeToolAdapter() setupKeyboardExtension() @@ -190,15 +184,20 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag codeToolbarAdapter = codeToolbarAdapter ) - coreCodeStepDelegate.setLanguage(CodeStepQuizFormState.Lang(lang, code)) + coreCodeStepDelegate.setLanguage(lang, code) coreCodeStepDelegate.setDetailsContentData(lang) fullScreenCodeViewPager.setCurrentItem(1, false) + + codeSubmitButton.setOnClickListener { + callback.onSyncCodeStateWithParent(lang, codeLayout.text.toString(), onSubmitClicked = true) + dismiss() + } } override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) outState.putString(LANG, lang) - outState.putString(CODE, codeStepLayout.text.toString()) + outState.putString(CODE, codeLayout.text.toString()) } private fun initViewPager() { @@ -259,7 +258,7 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag } override fun onPause() { - callback.onSyncCodeStateWithParent(lang, codeStepLayout.text.toString()) + callback.onSyncCodeStateWithParent(lang, codeLayout.text.toString()) super.onPause() } @@ -274,14 +273,13 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag override fun onLanguageChosen(programmingLanguage: String) { lang = programmingLanguage - coreCodeStepDelegate.setLanguage(coreCodeStepDelegate.onLanguageSelected(programmingLanguage)) + coreCodeStepDelegate.setLanguage(programmingLanguage) coreCodeStepDelegate.setDetailsContentData(programmingLanguage) } override fun onReset() { - coreCodeStepDelegate.onResetCode().let { codeTemplate -> - code = codeTemplate - playgroundLayout.codeStepLayout.setText(codeTemplate) + coreCodeStepDelegate.resetCode(lang).let { codeTemplate -> + codeLayout.setText(codeTemplate) } } From a01fdfb6419e10f7810fcc1a0977bb4038b9b31c Mon Sep 17 00:00:00 2001 From: Stepik Bot Date: Mon, 9 Sep 2019 18:00:17 +0000 Subject: [PATCH 41/51] "inc version to 2034" --- dependencies.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index d8a75c0dc1..f2c24914d0 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -1,6 +1,6 @@ ext.versions = [ - code : 2033, - name : '1.91', + code : 2034, + name : '1.92', minSdk : 16, targetSdk : 26, From f9c886e6c3687dc70aef19b772fb91b87818a3ea Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 9 Sep 2019 22:30:12 +0300 Subject: [PATCH 42/51] clean up --- ...eStepDelegate.kt => CodeLayoutDelegate.kt} | 26 ++-------- .../ui/delegate/CodeStepQuizFormDelegate.kt | 19 ++++---- .../ui/fragment/CodeStepQuizFragment.kt | 47 +++++++++---------- .../CodeStepQuizFullScreenDialogFragment.kt | 40 +++++++--------- 4 files changed, 55 insertions(+), 77 deletions(-) rename app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/{CoreCodeStepDelegate.kt => CodeLayoutDelegate.kt} (64%) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeLayoutDelegate.kt similarity index 64% rename from app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt rename to app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeLayoutDelegate.kt index a1502103d3..f5d95a3e0e 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CoreCodeStepDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeLayoutDelegate.kt @@ -7,14 +7,13 @@ import org.stepic.droid.model.code.extensionForLanguage import org.stepic.droid.persistence.model.StepPersistentWrapper import org.stepic.droid.ui.adapters.CodeToolbarAdapter import org.stepic.droid.ui.util.setCompoundDrawables -import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState -class CoreCodeStepDelegate( +class CodeLayoutDelegate( codeContainerView: View, private val stepWrapper: StepPersistentWrapper, private val codeQuizInstructionDelegate: CodeQuizInstructionDelegate, - private val actionsListener: ActionsListener, - private var codeToolbarAdapter: CodeToolbarAdapter? + private var codeToolbarAdapter: CodeToolbarAdapter?, + private val onChangeLanguageClicked: () -> Unit ) { private val codeLayout = codeContainerView.codeStepLayout @@ -26,7 +25,7 @@ class CoreCodeStepDelegate( /** * Actions */ - stepQuizActionChangeLang.setOnClickListener { actionsListener.onChangeLanguageClicked() } + stepQuizActionChangeLang.setOnClickListener { onChangeLanguageClicked } stepQuizActionChangeLang.setCompoundDrawables(end = R.drawable.ic_arrow_bottom) } @@ -36,7 +35,7 @@ class CoreCodeStepDelegate( fun setLanguage(lang: String, code: String? = null) { codeLayout.lang = extensionForLanguage(lang) stepQuizActionChangeLang.text = lang - codeLayout.setText(code ?: resetCode(lang)) + codeLayout.setText(code ?: codeOptions.codeTemplates[lang] ?: "") codeToolbarAdapter?.setLanguage(lang) } @@ -44,23 +43,8 @@ class CoreCodeStepDelegate( codeQuizInstructionDelegate.setCodeDetailsData(stepWrapper.step, lang) } - fun onFullscreenClicked(lang: String, code: String) { - actionsListener.onFullscreenClicked(lang, code) - } - - fun onLanguageSelected(lang: String): CodeStepQuizFormState.Lang = - CodeStepQuizFormState.Lang(lang, codeOptions.codeTemplates[lang] ?: "") - - fun resetCode(lang: String): String = - codeOptions.codeTemplates[lang] ?: "" - fun setEnabled(isEnabled: Boolean) { codeLayout.isEnabled = isEnabled stepQuizActionChangeLang.isEnabled = isEnabled } - - interface ActionsListener { - fun onChangeLanguageClicked() - fun onFullscreenClicked(lang: String, code: String) - } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt index 67d720878b..df1d955a29 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt @@ -20,7 +20,8 @@ import ru.nobird.android.ui.adapterssupport.DefaultDelegateAdapter class CodeStepQuizFormDelegate( containerView: View, - private val coreCodeStepDelegate: CoreCodeStepDelegate + private val codeLayoutDelegate: CodeLayoutDelegate, + private val onFullscreenClicked: (lang: String, code: String) -> Unit ) : StepQuizFormDelegate { private var state: CodeStepQuizFormState = CodeStepQuizFormState.Idle set(value) { @@ -30,9 +31,9 @@ class CodeStepQuizFormDelegate( when (value) { is CodeStepQuizFormState.Lang -> - coreCodeStepDelegate.setLanguage(value.lang, value.code) + codeLayoutDelegate.setLanguage(value.lang, value.code) } - coreCodeStepDelegate.setDetailsContentData((value as? CodeStepQuizFormState.Lang)?.lang) + codeLayoutDelegate.setDetailsContentData((value as? CodeStepQuizFormState.Lang)?.lang) } private val viewStateDelegate = ViewStateDelegate() @@ -54,9 +55,9 @@ class CodeStepQuizFormDelegate( /** * Lang chooser */ - stepQuizCodeLangChooserAdapter += CodeLangAdapterDelegate { state = CodeStepQuizFormState.Lang(it, coreCodeStepDelegate.codeOptions.codeTemplates[it] ?: "") } + stepQuizCodeLangChooserAdapter += CodeLangAdapterDelegate { state = CodeStepQuizFormState.Lang(it, codeLayoutDelegate.codeOptions.codeTemplates[it] ?: "") } stepQuizCodeLangChooserAdapter.items = - coreCodeStepDelegate.codeOptions.codeTemplates.keys.toList().sorted() + codeLayoutDelegate.codeOptions.codeTemplates.keys.toList().sorted() stepQuizCodeLangChooserTitle.setCompoundDrawables(start = R.drawable.ic_step_quiz_code_lang) with(stepQuizCodeLangChooser) { @@ -68,7 +69,7 @@ class CodeStepQuizFormDelegate( codeLayout.codeEditor.setOnClickListener { val oldState = (state as? CodeStepQuizFormState.Lang) ?: return@setOnClickListener - coreCodeStepDelegate.onFullscreenClicked(oldState.lang, oldState.code) + onFullscreenClicked(oldState.lang, oldState.code) } } @@ -82,17 +83,17 @@ class CodeStepQuizFormDelegate( } override fun setState(state: StepQuizView.State.AttemptLoaded) { - this.state = codeStepQuizFormStateMapper.mapToFormState(coreCodeStepDelegate.codeOptions, state) + this.state = codeStepQuizFormStateMapper.mapToFormState(codeLayoutDelegate.codeOptions, state) val isEnabled = StepQuizFormResolver.isQuizEnabled(state) - coreCodeStepDelegate.setEnabled(isEnabled) + codeLayoutDelegate.setEnabled(isEnabled) } fun onLanguageSelected(lang: String) { if (state !is CodeStepQuizFormState.Lang) { return } - state = coreCodeStepDelegate.onLanguageSelected(lang) + state = CodeStepQuizFormState.Lang(lang, codeLayoutDelegate.codeOptions.codeTemplates[lang] ?: "") } fun updateCodeLayoutFromDialog(lang: String, code: String) { diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt index 21b970ff09..81b8723dbb 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt @@ -11,9 +11,9 @@ import org.stepik.android.domain.lesson.model.LessonData import org.stepik.android.presentation.step_quiz.StepQuizView import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFormDelegate import org.stepik.android.view.step_quiz.ui.fragment.DefaultStepQuizFragment +import org.stepik.android.view.step_quiz_code.ui.delegate.CodeLayoutDelegate import org.stepik.android.view.step_quiz_code.ui.delegate.CodeQuizInstructionDelegate import org.stepik.android.view.step_quiz_code.ui.delegate.CodeStepQuizFormDelegate -import org.stepik.android.view.step_quiz_code.ui.delegate.CoreCodeStepDelegate import org.stepik.android.view.step_quiz_fullscreen_code.ui.dialog.CodeStepQuizFullScreenDialogFragment class CodeStepQuizFragment : DefaultStepQuizFragment(), StepQuizView, ChangeCodeLanguageDialog.Callback, ProgrammingLanguageChooserDialogFragment.Callback, CodeStepQuizFullScreenDialogFragment.Callback { @@ -35,34 +35,16 @@ class CodeStepQuizFragment : DefaultStepQuizFragment(), StepQuizView, ChangeCode get() = arrayOf(stepQuizCodeContainer) override fun createStepQuizFormDelegate(view: View): StepQuizFormDelegate { - val actionsListener = object : CoreCodeStepDelegate.ActionsListener { - override fun onChangeLanguageClicked() { - val dialog = ChangeCodeLanguageDialog.newInstance() - if (!dialog.isAdded) { - dialog.show(childFragmentManager, null) - } - } - - override fun onFullscreenClicked(lang: String, code: String) { - val supportFragmentManager = fragmentManager - ?.takeIf { it.findFragmentByTag(CodeStepQuizFullScreenDialogFragment.TAG) == null } - ?: return - - val dialog = CodeStepQuizFullScreenDialogFragment.newInstance(lang, code, stepWrapper, lessonData) - dialog.setTargetFragment(this@CodeStepQuizFragment, CodeStepQuizFullScreenDialogFragment.CODE_PLAYGROUND_REQUEST) - dialog.show(supportFragmentManager, CodeStepQuizFullScreenDialogFragment.TAG) - } - } - codeStepQuizFormDelegate = CodeStepQuizFormDelegate( containerView = view, - coreCodeStepDelegate = CoreCodeStepDelegate( + codeLayoutDelegate = CodeLayoutDelegate( codeContainerView = view, stepWrapper = stepWrapper, codeQuizInstructionDelegate = CodeQuizInstructionDelegate(view, true), - actionsListener = actionsListener, - codeToolbarAdapter = null - ) + codeToolbarAdapter = null, + onChangeLanguageClicked = ::onChangeLanguageClicked + ), + onFullscreenClicked = ::onFullScreenClicked ) return codeStepQuizFormDelegate @@ -87,4 +69,21 @@ class CodeStepQuizFragment : DefaultStepQuizFragment(), StepQuizView, ChangeCode onActionButtonClicked() } } + + private fun onChangeLanguageClicked() { + val dialog = ChangeCodeLanguageDialog.newInstance() + if (!dialog.isAdded) { + dialog.show(childFragmentManager, null) + } + } + + private fun onFullScreenClicked(lang: String, code: String) { + val supportFragmentManager = fragmentManager + ?.takeIf { it.findFragmentByTag(CodeStepQuizFullScreenDialogFragment.TAG) == null } + ?: return + + val dialog = CodeStepQuizFullScreenDialogFragment.newInstance(lang, code, stepWrapper, lessonData) + dialog.setTargetFragment(this@CodeStepQuizFragment, CodeStepQuizFullScreenDialogFragment.CODE_PLAYGROUND_REQUEST) + dialog.show(supportFragmentManager, CodeStepQuizFullScreenDialogFragment.TAG) + } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt index 6e194856d8..94eee5e932 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt @@ -36,8 +36,8 @@ import org.stepic.droid.ui.util.hideKeyboard import org.stepic.droid.ui.util.setOnKeyboardOpenListener import org.stepic.droid.util.argument import org.stepik.android.domain.lesson.model.LessonData +import org.stepik.android.view.step_quiz_code.ui.delegate.CodeLayoutDelegate import org.stepik.android.view.step_quiz_code.ui.delegate.CodeQuizInstructionDelegate -import org.stepik.android.view.step_quiz_code.ui.delegate.CoreCodeStepDelegate import org.stepik.android.view.step_quiz_fullscreen_code.ui.adapter.CodeStepQuizFullScreenPagerAdapter import uk.co.chrisjenx.calligraphy.TypefaceUtils import javax.inject.Inject @@ -65,7 +65,7 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag private lateinit var callback: Callback - private lateinit var coreCodeStepDelegate: CoreCodeStepDelegate + private lateinit var codeLayoutDelegate: CodeLayoutDelegate private lateinit var instructionsLayout: View private lateinit var playgroundLayout: View @@ -151,17 +151,6 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag instructionsLayout.stepQuizCodeTextContent.setTextIsSelectable(true) } - val actionsListener = object : CoreCodeStepDelegate.ActionsListener { - override fun onChangeLanguageClicked() { - val dialog = ChangeCodeLanguageDialog.newInstance() - if (!dialog.isAdded) { - dialog.show(childFragmentManager, null) - } - } - - override fun onFullscreenClicked(lang: String, code: String) {} - } - if (savedInstanceState != null) { lang = savedInstanceState.getString(LANG) ?: return code = savedInstanceState.getString(CODE) ?: return @@ -176,16 +165,16 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag setupCodeToolAdapter() setupKeyboardExtension() - coreCodeStepDelegate = CoreCodeStepDelegate( + codeLayoutDelegate = CodeLayoutDelegate( codeContainerView = playgroundLayout, stepWrapper = stepWrapper, codeQuizInstructionDelegate = CodeQuizInstructionDelegate(instructionsLayout, false), - actionsListener = actionsListener, - codeToolbarAdapter = codeToolbarAdapter + codeToolbarAdapter = codeToolbarAdapter, + onChangeLanguageClicked = ::onChangeLanguageClicked ) - coreCodeStepDelegate.setLanguage(lang, code) - coreCodeStepDelegate.setDetailsContentData(lang) + codeLayoutDelegate.setLanguage(lang, code) + codeLayoutDelegate.setDetailsContentData(lang) fullScreenCodeViewPager.setCurrentItem(1, false) codeSubmitButton.setOnClickListener { @@ -273,14 +262,12 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag override fun onLanguageChosen(programmingLanguage: String) { lang = programmingLanguage - coreCodeStepDelegate.setLanguage(programmingLanguage) - coreCodeStepDelegate.setDetailsContentData(programmingLanguage) + codeLayoutDelegate.setLanguage(programmingLanguage) + codeLayoutDelegate.setDetailsContentData(programmingLanguage) } override fun onReset() { - coreCodeStepDelegate.resetCode(lang).let { codeTemplate -> - codeLayout.setText(codeTemplate) - } + codeLayoutDelegate.setLanguage(lang) } private fun setupCodeToolAdapter() { @@ -347,6 +334,13 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag fullScreenCodeSeparator.changeVisibility(needShow) } + private fun onChangeLanguageClicked() { + val dialog = ChangeCodeLanguageDialog.newInstance() + if (!dialog.isAdded) { + dialog.show(childFragmentManager, null) + } + } + interface Callback { fun onSyncCodeStateWithParent(lang: String, code: String, onSubmitClicked: Boolean = false) } From 89437562858d2fca48723024c21dc25bef99ee53 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Mon, 9 Sep 2019 23:37:39 +0300 Subject: [PATCH 43/51] clean up --- .../ui/delegate/CodeLayoutDelegate.kt | 2 +- .../CodeStepQuizFullScreenDialogFragment.kt | 22 ++++++++----------- ...l => dialog_step_quiz_code_fullscreen.xml} | 0 3 files changed, 10 insertions(+), 14 deletions(-) rename app/src/main/res/layout/{activity_step_quiz_code_fullscreen.xml => dialog_step_quiz_code_fullscreen.xml} (100%) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeLayoutDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeLayoutDelegate.kt index f5d95a3e0e..d51beef388 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeLayoutDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeLayoutDelegate.kt @@ -25,7 +25,7 @@ class CodeLayoutDelegate( /** * Actions */ - stepQuizActionChangeLang.setOnClickListener { onChangeLanguageClicked } + stepQuizActionChangeLang.setOnClickListener { onChangeLanguageClicked() } stepQuizActionChangeLang.setCompoundDrawables(end = R.drawable.ic_arrow_bottom) } diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt index 94eee5e932..64311704df 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt @@ -14,7 +14,7 @@ import android.view.Window import android.view.WindowManager import android.widget.RelativeLayout import android.widget.TextView -import kotlinx.android.synthetic.main.activity_step_quiz_code_fullscreen.* +import kotlinx.android.synthetic.main.dialog_step_quiz_code_fullscreen.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_instruction.view.* import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playground.view.* import kotlinx.android.synthetic.main.layout_step_quiz_code_keyboard_extension.* @@ -109,7 +109,7 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag } override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = - inflater.inflate(R.layout.activity_step_quiz_code_fullscreen, container, false) + inflater.inflate(R.layout.dialog_step_quiz_code_fullscreen, container, false) override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) @@ -122,18 +122,14 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag centeredToolbar.setNavigationIcon(R.drawable.ic_close_dark) centeredToolbar.setBackgroundColor(ContextCompat.getColor(requireContext(), R.color.new_primary_color)) centeredToolbar.setOnMenuItemClickListener { item -> - when (item?.itemId) { - android.R.id.home -> { - true + if (item?.itemId == R.id.action_reset_code) { + val dialog = ResetCodeDialogFragment.newInstance() + if (!dialog.isAdded) { + dialog.show(childFragmentManager, null) } - R.id.action_reset_code -> { - val dialog = ResetCodeDialogFragment.newInstance() - if (!dialog.isAdded) { - dialog.show(childFragmentManager, null) - } - true - } - else -> false + true + } else { + false } } diff --git a/app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml b/app/src/main/res/layout/dialog_step_quiz_code_fullscreen.xml similarity index 100% rename from app/src/main/res/layout/activity_step_quiz_code_fullscreen.xml rename to app/src/main/res/layout/dialog_step_quiz_code_fullscreen.xml From 7e96acecd57530919fc0f34bea68706eee950382 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Tue, 10 Sep 2019 02:49:27 +0300 Subject: [PATCH 44/51] string resources --- app/src/main/res/values-ru/strings.xml | 1 + app/src/main/res/values/strings.xml | 1 + 2 files changed, 2 insertions(+) diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index e75ce03ea5..35bb57bf18 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -713,6 +713,7 @@ Сопоставьте значения из двух списков Выберите один элемент Выберите один или несколько элементов + Введите SQL запрос Ответ не может быть пустым Ответ должен быть числом diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 840e7852c4..7f351c73c0 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -742,6 +742,7 @@ Match two lists Choose one option Choose one or multiple options + Enter an SQL query An answer cannot be empty The answer must be a number From 9857bae88edb8c19166579dcad0fd5a0b8f8823f Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Tue, 10 Sep 2019 02:50:25 +0300 Subject: [PATCH 45/51] don't recreate attempt for sql quiz --- .../android/domain/step_quiz/interactor/StepQuizInteractor.kt | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/app/src/main/java/org/stepik/android/domain/step_quiz/interactor/StepQuizInteractor.kt b/app/src/main/java/org/stepik/android/domain/step_quiz/interactor/StepQuizInteractor.kt index db783c20bb..537a1b415c 100644 --- a/app/src/main/java/org/stepik/android/domain/step_quiz/interactor/StepQuizInteractor.kt +++ b/app/src/main/java/org/stepik/android/domain/step_quiz/interactor/StepQuizInteractor.kt @@ -117,10 +117,9 @@ constructor( AppConstants.TYPE_MATH, AppConstants.TYPE_FREE_ANSWER, AppConstants.TYPE_CODE, - + AppConstants.TYPE_SQL, AppConstants.TYPE_SORTING, AppConstants.TYPE_MATCHING -> - // TODO Check if we need to recreate SQL quiz false else -> From 6b79c74fd5402c0a0f9e85b0b0de11c217d738ef Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Tue, 10 Sep 2019 02:51:03 +0300 Subject: [PATCH 46/51] hide details view if there are none --- .../ui/delegate/CodeQuizInstructionDelegate.kt | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizInstructionDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizInstructionDelegate.kt index 7522f43c81..60a1b1323f 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizInstructionDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeQuizInstructionDelegate.kt @@ -57,5 +57,10 @@ class CodeQuizInstructionDelegate( fun setCodeDetailsData(step: Step, lang: String?) { stepQuizCodeDetailsAdapter.items = codeStepQuizDetailsMapper.mapToCodeDetails(step, lang) + stepQuizCodeDetails.visibility = if (stepQuizCodeDetailsAdapter.items.isEmpty()) { + View.GONE + } else { + View.VISIBLE + } } } \ No newline at end of file From 05d8f145262812493976104dbbf7588cbf4e8486 Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Tue, 10 Sep 2019 02:56:27 +0300 Subject: [PATCH 47/51] inherit sql quiz from default quiz, remove code options from CodeLayoutDelegate, update sql quiz form delegate --- .../ui/delegate/CodeLayoutDelegate.kt | 5 +- .../ui/delegate/CodeStepQuizFormDelegate.kt | 11 +- .../ui/fragment/CodeStepQuizFragment.kt | 11 +- .../CodeStepQuizFullScreenDialogFragment.kt | 19 ++- .../ui/delegate/SqlStepQuizFormDelegate.kt | 54 +++---- .../ui/fragment/SqlStepQuizFragment.kt | 137 ++++-------------- .../main/res/layout/layout_step_quiz_sql.xml | 46 +++--- 7 files changed, 96 insertions(+), 187 deletions(-) diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeLayoutDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeLayoutDelegate.kt index d51beef388..94d930e035 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeLayoutDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeLayoutDelegate.kt @@ -11,6 +11,7 @@ import org.stepic.droid.ui.util.setCompoundDrawables class CodeLayoutDelegate( codeContainerView: View, private val stepWrapper: StepPersistentWrapper, + private val codeTemplates: Map, private val codeQuizInstructionDelegate: CodeQuizInstructionDelegate, private var codeToolbarAdapter: CodeToolbarAdapter?, private val onChangeLanguageClicked: () -> Unit @@ -19,8 +20,6 @@ class CodeLayoutDelegate( private val codeLayout = codeContainerView.codeStepLayout private val stepQuizActionChangeLang = codeContainerView.stepQuizActionChangeLang - val codeOptions = stepWrapper.step.block?.options ?: throw IllegalArgumentException("Code options shouldn't be null") - init { /** * Actions @@ -35,7 +34,7 @@ class CodeLayoutDelegate( fun setLanguage(lang: String, code: String? = null) { codeLayout.lang = extensionForLanguage(lang) stepQuizActionChangeLang.text = lang - codeLayout.setText(code ?: codeOptions.codeTemplates[lang] ?: "") + codeLayout.setText(code ?: codeTemplates[lang] ?: "") codeToolbarAdapter?.setLanguage(lang) } diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt index df1d955a29..9cf7fe1991 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/delegate/CodeStepQuizFormDelegate.kt @@ -8,6 +8,7 @@ import kotlinx.android.synthetic.main.layout_step_quiz_code_fullscreen_playgroun import org.stepic.droid.R import org.stepic.droid.ui.util.setCompoundDrawables import org.stepik.android.model.Reply +import org.stepik.android.model.code.CodeOptions import org.stepik.android.presentation.step_quiz.StepQuizView import org.stepik.android.presentation.step_quiz.model.ReplyResult import org.stepik.android.view.step_quiz.resolver.StepQuizFormResolver @@ -20,6 +21,7 @@ import ru.nobird.android.ui.adapterssupport.DefaultDelegateAdapter class CodeStepQuizFormDelegate( containerView: View, + private val codeOptions: CodeOptions, private val codeLayoutDelegate: CodeLayoutDelegate, private val onFullscreenClicked: (lang: String, code: String) -> Unit ) : StepQuizFormDelegate { @@ -55,9 +57,8 @@ class CodeStepQuizFormDelegate( /** * Lang chooser */ - stepQuizCodeLangChooserAdapter += CodeLangAdapterDelegate { state = CodeStepQuizFormState.Lang(it, codeLayoutDelegate.codeOptions.codeTemplates[it] ?: "") } - stepQuizCodeLangChooserAdapter.items = - codeLayoutDelegate.codeOptions.codeTemplates.keys.toList().sorted() + stepQuizCodeLangChooserAdapter += CodeLangAdapterDelegate { state = CodeStepQuizFormState.Lang(it, codeOptions.codeTemplates[it] ?: "") } + stepQuizCodeLangChooserAdapter.items = codeOptions.codeTemplates.keys.toList().sorted() stepQuizCodeLangChooserTitle.setCompoundDrawables(start = R.drawable.ic_step_quiz_code_lang) with(stepQuizCodeLangChooser) { @@ -83,7 +84,7 @@ class CodeStepQuizFormDelegate( } override fun setState(state: StepQuizView.State.AttemptLoaded) { - this.state = codeStepQuizFormStateMapper.mapToFormState(codeLayoutDelegate.codeOptions, state) + this.state = codeStepQuizFormStateMapper.mapToFormState(codeOptions, state) val isEnabled = StepQuizFormResolver.isQuizEnabled(state) codeLayoutDelegate.setEnabled(isEnabled) @@ -93,7 +94,7 @@ class CodeStepQuizFormDelegate( if (state !is CodeStepQuizFormState.Lang) { return } - state = CodeStepQuizFormState.Lang(lang, codeLayoutDelegate.codeOptions.codeTemplates[lang] ?: "") + state = CodeStepQuizFormState.Lang(lang, codeOptions.codeTemplates[lang] ?: "") } fun updateCodeLayoutFromDialog(lang: String, code: String) { diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt index 81b8723dbb..fab8d6ca62 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_code/ui/fragment/CodeStepQuizFragment.kt @@ -8,6 +8,7 @@ import org.stepic.droid.persistence.model.StepPersistentWrapper import org.stepic.droid.ui.dialogs.ChangeCodeLanguageDialog import org.stepic.droid.ui.dialogs.ProgrammingLanguageChooserDialogFragment import org.stepik.android.domain.lesson.model.LessonData +import org.stepik.android.model.code.CodeOptions import org.stepik.android.presentation.step_quiz.StepQuizView import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFormDelegate import org.stepik.android.view.step_quiz.ui.fragment.DefaultStepQuizFragment @@ -26,6 +27,8 @@ class CodeStepQuizFragment : DefaultStepQuizFragment(), StepQuizView, ChangeCode } } + private lateinit var codeOptions: CodeOptions + private lateinit var codeStepQuizFormDelegate: CodeStepQuizFormDelegate override val quizLayoutRes: Int = @@ -35,11 +38,15 @@ class CodeStepQuizFragment : DefaultStepQuizFragment(), StepQuizView, ChangeCode get() = arrayOf(stepQuizCodeContainer) override fun createStepQuizFormDelegate(view: View): StepQuizFormDelegate { + codeOptions = stepWrapper.step.block?.options ?: throw IllegalArgumentException("Code options shouldn't be null") + codeStepQuizFormDelegate = CodeStepQuizFormDelegate( containerView = view, + codeOptions = codeOptions, codeLayoutDelegate = CodeLayoutDelegate( codeContainerView = view, stepWrapper = stepWrapper, + codeTemplates = codeOptions.codeTemplates, codeQuizInstructionDelegate = CodeQuizInstructionDelegate(view, true), codeToolbarAdapter = null, onChangeLanguageClicked = ::onChangeLanguageClicked @@ -82,8 +89,8 @@ class CodeStepQuizFragment : DefaultStepQuizFragment(), StepQuizView, ChangeCode ?.takeIf { it.findFragmentByTag(CodeStepQuizFullScreenDialogFragment.TAG) == null } ?: return - val dialog = CodeStepQuizFullScreenDialogFragment.newInstance(lang, code, stepWrapper, lessonData) - dialog.setTargetFragment(this@CodeStepQuizFragment, CodeStepQuizFullScreenDialogFragment.CODE_PLAYGROUND_REQUEST) + val dialog = CodeStepQuizFullScreenDialogFragment.newInstance(lang, code, codeOptions.codeTemplates, stepWrapper, lessonData) + dialog.setTargetFragment(this, CodeStepQuizFullScreenDialogFragment.CODE_PLAYGROUND_REQUEST) dialog.show(supportFragmentManager, CodeStepQuizFullScreenDialogFragment.TAG) } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt index 64311704df..c573e88bd8 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_fullscreen_code/ui/dialog/CodeStepQuizFullScreenDialogFragment.kt @@ -47,14 +47,15 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag const val TAG = "CodeStepQuizFullScreenDialogFragment" const val CODE_PLAYGROUND_REQUEST = 153 - private const val LANG = "LANG" - private const val CODE = "CODE" + private const val ARG_LANG = "LANG" + private const val ARG_CODE = "CODE" - fun newInstance(lang: String, code: String, stepPersistentWrapper: StepPersistentWrapper, lessonData: LessonData): DialogFragment = + fun newInstance(lang: String, code: String, codeTemplates: Map, stepPersistentWrapper: StepPersistentWrapper, lessonData: LessonData): DialogFragment = CodeStepQuizFullScreenDialogFragment() .apply { this.lang = lang this.code = code + this.codeTemplates = codeTemplates this.stepWrapper = stepPersistentWrapper this.lessonData = lessonData } @@ -82,6 +83,7 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag private var lang: String by argument() private var code: String by argument() + private var codeTemplates: Map by argument() private var lessonData: LessonData by argument() private var stepWrapper: StepPersistentWrapper by argument() @@ -148,8 +150,8 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag } if (savedInstanceState != null) { - lang = savedInstanceState.getString(LANG) ?: return - code = savedInstanceState.getString(CODE) ?: return + lang = savedInstanceState.getString(ARG_LANG) ?: return + code = savedInstanceState.getString(ARG_CODE) ?: return } submitButtonSeparator = playgroundLayout.submitButtonSeparator @@ -164,6 +166,7 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag codeLayoutDelegate = CodeLayoutDelegate( codeContainerView = playgroundLayout, stepWrapper = stepWrapper, + codeTemplates = codeTemplates, codeQuizInstructionDelegate = CodeQuizInstructionDelegate(instructionsLayout, false), codeToolbarAdapter = codeToolbarAdapter, onChangeLanguageClicked = ::onChangeLanguageClicked @@ -181,8 +184,8 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag override fun onSaveInstanceState(outState: Bundle) { super.onSaveInstanceState(outState) - outState.putString(LANG, lang) - outState.putString(CODE, codeLayout.text.toString()) + outState.putString(ARG_LANG, lang) + outState.putString(ARG_CODE, codeLayout.text.toString()) } private fun initViewPager() { @@ -248,7 +251,7 @@ class CodeStepQuizFullScreenDialogFragment : DialogFragment(), ChangeCodeLanguag } override fun onChangeLanguage() { - val languages = stepWrapper.step.block?.options?.limits?.keys?.sorted()?.toTypedArray() ?: emptyArray() + val languages = codeTemplates.keys.sorted().toTypedArray() val dialog = ProgrammingLanguageChooserDialogFragment.newInstance(languages) if (!dialog.isAdded) { diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_sql/ui/delegate/SqlStepQuizFormDelegate.kt b/app/src/main/java/org/stepik/android/view/step_quiz_sql/ui/delegate/SqlStepQuizFormDelegate.kt index 6a1042cfdb..77ce0813bc 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_sql/ui/delegate/SqlStepQuizFormDelegate.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_sql/ui/delegate/SqlStepQuizFormDelegate.kt @@ -1,66 +1,46 @@ package org.stepik.android.view.step_quiz_sql.ui.delegate import android.view.View +import kotlinx.android.synthetic.main.fragment_step_quiz.view.* import kotlinx.android.synthetic.main.layout_step_quiz_code.view.* import org.stepic.droid.R -import org.stepic.droid.model.code.extensionForLanguage -import org.stepic.droid.persistence.model.StepPersistentWrapper +import org.stepic.droid.model.code.ProgrammingLanguage import org.stepik.android.model.Reply import org.stepik.android.presentation.step_quiz.StepQuizView import org.stepik.android.presentation.step_quiz.model.ReplyResult import org.stepik.android.view.step_quiz.resolver.StepQuizFormResolver import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFormDelegate -import org.stepik.android.view.step_quiz_code.model.CodeStepQuizFormState -import org.stepik.android.view.ui.delegate.ViewStateDelegate class SqlStepQuizFormDelegate( containerView: View, - private val stepWrapper: StepPersistentWrapper + private val onFullscreenClicked: (lang: String, code: String) -> Unit ) : StepQuizFormDelegate { - companion object { - private const val SQL_LANG = "sql" - } - private var state: CodeStepQuizFormState = CodeStepQuizFormState.Idle - set(value) { - field = value - - viewStateDelegate.switchState(value) - when (value) { - is CodeStepQuizFormState.Lang -> { - codeLayout.setText(value.code) - codeLayout.lang = extensionForLanguage(value.lang) - } - } - } + private val quizDescription = containerView.stepQuizDescription - private val viewStateDelegate = ViewStateDelegate() - - private val stepQuizActions = containerView.stepQuizActions private val codeLayout = containerView.codeStepLayout init { - viewStateDelegate.addState() - viewStateDelegate.addState(codeLayout, stepQuizActions) - } + quizDescription.setText(R.string.step_quiz_sql_description) - override fun createReply(): ReplyResult { - val state = state - return if (state is CodeStepQuizFormState.Lang) { - ReplyResult.Success(Reply(solveSql = codeLayout.text.toString())) - } else { - ReplyResult.Error(codeLayout.context.getString(R.string.step_quiz_code_empty_lang)) + codeLayout.codeEditor.isFocusable = false + codeLayout.codeEditor.setOnClickListener { + onFullscreenClicked(ProgrammingLanguage.SQL.serverPrintableName, codeLayout.text.toString()) } } + override fun createReply(): ReplyResult = + ReplyResult.Success(Reply(solveSql = codeLayout.text.toString())) + override fun setState(state: StepQuizView.State.AttemptLoaded) { val submission = (state.submissionState as? StepQuizView.SubmissionState.Loaded) ?.submission - this.state = CodeStepQuizFormState.Lang(SQL_LANG, submission?.reply?.solveSql ?: "") - - val isEnabled = StepQuizFormResolver.isQuizEnabled(state) - // codeLayout.isEnabled = isEnabled + codeLayout.setText(submission?.reply?.solveSql ?: "") + codeLayout.lang = ProgrammingLanguage.SQL.serverPrintableName + codeLayout.isEnabled = StepQuizFormResolver.isQuizEnabled(state) } - + fun updateCodeLayoutFromDialog(code: String) { + codeLayout.setText(code) + } } \ No newline at end of file diff --git a/app/src/main/java/org/stepik/android/view/step_quiz_sql/ui/fragment/SqlStepQuizFragment.kt b/app/src/main/java/org/stepik/android/view/step_quiz_sql/ui/fragment/SqlStepQuizFragment.kt index 80b7c22946..f68b8db2bf 100644 --- a/app/src/main/java/org/stepik/android/view/step_quiz_sql/ui/fragment/SqlStepQuizFragment.kt +++ b/app/src/main/java/org/stepik/android/view/step_quiz_sql/ui/fragment/SqlStepQuizFragment.kt @@ -1,36 +1,19 @@ package org.stepik.android.view.step_quiz_sql.ui.fragment -import android.arch.lifecycle.ViewModelProvider -import android.arch.lifecycle.ViewModelProviders -import android.os.Bundle -import android.support.design.widget.Snackbar import android.support.v4.app.Fragment -import android.support.v4.content.ContextCompat -import android.view.LayoutInflater import android.view.View -import android.view.ViewGroup -import kotlinx.android.synthetic.main.error_no_connection_with_button_small.view.* -import kotlinx.android.synthetic.main.fragment_step_quiz.* import kotlinx.android.synthetic.main.layout_step_quiz_code.* -import kotlinx.android.synthetic.main.view_step_quiz_submit_button.* import org.stepic.droid.R -import org.stepic.droid.base.App -import org.stepic.droid.core.ScreenManager -import org.stepic.droid.fonts.FontsProvider +import org.stepic.droid.model.code.ProgrammingLanguage import org.stepic.droid.persistence.model.StepPersistentWrapper -import org.stepic.droid.ui.listeners.NextMoveable -import org.stepic.droid.util.argument -import org.stepic.droid.util.setTextColor import org.stepik.android.domain.lesson.model.LessonData -import org.stepik.android.presentation.step_quiz.StepQuizPresenter import org.stepik.android.presentation.step_quiz.StepQuizView -import org.stepik.android.view.step_quiz.ui.delegate.StepQuizDelegate -import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFeedbackBlocksDelegate +import org.stepik.android.view.step_quiz.ui.delegate.StepQuizFormDelegate +import org.stepik.android.view.step_quiz.ui.fragment.DefaultStepQuizFragment +import org.stepik.android.view.step_quiz_fullscreen_code.ui.dialog.CodeStepQuizFullScreenDialogFragment import org.stepik.android.view.step_quiz_sql.ui.delegate.SqlStepQuizFormDelegate -import org.stepik.android.view.ui.delegate.ViewStateDelegate -import javax.inject.Inject -class SqlStepQuizFragment : Fragment(), StepQuizView { +class SqlStepQuizFragment : DefaultStepQuizFragment(), StepQuizView, CodeStepQuizFullScreenDialogFragment.Callback { companion object { fun newInstance(stepPersistentWrapper: StepPersistentWrapper, lessonData: LessonData): Fragment = SqlStepQuizFragment() @@ -40,104 +23,36 @@ class SqlStepQuizFragment : Fragment(), StepQuizView { } } - @Inject - internal lateinit var viewModelFactory: ViewModelProvider.Factory - - @Inject - internal lateinit var fontsProvider: FontsProvider - - @Inject - internal lateinit var screenManager: ScreenManager - - private lateinit var presenter: StepQuizPresenter - - private var lessonData: LessonData by argument() - private var stepWrapper: StepPersistentWrapper by argument() - - private lateinit var viewStateDelegate: ViewStateDelegate - private lateinit var stepQuizDelegate: StepQuizDelegate - private lateinit var sqlStepQuizFormDelegate: SqlStepQuizFormDelegate - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - injectComponent() - - presenter = ViewModelProviders.of(this, viewModelFactory).get(StepQuizPresenter::class.java) - presenter.onStepData(stepWrapper, lessonData) - } - - private fun injectComponent() { - App.component() - .stepComponentBuilder() - .build() - .inject(this) - } + override val quizLayoutRes: Int = + R.layout.layout_step_quiz_sql - override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? = - (inflater.inflate(R.layout.fragment_step_quiz, container, false) as ViewGroup) - .apply { - addView(inflater.inflate(R.layout.layout_step_quiz_sql, this, false)) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - stepQuizDescription.visibility = View.GONE - - viewStateDelegate = ViewStateDelegate() - viewStateDelegate.addState() - viewStateDelegate.addState(stepQuizProgress) - viewStateDelegate.addState(stepQuizDiscountingPolicy, stepQuizFeedbackBlocks, stepQuizCodeContainer, stepQuizActionContainer) - viewStateDelegate.addState(stepQuizNetworkError) - - stepQuizNetworkError.tryAgain.setOnClickListener { presenter.onStepData(stepWrapper, lessonData, forceUpdate = true) } - - sqlStepQuizFormDelegate = SqlStepQuizFormDelegate(view, stepWrapper) - - stepQuizDelegate = - StepQuizDelegate( - step = stepWrapper.step, - lessonData = lessonData, - stepQuizFormDelegate = sqlStepQuizFormDelegate, - stepQuizFeedbackBlocksDelegate = StepQuizFeedbackBlocksDelegate( - stepQuizFeedbackBlocks, - fontsProvider, - stepWrapper.step.actions?.doReview != null, - { screenManager.openStepInWeb(requireContext(), stepWrapper.step) } - ), - stepQuizActionButton = stepQuizAction, - stepRetryButton = stepQuizRetry, - stepQuizDiscountingPolicy = stepQuizDiscountingPolicy, - stepQuizPresenter = presenter - ) { - (parentFragment as? NextMoveable)?.moveNext() - } - } - - - override fun onStart() { - super.onStart() - presenter.attachView(this) - } + override val quizViews: Array + get() = arrayOf(stepQuizCodeContainer) - override fun onStop() { - presenter.detachView(this) - stepQuizDelegate.syncReplyState() - super.onStop() + override fun createStepQuizFormDelegate(view: View): StepQuizFormDelegate { + sqlStepQuizFormDelegate = SqlStepQuizFormDelegate( + containerView = view, + onFullscreenClicked = ::onFullScreenClicked + ) + return sqlStepQuizFormDelegate } - override fun setState(state: StepQuizView.State) { - viewStateDelegate.switchState(state) - if (state is StepQuizView.State.AttemptLoaded) { - stepQuizDelegate.setState(state) + override fun onSyncCodeStateWithParent(lang: String, code: String, onSubmitClicked: Boolean) { + sqlStepQuizFormDelegate.updateCodeLayoutFromDialog(code) + if (onSubmitClicked) { + onActionButtonClicked() } } - override fun showNetworkError() { - val view = view ?: return + private fun onFullScreenClicked(lang: String, code: String) { + val supportFragmentManager = fragmentManager + ?.takeIf { it.findFragmentByTag(CodeStepQuizFullScreenDialogFragment.TAG) == null } + ?: return - Snackbar - .make(view, R.string.no_connection, Snackbar.LENGTH_SHORT) - .setTextColor(ContextCompat.getColor(requireContext(), R.color.white)) - .show() + val dialog = CodeStepQuizFullScreenDialogFragment.newInstance(lang, code, mapOf(ProgrammingLanguage.SQL.serverPrintableName to ""), stepWrapper, lessonData) + dialog.setTargetFragment(this, CodeStepQuizFullScreenDialogFragment.CODE_PLAYGROUND_REQUEST) + dialog.show(supportFragmentManager, CodeStepQuizFullScreenDialogFragment.TAG) } } \ No newline at end of file diff --git a/app/src/main/res/layout/layout_step_quiz_sql.xml b/app/src/main/res/layout/layout_step_quiz_sql.xml index 3bcbacd0b0..8eaa24e751 100644 --- a/app/src/main/res/layout/layout_step_quiz_sql.xml +++ b/app/src/main/res/layout/layout_step_quiz_sql.xml @@ -14,42 +14,46 @@ app:layout_constraintVertical_bias="0" - app:layout_constraintTop_toBottomOf="@id/stepQuizDiscountingPolicy" + app:layout_constraintTop_toBottomOf="@id/stepQuizDescription" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toTopOf="@id/stepQuizFeedbackBlocks"> + + - + android:paddingLeft="16dp" + android:paddingRight="16dp" - + tools:text="python3 dasjdlkas dadlj aldj akjsdlakj lkjasdkl jkdas" /> Date: Tue, 10 Sep 2019 11:30:49 +0300 Subject: [PATCH 48/51] remove old sql quiz --- .../droid/ui/fragments/SqlStepFragment.kt | 96 ------------------- .../util/resolvers/StepTypeResolverImpl.java | 3 - app/src/main/res/layout/view_py_step.xml | 11 --- app/src/main/res/layout/view_sql_quiz.xml | 18 ---- 4 files changed, 128 deletions(-) delete mode 100644 app/src/main/java/org/stepic/droid/ui/fragments/SqlStepFragment.kt delete mode 100644 app/src/main/res/layout/view_py_step.xml delete mode 100644 app/src/main/res/layout/view_sql_quiz.xml diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/SqlStepFragment.kt b/app/src/main/java/org/stepic/droid/ui/fragments/SqlStepFragment.kt deleted file mode 100644 index 74e5c4d3fc..0000000000 --- a/app/src/main/java/org/stepic/droid/ui/fragments/SqlStepFragment.kt +++ /dev/null @@ -1,96 +0,0 @@ -package org.stepic.droid.ui.fragments - -import android.os.Bundle -import android.support.v7.widget.LinearLayoutManager -import android.view.View -import android.view.ViewGroup -import android.view.ViewTreeObserver -import kotlinx.android.synthetic.main.fragment_step_attempt.* -import kotlinx.android.synthetic.main.view_code_editor.* -import kotlinx.android.synthetic.main.view_code_editor_layout.* -import kotlinx.android.synthetic.main.view_code_toolbar.* -import org.stepic.droid.R -import org.stepic.droid.code.util.CodeToolbarUtil -import org.stepik.android.model.attempts.Attempt -import org.stepic.droid.ui.adapters.CodeToolbarAdapter -import org.stepic.droid.ui.util.listenKeyboardChanges -import org.stepic.droid.ui.util.stopListenKeyboardChanges -import org.stepik.android.model.Reply - -class SqlStepFragment: StepAttemptFragment(), CodeToolbarAdapter.OnSymbolClickListener { - companion object { - private const val SQL_LANG = "sql" - fun newInstance(): SqlStepFragment = SqlStepFragment() - } - - private var codeToolbarAdapter: CodeToolbarAdapter? = null - private var onGlobalLayoutListener: ViewTreeObserver.OnGlobalLayoutListener? = null - - override fun onCreate(savedInstanceState: Bundle?) { - super.onCreate(savedInstanceState) - codeToolbarAdapter = CodeToolbarAdapter(requireContext()) - } - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - super.onViewCreated(view, savedInstanceState) - val viewGroup = layoutInflater.inflate(R.layout.view_sql_quiz, attemptContainer, false) as ViewGroup - attemptContainer.addView(viewGroup) - codeEditor.lang = SQL_LANG - - codeToolbarView.adapter = codeToolbarAdapter - codeToolbarAdapter?.onSymbolClickListener = this - codeToolbarAdapter?.setLanguage(SQL_LANG) - codeToolbarView.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) - codeEditor.codeToolbarAdapter = codeToolbarAdapter - } - - override fun onStart() { - super.onStart() - onGlobalLayoutListener = listenKeyboardChanges( - rootFrameLayoutInStepAttempt, - onKeyboardShown = { - codeToolbarView.visibility = View.VISIBLE - codeToolbarSpaceInContainer.visibility = View.VISIBLE - }, - onKeyboardHidden = { - codeToolbarView.visibility = View.GONE - codeToolbarSpaceInContainer.visibility = View.GONE - } - ) - } - - override fun onStop() { - super.onStop() - stopListenKeyboardChanges(rootFrameLayoutInStepAttempt, onGlobalLayoutListener) - onGlobalLayoutListener = null - } - - override fun onDestroyView() { - super.onDestroyView() - codeToolbarAdapter?.onSymbolClickListener = null - } - - override fun onDestroy() { - super.onDestroy() - codeToolbarAdapter = null - } - - override fun onSymbolClick(symbol: String, offset: Int) { - codeEditor.insertText(CodeToolbarUtil.mapToolbarSymbolToPrintable(symbol, codeEditor.indentSize), offset) - } - - override fun showAttempt(attempt: Attempt?) { - // no-op - } - - override fun generateReply() = Reply(solveSql = codeEditor.text.toString()) - - - override fun blockUIBeforeSubmit(needBlock: Boolean) { - codeEdit.isEnabled = !needBlock - } - - override fun onRestoreSubmission() { - codeEditor.setText(submission.reply?.solveSql) - } -} \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolverImpl.java b/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolverImpl.java index 164c4e14c2..0d966d654f 100644 --- a/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolverImpl.java +++ b/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolverImpl.java @@ -7,7 +7,6 @@ import org.stepic.droid.R; import org.stepic.droid.base.StepBaseFragment; import org.stepic.droid.di.AppSingleton; -import org.stepic.droid.ui.fragments.SqlStepFragment; import org.stepic.droid.ui.quiz.ChoiceQuizDelegate; import org.stepic.droid.ui.quiz.NotSupportedQuizDelegate; import org.stepic.droid.ui.quiz.NumberQuizDelegate; @@ -96,8 +95,6 @@ public StepBaseFragment getFragment(Step step) { String type = step.getBlock().getName(); switch (type) { - case AppConstants.TYPE_SQL: - return SqlStepFragment.Companion.newInstance(); default: return null; } diff --git a/app/src/main/res/layout/view_py_step.xml b/app/src/main/res/layout/view_py_step.xml deleted file mode 100644 index e2fa247450..0000000000 --- a/app/src/main/res/layout/view_py_step.xml +++ /dev/null @@ -1,11 +0,0 @@ - - \ No newline at end of file diff --git a/app/src/main/res/layout/view_sql_quiz.xml b/app/src/main/res/layout/view_sql_quiz.xml deleted file mode 100644 index 881c3e8e66..0000000000 --- a/app/src/main/res/layout/view_sql_quiz.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - \ No newline at end of file From 5333d9ed5d602ea69b202842082885c797dfd87d Mon Sep 17 00:00:00 2001 From: Rostislav Smirnov Date: Tue, 10 Sep 2019 12:00:37 +0300 Subject: [PATCH 49/51] remove old container logic --- .../stepic/droid/base/StepBaseFragment.java | 370 --------- .../core/presenters/AnonymousPresenter.kt | 23 - .../core/presenters/RouteStepPresenter.kt | 276 ------- .../core/presenters/StepAttemptPresenter.kt | 337 -------- .../presenters/contracts/AnonymousView.kt | 6 - .../presenters/contracts/RouteStepView.java | 23 - .../presenters/contracts/StepAttemptView.kt | 33 - .../org/stepic/droid/di/step/StepComponent.kt | 6 - .../droid/ui/adapters/StepFragmentAdapter.kt | 16 +- .../stepic/droid/ui/custom/StepTextWrapper.kt | 49 -- .../ui/fragments/StepAttemptFragment.java | 738 ------------------ .../droid/util/resolvers/StepTypeResolver.kt | 6 +- .../util/resolvers/StepTypeResolverImpl.java | 45 -- app/src/main/res/layout/auth_line_view.xml | 18 - .../main/res/layout/fragment_step_attempt.xml | 146 ---- app/src/main/res/layout/next_lesson_view.xml | 34 - app/src/main/res/layout/open_comment_view.xml | 17 - .../presenters/RouteStepPresenterTest.java | 410 ---------- 18 files changed, 2 insertions(+), 2551 deletions(-) delete mode 100644 app/src/main/java/org/stepic/droid/base/StepBaseFragment.java delete mode 100644 app/src/main/java/org/stepic/droid/core/presenters/AnonymousPresenter.kt delete mode 100644 app/src/main/java/org/stepic/droid/core/presenters/RouteStepPresenter.kt delete mode 100644 app/src/main/java/org/stepic/droid/core/presenters/StepAttemptPresenter.kt delete mode 100644 app/src/main/java/org/stepic/droid/core/presenters/contracts/AnonymousView.kt delete mode 100644 app/src/main/java/org/stepic/droid/core/presenters/contracts/RouteStepView.java delete mode 100644 app/src/main/java/org/stepic/droid/core/presenters/contracts/StepAttemptView.kt delete mode 100644 app/src/main/java/org/stepic/droid/ui/custom/StepTextWrapper.kt delete mode 100644 app/src/main/java/org/stepic/droid/ui/fragments/StepAttemptFragment.java delete mode 100644 app/src/main/res/layout/auth_line_view.xml delete mode 100644 app/src/main/res/layout/fragment_step_attempt.xml delete mode 100644 app/src/main/res/layout/next_lesson_view.xml delete mode 100644 app/src/main/res/layout/open_comment_view.xml delete mode 100644 app/src/test/java/org/stepic/droid/core/presenters/RouteStepPresenterTest.java diff --git a/app/src/main/java/org/stepic/droid/base/StepBaseFragment.java b/app/src/main/java/org/stepic/droid/base/StepBaseFragment.java deleted file mode 100644 index 413811a5f4..0000000000 --- a/app/src/main/java/org/stepic/droid/base/StepBaseFragment.java +++ /dev/null @@ -1,370 +0,0 @@ -package org.stepic.droid.base; - -import android.os.Bundle; -import android.support.annotation.Nullable; -import android.support.v4.app.DialogFragment; -import android.support.v4.widget.NestedScrollView; -import android.view.Menu; -import android.view.MenuInflater; -import android.view.MenuItem; -import android.view.View; -import android.widget.TextView; -import android.widget.Toast; - -import org.jetbrains.annotations.NotNull; -import org.stepic.droid.R; -import org.stepic.droid.analytic.Analytic; -import org.stepic.droid.core.commentcount.contract.CommentCountListener; -import org.stepic.droid.core.presenters.AnonymousPresenter; -import org.stepic.droid.core.presenters.RouteStepPresenter; -import org.stepic.droid.core.presenters.contracts.AnonymousView; -import org.stepic.droid.core.presenters.contracts.RouteStepView; -import org.stepic.droid.persistence.model.StepPersistentWrapper; -import org.stepic.droid.storage.operations.DatabaseFacade; -import org.stepic.droid.ui.custom.StepTextWrapper; -import org.stepic.droid.ui.dialogs.LoadingProgressDialogFragment; -import org.stepic.droid.ui.dialogs.StepShareDialogFragment; -import org.stepic.droid.util.AppConstants; -import org.stepic.droid.util.ProgressHelper; -import org.stepik.android.model.Lesson; -import org.stepik.android.model.Section; -import org.stepik.android.model.Step; -import org.stepik.android.model.Unit; -import org.stepik.android.remote.step.model.StepResponse; - -import java.lang.ref.WeakReference; -import java.util.concurrent.ThreadPoolExecutor; - -import javax.inject.Inject; - -import butterknife.BindView; -import io.reactivex.SingleObserver; -import io.reactivex.android.schedulers.AndroidSchedulers; -import io.reactivex.disposables.Disposable; -import io.reactivex.schedulers.Schedulers; - -public abstract class StepBaseFragment extends FragmentBase - implements RouteStepView, - AnonymousView, - CommentCountListener { - - @BindView(R.id.open_comments_text) - protected TextView textForComment; - - @BindView(R.id.auth_line_text) - TextView authLineText; - - /** - * default: Gone - */ - @BindView(R.id.route_lesson_root) - protected View routeLessonRoot; - - /** - * do not make it gone, only invisible. Default: invisible - */ - @BindView(R.id.next_lesson_view) - protected View nextLessonView; - - /** - * do not make it gone, only invisible. Default: invisible - */ - @BindView(R.id.previous_lesson_view) - protected View previousLessonView; - - @BindView(R.id.rootScrollView) - @Nullable - protected NestedScrollView nestedScrollView; - - protected StepPersistentWrapper stepWrapper; - protected Step step; - protected Lesson lesson; - protected Section section; - - @Nullable - protected Unit unit; - - private final static String LOAD_DIALOG_TAG = "stepBaseFragmentLoad"; - - private final static String ROUTER_ROOT_VISIBILITY_KEY = "visibility_router_root"; - private final static String NEXT_LESSON_VISIBILITY_KEY = "visibility_next_lesson"; - private final static String PREVIOUS_LESSON_VISIBILITY_KEY = "visibility_previous_lesson"; - - @Inject - protected StepTextWrapper stepTextWrapper; - - @Inject - protected RouteStepPresenter routeStepPresenter; - - @Inject - AnonymousPresenter anonymousPresenter; - - @Inject - Client commentCountListenerClient; - - @Override - protected void injectComponent() { - App.Companion - .componentManager() - .stepComponent(step.getId()) - .inject(this); - } - - @Override - protected final void onReleaseComponent() { - App - .Companion - .componentManager() - .releaseStepComponent(step.getId()); - } - - @Override - public void onCreate(Bundle savedInstanceState) { - stepWrapper = getArguments().getParcelable(AppConstants.KEY_STEP_BUNDLE); - step = stepWrapper.getStep(); - lesson = getArguments().getParcelable(AppConstants.KEY_LESSON_BUNDLE); - unit = getArguments().getParcelable(AppConstants.KEY_UNIT_BUNDLE); - section = getArguments().getParcelable(AppConstants.KEY_SECTION_BUNDLE); - super.onCreate(savedInstanceState); - } - - @Override - public void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - - setHasOptionsMenu(true); - stepTextWrapper.bind(step); - - updateCommentState(); - - commentCountListenerClient.subscribe(this); - routeStepPresenter.attachView(this); - anonymousPresenter.attachView(this); - anonymousPresenter.checkForAnonymous(); - if (unit != null) { - nextLessonView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - routeStepPresenter.clickNextLesson(unit); - } - }); - previousLessonView.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - routeStepPresenter.clickPreviousLesson(unit); - } - }); - - - routeStepPresenter.checkStepForFirst(step.getId(), lesson, unit); - routeStepPresenter.checkStepForLast(step.getId(), lesson, unit); - } - } - - protected abstract void attachStepTextWrapper(); - protected abstract void detachStepTextWrapper(); - - @Override - public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { - super.onViewCreated(view, savedInstanceState); - attachStepTextWrapper(); - authLineText.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - getScreenManager().showLaunchScreen(getActivity()); - } - }); - } - - private void updateCommentState() { - if (step != null && step.getDiscussionProxy() != null) { - showComment(); - } else { - textForComment.setVisibility(View.GONE); - } - } - - private void showComment() { - textForComment.setVisibility(View.VISIBLE); - textForComment.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - int discussionCount = step.getDiscussionsCount(); - getAnalytic().reportEvent(Analytic.Comments.OPEN_FROM_STEP_UI); - - if (discussionCount == 0) { - getScreenManager().openComments(getActivity(), step.getDiscussionProxy(), step.getId(), true); //show new form, but in back stack comment oldList is exist. - } else { - getScreenManager().openComments(getActivity(), step.getDiscussionProxy(), step.getId()); - } - } - }); - int discussionCount = step.getDiscussionsCount(); - if (discussionCount > 0) { - textForComment.setText(App.Companion.getAppContext().getString(R.string.step_discussion_show, discussionCount)); - } else { - textForComment.setText(App.Companion.getAppContext().getResources().getString(R.string.open_comments_zero)); - } - } - - @Override - public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) { - inflater.inflate(R.menu.share_menu, menu); - super.onCreateOptionsMenu(menu, inflater); - } - - @Override - public boolean onOptionsItemSelected(MenuItem item) { - switch (item.getItemId()) { - case R.id.menu_item_share: - getAnalytic().reportEvent(Analytic.Interaction.SHARE_STEP_CLICK); - DialogFragment bottomSheetDialogFragment = StepShareDialogFragment.newInstance(step, lesson, unit); - if (bottomSheetDialogFragment != null && !bottomSheetDialogFragment.isAdded()) { - bottomSheetDialogFragment.show(getFragmentManager(), null); - } - return true; - } - return super.onOptionsItemSelected(item); - } - - - @Override - public void onDestroyView() { - detachStepTextWrapper(); - authLineText.setOnClickListener(null); - textForComment.setOnClickListener(null); - routeStepPresenter.detachView(this); - commentCountListenerClient.unsubscribe(this); - anonymousPresenter.detachView(this); - nextLessonView.setOnClickListener(null); - previousLessonView.setOnClickListener(null); - super.onDestroyView(); - } - - public void onDiscussionWasUpdatedFromInternet(Step updatedStep) { - if (updatedStep.getId() == step.getId()) { - step.setDiscussionProxy(updatedStep.getDiscussionProxy()); //fixme do it in immutable way - step.setDiscussionsCount(updatedStep.getDiscussionsCount()); - updateCommentState(); - } - } - - @Override - public final void showNextLessonView() { - routeLessonRoot.setVisibility(View.VISIBLE); - nextLessonView.setVisibility(View.VISIBLE); - } - - @Override - public final void openNextLesson(@NotNull Unit nextUnit, @NotNull Lesson nextLesson, @NotNull Section nextSection) { - ProgressHelper.dismiss(getFragmentManager(), LOAD_DIALOG_TAG); - getScreenManager().showSteps(getActivity(), nextUnit, nextLesson, nextSection); - getActivity().finish(); - } - - @Override - public void showLoading() { - DialogFragment dialogFragment = LoadingProgressDialogFragment.Companion.newInstance(); - if (!dialogFragment.isAdded()) { - dialogFragment.show(getFragmentManager(), LOAD_DIALOG_TAG); - } - } - - @Override - public void showCantGoNext() { - ProgressHelper.dismiss(getFragmentManager(), LOAD_DIALOG_TAG); - Toast.makeText(getContext(), R.string.cant_show_next_step, Toast.LENGTH_SHORT).show(); - } - - @Override - public void showPreviousLessonView() { - routeLessonRoot.setVisibility(View.VISIBLE); - previousLessonView.setVisibility(View.VISIBLE); - } - - @Override - public void openPreviousLesson(@NotNull Unit previousUnit, @NotNull Lesson previousLesson, @NotNull Section previousSection) { - ProgressHelper.dismiss(getFragmentManager(), LOAD_DIALOG_TAG); - getScreenManager().showSteps(getActivity(), previousUnit, previousLesson, true, previousSection); - getActivity().finish(); - } - - @Override - public void showCantGoPrevious() { - ProgressHelper.dismiss(getFragmentManager(), LOAD_DIALOG_TAG); - Toast.makeText(getContext(), R.string.cant_show_previous_step, Toast.LENGTH_SHORT).show(); - } - - @Override - public void onSaveInstanceState(Bundle outState) { - super.onSaveInstanceState(outState); - outState.putBoolean(ROUTER_ROOT_VISIBILITY_KEY, routeLessonRoot.getVisibility() == View.VISIBLE); - outState.putBoolean(NEXT_LESSON_VISIBILITY_KEY, nextLessonView.getVisibility() == View.VISIBLE); - outState.putBoolean(PREVIOUS_LESSON_VISIBILITY_KEY, previousLessonView.getVisibility() == View.VISIBLE); - } - - @Override - public final void onShowAnonymous(boolean isAnonymous) { - authLineText.setVisibility(isAnonymous ? View.VISIBLE : View.GONE); - } - - @Override - public void onResume() { - super.onResume(); - hideSoftKeypad(); - } - - @Override - public void onCommentCountUpdated() { - long[] arr = new long[]{step.getId()}; - getApi().getSteps(arr) - .subscribeOn(Schedulers.io()) - .observeOn(AndroidSchedulers.mainThread()) - .subscribe(new StepResponseCallback(getThreadPoolExecutor(), getDatabaseFacade(), this)); - } - - - //// TODO: 13.06.17 rework it in MVP style - static class StepResponseCallback implements SingleObserver { - - private final ThreadPoolExecutor threadPoolExecutor; - private final DatabaseFacade databaseFacade; - private final WeakReference stepBaseFragmentWeakReference; - - - public StepResponseCallback(ThreadPoolExecutor threadPoolExecutor, DatabaseFacade databaseFacade, StepBaseFragment stepBaseFragment) { - this.threadPoolExecutor = threadPoolExecutor; - this.databaseFacade = databaseFacade; - stepBaseFragmentWeakReference = new WeakReference<>(stepBaseFragment); - } - - @Override - public void onSubscribe(Disposable d) {} - - @Override - public void onSuccess(StepResponse stepResponse) { - if (stepResponse != null && stepResponse.getSteps() != null && !stepResponse.getSteps().isEmpty()) { - final Step stepFromInternet = stepResponse.getSteps().get(0); - if (stepFromInternet != null) { - threadPoolExecutor.execute(new Runnable() { - @Override - public void run() { - databaseFacade.addStep(stepFromInternet); //fixme: fragment in closure -> leak - } - }); - - - StepBaseFragment stepBaseFragment = stepBaseFragmentWeakReference.get(); - if (stepBaseFragment != null) { - stepBaseFragment.onDiscussionWasUpdatedFromInternet(stepFromInternet); - } - } - } - } - - @Override - public void onError(Throwable e) { - - } - } -} diff --git a/app/src/main/java/org/stepic/droid/core/presenters/AnonymousPresenter.kt b/app/src/main/java/org/stepic/droid/core/presenters/AnonymousPresenter.kt deleted file mode 100644 index 13947b083f..0000000000 --- a/app/src/main/java/org/stepic/droid/core/presenters/AnonymousPresenter.kt +++ /dev/null @@ -1,23 +0,0 @@ -package org.stepic.droid.core.presenters - -import org.stepic.droid.concurrency.MainHandler -import org.stepic.droid.core.presenters.contracts.AnonymousView -import org.stepic.droid.preferences.SharedPreferenceHelper -import java.util.concurrent.ThreadPoolExecutor -import javax.inject.Inject - -class AnonymousPresenter -@Inject constructor( - private val sharedPreferenceHelper: SharedPreferenceHelper, - private val threadPoolExecutor: ThreadPoolExecutor, - private val mainHandler: MainHandler) : PresenterBase() { - - fun checkForAnonymous() { - threadPoolExecutor.execute { - val isAnonymous = sharedPreferenceHelper.authResponseFromStore == null - mainHandler.post { - view?.onShowAnonymous(isAnonymous) - } - } - } -} diff --git a/app/src/main/java/org/stepic/droid/core/presenters/RouteStepPresenter.kt b/app/src/main/java/org/stepic/droid/core/presenters/RouteStepPresenter.kt deleted file mode 100644 index b9319ca176..0000000000 --- a/app/src/main/java/org/stepic/droid/core/presenters/RouteStepPresenter.kt +++ /dev/null @@ -1,276 +0,0 @@ -package org.stepic.droid.core.presenters - -import android.support.annotation.MainThread -import org.stepic.droid.analytic.Analytic -import org.stepic.droid.concurrency.MainHandler -import org.stepic.droid.core.presenters.contracts.RouteStepView -import org.stepik.android.model.Course -import org.stepik.android.model.Lesson -import org.stepik.android.model.Section -import org.stepik.android.model.Unit -import org.stepic.droid.storage.repositories.Repository -import org.stepic.droid.util.hasUserAccessAndNotEmpty -import java.util.concurrent.ThreadPoolExecutor -import javax.inject.Inject - -class RouteStepPresenter -@Inject constructor( - private val threadPoolExecutor: ThreadPoolExecutor, - private val mainHandler: MainHandler, - private val analytic: Analytic, - private val courseRepository: Repository, - private val sectionRepository: Repository
, - private val unitRepository: Repository, - private val lessonRepository: Repository -) : PresenterBase() { - - /** - * Last step in lesson can be shown differently - */ - @MainThread - fun checkStepForLast(stepId: Long, lesson: Lesson, unit: Unit) { - checkStepBase( - Direction.next, - stepId, - lesson, - unit, - resultForView = { view?.showNextLessonView() }) //need only last - } - - @MainThread - fun checkStepForFirst(stepId: Long, lesson: Lesson, unit: Unit) { - checkStepBase( - Direction.previous, - stepId, - lesson, - unit, - resultForView = { view?.showPreviousLessonView() }) //need only the first element - } - - @MainThread - private fun checkStepBase(direction: Direction, stepId: Long, lesson: Lesson, unit: Unit, resultForView: () -> kotlin.Unit) { - val stepIds = lesson.steps - if (stepIds == null || stepIds.isEmpty()) { - return - } - - val indexForChecking = - when (direction) { - RouteStepPresenter.Direction.previous -> 0 - RouteStepPresenter.Direction.next -> stepIds.size - 1 - } - if (stepIds[indexForChecking] != stepId) { - // it is not the last or the fist in the lesson - return - } - - //yes, step is candidate for showing - if (direction == Direction.previous) { - if (unit.position > 1) { //not first - resultForView.invoke() - } else { - //unit.position is 1 (it is first). We should check for previous section is available or not - threadPoolExecutor.execute { - val section: Section = sectionRepository.getObject(unit.section) ?: return@execute - if (section.position <= 1) { - //it is fist section in course - return@execute - } - - //only if it is not 1st module we have a chance - val course = courseRepository.getObject(section.course) - val slicedSectionIds = getSlicedSectionIds(direction, section, course) - slicedSectionIds - ?.let { - val sections = sectionRepository.getObjects(slicedSectionIds) - //this section are previous our - sections - .reversed() - .forEach { - if (it.hasUserAccessAndNotEmpty(course)) { - mainHandler.post { - resultForView.invoke() - } - return@execute - } - } - } - } - } - } else if (direction == Direction.next) { - threadPoolExecutor.execute { - val section = sectionRepository.getObject(unit.section) ?: return@execute - val unitIds = section.units ?: return@execute - if (unitIds[unitIds.size - 1] == unit.id) { - //we should check next sections with access - - val course = courseRepository.getObject(section.course) - val sectionIds = getSlicedSectionIds(direction, section, course) - sectionIds?.let { - val sections = sectionRepository.getObjects(it) - sections - .forEach { - if (it.hasUserAccessAndNotEmpty(course)) { - mainHandler.post { - resultForView.invoke() - } - return@execute - } - } - } - - } else { - mainHandler.post { - resultForView.invoke() - } - } - } - } - } - - private fun getSlicedSectionIds(direction: Direction, currentSection: Section, course: Course?): LongArray? { - val sectionIds = course?.sections - - return when (direction) { - RouteStepPresenter.Direction.previous -> { - sectionIds?.slice(0..currentSection.position - 2) - ?.toLongArray() - } - RouteStepPresenter.Direction.next -> { - sectionIds - ?.slice(currentSection.position until sectionIds.size) - ?.toLongArray() - } - } - } - - fun clickNextLesson(unit: Unit) { - analytic.reportEvent(Analytic.Interaction.CLICK_NEXT_LESSON_IN_STEPS) - clickLessonBase( - direction = Direction.next, - unit = unit, - nextIndex = { index -> index + 1 }, - onOpen = { nextUnit, nextLesson, nextSection -> view?.openNextLesson(nextUnit, nextLesson, nextSection) }, - onCantGoAnalytic = { unit -> analytic.reportError(Analytic.Error.ILLEGAL_STATE_NEXT_LESSON, IllegalStateRouteLessonException(unit.id)) }, - onCantGoEvent = { view?.showCantGoNext() } - ) - } - - - fun clickPreviousLesson(unit: Unit) { - analytic.reportEvent(Analytic.Interaction.CLICK_PREVIOUS_LESSON_IN_STEPS) - clickLessonBase(direction = Direction.previous, - unit = unit, - nextIndex = { index -> index - 1 }, - onOpen = { previousUnit, previousLesson, previousSection -> view?.openPreviousLesson(previousUnit, previousLesson, previousSection) }, - onCantGoAnalytic = { unit -> analytic.reportError(Analytic.Error.ILLEGAL_STATE_PREVIOUS_LESSON, IllegalStateRouteLessonException(unit.id)) }, - onCantGoEvent = { view?.showCantGoPrevious() } - ) - } - - private fun clickLessonBase( - direction: Direction, - unit: Unit, - nextIndex: (Int) -> Int, - onOpen: (Unit, Lesson, Section) -> kotlin.Unit, - onCantGoAnalytic: (Unit) -> kotlin.Unit, - onCantGoEvent: () -> kotlin.Unit) { - view?.showLoading() - threadPoolExecutor.execute { - val section = sectionRepository.getObject(unit.section) - - var nextUnitId: Long? = null - val unitIds = section?.units - val numberOfUnits = unitIds?.size ?: 0 - let { - unitIds?.forEachIndexed { index, unitId -> - if (unit.id == unitId && nextIndex(index) < numberOfUnits && nextIndex(index) >= 0) { - nextUnitId = unitIds[nextIndex(index)] - return@let //alias for break - } - } - } - - nextUnitId?.let { - val nextUnit = unitRepository.getObject(it) - if (nextUnit != null && section != null) { - val nextLesson = lessonRepository.getObject(nextUnit.lesson) - if (nextLesson != null) { - mainHandler.post { - onOpen.invoke(nextUnit, nextLesson, section) - } - return@execute - } - } - } - if (nextUnitId == null && section != null) { - //unit in previous or next section - val course = courseRepository.getObject(section.course) - val slicedSectionIds = getSlicedSectionIds(direction, section, course) - slicedSectionIds?.let { - val sections = sectionRepository.getObjects(slicedSectionIds) - when (direction) { - RouteStepPresenter.Direction.previous -> { - sections - .reversed() - .forEach { - if (it.hasUserAccessAndNotEmpty(course)) { - it.units?.last()?.let { previousUnitId -> - val previousUnit = unitRepository.getObject(previousUnitId) - if (previousUnit != null) { - val previousLesson = lessonRepository.getObject(previousUnit.lesson) - if (previousLesson != null) { - mainHandler.post { - onOpen(previousUnit, previousLesson, it) - } - return@execute - } - } - } - return@let - } - } - } - RouteStepPresenter.Direction.next -> { - sections - .forEach { nextSection -> - if (nextSection.hasUserAccessAndNotEmpty(course)) { - nextSection.units?.first()?.let { nextUnitId -> - val nextUnit = unitRepository.getObject(nextUnitId) - nextUnit?.lesson?.let { lessonId -> - val nextLesson = lessonRepository.getObject(lessonId) - if (nextLesson != null) { - mainHandler.post { - onOpen(nextUnit, nextLesson, nextSection) - } - return@execute - } - } - - } - mainHandler.post { - } - - return@let - } - } - } - } - } - } - - //when Internet is not available AND when course structure is changing in real time - //if something is null -> show error - onCantGoAnalytic.invoke(unit) - mainHandler.post { - onCantGoEvent.invoke() - } - } - } - - inner class IllegalStateRouteLessonException(unitId: Long) : IllegalStateException("Next or previous lesson is shouldn't be shown, lessonId = $unitId") - - enum class Direction { - previous, next - } -} \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/core/presenters/StepAttemptPresenter.kt b/app/src/main/java/org/stepic/droid/core/presenters/StepAttemptPresenter.kt deleted file mode 100644 index 62b7d7f05c..0000000000 --- a/app/src/main/java/org/stepic/droid/core/presenters/StepAttemptPresenter.kt +++ /dev/null @@ -1,337 +0,0 @@ -package org.stepic.droid.core.presenters - -import android.os.Bundle -import android.support.annotation.MainThread -import android.support.annotation.WorkerThread -import com.google.firebase.remoteconfig.FirebaseRemoteConfig -import org.stepic.droid.analytic.AmplitudeAnalytic -import org.stepic.droid.analytic.Analytic -import org.stepic.droid.concurrency.MainHandler -import org.stepic.droid.configuration.RemoteConfig -import org.stepic.droid.core.LessonSessionManager -import org.stepic.droid.core.presenters.contracts.StepAttemptView -import org.stepik.android.model.Reply -import org.stepik.android.model.attempts.Attempt -import org.stepic.droid.preferences.SharedPreferenceHelper -import org.stepic.droid.util.DateTimeHelper -import org.stepic.droid.util.StepikUtil -import org.stepic.droid.util.getStepType -import org.stepic.droid.web.Api -import org.stepik.android.domain.feedback.interactor.FeedbackInteractor -import org.stepik.android.model.Submission -import org.stepik.android.model.DiscountingPolicyType -import org.stepik.android.model.Section -import org.stepik.android.model.Step -import java.util.* -import java.util.concurrent.Executors -import java.util.concurrent.ScheduledExecutorService -import java.util.concurrent.ThreadPoolExecutor -import java.util.concurrent.TimeUnit -import javax.inject.Inject - -class StepAttemptPresenter -@Inject constructor( - private val mainHandler: MainHandler, - private val threadPoolExecutor: ThreadPoolExecutor, - private val lessonManager: LessonSessionManager, - private val api: Api, - private var firebaseRemoteConfig: FirebaseRemoteConfig, - private val analytic: Analytic, - private val sharedPreferenceHelper: SharedPreferenceHelper, - private val feedbackInteractor: FeedbackInteractor -) : PresenterBase() { - companion object { - private const val FIRST_DELAY = 1000L - private const val MAX_RATE_TIMES = 5 - } - - private val minNumberOfSolvedStepsForRate = 5 - - private var worker: ScheduledExecutorService? = null - - override fun attachView(view: StepAttemptView) { - super.attachView(view) - worker = Executors.newSingleThreadScheduledExecutor() - } - - override fun detachView(view: StepAttemptView) { - worker = null - super.detachView(view) - } - - @MainThread - fun handleStepRestriction(step: Step, numberOfSubmission: Int) { - if (!step.hasSubmissionRestriction) { - view?.onResultHandlingSubmissionRestriction(needShow = false, numberForShow = 0) - } else { - val remainTries = step.maxSubmissionCount - numberOfSubmission - view?.onResultHandlingSubmissionRestriction(needShow = true, numberForShow = remainTries) - } - } - - @MainThread - fun handleDiscountingPolicy(numberOfSubmission: Int, section: Section?, step: Step) { - if (section?.discountingPolicy == null || section.discountingPolicy == DiscountingPolicyType.NoDiscount || numberOfSubmission < 0 || step.isCustomPassed) { - view?.onResultHandlingDiscountPolicy(needShow = false) - return - } - - section.discountingPolicy?.let { - when (section.discountingPolicy) { - DiscountingPolicyType.Inverse -> view?.onResultHandlingDiscountPolicy( - needShow = true, - discountingPolicyType = it, - remainTries = Int.MAX_VALUE) - - DiscountingPolicyType.FirstOne, DiscountingPolicyType.FirstThree -> view?.onResultHandlingDiscountPolicy( - needShow = true, - discountingPolicyType = it, - remainTries = (it.numberOfTries() - numberOfSubmission)) - - else -> view?.onResultHandlingDiscountPolicy(needShow = false) - } - } - } - - @MainThread - fun postSubmission(step: Step, reply: Reply, attemptId: Long) { - threadPoolExecutor.execute { - try { - api.createNewSubmission(reply, attemptId).execute().body()?.submissions - val bundle = Bundle() - bundle.putString(Analytic.Steps.STEP_TYPE_KEY, step.getStepType()) - reply.language?.let { - bundle.putString(Analytic.Steps.CODE_LANGUAGE_KEY, reply.language) - } - analytic.reportEvent(Analytic.Steps.SUBMISSION_CREATED, bundle) - mainHandler.post { - getStatusOfSubmission(step, attemptId, fromPosting = true) - } - } catch (ex: Exception) { - mainHandler.post { view?.onConnectionFailOnSubmit() } - } - } - } - - @JvmOverloads - @MainThread - fun startLoadAttempt(step: Step, onlyFromInternet: Boolean = false) { - startWork(step, onlyFromInternet) - } - - @MainThread - fun tryAgain(stepId: Long) { - threadPoolExecutor.execute { - createNewAttempt(stepId) - } - } - - private fun startWork(step: Step, onlyFromInternet: Boolean) { - view?.onStartLoadingAttempt() - view?.onNeedResolveActionButtonText() - threadPoolExecutor.execute { - if (onlyFromInternet || !tryRestoreState(step.id)) { - getExistingAttempts(step.id) - } - if (step.actions?.doReview != null) { - mainHandler.post { - view?.onNeedShowPeerReview() - } - } - } - } - - @JvmOverloads - @MainThread - fun getStatusOfSubmission(step: Step, attemptId: Long, fromPosting: Boolean = false) { - - fun getStatusOfSubmission(numberOfTry: Int) { - worker?.schedule( - Runnable { - try { - var submissions = api.getSubmissionForStep(step.id).execute().body()?.submissions - if (submissions?.isNotEmpty() == true && submissions.firstOrNull()?.attempt != attemptId) { - submissions = api.getSubmissions(attemptId).execute()?.body()?.submissions // if we have another attempt id on server - } - - - if (submissions != null) { - val numberOfSubmissions = submissions.size - val submission = submissions.firstOrNull() - // if null -> we do not have submissions for THIS ATTEMPT - - if (submission?.status == Submission.Status.EVALUATION) { - mainHandler.post { - getStatusOfSubmission(numberOfTry + 1) - } - return@Runnable - } - - val isCorrectSolution: Boolean = !step.isCustomPassed && submission?.status == Submission.Status.CORRECT - if (isCorrectSolution) { - sharedPreferenceHelper.trackWhenUserSolved() - sharedPreferenceHelper.incrementUserSolved() - } - - if (fromPosting && submission != null) { - sharedPreferenceHelper.incrementSubmissionsCount() - - val params = mutableMapOf( - AmplitudeAnalytic.Steps.Params.TYPE to step.getStepType(), - AmplitudeAnalytic.Steps.Params.STEP to step.id - ) - submission.reply?.language?.let { - params[AmplitudeAnalytic.Steps.Params.LANGUAGE] = it - } - analytic.reportAmplitudeEvent(AmplitudeAnalytic.Steps.SUBMISSION_MADE, params) - } - - val needShowStreakDialog = - fromPosting - && isCorrectSolution - && (sharedPreferenceHelper.isStreakNotificationEnabledNullable == null) // default value, user not change in profile - && sharedPreferenceHelper.canShowStreakDialog() - && (sharedPreferenceHelper.authResponseFromStore != null) - - - val streakDayNumber: Int = - if (needShowStreakDialog) { - try { - val pins: ArrayList = api.getUserActivities(sharedPreferenceHelper.profile?.id ?: throw Exception("User is not auth")).execute()?.body()?.userActivities?.firstOrNull()?.pins!! - val pair = StepikUtil.getCurrentStreakExtended(pins) - pair.currentStreak - } catch (exception: Exception) { - analytic.reportError(Analytic.Error.STREAK_ON_STEP_SOLVED, exception) - -1 - } - } else { - -1 - } - - - val needShowRateAppDialog = !needShowStreakDialog - && fromPosting - && isCorrectSolution - && !sharedPreferenceHelper.wasRateHandled() - && isUserSolveEnough() - && isRateDelayGreater() - && isRateWasShownFewTimes() - - if (!needShowStreakDialog && needShowRateAppDialog) { - sharedPreferenceHelper.rateShown(DateTimeHelper.nowUtc()) - } - - mainHandler.post { - if (needShowStreakDialog) { - view?.onNeedShowStreakDialog(streakDayNumber) // it can be -1, if we fail to get streaks - } else if (needShowRateAppDialog) { - view?.onNeedShowRateDialog() - } - view?.onNeedFillSubmission(submission, numberOfSubmissions) - } - - } else { - mainHandler.post { - getStatusOfSubmission(numberOfTry + 1) - } - } - } catch (ex: Exception) { - mainHandler.post { - view?.onConnectionFailOnSubmit() - } - } - }, numberOfTry * FIRST_DELAY, TimeUnit.MILLISECONDS) - } - - getStatusOfSubmission(0) - } - - fun sendTextFeedback(subject: String, aboutSystemInfo: String) { - threadPoolExecutor.execute { - val supportMailData = feedbackInteractor.createSupportEmailData(subject, aboutSystemInfo).blockingGet() - mainHandler.post { view?.sendTextFeedback(supportMailData) } - } - } - - @WorkerThread - private fun isRateDelayGreater(): Boolean { - val wasShownMillis = sharedPreferenceHelper.whenRateWasShown() - if (wasShownMillis < 0) { - return true // we can show it - } - - val delayMillis = firebaseRemoteConfig.getLong(RemoteConfig.MIN_DELAY_RATE_DIALOG_SEC).toInt() * 1000L - - return DateTimeHelper.isBeforeNowUtc(delayMillis + wasShownMillis) //if delay is expired (before now) -> show - } - - @WorkerThread - private fun isRateWasShownFewTimes(): Boolean { - val wasShown = sharedPreferenceHelper.howManyRateWasShownBefore() - return wasShown <= MAX_RATE_TIMES - } - - @WorkerThread - private fun isUserSolveEnough(): Boolean { - val numberOfSolved = sharedPreferenceHelper.numberOfSolved() - return numberOfSolved >= minNumberOfSolvedStepsForRate - } - - - /** - * @return false if restore was failed; - */ - @WorkerThread - private fun tryRestoreState(stepId: Long): Boolean { - val lessonSession = lessonManager.restoreLessonSession(stepId) ?: return false - - val attempt = lessonSession.attempt - val submission = lessonSession.submission - val numberOfSubmissions = lessonSession.numberOfSubmissionsOnFirstPage - if (submission == null || attempt == null) return false - - mainHandler.post { - view?.onNeedShowAttempt(attempt, false, numberOfSubmissions) - view?.onNeedFillSubmission(submission, numberOfSubmissions) - } - return true - } - - - @WorkerThread - private fun getExistingAttempts(stepId: Long) { - try { - val existingAttemptsResponse = api.getExistingAttempts(stepId).execute() - val firstAttempt = existingAttemptsResponse?.body()?.attempts?.firstOrNull() - if (existingAttemptsResponse.isSuccessful && firstAttempt?.status == "active") { - mainHandler.post { - // we do not need number of submissions, because it will be calculated in getSubmissions - view?.onNeedShowAttempt(firstAttempt, false, null) - } - } else { - createNewAttempt(stepId) - } - } catch (ex: Exception) { - //Internet is not available - mainHandler.post { - view?.onConnectionFailWhenLoadAttempt() - } - } - } - - @WorkerThread - private fun createNewAttempt(stepId: Long) { - try { - val createdAttempt: Attempt = api.createNewAttempt(stepId).execute().body()!!.attempts.first() - val numberOfSubmissions: Int = api.getSubmissionForStep(stepId).execute().body()!!.submissions.size - mainHandler.post { view?.onNeedShowAttempt(attempt = createdAttempt, numberOfSubmissionsForStep = numberOfSubmissions, isCreated = true) } - } catch (ex: Exception) { - //Internet is not available - mainHandler.post { - view?.onConnectionFailWhenLoadAttempt() - } - } - - } - -} diff --git a/app/src/main/java/org/stepic/droid/core/presenters/contracts/AnonymousView.kt b/app/src/main/java/org/stepic/droid/core/presenters/contracts/AnonymousView.kt deleted file mode 100644 index f8540f821d..0000000000 --- a/app/src/main/java/org/stepic/droid/core/presenters/contracts/AnonymousView.kt +++ /dev/null @@ -1,6 +0,0 @@ -package org.stepic.droid.core.presenters.contracts - -interface AnonymousView { - fun onShowAnonymous(isAnonymous: Boolean) -} - diff --git a/app/src/main/java/org/stepic/droid/core/presenters/contracts/RouteStepView.java b/app/src/main/java/org/stepic/droid/core/presenters/contracts/RouteStepView.java deleted file mode 100644 index e286be49a5..0000000000 --- a/app/src/main/java/org/stepic/droid/core/presenters/contracts/RouteStepView.java +++ /dev/null @@ -1,23 +0,0 @@ -package org.stepic.droid.core.presenters.contracts; - -import org.jetbrains.annotations.NotNull; -import org.stepik.android.model.Lesson; -import org.stepik.android.model.Section; -import org.stepik.android.model.Unit; - -public interface RouteStepView { - void showNextLessonView(); - - void openNextLesson(@NotNull Unit nextUnit, @NotNull Lesson nextLesson, @NotNull Section nextSection); - - void showLoading(); - - void showCantGoNext(); - - void showPreviousLessonView(); - - void openPreviousLesson(@NotNull Unit previousUnit, @NotNull Lesson previousLesson, @NotNull Section previousSection); - - void showCantGoPrevious(); - -} diff --git a/app/src/main/java/org/stepic/droid/core/presenters/contracts/StepAttemptView.kt b/app/src/main/java/org/stepic/droid/core/presenters/contracts/StepAttemptView.kt deleted file mode 100644 index 1f88374266..0000000000 --- a/app/src/main/java/org/stepic/droid/core/presenters/contracts/StepAttemptView.kt +++ /dev/null @@ -1,33 +0,0 @@ -package org.stepic.droid.core.presenters.contracts - -import org.stepik.android.domain.feedback.model.SupportEmailData -import org.stepik.android.model.attempts.Attempt -import org.stepik.android.model.DiscountingPolicyType -import org.stepik.android.model.Submission - -interface StepAttemptView { - fun onResultHandlingDiscountPolicy(needShow: Boolean, discountingPolicyType: DiscountingPolicyType? = null, remainTries: Int = -1) - - fun onStartLoadingAttempt() - - fun onNeedShowAttempt(attempt: Attempt?, isCreated: Boolean, numberOfSubmissionsForStep: Int?) - - fun onConnectionFailWhenLoadAttempt() - - fun onNeedFillSubmission(submission: Submission?, numberOfSubmissions: Int) - - fun onConnectionFailOnSubmit() - - fun onNeedShowPeerReview() - - fun onNeedResolveActionButtonText() - - fun onResultHandlingSubmissionRestriction(needShow: Boolean, numberForShow: Int) - - fun onNeedShowStreakDialog(streakDays: Int) - - fun onNeedShowRateDialog() - - fun sendTextFeedback(supportEmailData: SupportEmailData) - -} \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/di/step/StepComponent.kt b/app/src/main/java/org/stepic/droid/di/step/StepComponent.kt index 68d9f72834..3df87047b1 100644 --- a/app/src/main/java/org/stepic/droid/di/step/StepComponent.kt +++ b/app/src/main/java/org/stepic/droid/di/step/StepComponent.kt @@ -1,10 +1,8 @@ package org.stepic.droid.di.step import dagger.Subcomponent -import org.stepic.droid.base.StepBaseFragment import org.stepic.droid.di.comment.CommentsComponent import org.stepic.droid.di.streak.StreakModule -import org.stepic.droid.ui.fragments.StepAttemptFragment import org.stepik.android.view.injection.feedback.FeedbackDataModule @StepScope @@ -16,8 +14,4 @@ interface StepComponent { } fun commentsComponentBuilder(): CommentsComponent.Builder - - fun inject(stepFragment: StepBaseFragment) - - fun inject(stepAttemptFragment: StepAttemptFragment) } diff --git a/app/src/main/java/org/stepic/droid/ui/adapters/StepFragmentAdapter.kt b/app/src/main/java/org/stepic/droid/ui/adapters/StepFragmentAdapter.kt index c2ea53ddd6..79dfa44b70 100644 --- a/app/src/main/java/org/stepic/droid/ui/adapters/StepFragmentAdapter.kt +++ b/app/src/main/java/org/stepic/droid/ui/adapters/StepFragmentAdapter.kt @@ -1,13 +1,11 @@ package org.stepic.droid.ui.adapters -import android.os.Bundle import android.support.annotation.ColorRes import android.support.annotation.DrawableRes import android.support.v4.app.Fragment import android.support.v4.app.FragmentManager import android.support.v4.app.FragmentStatePagerAdapter import android.view.ViewGroup -import org.stepic.droid.util.AppConstants import org.stepic.droid.util.resolvers.StepTypeResolver import org.stepik.android.domain.lesson.model.LessonData import org.stepik.android.domain.lesson.model.StepItem @@ -39,19 +37,7 @@ class StepFragmentAdapter( override fun getItem(position: Int): Fragment { val stepWrapper = items[position].stepWrapper - - val fragment = stepTypeResolver.getFragment(stepWrapper.step) - return if (stepTypeResolver.isNeedUseOldStepContainer(stepWrapper.step) && fragment != null) { - val args = Bundle() - args.putParcelable(AppConstants.KEY_STEP_BUNDLE, stepWrapper) - args.putParcelable(AppConstants.KEY_LESSON_BUNDLE, lessonData.lesson) - args.putParcelable(AppConstants.KEY_UNIT_BUNDLE, lessonData.unit) - args.putParcelable(AppConstants.KEY_SECTION_BUNDLE, lessonData.section) - fragment.arguments = args - fragment - } else { - StepFragment.newInstance(stepWrapper, lessonData) - } + return StepFragment.newInstance(stepWrapper, lessonData) } override fun getCount(): Int = diff --git a/app/src/main/java/org/stepic/droid/ui/custom/StepTextWrapper.kt b/app/src/main/java/org/stepic/droid/ui/custom/StepTextWrapper.kt deleted file mode 100644 index 7ce85d31d7..0000000000 --- a/app/src/main/java/org/stepic/droid/ui/custom/StepTextWrapper.kt +++ /dev/null @@ -1,49 +0,0 @@ -package org.stepic.droid.ui.custom - -import android.view.LayoutInflater -import android.view.View -import android.view.ViewGroup -import org.stepic.droid.R -import org.stepik.android.model.Step -import javax.inject.Inject - -class StepTextWrapper -@Inject -constructor() { - private var latexLayout: LatexSupportableEnhancedFrameLayout? = null - - private var stepText: String? = null - - fun attach(parent: ViewGroup, attachToTop: Boolean = true) { - if (latexLayout == null) { - latexLayout = LayoutInflater.from(parent.context).inflate(R.layout.step_text_header, parent, false) - as LatexSupportableEnhancedFrameLayout - } - - if (attachToTop) { - parent.addView(latexLayout, 0) - } else { - parent.addView(latexLayout) - } - } - - fun bind(step: Step?) { - val text = step?.block?.text?.takeIf(String::isNotEmpty) - if (text == stepText) return - stepText = text - - val layout = latexLayout ?: return - - if (text != null) { - layout.setText(text) - layout.setTextIsSelectable(true) - layout.visibility = View.VISIBLE - } else { - layout.visibility = View.GONE - } - } - - fun detach(parent: ViewGroup) { - latexLayout?.let(parent::removeView) - } -} \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/ui/fragments/StepAttemptFragment.java b/app/src/main/java/org/stepic/droid/ui/fragments/StepAttemptFragment.java deleted file mode 100644 index f047d566ec..0000000000 --- a/app/src/main/java/org/stepic/droid/ui/fragments/StepAttemptFragment.java +++ /dev/null @@ -1,738 +0,0 @@ -package org.stepic.droid.ui.fragments; - -import android.app.Activity; -import android.content.Intent; -import android.graphics.Color; -import android.graphics.drawable.Drawable; -import android.os.AsyncTask; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.annotation.Nullable; -import android.support.design.widget.Snackbar; -import android.support.v4.app.DialogFragment; -import android.text.Spannable; -import android.text.SpannableString; -import android.text.style.ForegroundColorSpan; -import android.view.LayoutInflater; -import android.view.View; -import android.view.ViewGroup; -import android.widget.Button; -import android.widget.ProgressBar; -import android.widget.TextView; -import android.widget.Toast; - -import com.afollestad.materialdialogs.DialogAction; -import com.afollestad.materialdialogs.MaterialDialog; -import com.github.javiersantos.materialstyleddialogs.MaterialStyledDialog; -import com.google.firebase.analytics.FirebaseAnalytics; - -import org.jetbrains.annotations.NotNull; -import org.stepic.droid.R; -import org.stepic.droid.analytic.Analytic; -import org.stepic.droid.base.App; -import org.stepic.droid.base.Client; -import org.stepic.droid.base.StepBaseFragment; -import org.stepic.droid.core.LessonSessionManager; -import org.stepic.droid.core.internetstate.contract.InternetEnabledListener; -import org.stepic.droid.core.presenters.StepAttemptPresenter; -import org.stepic.droid.core.presenters.StreakPresenter; -import org.stepic.droid.core.presenters.contracts.StepAttemptView; -import org.stepic.droid.fonts.FontType; -import org.stepic.droid.model.LessonSession; -import org.stepic.droid.ui.custom.LatexSupportableEnhancedFrameLayout; -import org.stepic.droid.ui.dialogs.DiscountingPolicyDialogFragment; -import org.stepic.droid.ui.dialogs.TimeIntervalPickerDialogFragment; -import org.stepic.droid.ui.listeners.NextMoveable; -import org.stepic.droid.util.ColorUtil; -import org.stepic.droid.util.DeviceInfoUtil; -import org.stepic.droid.util.ProgressHelper; -import org.stepic.droid.util.RatingUtil; -import org.stepic.droid.util.RatingUtilKt; -import org.stepic.droid.util.SnackbarExtensionKt; -import org.stepic.droid.util.StepExtensionsKt; -import org.stepic.droid.util.SubmissionExtensionsKt; -import org.stepik.android.domain.feedback.model.SupportEmailData; -import org.stepik.android.domain.progress.interactor.LocalProgressInteractor; -import org.stepik.android.model.DiscountingPolicyType; -import org.stepik.android.model.Reply; -import org.stepik.android.model.Step; -import org.stepik.android.model.Submission; -import org.stepik.android.model.attempts.Attempt; -import org.stepik.android.view.app_rating.ui.dialog.RateAppDialog; - -import javax.inject.Inject; - -import butterknife.BindDrawable; -import butterknife.BindString; -import butterknife.BindView; -import kotlin.collections.CollectionsKt; -import uk.co.chrisjenx.calligraphy.CalligraphyTypefaceSpan; -import uk.co.chrisjenx.calligraphy.TypefaceUtils; - -public abstract class StepAttemptFragment extends StepBaseFragment implements - StepAttemptView, - InternetEnabledListener, - RateAppDialog.Companion.Callback, - TimeIntervalPickerDialogFragment.Companion.Callback { - - private final int DISCOUNTING_POLICY_REQUEST_CODE = 131; - - @BindView(R.id.rootStepAttemptView) - ViewGroup rootView; - - @BindView(R.id.answer_status_text) - TextView statusTextView; - - @BindView(R.id.progress_bar) - ProgressBar progressBar; - - @BindView(R.id.reportProblem) - View connectionProblem; - - @BindView(R.id.attempt_container) - ViewGroup attemptContainer; - - @BindView(R.id.stepAttemptSubmitButton) - Button actionButton; - - @BindView(R.id.buttonsContainer) - ViewGroup actionButtonsContainer; - - @BindView(R.id.peer_review_warning) - View peerReviewIndicator; - - @BindString(R.string.correct) - String correctString; - - @BindString(R.string.wrong) - protected String wrongString; - - @BindString(R.string.submit) - protected String submitText; - - @BindString(R.string.try_again) - protected String tryAgainText; - - @BindString(R.string.next) - String next; - - @BindView(R.id.discounting_policy_textview) - TextView discountingPolicyTextView; - - @BindView(R.id.submission_restriction_textview) - TextView submissionRestrictionTextView; - - @BindView(R.id.tryAgainOnCorrectButton) - View tryAgainOnCorrectButton; - - private View.OnClickListener onNextListener; - - protected Attempt attempt = null; - protected Submission submission = null; - protected int numberOfSubmissions = -1; - - @BindDrawable(R.drawable.ic_correct) - protected Drawable correctIcon; - - @BindDrawable(R.drawable.ic_error) - protected Drawable wrongIcon; - - @BindView(R.id.hint_text_view) - LatexSupportableEnhancedFrameLayout hintTextView; - - @Inject - StepAttemptPresenter stepAttemptPresenter; - - @Inject - LessonSessionManager lessonManager; - - @Inject - Client internetEnabledListenerClient; - - @Inject - StreakPresenter streakPresenter; - - @Inject - LocalProgressInteractor localProgressInteractor; - - private View.OnClickListener actionButtonGeneralListener; - - @Override - protected void injectComponent() { - App.Companion - .componentManager() - .stepComponent(step.getId()) - .inject(this); - } - - @Nullable - @Override - public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { - return inflater.inflate(R.layout.fragment_step_attempt, container, false); - } - - @Override - public final void onActivityCreated(@Nullable Bundle savedInstanceState) { - super.onActivityCreated(savedInstanceState); - actionButtonGeneralListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - if (submission == null || submission.getStatus() == Submission.Status.LOCAL) { - Bundle bundle = new Bundle(); - bundle.putLong(FirebaseAnalytics.Param.VALUE, 1L); - bundle.putString(FirebaseAnalytics.Param.ITEM_ID, step.getId() + ""); - String codeLanguage = SubmissionExtensionsKt.getLanguage(submission); - if (codeLanguage != null) { - bundle.putString(Analytic.Steps.CODE_LANGUAGE_KEY, codeLanguage); - } - String stepType = StepExtensionsKt.getStepType(step); - bundle.putString(Analytic.Steps.STEP_TYPE_KEY, stepType); - getAnalytic().reportEventWithName(Analytic.Steps.CLICK_SEND_SUBMISSION_STEP_TYPE, stepType); - - makeSubmission(); - } else { - getAnalytic().reportEvent(Analytic.Interaction.CLICK_TRY_STEP_AGAIN); - tryAgain(); - } - } - }; - setListenerToActionButton(actionButtonGeneralListener); - - View.OnClickListener onTryAgainCorrectListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - getAnalytic().reportEvent(Analytic.Interaction.CLICK_TRY_STEP_AGAIN_AFTER_CORRECT); - tryAgain(); - } - }; - tryAgainOnCorrectButton.setOnClickListener(onTryAgainCorrectListener); - - onNextListener = new View.OnClickListener() { - @Override - public void onClick(View v) { - v.setEnabled(false); - boolean handled = ((NextMoveable) getActivity()).moveNext(); - if (!handled) { - if (unit != null) { - routeStepPresenter.clickNextLesson(unit); - } else { - Toast.makeText(getContext(), R.string.cant_show_next_step, Toast.LENGTH_SHORT).show(); - } - } - v.setEnabled(true); - } - }; - - connectionProblem.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - stepAttemptPresenter.startLoadAttempt(step, true); - } - }); - stepAttemptPresenter.attachView(this); - internetEnabledListenerClient.subscribe(this); - stepAttemptPresenter.startLoadAttempt(step); - } - - private void makeSubmission() { - if (attempt == null || attempt.getId() <= 0) return; - - if (section != null && section.getDiscountingPolicy() != DiscountingPolicyType.NoDiscount - && getUserPreferences().isShowDiscountingPolicyWarning() && !step.isCustomPassed()) { - //showDialog - DialogFragment dialogFragment = DiscountingPolicyDialogFragment.Companion.newInstance(); - if (!dialogFragment.isAdded()) { - dialogFragment.setTargetFragment(this, DISCOUNTING_POLICY_REQUEST_CODE); - dialogFragment.show(getFragmentManager(), null); - } - } else { - makeSubmissionDirectly(); - } - - } - - @Override - protected void attachStepTextWrapper() { - stepTextWrapper.attach(rootView, true); - } - - @Override - protected void detachStepTextWrapper() { - stepTextWrapper.detach(rootView); - } - - private void makeSubmissionDirectly() { - showActionButtonLoadState(true); - blockUIBeforeSubmit(true); - final long attemptId = attempt.getId(); - final Reply reply = generateReply(); - stepAttemptPresenter.postSubmission(step, reply, attemptId); - } - - @Override - public void onDestroyView() { - saveSession(true); - internetEnabledListenerClient.unsubscribe(this); - stepAttemptPresenter.detachView(this); - super.onDestroyView(); - } - - protected final void fillSubmission(@Nullable Submission submission) { - stepAttemptPresenter.handleDiscountingPolicy(numberOfSubmissions, section, step); - stepAttemptPresenter.handleStepRestriction(step, numberOfSubmissions); - if (submission == null || submission.getStatus() == null) { - return; - } - - if (submission.getHint() != null && !submission.getHint().isEmpty()) { - hintTextView.setPlainOrLaTeXTextColored(submission.getHint(), R.color.white); - hintTextView.setVisibility(View.VISIBLE); - } else { - hintTextView.setVisibility(View.GONE); - } - - switch (submission.getStatus()) { - case CORRECT: - discountingPolicyTextView.setVisibility(View.GONE); // remove if user was correct - submissionRestrictionTextView.setVisibility(View.GONE); - tryAgainOnCorrectButton.setVisibility(View.VISIBLE); - actionButtonsContainer.setVisibility(View.VISIBLE); - if (step.getHasSubmissionRestriction()) { - tryAgainOnCorrectButton.setVisibility(View.GONE); - } - setListenerToActionButton(onNextListener); - onCorrectSubmission(); - setTextToActionButton(next); - blockUIBeforeSubmit(true); - break; - case WRONG: - onWrongSubmission(); - setListenerToActionButton(actionButtonGeneralListener); - tryAgainOnCorrectButton.setVisibility(View.GONE); - setTextToActionButton(tryAgainText); - actionButton.setEnabled(true); // "try again" always - blockUIBeforeSubmit(true); - break; - } - - onRestoreSubmission(); - } - - private void showStreakDialog(int daysOfCurrentStreakIncludeToday) { - SpannableString streakTitle = new SpannableString(getString(R.string.streak_dialog_title)); - streakTitle.setSpan(new ForegroundColorSpan(Color.BLACK), 0, streakTitle.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - CalligraphyTypefaceSpan typefaceSpan = new CalligraphyTypefaceSpan(TypefaceUtils.load(getContext().getAssets(), getFontsProvider().provideFontPath(FontType.bold))); - streakTitle.setSpan(typefaceSpan, 0, streakTitle.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); - - String description; - if (daysOfCurrentStreakIncludeToday > 0) { - getAnalytic().reportEvent(Analytic.Streak.SHOW_DIALOG_UNDEFINED_STREAKS, daysOfCurrentStreakIncludeToday + ""); - description = getResources().getQuantityString(R.plurals.streak_description, daysOfCurrentStreakIncludeToday, daysOfCurrentStreakIncludeToday); - } else { - getAnalytic().reportEvent(Analytic.Streak.SHOW_DIALOG_POSITIVE_STREAKS, daysOfCurrentStreakIncludeToday + ""); - description = getString(R.string.streak_description_not_positive); - } - - getAnalytic().reportEvent(Analytic.Streak.SHOWN_MATERIAL_DIALOG); - MaterialStyledDialog dialog = new MaterialStyledDialog.Builder(getContext()) - .setTitle(streakTitle) - .setDescription(description) - .setHeaderDrawable(R.drawable.dialog_background) - .setPositiveText(R.string.ok) - .setNegativeText(R.string.later_tatle) - .setScrollable(true, 10) // number of lines lines - .onPositive(new MaterialDialog.SingleButtonCallback() { - @Override - public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) { - getAnalytic().reportEvent(Analytic.Streak.POSITIVE_MATERIAL_DIALOG); - DialogFragment dialogFragment = TimeIntervalPickerDialogFragment.Companion.newInstance(); - if (!dialogFragment.isAdded()) { - dialogFragment.setTargetFragment(StepAttemptFragment.this, 0); - dialogFragment.show(getFragmentManager(), null); - } - } - }) - .onNegative(new MaterialDialog.SingleButtonCallback() { - @Override - public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) { - getAnalytic().reportEvent(Analytic.Streak.NEGATIVE_MATERIAL_DIALOG); - messageOnNotEnablingNotification(); - } - }) - .build(); - dialog.show(); - } - - protected final void saveSession(boolean isNeedGetFromUI) { - if (attempt == null) return; - - if (submission == null || (isNeedGetFromUI && submission.getStatus() == Submission.Status.LOCAL)) { - Reply reply = generateReply(); - submission = new Submission(reply, attempt.getId(), Submission.Status.LOCAL); - } - - lessonManager.saveSession(step.getId(), attempt, submission, numberOfSubmissions); - } - - protected final void showOnlyInternetProblem(boolean isNeedShow) { - showActionButtonLoadState(!isNeedShow); - if (isNeedShow) { - tryAgainOnCorrectButton.setVisibility(View.GONE); - actionButtonsContainer.setVisibility(View.GONE); - } else { - actionButtonsContainer.setVisibility(View.VISIBLE); - } - showAnswerField(!isNeedShow); - enableInternetMessage(isNeedShow); - - if (isNeedShow) { - discountingPolicyTextView.setVisibility(View.GONE); - } - } - - private void setTextToActionButton(String text) { - actionButton.setText(text); - } - - protected final void onWrongSubmission() { - if (step != null) { - getAnalytic().reportEvent(Analytic.Steps.WRONG_SUBMISSION_FILL, step.getId() + ""); - } - attemptContainer.setBackgroundResource(R.color.wrong_answer_background); - statusTextView.setCompoundDrawablesWithIntrinsicBounds(wrongIcon, null, null, null); - statusTextView.setText(wrongString); - statusTextView.setBackgroundResource(R.color.wrong_answer_background); - statusTextView.setVisibility(View.VISIBLE); - } - - protected final void onCorrectSubmission() { - if (step != null) { - getAnalytic().reportEvent(Analytic.Steps.CORRECT_SUBMISSION_FILL, step.getId() + ""); - } - markLocalProgressAsViewed(); - attemptContainer.setBackgroundResource(R.color.correct_answer_background); - statusTextView.setCompoundDrawablesWithIntrinsicBounds(correctIcon, null, null, null); - statusTextView.setText(getCorrectString()); - statusTextView.setBackgroundResource(R.color.correct_answer_background); - statusTextView.setVisibility(View.VISIBLE); - } - - protected final void tryAgain() { - showActionButtonLoadState(true); - blockUIBeforeSubmit(false); - setListenerToActionButton(actionButtonGeneralListener); - - resetBackgroundOfAttempt(); - - hintTextView.setVisibility(View.GONE); - statusTextView.setVisibility(View.GONE); - tryAgainOnCorrectButton.setVisibility(View.GONE); - setTextToActionButton(submitText); - - stepAttemptPresenter.tryAgain(step.getId()); - submission = null; - - } - - protected final void resetBackgroundOfAttempt() { - if (attemptContainer.getBackground() == rootView.getBackground()) { - return; - } - - attemptContainer.setBackground(rootView.getBackground()); - } - - private void setListenerToActionButton(View.OnClickListener listener) { - actionButton.setOnClickListener(listener); - } - - protected final void markLocalProgressAsViewed() { - if (!step.isCustomPassed()) { - AsyncTask task = new AsyncTask() { - private final Step step = StepAttemptFragment.this.step; - - protected Void doInBackground(Void... params) { - long assignmentId = getDatabaseFacade().getAssignmentIdByStepId(this.step.getId()); - getDatabaseFacade().markProgressAsPassed(assignmentId); - try { - localProgressInteractor.updateStepsProgress(CollectionsKt.listOf(this.step)).blockingAwait(); - } catch (Exception e) { - // no op - } - return null; - } - }; - task.executeOnExecutor(getThreadPoolExecutor()); - } - } - - protected final void enableInternetMessage(boolean needShow) { - if (needShow) { - connectionProblem.setVisibility(View.VISIBLE); - } else { - connectionProblem.setVisibility(View.GONE); - } - } - - protected final void showAnswerField(boolean needShow) { - if (needShow) { - attemptContainer.setVisibility(View.VISIBLE); - } else { - attemptContainer.setVisibility(View.GONE); - } - } - - protected void showActionButtonLoadState(boolean isLoading) { - if (isLoading) { - actionButtonsContainer.setVisibility(View.GONE); - ProgressHelper.activate(progressBar); - } else { - ProgressHelper.dismiss(progressBar); - actionButtonsContainer.setVisibility(View.VISIBLE); - } - - } - - private void showAttemptAbstractWrapMethod(Attempt attempt, boolean isCreatedAttempt) { - showAttempt(attempt); - LessonSession lessonSession = lessonManager.restoreLessonSession(step.getId()); - if ((lessonSession == null || lessonSession.getSubmission() == null) && !isCreatedAttempt) { - stepAttemptPresenter.getStatusOfSubmission(step, attempt.getId());//fill last server submission if exist - } else { - // when just now created --> do not need show submission, it is not exist. - stepAttemptPresenter.handleDiscountingPolicy(numberOfSubmissions, section, step); - showActionButtonLoadState(false); - showAnswerField(true); - - stepAttemptPresenter.handleStepRestriction(step, numberOfSubmissions); - } - } - - protected abstract void showAttempt(Attempt attempt); - - protected abstract Reply generateReply(); - - protected abstract void blockUIBeforeSubmit(boolean needBlock); - - protected abstract void onRestoreSubmission(); - - protected String getCorrectString() { - return correctString; - } - - @Override - public void onResume() { - super.onResume(); - rootView.requestFocus(); - } - - @Override - public void onResultHandlingDiscountPolicy(boolean needShow, DiscountingPolicyType discountingPolicyType, int remainTries) { - if (!needShow || discountingPolicyType == null) { - discountingPolicyTextView.setVisibility(View.GONE); - return; - } - - String warningText; - if (discountingPolicyType == DiscountingPolicyType.Inverse) { - warningText = getString(R.string.discount_policy_inverse_title); - } else if (discountingPolicyType == DiscountingPolicyType.FirstOne || discountingPolicyType == DiscountingPolicyType.FirstThree) { - if (remainTries > 0) { - warningText = getResources().getQuantityString(R.plurals.discount_policy_first_n, remainTries, remainTries); - } else { - warningText = getString(R.string.discount_policy_no_way); - } - } else { - discountingPolicyTextView.setVisibility(View.GONE); - return; - } - - discountingPolicyTextView.setText(warningText); - discountingPolicyTextView.setVisibility(View.VISIBLE); - } - - @Override - public void onStartLoadingAttempt() { - enableInternetMessage(false); - showAnswerField(false); - showActionButtonLoadState(true); - } - - @Override - public void onNeedShowAttempt(@Nullable Attempt attempt, boolean isCreated, @Nullable Integer numberOfSubmissionsForStep) { - if (numberOfSubmissionsForStep != null) { - this.numberOfSubmissions = numberOfSubmissionsForStep; - } - this.attempt = attempt; - showAttemptAbstractWrapMethod(this.attempt, isCreated); - } - - @Override - public void onConnectionFailWhenLoadAttempt() { - showOnlyInternetProblem(true); - } - - @Override - public void onNeedFillSubmission(@Nullable Submission submission, int numberOfSubmissions) { - enableInternetMessage(false); - showActionButtonLoadState(false); - showAnswerField(true); - - showActionButtonLoadState(false); - this.numberOfSubmissions = numberOfSubmissions; - this.submission = submission; - saveSession(false); - fillSubmission(submission); - } - - @Override - public void onConnectionFailOnSubmit() { - blockUIBeforeSubmit(false); - showActionButtonLoadState(false); - Toast.makeText(getContext(), R.string.internet_problem, Toast.LENGTH_SHORT).show(); - } - - @Override - public void onNeedShowPeerReview() { - peerReviewIndicator.setVisibility(View.VISIBLE); - peerReviewIndicator.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - getScreenManager().openStepInWeb(getContext(), step); - } - }); - } - - @Override - public final void onNeedResolveActionButtonText() { - if (submission == null || submission.getStatus() == Submission.Status.LOCAL) { - setTextToActionButton(submitText); - } else { - setTextToActionButton(tryAgainText); - } - } - - @Override - public void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - if (requestCode == DISCOUNTING_POLICY_REQUEST_CODE && resultCode == Activity.RESULT_OK) { - makeSubmissionDirectly(); - } - } - - private void messageOnNotEnablingNotification() { - SnackbarExtensionKt - .setTextColor( - Snackbar.make(rootView, - R.string.streak_notification_canceled, - Snackbar.LENGTH_LONG), - ColorUtil.INSTANCE.getColorArgb(R.color.white, - getContext())) - .show(); - } - - @Override - public void onResultHandlingSubmissionRestriction(boolean needShow, int numberForShow) { - if (needShow) { - String warningText; - if (numberForShow > 0) { - warningText = getResources().getQuantityString(R.plurals.restriction_submission, numberForShow, numberForShow); - } else { - warningText = getString(R.string.restriction_submission_enough); - blockUIBeforeSubmit(true); - actionButtonsContainer.setVisibility(View.GONE); //we cant send more - } - submissionRestrictionTextView.setText(warningText); - submissionRestrictionTextView.setVisibility(View.VISIBLE); - } else { - submissionRestrictionTextView.setVisibility(View.GONE); - } - } - - @Override - public void onNeedShowStreakDialog(int numberOfStreakDayIncludeToday) { - // this submission is correct and user posted it 1st time - showStreakDialog(numberOfStreakDayIncludeToday); - } - - @Override - public void onInternetEnabled() { - if (connectionProblem.getVisibility() == View.VISIBLE) { - stepAttemptPresenter.startLoadAttempt(step); - } - } - - @Override - public void onNeedShowRateDialog() { - RateAppDialog rateAppDialog = RateAppDialog.Companion.newInstance(); - rateAppDialog.setTargetFragment(this, 0); - if (!rateAppDialog.isAdded()) { - getAnalytic().reportEvent(Analytic.Rating.SHOWN); - rateAppDialog.show(getFragmentManager(), null); - } - } - - //Rate dialog callback: - - @Override - public void onClickLater(int starNumber) { - if (RatingUtil.INSTANCE.isExcellent(starNumber)) { - RatingUtilKt.reportRateEvent(getAnalytic(), starNumber, Analytic.Rating.POSITIVE_LATER); - } else { - RatingUtilKt.reportRateEvent(getAnalytic(), starNumber, Analytic.Rating.NEGATIVE_LATER); - } - } - - @Override - public void onClickGooglePlay(int starNumber) { - getSharedPreferenceHelper().afterRateWasHandled(); - RatingUtilKt.reportRateEvent(getAnalytic(), starNumber, Analytic.Rating.POSITIVE_APPSTORE); - - if (getConfig().isAppInStore()) { - getScreenManager().showStoreWithApp(getActivity()); - } else { - setupTextFeedback(); - } - } - - @Override - public void onClickSupport(int starNumber) { - getSharedPreferenceHelper().afterRateWasHandled(); - RatingUtilKt.reportRateEvent(getAnalytic(), starNumber, Analytic.Rating.NEGATIVE_EMAIL); - setupTextFeedback(); - } - - @Override - public void sendTextFeedback(@NotNull SupportEmailData supportEmailData) { - screenManager.openTextFeedBack(requireContext(), supportEmailData); - } - - @Override - public void onTimeIntervalPicked(int chosenInterval) { - streakPresenter.setStreakTime(chosenInterval); - getAnalytic().reportEvent(Analytic.Streak.CHOOSE_INTERVAL, chosenInterval + ""); - SnackbarExtensionKt - .setTextColor( - Snackbar.make(rootView, - R.string.streak_notification_enabled_successfully, - Snackbar.LENGTH_LONG), - ColorUtil.INSTANCE.getColorArgb(R.color.white, - getContext())) - .show(); - } - - protected final void hideWrongStatus() { - statusTextView.setVisibility(View.GONE); - } - - protected final void hideHint() { - hintTextView.setVisibility(View.GONE); - } - - private void setupTextFeedback() { - stepAttemptPresenter.sendTextFeedback( - getString(R.string.feedback_subject), - DeviceInfoUtil.getInfosAboutDevice(getContext(), "\n") - ); - } -} \ No newline at end of file diff --git a/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolver.kt b/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolver.kt index 132bad510f..c8e297cf9c 100644 --- a/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolver.kt +++ b/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolver.kt @@ -2,9 +2,8 @@ package org.stepic.droid.util.resolvers import android.support.annotation.ColorRes import android.support.annotation.DrawableRes -import org.stepic.droid.base.StepBaseFragment -import org.stepik.android.model.Step import org.stepic.droid.ui.quiz.QuizDelegate +import org.stepik.android.model.Step interface StepTypeResolver { @@ -14,8 +13,5 @@ interface StepTypeResolver { @ColorRes fun getDrawableTintForStep(isViewed: Boolean): Int - fun getFragment(step: Step?): StepBaseFragment? fun getQuizDelegate(step: Step?): QuizDelegate - - fun isNeedUseOldStepContainer(step: Step): Boolean } diff --git a/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolverImpl.java b/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolverImpl.java index 0d966d654f..f6c0d7129d 100644 --- a/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolverImpl.java +++ b/app/src/main/java/org/stepic/droid/util/resolvers/StepTypeResolverImpl.java @@ -3,9 +3,7 @@ import android.support.annotation.DrawableRes; import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; import org.stepic.droid.R; -import org.stepic.droid.base.StepBaseFragment; import org.stepic.droid.di.AppSingleton; import org.stepic.droid.ui.quiz.ChoiceQuizDelegate; import org.stepic.droid.ui.quiz.NotSupportedQuizDelegate; @@ -84,22 +82,6 @@ public int getDrawableTintForStep(boolean isViewed) { } } - @Override - @Nullable - public StepBaseFragment getFragment(Step step) { - if (step == null - || step.getBlock() == null - || step.getBlock().getName() == null - || step.getBlock().getName().equals("")) - return null; - - String type = step.getBlock().getName(); - switch (type) { - default: - return null; - } - } - @NotNull @Override public QuizDelegate getQuizDelegate(Step step) { @@ -122,31 +104,4 @@ public QuizDelegate getQuizDelegate(Step step) { return errorDelegate; } } - - @Override - public boolean isNeedUseOldStepContainer(@NotNull Step step) { - if (step.getBlock() == null - || step.getBlock().getName() == null - || step.getBlock().getName().equals("")) - return true; - - switch (step.getBlock().getName()) { - case AppConstants.TYPE_TEXT: - case AppConstants.TYPE_VIDEO: - - case AppConstants.TYPE_STRING: - case AppConstants.TYPE_NUMBER: - case AppConstants.TYPE_MATH: - case AppConstants.TYPE_FREE_ANSWER: - case AppConstants.TYPE_CODE: - case AppConstants.TYPE_CHOICE: - - case AppConstants.TYPE_SORTING: - case AppConstants.TYPE_MATCHING: - case AppConstants.TYPE_SQL: - return false; - default: - return true; - } - } } diff --git a/app/src/main/res/layout/auth_line_view.xml b/app/src/main/res/layout/auth_line_view.xml deleted file mode 100644 index 2bd601ae04..0000000000 --- a/app/src/main/res/layout/auth_line_view.xml +++ /dev/null @@ -1,18 +0,0 @@ - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_step_attempt.xml b/app/src/main/res/layout/fragment_step_attempt.xml deleted file mode 100644 index 81d707163b..0000000000 --- a/app/src/main/res/layout/fragment_step_attempt.xml +++ /dev/null @@ -1,146 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - -