diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index c632728593b..0958158687b 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -2,7 +2,7 @@ - + , + selectedLanguageCode ) - dialogFragment.showNow(fragmentManager, TAG_DIALOG) + dialogFragment.showNow(childFragmentManager, TAG_LANGUAGE_DIALOG) } private fun getDummyAudioLanguageList(): List { @@ -52,4 +48,9 @@ class AudioFragment : InjectableFragment() { languageCodeList.add("hi-en") return languageCodeList } + + override fun onLanguageSelected(currentLanguageCode: String) { + selectedLanguageCode = currentLanguageCode + audioFragmentPresenter.languageSelected(currentLanguageCode) + } } diff --git a/app/src/main/java/org/oppia/app/player/audio/AudioFragmentPresenter.kt b/app/src/main/java/org/oppia/app/player/audio/AudioFragmentPresenter.kt index 82e6cc80e26..901b33c47a3 100755 --- a/app/src/main/java/org/oppia/app/player/audio/AudioFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/app/player/audio/AudioFragmentPresenter.kt @@ -9,7 +9,7 @@ import org.oppia.app.fragment.FragmentScope import org.oppia.app.viewmodel.ViewModelProvider import javax.inject.Inject -/** The controller for [AudioFragment]. */ +/** The presenter for [AudioFragment]. */ @FragmentScope class AudioFragmentPresenter @Inject constructor( private val fragment: Fragment, diff --git a/app/src/main/java/org/oppia/app/player/audio/AudioViewModel.kt b/app/src/main/java/org/oppia/app/player/audio/AudioViewModel.kt index 018dbbed522..63f49920c40 100644 --- a/app/src/main/java/org/oppia/app/player/audio/AudioViewModel.kt +++ b/app/src/main/java/org/oppia/app/player/audio/AudioViewModel.kt @@ -9,7 +9,6 @@ import javax.inject.Inject @FragmentScope class AudioViewModel @Inject constructor( ) : ViewModel() { - val currentLanguageCode = ObservableField("en") fun setAudioLanguageCode(languageCode: String) { diff --git a/app/src/main/java/org/oppia/app/player/audio/CellularDataDialogFragment.kt b/app/src/main/java/org/oppia/app/player/audio/CellularDataDialogFragment.kt new file mode 100755 index 00000000000..417465ef018 --- /dev/null +++ b/app/src/main/java/org/oppia/app/player/audio/CellularDataDialogFragment.kt @@ -0,0 +1,47 @@ +package org.oppia.app.player.audio + +import android.app.Dialog +import android.content.Context +import android.os.Bundle +import androidx.appcompat.app.AlertDialog +import androidx.fragment.app.DialogFragment +import android.widget.CheckBox +import org.oppia.app.R +import org.oppia.app.player.state.StateFragment + +/** + * DialogFragment that indicates to the user they are on cellular when trying to play an audio voiceover. + */ +class CellularDataDialogFragment : DialogFragment() { + companion object { + /** + * This function is responsible for displaying content in DialogFragment. + * + * @return [CellularDataDialogFragment]: DialogFragment + */ + fun newInstance(): CellularDataDialogFragment { + return CellularDataDialogFragment() + } + } + + override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { + val view = activity!!.layoutInflater.inflate(R.layout.cellular_data_dialog, null) + val checkBox = view.findViewById(R.id.cellular_data_dialog_checkbox) + + val cellularDataInterface: CellularDataInterface = parentFragment as StateFragment + + return AlertDialog.Builder(activity as Context) + .setTitle(R.string.cellular_data_alert_dialog_title) + .setView(view) + .setMessage(R.string.cellular_data_alert_dialog_description) + .setPositiveButton(R.string.cellular_data_alert_dialog_okay_button) { dialog, whichButton -> + cellularDataInterface.enableAudioWhileOnCellular(checkBox.isChecked) + dismiss() + } + .setNegativeButton(R.string.cellular_data_alert_dialog_cancel_button) { dialog, whichButton -> + cellularDataInterface.disableAudioWhileOnCellular(checkBox.isChecked) + dismiss() + } + .create() + } +} diff --git a/app/src/main/java/org/oppia/app/player/audio/CellularDataInterface.kt b/app/src/main/java/org/oppia/app/player/audio/CellularDataInterface.kt new file mode 100755 index 00000000000..5f2f15ba88b --- /dev/null +++ b/app/src/main/java/org/oppia/app/player/audio/CellularDataInterface.kt @@ -0,0 +1,16 @@ +package org.oppia.app.player.audio + +/** Interface to check the preference regarding alert for [CellularDataDialogFragment]. */ +interface CellularDataInterface { + /** + * If saveUserChoice is true, show audio-player and save preference do not show dialog again. + * If saveUserChoice is false, show audio-player and do not save preference and show this dialog next time too. + */ + fun enableAudioWhileOnCellular(saveUserChoice: Boolean) + + /** + * If saveUserChoice is true, do not show audio-player on cellular network and save preference. + * If saveUserChoice is false, do not show audio-player and do not save preference. + */ + fun disableAudioWhileOnCellular(saveUserChoice: Boolean) +} diff --git a/app/src/main/java/org/oppia/app/player/audio/LanguageDialogFragment.kt b/app/src/main/java/org/oppia/app/player/audio/LanguageDialogFragment.kt index 8e3cfd1b23b..f5ce5e65a7d 100644 --- a/app/src/main/java/org/oppia/app/player/audio/LanguageDialogFragment.kt +++ b/app/src/main/java/org/oppia/app/player/audio/LanguageDialogFragment.kt @@ -6,75 +6,58 @@ import android.os.Bundle import androidx.appcompat.app.AlertDialog import androidx.fragment.app.DialogFragment import org.oppia.app.R -import java.util.ArrayList private const val KEY_LANGUAGE_LIST = "LANGUAGE_LIST" -private const val KEY_CURRENT_LANGUAGE = "CURRENT_LANGUAGE" +private const val KEY_SELECTED_INDEX = "SELECTED_INDEX" /** - * DialogFragment that controls language selection in audio and written translations + * DialogFragment that controls language selection in audio and written translations. */ class LanguageDialogFragment : DialogFragment() { companion object { - lateinit var languageInterface1: LanguageInterface /** - * This function is responsible for displaying content in DialogFragment - * @param languageInterface: [LanguageInterface] to send data back to parent - * @param languageCodeList: List of strings containing languages + * This function is responsible for displaying content in DialogFragment. + * + * @param languageArrayList: List of strings containing languages * @param currentLanguageCode: Currently selected language code - * @return LanguageDialogFragment: DialogFragment + * @return [LanguageDialogFragment]: DialogFragment */ fun newInstance( - languageInterface: LanguageInterface, - languageCodeList: List, + languageArrayList: ArrayList, currentLanguageCode: String ): LanguageDialogFragment { - - languageInterface1 = languageInterface - val selectedIndex: Int = languageCodeList.indexOf(currentLanguageCode) - val fragment = LanguageDialogFragment() + val selectedIndex = languageArrayList.indexOf(currentLanguageCode) + val languageDialogFragment = LanguageDialogFragment() val args = Bundle() - args.putStringArrayList( - KEY_LANGUAGE_LIST, - languageCodeList as ArrayList - ) - args.putInt(KEY_CURRENT_LANGUAGE, selectedIndex) - fragment.arguments = args - return fragment + args.putStringArrayList(KEY_LANGUAGE_LIST, languageArrayList) + args.putInt(KEY_SELECTED_INDEX, selectedIndex) + languageDialogFragment.arguments = args + return languageDialogFragment } } override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { - var languageList = savedInstanceState?.getStringArrayList(KEY_LANGUAGE_LIST) - var currentIndex = savedInstanceState?.getInt(KEY_CURRENT_LANGUAGE, 0) - if (languageList != null) { - // Not null - // Currently data is not getting transferred to LanguageDialogFragment. - } else { - // Null - // Error handling can be done here if needed. - languageList = ArrayList() - languageList.add("en") - languageList.add("hi") - languageList.add("hi-en") - } + val args = checkNotNull(arguments) { "Expected arguments to be pass to LanguageDialogFragment" } + + var selectedIndex = args.getInt(KEY_SELECTED_INDEX, 0) + val languageArrayList: ArrayList = args.getStringArrayList(KEY_LANGUAGE_LIST) + val options = languageArrayList.toTypedArray() - val options = languageList!!.toTypedArray() + val languageInterface: LanguageInterface = parentFragment as AudioFragment return AlertDialog.Builder(activity as Context) .setTitle(R.string.audio_language_select_dialog_title) - .setSingleChoiceItems(options, 0) { dialog, which -> - currentIndex = which + .setSingleChoiceItems(options, selectedIndex) { dialog, which -> + selectedIndex = which } .setPositiveButton(R.string.audio_language_select_dialog_okay_button) { dialog, whichButton -> - languageInterface1.onLanguageSelected(languageList.get(currentIndex!!)) + languageInterface.onLanguageSelected(languageArrayList[selectedIndex]) dismiss() } .setNegativeButton(R.string.audio_language_select_dialog_cancel_button) { dialog, whichButton -> dismiss() } - .setCancelable(true) .create() } } diff --git a/app/src/main/java/org/oppia/app/player/audio/LanguageInterface.kt b/app/src/main/java/org/oppia/app/player/audio/LanguageInterface.kt index 12e0eb3d99b..7a2d7cd43bc 100644 --- a/app/src/main/java/org/oppia/app/player/audio/LanguageInterface.kt +++ b/app/src/main/java/org/oppia/app/player/audio/LanguageInterface.kt @@ -1,6 +1,7 @@ package org.oppia.app.player.audio -/** Interface to receive selected language from [LanguageDialogFragment] */ +/** Interface to receive selected language from [LanguageDialogFragment]. */ interface LanguageInterface { + /** Play the audio corresponding to the language-selected. */ fun onLanguageSelected(currentLanguageCode: String) } diff --git a/app/src/main/java/org/oppia/app/player/state/StateFragment.kt b/app/src/main/java/org/oppia/app/player/state/StateFragment.kt index 20908b50513..665d2dea6cb 100755 --- a/app/src/main/java/org/oppia/app/player/state/StateFragment.kt +++ b/app/src/main/java/org/oppia/app/player/state/StateFragment.kt @@ -6,11 +6,22 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import org.oppia.app.fragment.InjectableFragment +import org.oppia.app.player.audio.CellularDataDialogFragment +import org.oppia.app.player.audio.CellularDataInterface import javax.inject.Inject -/** Fragment that represents the current state card of an exploration. */ -class StateFragment : InjectableFragment() { - @Inject lateinit var stateFragmentPresenter: StateFragmentPresenter +private const val TAG_CELLULAR_DATA_DIALOG = "CELLULAR_DATA_DIALOG" + +/** Fragment that represents the current state of an exploration. */ +class StateFragment : InjectableFragment(), CellularDataInterface { + @Inject + lateinit var stateFragmentPresenter: StateFragmentPresenter + // Control this boolean value from controllers in domain module. + private var showCellularDataDialog = true + + init { + // TODO(#116): Code to control the value of showCellularDataDialog using AudioController. + } override fun onAttach(context: Context?) { super.onAttach(context) @@ -20,4 +31,33 @@ class StateFragment : InjectableFragment() { override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? { return stateFragmentPresenter.handleCreateView(inflater, container) } + + fun dummyButtonClicked() { + if (showCellularDataDialog) { + stateFragmentPresenter.setAudioFragmentVisible(false) + showCellularDataDialogFragment() + } else { + stateFragmentPresenter.setAudioFragmentVisible(true) + } + } + + private fun showCellularDataDialogFragment() { + val previousFragment = childFragmentManager.findFragmentByTag(TAG_CELLULAR_DATA_DIALOG) + if (previousFragment != null) { + childFragmentManager.beginTransaction().remove(previousFragment).commitNow() + } + val dialogFragment = CellularDataDialogFragment.newInstance() + dialogFragment.showNow(childFragmentManager, TAG_CELLULAR_DATA_DIALOG) + } + + override fun enableAudioWhileOnCellular(saveUserChoice: Boolean) { + stateFragmentPresenter.setAudioFragmentVisible(true) + // saveUserChoice -> true -> save this preference + // saveUserChoice -> false -> do not save this preference + } + + override fun disableAudioWhileOnCellular(saveUserChoice: Boolean) { + // saveUserChoice -> true -> save this preference + // saveUserChoice -> false -> do not save this preference + } } diff --git a/app/src/main/java/org/oppia/app/player/state/StateFragmentPresenter.kt b/app/src/main/java/org/oppia/app/player/state/StateFragmentPresenter.kt index f43accab6d8..6a6f020d30c 100755 --- a/app/src/main/java/org/oppia/app/player/state/StateFragmentPresenter.kt +++ b/app/src/main/java/org/oppia/app/player/state/StateFragmentPresenter.kt @@ -6,14 +6,29 @@ import android.view.ViewGroup import androidx.fragment.app.Fragment import org.oppia.app.databinding.StateFragmentBinding import org.oppia.app.fragment.FragmentScope +import org.oppia.app.viewmodel.ViewModelProvider import javax.inject.Inject -/** The controller for [StateFragment]. */ +/** The presenter for [StateFragment]. */ @FragmentScope class StateFragmentPresenter @Inject constructor( - private val fragment: Fragment + private val fragment: Fragment, + private val viewModelProvider: ViewModelProvider ) { fun handleCreateView(inflater: LayoutInflater, container: ViewGroup?): View? { - return StateFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false).root + val binding = StateFragmentBinding.inflate(inflater, container, /* attachToRoot= */ false) + binding.let { + it.stateFragment = fragment as StateFragment + it.viewModel = getStateViewModel() + } + return binding.root + } + + private fun getStateViewModel(): StateViewModel { + return viewModelProvider.getForFragment(fragment, StateViewModel::class.java) + } + + fun setAudioFragmentVisible(isVisible: Boolean) { + getStateViewModel().setAudioFragmentVisible(isVisible) } } diff --git a/app/src/main/java/org/oppia/app/player/state/StateViewModel.kt b/app/src/main/java/org/oppia/app/player/state/StateViewModel.kt new file mode 100644 index 00000000000..5af8d2ac519 --- /dev/null +++ b/app/src/main/java/org/oppia/app/player/state/StateViewModel.kt @@ -0,0 +1,16 @@ +package org.oppia.app.player.state + +import androidx.databinding.ObservableField +import androidx.lifecycle.ViewModel +import org.oppia.app.fragment.FragmentScope +import javax.inject.Inject + +/** [ViewModel] for state-fragment. */ +@FragmentScope +class StateViewModel @Inject constructor() : ViewModel() { + var isAudioFragmentVisible = ObservableField(false) + + fun setAudioFragmentVisible(isVisible: Boolean) { + isAudioFragmentVisible.set(isVisible) + } +} diff --git a/app/src/main/res/layout/cellular_data_dialog.xml b/app/src/main/res/layout/cellular_data_dialog.xml new file mode 100755 index 00000000000..cbab58156a6 --- /dev/null +++ b/app/src/main/res/layout/cellular_data_dialog.xml @@ -0,0 +1,14 @@ + + + + + diff --git a/app/src/main/res/layout/state_fragment.xml b/app/src/main/res/layout/state_fragment.xml index b905de6cc77..d1cff627ed7 100755 --- a/app/src/main/res/layout/state_fragment.xml +++ b/app/src/main/res/layout/state_fragment.xml @@ -1,10 +1,47 @@ - + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:app="http://schemas.android.com/apk/res-auto"> + + + + + - + + + +