Skip to content

Commit

Permalink
add record edit quick action to change activity
Browse files Browse the repository at this point in the history
  • Loading branch information
Razeeman committed Dec 1, 2024
1 parent 451d462 commit 2618968
Show file tree
Hide file tree
Showing 19 changed files with 532 additions and 420 deletions.
9 changes: 9 additions & 0 deletions core/src/main/res/drawable/action_change_item.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="M12,6v3l4,-4 -4,-4v3c-4.42,0 -8,3.58 -8,8 0,1.57 0.46,3.03 1.24,4.26L6.7,14.8c-0.45,-0.83 -0.7,-1.79 -0.7,-2.8 0,-3.31 2.69,-6 6,-6zM18.76,7.74L17.3,9.2c0.44,0.84 0.7,1.79 0.7,2.8 0,3.31 -2.69,6 -6,6v-3l-4,4 4,4v-3c4.42,0 8,-3.58 8,-8 0,-1.57 -0.46,-3.03 -1.24,-4.26z"/>
</vector>
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ class ChangeComplexRuleViewModel @Inject constructor(
selectedTypeIds = newAssignTagIds.toList(),
isMultiSelectAvailable = true,
idsShouldBeVisible = originalAssignTagIds.toList(),
showHints = true,
).let(router::navigate)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ class ChangeRecordTagViewModel @Inject constructor(
selectedTypeIds = listOf(newIconColorSource),
isMultiSelectAvailable = false,
idsShouldBeVisible = listOf(newIconColorSource),
showHints = true,
).let(router::navigate)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package com.example.util.simpletimetracker.feature_dialogs.recordQuickActions.adapter

import androidx.annotation.DrawableRes
import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType
import com.example.util.simpletimetracker.feature_base_adapter.createRecyclerBindingAdapterDelegate
import com.example.util.simpletimetracker.feature_dialogs.recordQuickActions.adapter.RecordQuickActionsWidthHolder.Width
import com.example.util.simpletimetracker.feature_dialogs.recordQuickActions.model.RecordQuickActionsButton
import com.example.util.simpletimetracker.feature_views.extension.setOnClickWith
import com.example.util.simpletimetracker.feature_dialogs.databinding.RecordQuickActionsButtonItemBinding as Binding
import com.example.util.simpletimetracker.feature_dialogs.recordQuickActions.adapter.RecordQuickActionsButtonViewData as ViewData

fun createRecordQuickActionsButtonAdapterDelegate(
onClick: (RecordQuickActionsButton) -> Unit,
) = createRecyclerBindingAdapterDelegate<ViewData, Binding>(
Binding::inflate,
) { binding, item, _ ->

with(binding) {
item as ViewData

tvRecordQuickActionsButton.text = item.text
ivRecordQuickActionsButton.setImageResource(item.icon)
btnRecordQuickActionsButton.setOnClickWith(item.block, onClick)
}
}

data class RecordQuickActionsButtonViewData(
override val block: RecordQuickActionsButton,
override val width: Width = Width.Small,
val text: String,
@DrawableRes val icon: Int,
) : ViewHolderType,
RecordQuickActionsBlockHolder,
RecordQuickActionsWidthHolder {

override fun getUniqueId(): Long = block.ordinal.toLong()

override fun isValidType(other: ViewHolderType): Boolean =
other is ViewData
}

interface RecordQuickActionsBlockHolder {
val block: RecordQuickActionsButton
}

interface RecordQuickActionsWidthHolder {
val width: Width

sealed interface Width {
data object Full : Width
data object Small : Width
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.example.util.simpletimetracker.feature_dialogs.recordQuickActions.adapter

import androidx.annotation.DrawableRes
import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType
import com.example.util.simpletimetracker.feature_base_adapter.createRecyclerBindingAdapterDelegate
import com.example.util.simpletimetracker.feature_dialogs.recordQuickActions.adapter.RecordQuickActionsWidthHolder.Width
import com.example.util.simpletimetracker.feature_dialogs.recordQuickActions.model.RecordQuickActionsButton
import com.example.util.simpletimetracker.feature_views.extension.setOnClickWith
import com.example.util.simpletimetracker.feature_dialogs.databinding.RecordQuickActionsButtonBigItemBinding as Binding
import com.example.util.simpletimetracker.feature_dialogs.recordQuickActions.adapter.RecordQuickActionsButtonBigViewData as ViewData

fun createRecordQuickActionsButtonBigAdapterDelegate(
onClick: (RecordQuickActionsButton) -> Unit,
) = createRecyclerBindingAdapterDelegate<ViewData, Binding>(
Binding::inflate,
) { binding, item, _ ->

with(binding) {
item as ViewData

tvRecordQuickActionsButtonBig.text = item.text
ivRecordQuickActionsButtonBig.setImageResource(item.icon)
btnRecordQuickActionsButtonBig.setOnClickWith(item.block, onClick)
}
}

data class RecordQuickActionsButtonBigViewData(
override val block: RecordQuickActionsButton,
override val width: Width = Width.Small,
val text: String,
@DrawableRes val icon: Int,
) : ViewHolderType,
RecordQuickActionsBlockHolder,
RecordQuickActionsWidthHolder {

override fun getUniqueId(): Long = block.ordinal.toLong()

override fun isValidType(other: ViewHolderType): Boolean =
other is ViewData
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
package com.example.util.simpletimetracker.feature_dialogs.recordQuickActions.interactor

import com.example.util.simpletimetracker.domain.interactor.AddRecordMediator
import com.example.util.simpletimetracker.domain.interactor.AddRunningRecordMediator
import com.example.util.simpletimetracker.domain.interactor.RecordInteractor
import com.example.util.simpletimetracker.domain.interactor.RemoveRunningRecordMediator
import com.example.util.simpletimetracker.domain.interactor.RunningRecordInteractor
import com.example.util.simpletimetracker.domain.interactor.UpdateExternalViewsInteractor
import com.example.util.simpletimetracker.domain.model.Record
import com.example.util.simpletimetracker.navigation.params.screen.RecordQuickActionsParams.Type
import javax.inject.Inject

class RecordQuickActionsInteractor @Inject constructor(
private val recordInteractor: RecordInteractor,
private val addRecordMediator: AddRecordMediator,
private val addRunningRecordMediator: AddRunningRecordMediator,
private val externalViewsInteractor: UpdateExternalViewsInteractor,
private val removeRunningRecordMediator: RemoveRunningRecordMediator,
private val runningRecordInteractor: RunningRecordInteractor,
) {

suspend fun changeType(
params: Type,
newTypeId: Long,
) {
when (params) {
is Type.RecordTracked -> {
val recordId = params.id
val record = recordInteractor.get(recordId) ?: return
if (record.typeId == newTypeId) return
Record(
id = recordId,
typeId = newTypeId,
timeStarted = record.timeStarted,
timeEnded = record.timeEnded,
comment = record.comment,
tagIds = emptyList(), // Reset tags.
).let {
addRecordMediator.add(it)
externalViewsInteractor.onRecordChangeType(record.typeId)
}
}
is Type.RecordUntracked -> {
val newTimeStarted = params.timeStarted
val newTimeEnded = params.timeEnded
Record(
id = 0L,
typeId = newTypeId,
timeStarted = newTimeStarted,
timeEnded = newTimeEnded,
comment = "",
tagIds = emptyList(),
).let {
addRecordMediator.add(it)
}
}
is Type.RecordRunning -> {
val recordId = params.id
val record = runningRecordInteractor.get(recordId) ?: return
// Widgets will update on adding.
removeRunningRecordMediator.remove(
typeId = recordId,
updateWidgets = false,
updateNotificationSwitch = false,
)
addRunningRecordMediator.addAfterChange(
typeId = newTypeId,
timeStarted = record.timeStarted,
comment = record.comment,
tagIds = emptyList(), // Reset tags
)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
package com.example.util.simpletimetracker.feature_dialogs.recordQuickActions.interactor

import com.example.util.simpletimetracker.core.repo.ResourceRepo
import com.example.util.simpletimetracker.domain.interactor.PrefsInteractor
import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType
import com.example.util.simpletimetracker.feature_dialogs.R
import com.example.util.simpletimetracker.feature_dialogs.recordQuickActions.adapter.RecordQuickActionsBlockHolder
import com.example.util.simpletimetracker.feature_dialogs.recordQuickActions.adapter.RecordQuickActionsButtonBigViewData
import com.example.util.simpletimetracker.feature_dialogs.recordQuickActions.adapter.RecordQuickActionsButtonViewData
import com.example.util.simpletimetracker.feature_dialogs.recordQuickActions.adapter.RecordQuickActionsWidthHolder
import com.example.util.simpletimetracker.feature_dialogs.recordQuickActions.model.RecordQuickActionsButton
import com.example.util.simpletimetracker.feature_dialogs.recordQuickActions.model.RecordQuickActionsState
import com.example.util.simpletimetracker.navigation.params.screen.RecordQuickActionsParams
import com.example.util.simpletimetracker.navigation.params.screen.RecordQuickActionsParams.Type
import javax.inject.Inject

class RecordQuickActionsViewDataInteractor @Inject constructor(
private val resourceRepo: ResourceRepo,
private val prefsInteractor: PrefsInteractor,
) {

suspend fun getViewData(
extra: RecordQuickActionsParams,
): RecordQuickActionsState {
val retroactiveTrackingModeEnabled = prefsInteractor.getRetroactiveTrackingMode()
val canContinue = !retroactiveTrackingModeEnabled
val allowedButtons = getAllowedButtons(extra, canContinue)
val buttons = getAllButtons().filter {
val block = (it as? RecordQuickActionsBlockHolder)?.block
block in allowedButtons
}.let(::applyWidth)

return RecordQuickActionsState(
buttons = buttons,
)
}

private fun getAllButtons(): List<ViewHolderType> {
return listOf(
RecordQuickActionsButtonBigViewData(
block = RecordQuickActionsButton.STATISTICS,
text = R.string.shortcut_navigation_statistics.let(resourceRepo::getString),
icon = R.drawable.statistics,
),
RecordQuickActionsButtonBigViewData(
block = RecordQuickActionsButton.DELETE,
text = R.string.archive_dialog_delete.let(resourceRepo::getString),
icon = R.drawable.delete,
),
RecordQuickActionsButtonViewData(
block = RecordQuickActionsButton.CONTINUE,
text = R.string.change_record_continue.let(resourceRepo::getString),
icon = R.drawable.action_continue,
),
RecordQuickActionsButtonViewData(
block = RecordQuickActionsButton.REPEAT,
text = R.string.change_record_repeat.let(resourceRepo::getString),
icon = R.drawable.repeat,
),
RecordQuickActionsButtonViewData(
block = RecordQuickActionsButton.DUPLICATE,
text = R.string.change_record_duplicate.let(resourceRepo::getString),
icon = R.drawable.action_copy,
),
RecordQuickActionsButtonViewData(
block = RecordQuickActionsButton.MERGE,
text = R.string.change_record_merge.let(resourceRepo::getString),
icon = R.drawable.action_merge,
),
RecordQuickActionsButtonViewData(
block = RecordQuickActionsButton.STOP,
text = R.string.notification_record_type_stop.let(resourceRepo::getString),
icon = R.drawable.action_stop,
),
RecordQuickActionsButtonViewData(
block = RecordQuickActionsButton.CHANGE_ACTIVITY,
text = resourceRepo.getString(R.string.data_edit_change_activity),
icon = R.drawable.action_change_item,
),
)
}

private fun getAllowedButtons(
extra: RecordQuickActionsParams,
canContinue: Boolean,
): List<RecordQuickActionsButton> {
return when (extra.type) {
is Type.RecordTracked -> listOfNotNull(
RecordQuickActionsButton.STATISTICS,
RecordQuickActionsButton.DELETE,
RecordQuickActionsButton.CONTINUE.takeIf { canContinue },
RecordQuickActionsButton.REPEAT,
RecordQuickActionsButton.DUPLICATE,
RecordQuickActionsButton.CHANGE_ACTIVITY,
)
is Type.RecordUntracked -> listOf(
RecordQuickActionsButton.STATISTICS,
RecordQuickActionsButton.MERGE,
RecordQuickActionsButton.CHANGE_ACTIVITY,
)
is Type.RecordRunning -> listOf(
RecordQuickActionsButton.STATISTICS,
RecordQuickActionsButton.DELETE,
RecordQuickActionsButton.STOP,
RecordQuickActionsButton.CHANGE_ACTIVITY,
)
null -> emptyList()
}
}

private fun applyWidth(
buttons: List<ViewHolderType>,
): List<ViewHolderType> {
val bigButtonsCount = buttons
.count { it is RecordQuickActionsButtonBigViewData }
val bigButtonLastIndex = buttons
.indexOfLast { it is RecordQuickActionsButtonBigViewData }
val smallButtonsCount = buttons
.count { it is RecordQuickActionsButtonViewData }
val smallButtonLastIndex = buttons
.indexOfLast { it is RecordQuickActionsButtonViewData }

return buttons.mapIndexed { index, button ->
when {
button is RecordQuickActionsButtonBigViewData &&
bigButtonsCount % 2 != 0 && index == bigButtonLastIndex -> {
button.copy(width = RecordQuickActionsWidthHolder.Width.Full)
}
button is RecordQuickActionsButtonViewData &&
smallButtonsCount % 2 != 0 && index == smallButtonLastIndex -> {
button.copy(width = RecordQuickActionsWidthHolder.Width.Full)
}
else -> button
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.example.util.simpletimetracker.feature_dialogs.recordQuickActions.model

enum class RecordQuickActionsButton {
STATISTICS,
DELETE,
CONTINUE,
REPEAT,
DUPLICATE,
MERGE,
STOP,
CHANGE_ACTIVITY,
}
Original file line number Diff line number Diff line change
@@ -1,38 +1,7 @@
package com.example.util.simpletimetracker.feature_dialogs.recordQuickActions.model

data class RecordQuickActionsState(
val buttons: List<Button>,
) {

sealed interface Button {
val wrapBefore: Boolean

data class Statistics(
override val wrapBefore: Boolean,
) : Button

data class Delete(
override val wrapBefore: Boolean,
) : Button

data class Continue(
override val wrapBefore: Boolean,
) : Button
import com.example.util.simpletimetracker.feature_base_adapter.ViewHolderType

data class Repeat(
override val wrapBefore: Boolean,
) : Button

data class Duplicate(
override val wrapBefore: Boolean,
) : Button

data class Merge(
override val wrapBefore: Boolean,
) : Button

data class Stop(
override val wrapBefore: Boolean,
) : Button
}
}
data class RecordQuickActionsState(
val buttons: List<ViewHolderType>,
)
Loading

0 comments on commit 2618968

Please sign in to comment.