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 c20cdf49..74e751d3 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.DataEditTagSelectionDialogFragment
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
@@ -24,6 +25,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.DataEditTagSelectionDialogParams
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
@@ -212,4 +214,14 @@ class NavigationDialogMapModule {
BundleCreator.empty()
)
}
+
+ @IntoMap
+ @Provides
+ @ScreenKey(DataEditTagSelectionDialogParams::class)
+ fun dataEditTagSelectionDialog(): NavigationData {
+ return NavigationData(
+ R.id.dataEditTagSelectionDialogFragment,
+ bundleCreatorDelegate(DataEditTagSelectionDialogFragment::createBundle)
+ )
+ }
}
\ 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 56351160..9e583d75 100644
--- a/app/src/main/res/navigation/nav_graph.xml
+++ b/app/src/main/res/navigation/nav_graph.xml
@@ -150,6 +150,11 @@
android:name="com.example.util.simpletimetracker.feature_data_edit.dialog.DataEditTypeSelectionDialogFragment"
android:label="DataEditTypeSelectionDialogFragment"
tools:layout="@layout/data_edit_type_selection_dialog_fragment" />
+
{
val isDarkTheme = prefsInteractor.getDarkMode()
val type = recordTypeInteractor.get(typeId)
@@ -39,7 +41,7 @@ class RecordTagViewDataInteractor @Inject constructor(
} + recordTagInteractor.getUntyped()
return recordTags
- .filterNot { it.archived }
+ .let { tags -> if (showArchived) tags else tags.filterNot { it.archived } }
.takeUnless { it.isEmpty() }
?.let { tags ->
val selected = tags.filter { it.id in selectedTags }
@@ -77,11 +79,13 @@ class RecordTagViewDataInteractor @Inject constructor(
)
}.let(viewData::addAll)
- if (selected.isNotEmpty() || available.isNotEmpty()) {
- DividerViewData(2)
- .takeIf { multipleChoiceAvailable }
- ?.let(viewData::add)
- mapRecordTagUntagged(isDarkTheme).let(viewData::add)
+ if (showUntaggedButton) {
+ if (selected.isNotEmpty() || available.isNotEmpty()) {
+ DividerViewData(2)
+ .takeIf { multipleChoiceAvailable }
+ ?.let(viewData::add)
+ mapRecordTagUntagged(isDarkTheme).let(viewData::add)
+ }
}
categoriesViewDataMapper.mapToRecordTagAddItem(isDarkTheme)
diff --git a/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordBaseViewModel.kt b/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordBaseViewModel.kt
index a088bf68..0c51d0dc 100644
--- a/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordBaseViewModel.kt
+++ b/features/feature_change_record/src/main/java/com/example/util/simpletimetracker/feature_change_record/viewModel/ChangeRecordBaseViewModel.kt
@@ -554,6 +554,8 @@ abstract class ChangeRecordBaseViewModel(
multipleChoiceAvailable = true,
showHint = true,
showAddButton = true,
+ showArchived = false,
+ showUntaggedButton = true,
)
}
diff --git a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTagSelectionDialogFragment.kt b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTagSelectionDialogFragment.kt
new file mode 100644
index 00000000..b4bc4d7b
--- /dev/null
+++ b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTagSelectionDialogFragment.kt
@@ -0,0 +1,112 @@
+package com.example.util.simpletimetracker.feature_data_edit.dialog
+
+import android.content.Context
+import android.content.DialogInterface
+import android.os.Bundle
+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.core.utils.fragmentArgumentDelegate
+import com.example.util.simpletimetracker.feature_base_adapter.BaseRecyclerAdapter
+import com.example.util.simpletimetracker.feature_base_adapter.category.createCategoryAdapterDelegate
+import com.example.util.simpletimetracker.feature_base_adapter.divider.createDividerAdapterDelegate
+import com.example.util.simpletimetracker.feature_base_adapter.hint.createHintAdapterDelegate
+import com.example.util.simpletimetracker.feature_base_adapter.info.createInfoAdapterDelegate
+import com.example.util.simpletimetracker.feature_base_adapter.loader.createLoaderAdapterDelegate
+import com.example.util.simpletimetracker.feature_views.extension.setOnClick
+import com.example.util.simpletimetracker.navigation.params.screen.DataEditTagSelectionDialogParams
+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.DataEditTagSelectionDialogFragmentBinding as Binding
+
+@AndroidEntryPoint
+class DataEditTagSelectionDialogFragment : BaseBottomSheetFragment() {
+
+ override val inflater: (LayoutInflater, ViewGroup?, Boolean) -> Binding =
+ Binding::inflate
+
+ private val viewModel: DataEditTagSelectionViewModel by viewModels()
+
+ private val adapter: BaseRecyclerAdapter by lazy {
+ BaseRecyclerAdapter(
+ createLoaderAdapterDelegate(),
+ createHintAdapterDelegate(),
+ createDividerAdapterDelegate(),
+ createInfoAdapterDelegate(),
+ createCategoryAdapterDelegate(viewModel::onTagClick),
+ )
+ }
+ private val params: DataEditTagSelectionDialogParams by fragmentArgumentDelegate(
+ key = ARGS_PARAMS, default = DataEditTagSelectionDialogParams()
+ )
+ private var listener: DataEditTagSelectionDialogListener? = null
+
+ override fun onAttach(context: Context) {
+ super.onAttach(context)
+ when (context) {
+ is DataEditTagSelectionDialogListener -> {
+ listener = context
+ return
+ }
+ is AppCompatActivity -> {
+ context.getAllFragments()
+ .firstOrNull { it is DataEditTagSelectionDialogListener && it.isResumed }
+ ?.let { listener = it as? DataEditTagSelectionDialogListener }
+ }
+ }
+ }
+
+ override fun onDismiss(dialog: DialogInterface) {
+ listener?.onTagsDismissed()
+ super.onDismiss(dialog)
+ }
+
+ override fun initDialog() {
+ setSkipCollapsed()
+ setFullScreen()
+ blockContentScroll(binding.rvDataEditTagSelectionContainer)
+ }
+
+ override fun initUi(): Unit = with(binding) {
+ rvDataEditTagSelectionContainer.apply {
+ layoutManager = FlexboxLayoutManager(requireContext()).apply {
+ flexDirection = FlexDirection.ROW
+ justifyContent = JustifyContent.CENTER
+ flexWrap = FlexWrap.WRAP
+ }
+ adapter = this@DataEditTagSelectionDialogFragment.adapter
+ }
+ }
+
+ override fun initUx() = with(binding) {
+ btnDataEditTagSelectionSave.setOnClick(viewModel::onSaveClick)
+ }
+
+ override fun initViewModel(): Unit = with(viewModel) {
+ extra = params
+ viewData.observe(adapter::replace)
+ tagSelected.observe(::dismiss)
+ }
+
+ private fun dismiss(tagIds: List) {
+ listener?.onTagsSelected(tagIds)
+ dismiss()
+ }
+
+ companion object {
+ private const val ARGS_PARAMS = "args_params"
+
+ fun createBundle(data: DataEditTagSelectionDialogParams) = Bundle().apply {
+ putParcelable(ARGS_PARAMS, data)
+ }
+ }
+}
\ No newline at end of file
diff --git a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTagSelectionDialogListener.kt b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTagSelectionDialogListener.kt
new file mode 100644
index 00000000..b7949529
--- /dev/null
+++ b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTagSelectionDialogListener.kt
@@ -0,0 +1,7 @@
+package com.example.util.simpletimetracker.feature_data_edit.dialog
+
+interface DataEditTagSelectionDialogListener {
+
+ fun onTagsSelected(tagIds: List)
+ fun onTagsDismissed()
+}
\ No newline at end of file
diff --git a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTagSelectionViewModel.kt b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTagSelectionViewModel.kt
new file mode 100644
index 00000000..2e9ff245
--- /dev/null
+++ b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/dialog/DataEditTagSelectionViewModel.kt
@@ -0,0 +1,77 @@
+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.extension.addOrRemove
+import com.example.util.simpletimetracker.core.extension.set
+import com.example.util.simpletimetracker.core.interactor.RecordTagViewDataInteractor
+import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType
+import com.example.util.simpletimetracker.feature_base_adapter.category.CategoryViewData
+import com.example.util.simpletimetracker.feature_base_adapter.loader.LoaderViewData
+import com.example.util.simpletimetracker.navigation.params.screen.DataEditTagSelectionDialogParams
+import dagger.hilt.android.lifecycle.HiltViewModel
+import javax.inject.Inject
+import kotlinx.coroutines.launch
+
+@HiltViewModel
+class DataEditTagSelectionViewModel @Inject constructor(
+ private val recordTagViewDataInteractor: RecordTagViewDataInteractor,
+) : ViewModel() {
+
+ lateinit var extra: DataEditTagSelectionDialogParams
+
+ val viewData: LiveData> by lazy {
+ return@lazy MutableLiveData>().let { initial ->
+ viewModelScope.launch {
+ initial.value = listOf(LoaderViewData())
+ initial.value = loadViewData()
+ }
+ initial
+ }
+ }
+ val tagSelected: LiveData> = MutableLiveData()
+
+ private var selectedIds: MutableList = mutableListOf()
+
+ fun onTagClick(item: CategoryViewData) {
+ viewModelScope.launch {
+ when (item) {
+ is CategoryViewData.Record.Tagged -> {
+ selectedIds.addOrRemove(item.id)
+ }
+ is CategoryViewData.Record.Untagged -> {
+ selectedIds.clear()
+ }
+ else -> return@launch
+ }
+ updateViewData()
+ }
+ }
+
+ fun onSaveClick() {
+ tagSelected.set(selectedIds)
+ }
+
+ private fun updateViewData() = viewModelScope.launch {
+ val data = loadViewData()
+ viewData.set(data)
+ }
+
+ private suspend fun loadViewData(): List {
+ val result: MutableList = mutableListOf()
+
+ recordTagViewDataInteractor.getViewData(
+ selectedTags = selectedIds,
+ typeId = extra.typeId,
+ multipleChoiceAvailable = true,
+ showHint = false,
+ showAddButton = false,
+ showArchived = true,
+ showUntaggedButton = false,
+ ).let(result::addAll)
+
+ return result
+ }
+}
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
index d4782381..a09f911e 100644
--- 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
@@ -57,7 +57,7 @@ class DataEditTypeSelectionDialogFragment : BaseBottomSheetFragment() {
}
override fun onDismiss(dialog: DialogInterface) {
- listener?.onDismissed()
+ listener?.onTypeDismissed()
super.onDismiss(dialog)
}
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
index f3d6c819..998c098f 100644
--- 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
@@ -3,5 +3,5 @@ package com.example.util.simpletimetracker.feature_data_edit.dialog
interface DataEditTypeSelectionDialogListener {
fun onTypeSelected(typeId: Long)
- fun onDismissed()
+ fun onTypeDismissed()
}
\ 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
index e4816e68..8777a13d 100644
--- 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
@@ -56,7 +56,6 @@ class DataEditTypeSelectionViewModel @Inject constructor(
}
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)
diff --git a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/interactor/DateEditChangeInteractor.kt b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/interactor/DateEditChangeInteractor.kt
index ee1c1339..47dde3b4 100644
--- a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/interactor/DateEditChangeInteractor.kt
+++ b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/interactor/DateEditChangeInteractor.kt
@@ -6,6 +6,8 @@ import com.example.util.simpletimetracker.domain.interactor.NotificationGoalTime
import com.example.util.simpletimetracker.domain.interactor.RecordInteractor
import com.example.util.simpletimetracker.domain.interactor.RecordTagInteractor
import com.example.util.simpletimetracker.domain.model.RecordsFilter
+import com.example.util.simpletimetracker.feature_base_adapter.category.CategoryViewData
+import com.example.util.simpletimetracker.feature_data_edit.model.DataEditAddTagsState
import com.example.util.simpletimetracker.feature_data_edit.model.DataEditChangeActivityState
import com.example.util.simpletimetracker.feature_data_edit.model.DataEditChangeCommentState
import javax.inject.Inject
@@ -21,33 +23,45 @@ class DateEditChangeInteractor @Inject constructor(
suspend fun changeData(
typeState: DataEditChangeActivityState,
commentState: DataEditChangeCommentState,
+ addTagState: DataEditAddTagsState,
filters: List
) {
if (filters.isEmpty()) return
- val newTypeId = (typeState as? DataEditChangeActivityState.Enabled)?.viewData?.id
- val newComment = (commentState as? DataEditChangeCommentState.Enabled)?.viewData
- if (newTypeId == null && newComment == null) return
+
+ val newTypeId = (typeState as? DataEditChangeActivityState.Enabled)
+ ?.viewData?.id
+ val newComment = (commentState as? DataEditChangeCommentState.Enabled)
+ ?.viewData
+ val addTags = (addTagState as? DataEditAddTagsState.Enabled)
+ ?.viewData?.map(CategoryViewData.Record::id)
+
+ if (newTypeId == null && newComment == null && addTags == null) return
val records = recordFilterInteractor.getByFilter(filters)
val tags = recordTagInteractor.getAll().associateBy { it.id }
val oldTypeIds = mutableSetOf()
- var newTagIds: List? = null
records.forEach { record ->
- if (newTypeId != null && record.typeId != newTypeId) {
- // Remove all typed tags.
- newTagIds = record.tagIds.filter { tagId ->
- tags[tagId]?.typeId == 0L
+ val finalTypeId = newTypeId ?: record.typeId
+ val finalComment = newComment ?: record.comment
+ val finalTagIds: Set = record.tagIds
+ .plus(addTags.orEmpty())
+ .filter { tagId ->
+ val tag = tags[tagId] ?: return@filter false
+ tag.typeId == 0L || tag.typeId == finalTypeId
}
- // Save old typeId before change to update data later.
+ .toSet()
+
+ // Save old typeId before change to update data later.
+ if (finalTypeId != record.typeId) {
oldTypeIds.add(record.typeId)
}
// Change activity
record.copy(
- typeId = newTypeId ?: record.typeId,
- comment = newComment ?: record.comment,
- tagIds = newTagIds ?: record.tagIds
+ typeId = finalTypeId,
+ comment = finalComment,
+ tagIds = finalTagIds.toList(),
).let {
recordInteractor.add(it)
}
diff --git a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/interactor/DateEditViewDataInteractor.kt b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/interactor/DateEditViewDataInteractor.kt
index 3cc3ec2b..e1c27fee 100644
--- a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/interactor/DateEditViewDataInteractor.kt
+++ b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/interactor/DateEditViewDataInteractor.kt
@@ -1,12 +1,15 @@
package com.example.util.simpletimetracker.feature_data_edit.interactor
import com.example.util.simpletimetracker.core.interactor.RecordFilterInteractor
+import com.example.util.simpletimetracker.core.mapper.CategoryViewDataMapper
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.RecordTagInteractor
import com.example.util.simpletimetracker.domain.interactor.RecordTypeInteractor
import com.example.util.simpletimetracker.domain.model.RecordsFilter
import com.example.util.simpletimetracker.feature_data_edit.R
+import com.example.util.simpletimetracker.feature_data_edit.model.DataEditAddTagsState
import com.example.util.simpletimetracker.feature_data_edit.model.DataEditChangeActivityState
import com.example.util.simpletimetracker.feature_data_edit.model.DataEditChangeButtonState
import com.example.util.simpletimetracker.feature_data_edit.model.DataEditChangeCommentState
@@ -16,7 +19,9 @@ class DateEditViewDataInteractor @Inject constructor(
private val resourceRepo: ResourceRepo,
private val recordFilterInteractor: RecordFilterInteractor,
private val recordTypeInteractor: RecordTypeInteractor,
+ private val recordTagInteractor: RecordTagInteractor,
private val recordTypeViewDataMapper: RecordTypeViewDataMapper,
+ private val categoryViewDataMapper: CategoryViewDataMapper,
private val prefsInteractor: PrefsInteractor,
) {
@@ -41,6 +46,7 @@ class DateEditViewDataInteractor @Inject constructor(
suspend fun getChangeActivityState(
newTypeId: Long,
): DataEditChangeActivityState {
+ val isDarkTheme = prefsInteractor.getDarkMode()
val type = newTypeId.let { recordTypeInteractor.get(it) }
return if (type == null) {
@@ -49,7 +55,7 @@ class DateEditViewDataInteractor @Inject constructor(
DataEditChangeActivityState.Enabled(
recordTypeViewDataMapper.map(
recordType = type,
- isDarkTheme = prefsInteractor.getDarkMode(),
+ isDarkTheme = isDarkTheme,
)
)
}
@@ -61,6 +67,26 @@ class DateEditViewDataInteractor @Inject constructor(
return DataEditChangeCommentState.Enabled(newComment)
}
+ suspend fun getAddTagState(
+ tagIds: List,
+ ): DataEditAddTagsState {
+ val isDarkTheme = prefsInteractor.getDarkMode()
+ val types = recordTypeInteractor.getAll().associateBy { it.id }
+
+ return recordTagInteractor.getAll()
+ .filter { it.id in tagIds }
+ .map {
+ categoryViewDataMapper.mapRecordTag(
+ tag = it,
+ type = types[it.typeId],
+ isDarkTheme = isDarkTheme,
+ )
+ }
+ .takeUnless { it.isEmpty() }
+ ?.let(DataEditAddTagsState::Enabled)
+ ?: DataEditAddTagsState.Disabled
+ }
+
suspend fun getChangeButtonState(
enabled: Boolean,
): DataEditChangeButtonState {
diff --git a/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/model/DataEditAddTagsState.kt b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/model/DataEditAddTagsState.kt
new file mode 100644
index 00000000..24365b73
--- /dev/null
+++ b/features/feature_data_edit/src/main/java/com/example/util/simpletimetracker/feature_data_edit/model/DataEditAddTagsState.kt
@@ -0,0 +1,9 @@
+package com.example.util.simpletimetracker.feature_data_edit.model
+
+import com.example.util.simpletimetracker.feature_base_adapter.category.CategoryViewData
+
+sealed interface DataEditAddTagsState {
+
+ object Disabled : DataEditAddTagsState
+ data class Enabled(val viewData: List) : DataEditAddTagsState
+}
\ 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 d1dd965a..5c637389 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
@@ -9,32 +9,56 @@ import androidx.fragment.app.viewModels
import com.example.util.simpletimetracker.core.base.BaseFragment
import com.example.util.simpletimetracker.core.extension.hideKeyboard
import com.example.util.simpletimetracker.core.extension.showKeyboard
+import com.example.util.simpletimetracker.feature_base_adapter.BaseRecyclerAdapter
+import com.example.util.simpletimetracker.feature_base_adapter.category.createCategoryAdapterDelegate
+import com.example.util.simpletimetracker.feature_data_edit.dialog.DataEditTagSelectionDialogListener
import com.example.util.simpletimetracker.feature_data_edit.dialog.DataEditTypeSelectionDialogListener
+import com.example.util.simpletimetracker.feature_data_edit.model.DataEditAddTagsState
import com.example.util.simpletimetracker.feature_data_edit.model.DataEditChangeActivityState
import com.example.util.simpletimetracker.feature_data_edit.model.DataEditChangeButtonState
import com.example.util.simpletimetracker.feature_data_edit.model.DataEditChangeCommentState
import com.example.util.simpletimetracker.feature_data_edit.viewModel.DataEditViewModel
import com.example.util.simpletimetracker.feature_views.extension.setOnClick
+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.DataEditFragmentBinding as Binding
@AndroidEntryPoint
class DataEditFragment :
BaseFragment(),
- DataEditTypeSelectionDialogListener {
+ DataEditTypeSelectionDialogListener,
+ DataEditTagSelectionDialogListener {
override val inflater: (LayoutInflater, ViewGroup?, Boolean) -> Binding =
Binding::inflate
private val viewModel: DataEditViewModel by viewModels()
- override fun initUi() = with(binding) {
- btnDataEditSelectRecords.setOnClick(throttle(viewModel::onSelectRecordsClick))
+ private val addTagsPreviewAdapter: BaseRecyclerAdapter by lazy {
+ BaseRecyclerAdapter(
+ createCategoryAdapterDelegate(),
+ )
+ }
+
+ override fun initUi(): Unit = with(binding) {
+ rvDataEditAddTagsPreview.apply {
+ layoutManager = FlexboxLayoutManager(requireContext()).apply {
+ flexDirection = FlexDirection.ROW
+ justifyContent = JustifyContent.FLEX_START
+ flexWrap = FlexWrap.WRAP
+ }
+ adapter = addTagsPreviewAdapter
+ }
}
override fun initUx() = with(binding) {
+ btnDataEditSelectRecords.setOnClick(throttle(viewModel::onSelectRecordsClick))
checkboxDataEditChangeActivity.setOnClick(viewModel::onChangeActivityClick)
checkboxDataEditChangeComment.setOnClick(viewModel::onChangeCommentClick)
+ checkboxDataEditAddTag.setOnClick(viewModel::onAddTagsClick)
etDataEditChangeComment.doAfterTextChanged { viewModel.onCommentChange(it.toString()) }
btnDataEditChange.setOnClick(throttle(viewModel::onChangeClick))
}
@@ -44,6 +68,7 @@ class DataEditFragment :
selectedRecordsCountViewData.observe(tvDataEditSelectedRecords::setText)
changeActivityState.observe(::setChangeActivityState)
changeCommentState.observe(::setChangeCommentState)
+ addTagsState.observe(::setAddTagState)
changeButtonState.observe(::setChangeButtonState)
keyboardVisibility.observe { visible ->
if (visible) showKeyboard(etDataEditChangeComment)
@@ -64,10 +89,18 @@ class DataEditFragment :
viewModel.onTypeSelected(typeId)
}
- override fun onDismissed() {
+ override fun onTypeDismissed() {
viewModel.onTypeDismissed()
}
+ override fun onTagsSelected(tagIds: List) {
+ viewModel.onTagsSelected(tagIds)
+ }
+
+ override fun onTagsDismissed() {
+ viewModel.onTagsDismissed()
+ }
+
private fun setChangeActivityState(
state: DataEditChangeActivityState,
) = with(binding) {
@@ -108,6 +141,22 @@ class DataEditFragment :
}
}
+ private fun setAddTagState(
+ state: DataEditAddTagsState,
+ ) = with(binding) {
+ when (state) {
+ is DataEditAddTagsState.Disabled -> {
+ checkboxDataEditAddTag.isChecked = false
+ rvDataEditAddTagsPreview.isVisible = false
+ }
+ is DataEditAddTagsState.Enabled -> {
+ checkboxDataEditAddTag.isChecked = true
+ rvDataEditAddTagsPreview.isVisible = true
+ addTagsPreviewAdapter.replace(state.viewData)
+ }
+ }
+ }
+
private fun setChangeButtonState(
state: DataEditChangeButtonState
) = with(binding) {
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 671f9519..3d233063 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
@@ -8,15 +8,20 @@ import com.example.util.simpletimetracker.core.extension.set
import com.example.util.simpletimetracker.core.extension.toParams
import com.example.util.simpletimetracker.core.repo.DataEditRepo
import com.example.util.simpletimetracker.core.repo.ResourceRepo
+import com.example.util.simpletimetracker.domain.extension.orZero
+import com.example.util.simpletimetracker.domain.interactor.RecordTagInteractor
+import com.example.util.simpletimetracker.domain.model.RecordTag
import com.example.util.simpletimetracker.domain.model.RecordsFilter
import com.example.util.simpletimetracker.feature_data_edit.R
import com.example.util.simpletimetracker.feature_data_edit.interactor.DateEditChangeInteractor
import com.example.util.simpletimetracker.feature_data_edit.interactor.DateEditViewDataInteractor
+import com.example.util.simpletimetracker.feature_data_edit.model.DataEditAddTagsState
import com.example.util.simpletimetracker.feature_data_edit.model.DataEditChangeActivityState
import com.example.util.simpletimetracker.feature_data_edit.model.DataEditChangeButtonState
import com.example.util.simpletimetracker.feature_data_edit.model.DataEditChangeCommentState
import com.example.util.simpletimetracker.navigation.Router
import com.example.util.simpletimetracker.navigation.params.notification.SnackBarParams
+import com.example.util.simpletimetracker.navigation.params.screen.DataEditTagSelectionDialogParams
import com.example.util.simpletimetracker.navigation.params.screen.DataEditTypeSelectionDialogParams
import com.example.util.simpletimetracker.navigation.params.screen.RecordsFilterParams
import dagger.hilt.android.lifecycle.HiltViewModel
@@ -30,6 +35,7 @@ class DataEditViewModel @Inject constructor(
private val dataEditRepo: DataEditRepo,
private val dataEditViewDataInteractor: DateEditViewDataInteractor,
private val dataEditChangeInteractor: DateEditChangeInteractor,
+ private val recordTagInteractor: RecordTagInteractor,
) : ViewModel() {
val selectedRecordsCountViewData: LiveData by lazy {
@@ -44,6 +50,9 @@ class DataEditViewModel @Inject constructor(
val changeCommentState: LiveData by lazy {
MutableLiveData(commentState)
}
+ val addTagsState: LiveData by lazy {
+ MutableLiveData(addTagState)
+ }
val changeButtonState: LiveData by lazy {
MutableLiveData().let { initial ->
viewModelScope.launch { initial.value = loadChangeButtonState() }
@@ -55,10 +64,12 @@ class DataEditViewModel @Inject constructor(
private var filters: List = emptyList()
private var typeState: DataEditChangeActivityState = DataEditChangeActivityState.Disabled
private var commentState: DataEditChangeCommentState = DataEditChangeCommentState.Disabled
+ private var addTagState: DataEditAddTagsState = DataEditAddTagsState.Disabled
private val changeButtonEnabled: Boolean
get() = typeState is DataEditChangeActivityState.Enabled ||
- commentState is DataEditChangeCommentState.Enabled
+ commentState is DataEditChangeCommentState.Enabled ||
+ addTagState is DataEditAddTagsState.Enabled
fun onSelectRecordsClick() {
router.setResultListener(FILTER_TAG) {
@@ -75,6 +86,7 @@ class DataEditViewModel @Inject constructor(
router.navigate(DataEditTypeSelectionDialogParams)
} else {
typeState = DataEditChangeActivityState.Disabled
+ checkAddTagStateConsistency()
updateChangeActivityState()
updateChangeButtonState()
}
@@ -82,6 +94,7 @@ class DataEditViewModel @Inject constructor(
fun onTypeSelected(typeId: Long) = viewModelScope.launch {
typeState = dataEditViewDataInteractor.getChangeActivityState(typeId)
+ checkAddTagStateConsistency()
updateChangeActivityState()
updateChangeButtonState()
}
@@ -101,6 +114,30 @@ class DataEditViewModel @Inject constructor(
updateChangeButtonState()
}
+ fun onAddTagsClick() {
+ if (addTagState is DataEditAddTagsState.Disabled) {
+ // Show tag selection with typed tags for changed activity (if it is selected)
+ // or for filtered activity (if it is only one).
+ // Otherwise show only general tags.
+ val typeId = getTypeForTagSelection().orZero()
+ router.navigate(DataEditTagSelectionDialogParams(typeId))
+ } else {
+ addTagState = DataEditAddTagsState.Disabled
+ updateAddTagState()
+ updateChangeButtonState()
+ }
+ }
+
+ fun onTagsSelected(tagIds: List) = viewModelScope.launch {
+ addTagState = dataEditViewDataInteractor.getAddTagState(tagIds)
+ updateAddTagState()
+ updateChangeButtonState()
+ }
+
+ fun onTagsDismissed() {
+ updateAddTagState()
+ }
+
fun onCommentChange(text: String) {
val state = commentState
if (state is DataEditChangeCommentState.Enabled && state.viewData != text) {
@@ -115,7 +152,8 @@ class DataEditViewModel @Inject constructor(
dataEditChangeInteractor.changeData(
typeState = typeState,
commentState = commentState,
- filters = filters
+ addTagState = addTagState,
+ filters = filters,
)
dataEditRepo.inProgress.set(false)
showMessage(R.string.data_edit_success_message)
@@ -124,6 +162,7 @@ class DataEditViewModel @Inject constructor(
private fun onFilterSelected(filters: List) {
this.filters = filters
+ checkAddTagStateConsistency()
updateSelectedRecordsCountViewData()
}
@@ -132,6 +171,40 @@ class DataEditViewModel @Inject constructor(
router.show(params)
}
+ private fun checkAddTagStateConsistency() = viewModelScope.launch {
+ // If there are some tags selected to add,
+ val tags = (addTagState as? DataEditAddTagsState.Enabled)
+ ?.viewData
+ ?: return@launch
+ val allTags = recordTagInteractor.getAll().associateBy(RecordTag::id)
+ // Find if there is a specific type selected by filter or change activity state,
+ val typeId = getTypeForTagSelection().orZero()
+ // Filter tags selected to add to have typed tags only for this selected activity.
+ val newTags = tags.filter {
+ val tag = allTags[it.id] ?: return@filter false
+ tag.typeId == 0L || tag.typeId == typeId
+ }
+
+ addTagState = if (newTags.isNotEmpty()) {
+ DataEditAddTagsState.Enabled(newTags)
+ } else {
+ DataEditAddTagsState.Disabled
+ }
+ updateAddTagState()
+ updateChangeButtonState()
+ }
+
+ private fun getTypeForTagSelection(): Long? {
+ return (typeState as? DataEditChangeActivityState.Enabled)
+ ?.viewData?.id
+ ?: filters
+ .filterIsInstance()
+ .firstOrNull()
+ ?.typeIds
+ ?.takeIf { it.size == 1 }
+ ?.firstOrNull()
+ }
+
private fun updateSelectedRecordsCountViewData() = viewModelScope.launch {
val data = loadSelectedRecordsCountViewData()
selectedRecordsCountViewData.set(data)
@@ -149,6 +222,10 @@ class DataEditViewModel @Inject constructor(
changeCommentState.set(commentState)
}
+ private fun updateAddTagState() = viewModelScope.launch {
+ addTagsState.set(addTagState)
+ }
+
private fun updateChangeButtonState() = viewModelScope.launch {
val data = loadChangeButtonState()
changeButtonState.set(data)
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 aa3d335c..103d057c 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
@@ -222,6 +222,21 @@
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
+
+
+
+
+
+
+
+
+
+
+
diff --git a/features/feature_tag_selection/src/main/java/com/example/util/simpletimetracker/feature_tag_selection/interactor/RecordTagSelectionViewDataInteractor.kt b/features/feature_tag_selection/src/main/java/com/example/util/simpletimetracker/feature_tag_selection/interactor/RecordTagSelectionViewDataInteractor.kt
index 45fe6eb4..6535baec 100644
--- a/features/feature_tag_selection/src/main/java/com/example/util/simpletimetracker/feature_tag_selection/interactor/RecordTagSelectionViewDataInteractor.kt
+++ b/features/feature_tag_selection/src/main/java/com/example/util/simpletimetracker/feature_tag_selection/interactor/RecordTagSelectionViewDataInteractor.kt
@@ -27,6 +27,8 @@ class RecordTagSelectionViewDataInteractor @Inject constructor(
multipleChoiceAvailable = !closeAfterOneTagSelected,
showHint = false,
showAddButton = false,
+ showArchived = false,
+ showUntaggedButton = true,
).let(result::addAll)
return result
diff --git a/navigation/src/main/java/com/example/util/simpletimetracker/navigation/params/screen/DataEditTagSelectionDialogParams.kt b/navigation/src/main/java/com/example/util/simpletimetracker/navigation/params/screen/DataEditTagSelectionDialogParams.kt
new file mode 100644
index 00000000..b76ead19
--- /dev/null
+++ b/navigation/src/main/java/com/example/util/simpletimetracker/navigation/params/screen/DataEditTagSelectionDialogParams.kt
@@ -0,0 +1,9 @@
+package com.example.util.simpletimetracker.navigation.params.screen
+
+import android.os.Parcelable
+import kotlinx.parcelize.Parcelize
+
+@Parcelize
+data class DataEditTagSelectionDialogParams(
+ val typeId: Long = 0L
+) : Parcelable, ScreenParams