From 5705fb78dd8ede06ae0df48a844f594daff5b444 Mon Sep 17 00:00:00 2001 From: Pronay Sarker Date: Thu, 11 Jul 2024 22:48:30 +0600 Subject: [PATCH] MIFOSAC-190 Migrate surveyList to compose (#2125) Backup backup backup --- .../online/surveylist/SurveyListFragment.kt | 72 +++--- .../surveylist/SurveyListFragmentOld.kt | 122 ++++++++++ .../online/surveylist/SurveyListScreen.kt | 228 ++++++++++++++++++ .../online/surveylist/SurveyListViewModel.kt | 8 +- .../main/res/layout/fragment_survey_list.xml | 10 +- 5 files changed, 389 insertions(+), 51 deletions(-) create mode 100644 mifosng-android/src/main/java/com/mifos/mifosxdroid/online/surveylist/SurveyListFragmentOld.kt create mode 100644 mifosng-android/src/main/java/com/mifos/mifosxdroid/online/surveylist/SurveyListScreen.kt diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/surveylist/SurveyListFragment.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/surveylist/SurveyListFragment.kt index 9c19eeacb04..d2e84a09d62 100755 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/surveylist/SurveyListFragment.kt +++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/surveylist/SurveyListFragment.kt @@ -12,14 +12,19 @@ import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.AdapterView +import androidx.compose.ui.platform.ComposeView +import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.lifecycle.ViewModelProvider +import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import com.mifos.core.objects.survey.Survey import com.mifos.mifosxdroid.R import com.mifos.mifosxdroid.adapters.SurveyListAdapter +import com.mifos.mifosxdroid.core.MifosBaseFragment import com.mifos.mifosxdroid.core.ProgressableFragment import com.mifos.mifosxdroid.core.util.Toaster import com.mifos.mifosxdroid.databinding.FragmentSurveyListBinding +import com.mifos.mifosxdroid.online.datatable.DataTableScreen import dagger.hilt.android.AndroidEntryPoint /** @@ -30,74 +35,55 @@ import dagger.hilt.android.AndroidEntryPoint * Created by Nasim Banu on 27,January,2016. */ @AndroidEntryPoint -class SurveyListFragment : ProgressableFragment() { +class SurveyListFragment : MifosBaseFragment() { private lateinit var binding: FragmentSurveyListBinding private val arg: SurveyListFragmentArgs by navArgs() - private lateinit var viewModel: SurveyListViewModel - private var mListener: OnFragmentInteractionListener? = null private var clientId = 0 + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) clientId = arg.clientId } + override fun onCreateView( inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? ): View { - binding = FragmentSurveyListBinding.inflate(inflater, container, false) - viewModel = ViewModelProvider(this)[SurveyListViewModel::class.java] - setToolbarTitle(getString(R.string.surveys)) - viewModel.loadSurveyList() - - viewModel.surveyListUiState.observe(viewLifecycleOwner) { - when (it) { - is SurveyListUiState.ShowAllSurvey -> { - showProgressbar(false) - showAllSurvey(it.syncSurvey) - } - - is SurveyListUiState.ShowFetchingError -> { - showProgressbar(false) - showFetchingError(it.message) - } - - is SurveyListUiState.ShowProgressbar -> showProgressbar(true) + return ComposeView(requireContext()).apply { + setViewCompositionStrategy(ViewCompositionStrategy.DisposeOnViewTreeLifecycleDestroyed) + setContent { + SurveyListScreen( + navigateBack = { findNavController().popBackStack() }, + onCardClicked = { position, surveys -> + openSurvey(position, surveys) + } + ) } } - - return binding.root } - private fun showAllSurvey(surveys: List) { - if (surveys.isEmpty()) { - binding.tvSurveyName.text = - resources.getString(R.string.no_survey_available_for_client) - } else { - val surveyListAdapter = SurveyListAdapter(requireActivity(), surveys) - binding.lvSurveysList.adapter = surveyListAdapter - binding.lvSurveysList.onItemClickListener = - AdapterView.OnItemClickListener { adapterView, view, position, l -> - mListener?.loadSurveyQuestion( - surveys[position], - clientId - ) - } - } + fun openSurvey(position: Int, surveys: List) { + mListener?.loadSurveyQuestion( + surveys[position], + clientId + ) } - private fun showFetchingError(errorMessage: Int) { - Toaster.show(binding.root, resources.getString(errorMessage)) + override fun onResume() { + super.onResume() + toolbar?.visibility = View.GONE } - private fun showProgressbar(b: Boolean) { - showProgress(b) + override fun onStop() { + super.onStop() + toolbar?.visibility = View.VISIBLE } - + override fun onOptionsItemSelected(item: MenuItem): Boolean { if (item.itemId == R.id.mItem_search) requireActivity().finish() return super.onOptionsItemSelected(item) diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/surveylist/SurveyListFragmentOld.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/surveylist/SurveyListFragmentOld.kt new file mode 100644 index 00000000000..6a45cfc8f49 --- /dev/null +++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/surveylist/SurveyListFragmentOld.kt @@ -0,0 +1,122 @@ +///* +// * This project is licensed under the open source MPL V2. +// * See https://github.com/openMF/android-client/blob/master/LICENSE.md +// */ +//package com.mifos.mifosxdroid.online.surveylist +// +//import android.app.Activity +//import android.content.Context +//import android.os.Bundle +//import android.view.LayoutInflater +//import android.view.MenuItem +//import android.view.View +//import android.view.ViewGroup +//import android.widget.AdapterView +//import androidx.lifecycle.ViewModelProvider +//import androidx.navigation.fragment.navArgs +//import com.mifos.core.objects.survey.Survey +//import com.mifos.mifosxdroid.R +//import com.mifos.mifosxdroid.adapters.SurveyListAdapter +//import com.mifos.mifosxdroid.core.ProgressableFragment +//import com.mifos.mifosxdroid.core.util.Toaster +//import com.mifos.mifosxdroid.databinding.FragmentSurveyListBinding +//import dagger.hilt.android.AndroidEntryPoint +// +///** +// * This Class shows the List of Surveys after fetching the surveys list from the REST API : +// * https://demo.openmf.org/fineract-provider/api/v1/surveys +// * +// * +// * Created by Nasim Banu on 27,January,2016. +// */ +//@AndroidEntryPoint +//class SurveyListFragment : ProgressableFragment() { +// +// private lateinit var binding: FragmentSurveyListBinding +// private val arg: SurveyListFragmentArgs by navArgs() +// +// private lateinit var viewModel: SurveyListViewModel +// +// private var mListener: OnFragmentInteractionListener? = null +// private var clientId = 0 +// override fun onCreate(savedInstanceState: Bundle?) { +// super.onCreate(savedInstanceState) +// clientId = arg.clientId +// } +// +// override fun onCreateView( +// inflater: LayoutInflater, +// container: ViewGroup?, +// savedInstanceState: Bundle? +// ): View { +// binding = FragmentSurveyListBinding.inflate(inflater, container, false) +// viewModel = ViewModelProvider(this)[SurveyListViewModel::class.java] +// setToolbarTitle(getString(R.string.surveys)) +// viewModel.loadSurveyList() +// +// viewModel.surveyListUiState.observe(viewLifecycleOwner) { +// when (it) { +// is SurveyListUiState.ShowAllSurvey -> { +// showProgressbar(false) +// showAllSurvey(it.syncSurvey) +// } +// +// is SurveyListUiState.ShowFetchingError -> { +// showProgressbar(false) +// showFetchingError(it.message) +// } +// +// is SurveyListUiState.ShowProgressbar -> showProgressbar(true) +// } +// } +// +// return binding.root +// } +// +// private fun showAllSurvey(surveys: List) { +// if (surveys.isEmpty()) { +// binding.tvSurveyName.text = +// resources.getString(R.string.no_survey_available_for_client) +// } else { +// val surveyListAdapter = SurveyListAdapter(requireActivity(), surveys) +// binding.lvSurveysList.adapter = surveyListAdapter +// binding.lvSurveysList.onItemClickListener = +// AdapterView.OnItemClickListener { adapterView, view, position, l -> +// mListener?.loadSurveyQuestion( +// surveys[position], +// clientId +// ) +// } +// } +// } +// +// private fun showFetchingError(errorMessage: Int) { +// Toaster.show(binding.root, resources.getString(errorMessage)) +// } +// +// private fun showProgressbar(b: Boolean) { +// showProgress(b) +// } +// +// override fun onOptionsItemSelected(item: MenuItem): Boolean { +// if (item.itemId == R.id.mItem_search) requireActivity().finish() +// return super.onOptionsItemSelected(item) +// } +// +// override fun onAttach(context: Context) { +// super.onAttach(context) +// val activity = if (context is Activity) context else null +// mListener = try { +// activity as OnFragmentInteractionListener? +// } catch (e: ClassCastException) { +// throw ClassCastException( +// activity.toString() + " must implement " + +// "OnFragmentInteractionListener" +// ) +// } +// } +// +// interface OnFragmentInteractionListener { +// fun loadSurveyQuestion(survey: Survey?, clientId: Int) +// } +//} \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/surveylist/SurveyListScreen.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/surveylist/SurveyListScreen.kt new file mode 100644 index 00000000000..b2eddcc3370 --- /dev/null +++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/surveylist/SurveyListScreen.kt @@ -0,0 +1,228 @@ +package com.mifos.mifosxdroid.online.surveylist + +import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.layout.size +import androidx.compose.foundation.lazy.LazyColumn +import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.ExperimentalMaterialApi +import androidx.compose.material3.Card +import androidx.compose.material3.CardDefaults +import androidx.compose.material3.CardElevation +import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.SnackbarHostState +import androidx.compose.material3.Text +import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.runtime.getValue +import androidx.compose.runtime.remember +import androidx.compose.ui.Modifier +import androidx.compose.ui.graphics.Color +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.text.TextStyle +import androidx.compose.ui.text.font.FontStyle +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.tooling.preview.Preview +import androidx.compose.ui.tooling.preview.PreviewParameter +import androidx.compose.ui.tooling.preview.PreviewParameterProvider +import androidx.compose.ui.unit.dp +import androidx.compose.ui.unit.sp +import androidx.hilt.navigation.compose.hiltViewModel +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.mifos.core.designsystem.component.MifosCircularProgress +import com.mifos.core.designsystem.component.MifosScaffold +import com.mifos.core.designsystem.component.MifosSweetError +import com.mifos.core.designsystem.icon.MifosIcons +import com.mifos.core.designsystem.theme.BluePrimary +import com.mifos.core.objects.survey.Survey +import com.mifos.core.ui.components.MifosEmptyUi +import com.mifos.mifosxdroid.R +import com.mifos.mifosxdroid.online.datatable.DataTablePreviewProvider +import com.mifos.mifosxdroid.online.datatable.DataTableUiState + +/** + * Created by Pronay Sarker on 03/07/2024 (6:05 AM) + */ + +@Composable +fun SurveyListScreen( + viewModel: SurveyListViewModel = hiltViewModel(), + navigateBack: () -> Unit, + onCardClicked: (index: Int, surveys: List) -> Unit + +) { + val uiState by viewModel.surveyListUiState.collectAsStateWithLifecycle() + + LaunchedEffect(key1 = Unit) { + viewModel.loadSurveyList() + } + + SurveyListScreen( + uiState = uiState, + navigateBack = navigateBack, + onRetry = { viewModel.loadSurveyList() }, + onCardClicked = onCardClicked + ) +} + +@Composable +fun SurveyListScreen( + uiState: SurveyListUiState, + navigateBack: () -> Unit, + onRetry: () -> Unit, + onCardClicked: (index: Int, surveys: List) -> Unit +) { + val snackbarHostState = remember { + SnackbarHostState() + } + + MifosScaffold( + snackbarHostState = snackbarHostState, + icon = MifosIcons.arrowBack, + onBackPressed = navigateBack, + title = stringResource(id = R.string.surveys) + ) { + Box(modifier = Modifier.padding(it)) { + when (uiState) { + + is SurveyListUiState.ShowAllSurvey -> { + if (uiState.syncSurvey.isEmpty()) { + MifosEmptyUi(text = stringResource(id = R.string.no_survey_available_for_client)) + } else { + SurveyListContent( + surveyList = uiState.syncSurvey, + onCardClicked = onCardClicked + ) + } + } + + is SurveyListUiState.ShowFetchingError -> { + MifosSweetError( + message = stringResource(id = uiState.message), + onclick = onRetry + ) + } + + SurveyListUiState.ShowProgressbar -> { + MifosCircularProgress() + } + } + } + } +} + +@Composable +fun SurveyListContent( + surveyList: List, + onCardClicked: (index: Int, surveys: List) -> Unit +) { + Column( + modifier = Modifier.fillMaxSize() + ) { + Text( + modifier = Modifier + .padding(horizontal = 18.dp) + .padding(top = 16.dp, bottom = 8.dp), + text = stringResource(id = R.string.select_one_survey), + style = TextStyle( + fontSize = 20.sp, + fontWeight = FontWeight.Normal, + fontStyle = FontStyle.Normal + ) + ) + + LazyColumn { + items(surveyList) { survey -> + SurveyCardItem( + surveyName = survey.name, + description = survey.description, + onCardClicked = { onCardClicked.invoke(surveyList.indexOf(survey), surveyList) } + ) + } + } + } +} + +@Composable +fun SurveyCardItem( + surveyName: String?, + description: String?, + onCardClicked: () -> Unit +) { + Card( + modifier = Modifier + .fillMaxWidth() + .padding(horizontal = 12.dp) + .padding(bottom = 12.dp), + colors = CardDefaults.cardColors( + containerColor = Color.White + ), + elevation = CardDefaults.cardElevation(2.dp), + onClick = onCardClicked, + shape = RoundedCornerShape(4.dp) + ) { + Column( + modifier = Modifier.fillMaxWidth() + ) { + Box( + modifier = Modifier + .fillMaxWidth() + .size(5.dp) + .background(color = Color(0xFF4285f6)) + ) + + Column( + modifier = Modifier.padding(horizontal = 8.dp, vertical = 8.dp) + ) { + Text( + text = surveyName ?: "", + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onBackground + ) + + Text( + text = description ?: "", + style = MaterialTheme.typography.bodyLarge, + color = MaterialTheme.colorScheme.onBackground.copy(alpha = .8f) + ) + } + } + } +} + +class SurveyListPreviewProvider : PreviewParameterProvider { + var demoSurvey = listOf( + Survey(name = "Survey header", description = "Survey description"), + Survey(name = "Header", description = null), + Survey(name = "General Knowledge", description = "What is the capital of MARS"), + Survey(name = "Favourite youtuber?", description = "Dhinkchak pooja"), + Survey(name = "Phone survey", description = "Samsung is better than iphone"), + ) + + override val values: Sequence + get() = sequenceOf( + SurveyListUiState.ShowProgressbar, + SurveyListUiState.ShowFetchingError(R.string.failed_to_fetch_datatable), + SurveyListUiState.ShowAllSurvey(demoSurvey) + ) +} + +@Composable +@Preview(showSystemUi = true) +fun PreviewSurveyListScreen( + @PreviewParameter(SurveyListPreviewProvider::class) surveyListUiState: SurveyListUiState +) { + SurveyListScreen( + uiState = surveyListUiState, + navigateBack = { }, + onRetry = { }, + onCardClicked = { _, _ -> + + } + ) +} \ No newline at end of file diff --git a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/surveylist/SurveyListViewModel.kt b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/surveylist/SurveyListViewModel.kt index fb0c764c431..3b385a9b3f1 100644 --- a/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/surveylist/SurveyListViewModel.kt +++ b/mifosng-android/src/main/java/com/mifos/mifosxdroid/online/surveylist/SurveyListViewModel.kt @@ -9,6 +9,8 @@ import com.mifos.core.objects.survey.Survey import com.mifos.mifosxdroid.R import com.mifos.utils.PrefManager import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.StateFlow import rx.Subscriber import rx.android.schedulers.AndroidSchedulers import rx.schedulers.Schedulers @@ -21,13 +23,13 @@ import javax.inject.Inject class SurveyListViewModel @Inject constructor(private val repository: SurveyListRepository) : ViewModel() { - private val _surveyListUiState = MutableLiveData() + private val _surveyListUiState = MutableStateFlow(SurveyListUiState.ShowProgressbar) + val surveyListUiState: StateFlow get() = _surveyListUiState + private var mDbSurveyList: List? = null private lateinit var mSyncSurveyList: List - val surveyListUiState: LiveData - get() = _surveyListUiState fun loadSurveyList() { _surveyListUiState.value = SurveyListUiState.ShowProgressbar diff --git a/mifosng-android/src/main/res/layout/fragment_survey_list.xml b/mifosng-android/src/main/res/layout/fragment_survey_list.xml index 9a9cd097c8a..a86ce31a50b 100755 --- a/mifosng-android/src/main/res/layout/fragment_survey_list.xml +++ b/mifosng-android/src/main/res/layout/fragment_survey_list.xml @@ -12,11 +12,11 @@ android:outAnimation="@android:anim/fade_out"> - + + + + +