From 8bb41557d892c50914dbc4f661e8618ee1d74980 Mon Sep 17 00:00:00 2001 From: razeeman Date: Sun, 9 Apr 2023 13:31:11 +0300 Subject: [PATCH] adding data edit change activity --- .../di/NavigationDialogMapModule.kt | 12 ++ app/src/main/res/navigation/nav_graph.xml | 5 + core/src/main/res/values/strings.xml | 5 + .../DataEditTypeSelectionDialogFragment.kt | 83 +++++++++ .../DataEditTypeSelectionDialogListener.kt | 6 + .../dialog/DataEditTypeSelectionViewModel.kt | 67 ++++++++ .../model/DataEditChangeActivityState.kt | 9 + .../view/DataEditFragment.kt | 44 ++++- .../viewModel/DataEditViewModel.kt | 51 ++++++ .../main/res/layout/data_edit_fragment.xml | 161 ++++++++++++++++-- ...ta_edit_type_selection_dialog_fragment.xml | 26 +++ .../src/main/res/values/styles.xml | 11 -- .../src/main/res/values/styles.xml | 7 + .../DataEditTypeSelectionDialogParams.kt | 3 + 14 files changed, 467 insertions(+), 23 deletions(-) create mode 100644 features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTypeSelectionDialogFragment.kt create mode 100644 features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTypeSelectionDialogListener.kt create mode 100644 features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTypeSelectionViewModel.kt create mode 100644 features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/model/DataEditChangeActivityState.kt create mode 100644 features/feature_data_edit/src/main/res/layout/data_edit_type_selection_dialog_fragment.xml delete mode 100644 features/feature_settings/src/main/res/values/styles.xml create mode 100644 navigation/src/main/java/com/example/util/simpletimetracker/navigation/params/screen/DataEditTypeSelectionDialogParams.kt diff --git a/app/src/main/java/com/example/util/simpletimetracker/di/NavigationDialogMapModule.kt b/app/src/main/java/com/example/util/simpletimetracker/di/NavigationDialogMapModule.kt index 32c3ef23..c20cdf49 100644 --- a/app/src/main/java/com/example/util/simpletimetracker/di/NavigationDialogMapModule.kt +++ b/app/src/main/java/com/example/util/simpletimetracker/di/NavigationDialogMapModule.kt @@ -1,6 +1,7 @@ package com.example.util.simpletimetracker.di import com.example.util.simpletimetracker.R +import com.example.util.simpletimetracker.feature_data_edit.dialog.DataEditTypeSelectionDialogFragment import com.example.util.simpletimetracker.feature_dialogs.archive.view.ArchiveDialogFragment import com.example.util.simpletimetracker.feature_dialogs.cardOrder.view.CardOrderDialogFragment import com.example.util.simpletimetracker.feature_dialogs.colorSelection.view.ColorSelectionDialogFragment @@ -23,6 +24,7 @@ import com.example.util.simpletimetracker.navigation.params.screen.ChartFilterDi import com.example.util.simpletimetracker.navigation.params.screen.ColorSelectionDialogParams import com.example.util.simpletimetracker.navigation.params.screen.DataExportSettingDialogParams import com.example.util.simpletimetracker.navigation.params.screen.CustomRangeSelectionParams +import com.example.util.simpletimetracker.navigation.params.screen.DataEditTypeSelectionDialogParams import com.example.util.simpletimetracker.navigation.params.screen.DateTimeDialogParams import com.example.util.simpletimetracker.navigation.params.screen.DefaultTypesSelectionDialogParams import com.example.util.simpletimetracker.navigation.params.screen.DurationDialogParams @@ -200,4 +202,14 @@ class NavigationDialogMapModule { bundleCreatorDelegate(HelpDialogFragment::createBundle) ) } + + @IntoMap + @Provides + @ScreenKey(DataEditTypeSelectionDialogParams::class) + fun dataEditTypeSelectionDialog(): NavigationData { + return NavigationData( + R.id.dataEditTypeSelectionDialogFragment, + BundleCreator.empty() + ) + } } \ No newline at end of file diff --git a/app/src/main/res/navigation/nav_graph.xml b/app/src/main/res/navigation/nav_graph.xml index 99447d8d..56351160 100644 --- a/app/src/main/res/navigation/nav_graph.xml +++ b/app/src/main/res/navigation/nav_graph.xml @@ -145,6 +145,11 @@ android:name="com.example.util.simpletimetracker.feature_dialogs.helpDialog.HelpDialogFragment" android:label="HelpDialogFragment" tools:layout="@layout/help_dialog_fragment"/> + \"%s\" setting is enabled, app will send events on activity started or These changes cannot be undone. Make sure to create a backup file before doing anything. Select records + Change activity + Tags of current activity will be removed. + Change comment + Add tags + Remove tags Activity diff --git a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTypeSelectionDialogFragment.kt b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTypeSelectionDialogFragment.kt new file mode 100644 index 00000000..08ea8fc7 --- /dev/null +++ b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTypeSelectionDialogFragment.kt @@ -0,0 +1,83 @@ +package com.example.util.simpletimetracker.feature_data_edit.dialog + +import android.content.Context +import android.view.LayoutInflater +import android.view.ViewGroup +import androidx.appcompat.app.AppCompatActivity +import androidx.fragment.app.viewModels +import com.example.util.simpletimetracker.core.base.BaseBottomSheetFragment +import com.example.util.simpletimetracker.core.extension.blockContentScroll +import com.example.util.simpletimetracker.core.extension.getAllFragments +import com.example.util.simpletimetracker.core.extension.setFullScreen +import com.example.util.simpletimetracker.core.extension.setSkipCollapsed +import com.example.util.simpletimetracker.feature_base_adapter.BaseRecyclerAdapter +import com.example.util.simpletimetracker.feature_base_adapter.hint.createHintAdapterDelegate +import com.example.util.simpletimetracker.feature_base_adapter.loader.createLoaderAdapterDelegate +import com.example.util.simpletimetracker.feature_base_adapter.recordType.RecordTypeViewData +import com.example.util.simpletimetracker.feature_base_adapter.recordType.createRecordTypeAdapterDelegate +import com.google.android.flexbox.FlexDirection +import com.google.android.flexbox.FlexWrap +import com.google.android.flexbox.FlexboxLayoutManager +import com.google.android.flexbox.JustifyContent +import dagger.hilt.android.AndroidEntryPoint +import com.example.util.simpletimetracker.feature_data_edit.databinding.DataEditTypeSelectionDialogFragmentBinding as Binding + +@AndroidEntryPoint +class DataEditTypeSelectionDialogFragment : BaseBottomSheetFragment() { + + override val inflater: (LayoutInflater, ViewGroup?, Boolean) -> Binding = + Binding::inflate + + private val viewModel: DataEditTypeSelectionViewModel by viewModels() + + private val adapter: BaseRecyclerAdapter by lazy { + BaseRecyclerAdapter( + createLoaderAdapterDelegate(), + createHintAdapterDelegate(), + createRecordTypeAdapterDelegate(::dismiss), + ) + } + + private var listener: DataEditTypeSelectionDialogListener? = null + + override fun onAttach(context: Context) { + super.onAttach(context) + when (context) { + is DataEditTypeSelectionDialogListener -> { + listener = context + return + } + is AppCompatActivity -> { + context.getAllFragments() + .firstOrNull { it is DataEditTypeSelectionDialogListener && it.isResumed } + ?.let { listener = it as? DataEditTypeSelectionDialogListener } + } + } + } + + override fun initDialog() { + setSkipCollapsed() + setFullScreen() + blockContentScroll(binding.rvDataEditTypeSelectionContainer) + } + + override fun initUi(): Unit = with(binding) { + rvDataEditTypeSelectionContainer.apply { + layoutManager = FlexboxLayoutManager(requireContext()).apply { + flexDirection = FlexDirection.ROW + justifyContent = JustifyContent.CENTER + flexWrap = FlexWrap.WRAP + } + adapter = this@DataEditTypeSelectionDialogFragment.adapter + } + } + + override fun initViewModel(): Unit = with(viewModel) { + viewData.observe(adapter::replace) + } + + private fun dismiss(item: RecordTypeViewData) { + listener?.onTypeSelected(item.id) + dismiss() + } +} \ No newline at end of file diff --git a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTypeSelectionDialogListener.kt b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTypeSelectionDialogListener.kt new file mode 100644 index 00000000..0f2b2145 --- /dev/null +++ b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTypeSelectionDialogListener.kt @@ -0,0 +1,6 @@ +package com.example.util.simpletimetracker.feature_data_edit.dialog + +interface DataEditTypeSelectionDialogListener { + + fun onTypeSelected(typeId: Long) +} \ No newline at end of file diff --git a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTypeSelectionViewModel.kt b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTypeSelectionViewModel.kt new file mode 100644 index 00000000..e4816e68 --- /dev/null +++ b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTypeSelectionViewModel.kt @@ -0,0 +1,67 @@ +package com.example.util.simpletimetracker.feature_data_edit.dialog + +import androidx.lifecycle.LiveData +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.ViewModel +import androidx.lifecycle.viewModelScope +import com.example.util.simpletimetracker.core.mapper.RecordTypeViewDataMapper +import com.example.util.simpletimetracker.core.repo.ResourceRepo +import com.example.util.simpletimetracker.domain.interactor.PrefsInteractor +import com.example.util.simpletimetracker.domain.interactor.RecordTypeInteractor +import com.example.util.simpletimetracker.domain.model.RecordType +import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType +import com.example.util.simpletimetracker.feature_base_adapter.hint.HintViewData +import com.example.util.simpletimetracker.feature_base_adapter.loader.LoaderViewData +import com.example.util.simpletimetracker.feature_data_edit.R +import dagger.hilt.android.lifecycle.HiltViewModel +import javax.inject.Inject +import kotlinx.coroutines.launch + +@HiltViewModel +class DataEditTypeSelectionViewModel @Inject constructor( + private val recordTypeInteractor: RecordTypeInteractor, + private val prefsInteractor: PrefsInteractor, + private val recordTypeViewDataMapper: RecordTypeViewDataMapper, + private val resourceRepo: ResourceRepo, +) : ViewModel() { + + val viewData: LiveData> by lazy { + return@lazy MutableLiveData>().let { initial -> + viewModelScope.launch { + initial.value = listOf(LoaderViewData()) + initial.value = loadViewData() + } + initial + } + } + + private var types: List = emptyList() + + private suspend fun getCache(): List { + return types.takeUnless { it.isEmpty() } ?: recordTypeInteractor.getAll() + } + + private suspend fun loadViewData(): List { + val result: MutableList = mutableListOf() + + val numberOfCards = prefsInteractor.getNumberOfCards() + val isDarkTheme = prefsInteractor.getDarkMode() + + val typesViewData = getCache().map { type -> + recordTypeViewDataMapper.map( + recordType = type, + numberOfCards = numberOfCards, + isDarkTheme = isDarkTheme, + ) + } + + if (typesViewData.isNotEmpty()) { + HintViewData(resourceRepo.getString(R.string.activity_hint)).let(result::add) + typesViewData.let(result::addAll) + } else { + HintViewData(resourceRepo.getString(R.string.record_types_empty)).let(result::add) + } + + return result + } +} diff --git a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/model/DataEditChangeActivityState.kt b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/model/DataEditChangeActivityState.kt new file mode 100644 index 00000000..575a823f --- /dev/null +++ b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/model/DataEditChangeActivityState.kt @@ -0,0 +1,9 @@ +package com.example.util.simpletimetracker.feature_data_edit.model + +import com.example.util.simpletimetracker.feature_base_adapter.recordType.RecordTypeViewData + +sealed interface DataEditChangeActivityState { + + object Disabled : DataEditChangeActivityState + data class Enabled(val viewData: RecordTypeViewData) : DataEditChangeActivityState +} \ No newline at end of file diff --git a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/view/DataEditFragment.kt b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/view/DataEditFragment.kt index e1c1ce91..8ab5f28b 100644 --- a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/view/DataEditFragment.kt +++ b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/view/DataEditFragment.kt @@ -2,28 +2,68 @@ package com.example.util.simpletimetracker.feature_data_edit.view import android.view.LayoutInflater import android.view.ViewGroup +import androidx.core.view.isVisible import androidx.fragment.app.viewModels import com.example.util.simpletimetracker.core.base.BaseFragment +import com.example.util.simpletimetracker.feature_data_edit.dialog.DataEditTypeSelectionDialogListener +import com.example.util.simpletimetracker.feature_data_edit.model.DataEditChangeActivityState import com.example.util.simpletimetracker.feature_data_edit.viewModel.DataEditViewModel import com.example.util.simpletimetracker.feature_views.extension.setOnClick import dagger.hilt.android.AndroidEntryPoint import com.example.util.simpletimetracker.feature_data_edit.databinding.DataEditFragmentBinding as Binding @AndroidEntryPoint -class DataEditFragment : BaseFragment() { +class DataEditFragment : + BaseFragment(), + DataEditTypeSelectionDialogListener { override val inflater: (LayoutInflater, ViewGroup?, Boolean) -> Binding = Binding::inflate private val viewModel: DataEditViewModel by viewModels() - override fun initUi(): Unit = with(binding) { + override fun initUi() = with(binding) { btnDataEditSelectRecords.setOnClick(throttle(viewModel::onSelectRecordsClick)) } + override fun initUx() = with(binding) { + checkboxDataEditChangeActivity.setOnClick(viewModel::onChangeActivityClick) + } + override fun initViewModel(): Unit = with(viewModel) { with(binding) { selectedRecordsCountViewData.observe(tvDataEditSelectedRecords::setText) + changeActivityCheckbox.observe { + when (it) { + is DataEditChangeActivityState.Disabled -> { + checkboxDataEditChangeActivity.isChecked = false + viewDataEditChangeActivityPreview.isVisible = false + } + is DataEditChangeActivityState.Enabled -> { + checkboxDataEditChangeActivity.isChecked = true + viewDataEditChangeActivityPreview.isVisible = true + viewDataEditChangeActivityPreview.apply { + itemColor = it.viewData.color + itemIcon = it.viewData.iconId + itemIconColor = it.viewData.iconColor + itemIconAlpha = it.viewData.iconAlpha + itemName = it.viewData.name + } + } + } + } } } + + override fun onResume() = with(binding) { + super.onResume() + checkboxDataEditChangeActivity.jumpDrawablesToCurrentState() + checkboxDataEditChangeComment.jumpDrawablesToCurrentState() + checkboxDataEditAddTag.jumpDrawablesToCurrentState() + checkboxDataEditRemoveTag.jumpDrawablesToCurrentState() + } + + override fun onTypeSelected(typeId: Long) { + viewModel.onTypeSelected(typeId) + } } diff --git a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/viewModel/DataEditViewModel.kt b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/viewModel/DataEditViewModel.kt index d6d7c6cb..c20cafa7 100644 --- a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/viewModel/DataEditViewModel.kt +++ b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/viewModel/DataEditViewModel.kt @@ -6,9 +6,14 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import com.example.util.simpletimetracker.core.extension.set import com.example.util.simpletimetracker.core.extension.toParams +import com.example.util.simpletimetracker.core.mapper.RecordTypeViewDataMapper +import com.example.util.simpletimetracker.domain.interactor.PrefsInteractor +import com.example.util.simpletimetracker.domain.interactor.RecordTypeInteractor import com.example.util.simpletimetracker.domain.model.RecordsFilter import com.example.util.simpletimetracker.feature_data_edit.interactor.DateEditViewDataInteractor +import com.example.util.simpletimetracker.feature_data_edit.model.DataEditChangeActivityState import com.example.util.simpletimetracker.navigation.Router +import com.example.util.simpletimetracker.navigation.params.screen.DataEditTypeSelectionDialogParams import com.example.util.simpletimetracker.navigation.params.screen.RecordsFilterParams import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject @@ -18,6 +23,9 @@ import kotlinx.coroutines.launch class DataEditViewModel @Inject constructor( private val router: Router, private val dateEditViewDataInteractor: DateEditViewDataInteractor, + private val recordTypeViewDataMapper: RecordTypeViewDataMapper, + private val prefsInteractor: PrefsInteractor, + private val recordTypeInteractor: RecordTypeInteractor, ) : ViewModel() { val selectedRecordsCountViewData: LiveData by lazy { @@ -26,8 +34,17 @@ class DataEditViewModel @Inject constructor( initial } } + val changeActivityCheckbox: LiveData by lazy { + MutableLiveData().let { initial -> + viewModelScope.launch { + initial.value = loadChangeActivityCheckbox() + } + initial + } + } private var filters: List = emptyList() + private var newTypeId: Long? = null fun onSelectRecordsClick() { router.setResultListener(FILTER_TAG) { @@ -39,6 +56,20 @@ class DataEditViewModel @Inject constructor( ).let(router::navigate) } + fun onChangeActivityClick() { + if (newTypeId == null) { + router.navigate(DataEditTypeSelectionDialogParams) + } else { + newTypeId = null + updateChangeActivityCheckbox() + } + } + + fun onTypeSelected(typeId: Long) { + newTypeId = typeId + updateChangeActivityCheckbox() + } + private fun onFilterSelected(filters: List) { this.filters = filters updateSelectedRecordsCountViewData() @@ -53,6 +84,26 @@ class DataEditViewModel @Inject constructor( return dateEditViewDataInteractor.getSelectedRecordsCount(filters) } + private fun updateChangeActivityCheckbox() = viewModelScope.launch { + val data = loadChangeActivityCheckbox() + changeActivityCheckbox.set(data) + } + + private suspend fun loadChangeActivityCheckbox(): DataEditChangeActivityState { + // TODO move to interactor + val type = newTypeId?.let { recordTypeInteractor.get(it) } + return if (type == null) { + DataEditChangeActivityState.Disabled + } else { + DataEditChangeActivityState.Enabled( + recordTypeViewDataMapper.map( + recordType = type, + isDarkTheme = prefsInteractor.getDarkMode(), + ) + ) + } + } + companion object { private const val FILTER_TAG = "date_edit_filter_tag" } diff --git a/features/feature_data_edit/src/main/res/layout/data_edit_fragment.xml b/features/feature_data_edit/src/main/res/layout/data_edit_fragment.xml index 9e89fdbe..7bfcfb8b 100644 --- a/features/feature_data_edit/src/main/res/layout/data_edit_fragment.xml +++ b/features/feature_data_edit/src/main/res/layout/data_edit_fragment.xml @@ -53,20 +53,16 @@ android:layout_height="wrap_content" android:layout_marginHorizontal="8dp" android:padding="16dp" - app:iconTint="?appLightTextColor" android:text="@string/data_edit_select_records" app:icon="@drawable/ic_list_24px" - app:iconGravity="end" /> + app:iconGravity="end" + app:iconTint="?appLightTextColor" /> + android:layout_marginHorizontal="6dp"> - + android:layout_marginHorizontal="6dp"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/features/feature_data_edit/src/main/res/layout/data_edit_type_selection_dialog_fragment.xml b/features/feature_data_edit/src/main/res/layout/data_edit_type_selection_dialog_fragment.xml new file mode 100644 index 00000000..617a53f4 --- /dev/null +++ b/features/feature_data_edit/src/main/res/layout/data_edit_type_selection_dialog_fragment.xml @@ -0,0 +1,26 @@ + + + + + + + + diff --git a/features/feature_settings/src/main/res/values/styles.xml b/features/feature_settings/src/main/res/values/styles.xml deleted file mode 100644 index 636e7a4d..00000000 --- a/features/feature_settings/src/main/res/values/styles.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/features/feature_views/src/main/res/values/styles.xml b/features/feature_views/src/main/res/values/styles.xml index d9c19968..c0eb09c5 100644 --- a/features/feature_views/src/main/res/values/styles.xml +++ b/features/feature_views/src/main/res/values/styles.xml @@ -235,6 +235,13 @@ @dimen/record_type_card_elevation + +