Skip to content

Commit

Permalink
Fix for Cancel button doesn't work in item edit mode.Closes #116.
Browse files Browse the repository at this point in the history
  • Loading branch information
Dima-Android committed Jul 31, 2024
1 parent e06afc0 commit 8ab234d
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusDirection
import androidx.compose.ui.focus.onFocusChanged
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.res.stringResource
Expand All @@ -30,7 +31,6 @@ import androidx.compose.ui.unit.dp
import org.zotero.android.architecture.ui.CustomLayoutSize
import org.zotero.android.database.objects.FieldKeys
import org.zotero.android.screens.itemdetails.data.ItemDetailCreator
import org.zotero.android.screens.itemdetails.data.ItemDetailField
import org.zotero.android.uicomponents.Strings
import org.zotero.android.uicomponents.foundation.safeClickable
import org.zotero.android.uicomponents.misc.CustomDivider
Expand Down Expand Up @@ -90,7 +90,12 @@ internal fun ItemDetailsEditScreen(
CustomDivider()
}

ListOfEditFieldRows(viewState, layoutType, viewModel::setFieldValue)
ListOfEditFieldRows(
viewState = viewState,
layoutType = layoutType,
onValueChange = viewModel::onFieldValueTextChange,
onFocusChanges = viewModel::onFieldFocusFieldChange
)
DatesRows(
dateAdded = viewState.data.dateAdded,
dateModified = viewState.data.dateModified,
Expand All @@ -105,13 +110,6 @@ internal fun ItemDetailsEditScreen(
}
}
}
notesTagsAndAttachmentsBlock(
viewState = viewState,
viewModel = viewModel,
layoutType = layoutType,
onNoteClicked = { viewModel.openNoteEditor(it) },
onAddNote = { viewModel.onAddNote() },
)
}
}

Expand Down Expand Up @@ -184,33 +182,41 @@ private fun ListOfEditFieldRows(
viewState: ItemDetailsViewState,
layoutType: CustomLayoutSize.LayoutType,
onValueChange: (String, String) -> Unit,
onFocusChanges: (String) -> Unit,
) {
for (fieldId in viewState.data.fieldIds) {
val field = viewState.data.fields.get(fieldId) ?: continue
val title = field.name
val value = field.additionalInfo?.get(ItemDetailField.AdditionalInfoKey.formattedDate)
?: field.value
val value = if (field.key == viewState.fieldFocusKey) {
viewState.fieldFocusText
} else {
field.valueOrAdditionalInfo
}
FieldEditableRow(
key = field.key,
fieldId = fieldId,
detailTitle = title,
detailValue = value,
layoutType = layoutType,
textColor = CustomTheme.colors.primaryContent,
onValueChange = onValueChange,
isMultilineAllowed = field.key == FieldKeys.Item.extra
isMultilineAllowed = field.key == FieldKeys.Item.extra,
onFocusChanges = onFocusChanges
)
}
}

@Composable
private fun FieldEditableRow(
key: String,
fieldId: String,
detailTitle: String,
detailValue: String,
layoutType: CustomLayoutSize.LayoutType,
textColor: Color = CustomTheme.colors.primaryContent,
isMultilineAllowed: Boolean = false,
onValueChange: (String, String) -> Unit,
onFocusChanges: (String) -> Unit,
) {
Column {
Spacer(modifier = Modifier.height(8.dp))
Expand All @@ -233,7 +239,12 @@ private fun FieldEditableRow(
if (isMultilineAllowed) {
CustomTextField(
modifier = Modifier
.fillMaxSize(),
.fillMaxSize()
.onFocusChanged {
if (it.hasFocus) {
onFocusChanges(fieldId)
}
},
value = detailValue,
hint = "",
textColor = textColor,
Expand All @@ -248,7 +259,12 @@ private fun FieldEditableRow(
}
CustomTextField(
modifier = Modifier
.fillMaxSize(),
.fillMaxSize()
.onFocusChanged {
if (it.hasFocus) {
onFocusChanges(fieldId)
}
},
value = detailValue,
hint = "",
textColor = textColor,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ internal fun ItemDetailsScreen(
CustomScaffold(
topBar = {
ItemDetailsTopBar(
type = viewState.type,
onViewOrEditClicked = viewModel::onSaveOrEditClicked,
onCancelOrBackClicked = viewModel::onCancelOrBackClicked,
isEditing = viewState.isEditing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,32 @@ package org.zotero.android.screens.itemdetails
import androidx.compose.runtime.Composable
import androidx.compose.ui.res.stringResource
import org.zotero.android.architecture.ui.CustomLayoutSize
import org.zotero.android.screens.itemdetails.data.DetailType
import org.zotero.android.uicomponents.Strings
import org.zotero.android.uicomponents.topbar.NewCustomTopBar
import org.zotero.android.uicomponents.topbar.NewHeadingTextButton

@Composable
internal fun ItemDetailsTopBar(
type: DetailType,
onViewOrEditClicked: () -> Unit,
onCancelOrBackClicked: () -> Unit,
isEditing: Boolean,
) {
NewCustomTopBar(
leftContainerContent = listOf {
ItemDetailsTopBarEditing(onCancelOrBackClicked, isEditing)
ItemDetailsTopBarEditing(
type = type,
onCancelOrBackClicked = onCancelOrBackClicked,
isEditing = isEditing
)
},
rightContainerContent = listOf {
NewHeadingTextButton(
isEnabled = true,
onClick = onViewOrEditClicked,
text = if (isEditing) {
stringResource(Strings.save)
stringResource(Strings.done)
} else {
stringResource(Strings.edit)
}
Expand All @@ -32,19 +38,34 @@ internal fun ItemDetailsTopBar(
}

@Composable
private fun ItemDetailsTopBarEditing(onCancelOrBackClicked: () -> Unit, isEditing: Boolean) {
NewHeadingTextButton(
isEnabled = true,
onClick = onCancelOrBackClicked,
text = if (isEditing) {
stringResource(Strings.cancel)
} else {
val layoutType = CustomLayoutSize.calculateLayoutType()
if (layoutType.isTablet()) {
stringResource(Strings.back)
} else {
stringResource(Strings.collections_all_items)
private fun ItemDetailsTopBarEditing(
type: DetailType,
onCancelOrBackClicked: () -> Unit,
isEditing: Boolean
) {
if (isEditing) {
when (type) {
is DetailType.creation, is DetailType.duplication -> {
NewHeadingTextButton(
onClick = onCancelOrBackClicked,
text = stringResource(Strings.cancel)
)
}

else -> {
//no-op
}
}
)
} else {
val layoutType = CustomLayoutSize.calculateLayoutType()
val text = if (layoutType.isTablet()) {
stringResource(Strings.back)
} else {
stringResource(Strings.collections_all_items)
}
NewHeadingTextButton(
onClick = onCancelOrBackClicked,
text = text
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ import io.realm.ObjectChangeSet
import io.realm.RealmObjectChangeListener
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import org.greenrobot.eventbus.EventBus
Expand Down Expand Up @@ -204,6 +207,7 @@ class ItemDetailsViewModel @Inject constructor(
fun init() = initOnce {
EventBus.getDefault().register(this)
setupFileObservers()
setupOnFieldValueTextChangeFlow()

val args = ScreenArguments.itemDetailsArgs

Expand Down Expand Up @@ -298,7 +302,7 @@ class ItemDetailsViewModel @Inject constructor(

fun onSaveOrEditClicked() {
if (viewState.isEditing) {
saveChanges()
endEditing()
} else {
val updatedStateData = viewState.data.deepCopy()
val updatedData = viewState.data.deepCopy(
Expand Down Expand Up @@ -372,7 +376,6 @@ class ItemDetailsViewModel @Inject constructor(
defaults = this.defaults
)
}
else -> {}
}
} catch (e: Exception) {
Timber.e(e, "can't load initial data ")
Expand All @@ -381,7 +384,6 @@ class ItemDetailsViewModel @Inject constructor(
}
return
}
data!!
val request = CreateItemFromDetailDbRequest(
key = key,
libraryId = libraryId,
Expand Down Expand Up @@ -620,7 +622,41 @@ class ItemDetailsViewModel @Inject constructor(
}
}

fun setFieldValue(id: String, value: String) {
private var onFieldValueTextChangeFlow = MutableStateFlow<Pair<String, String>?>(null)

private fun setupOnFieldValueTextChangeFlow() {
onFieldValueTextChangeFlow
.debounce(500)
.map { data ->
if (data != null) {
setFieldValue(data.first, data.second)
}
}
.launchIn(viewModelScope)
}

fun onFieldFocusFieldChange(fieldId: String) {
val changeFlowValue = onFieldValueTextChangeFlow.value
if (changeFlowValue != null) {
setFieldValue(changeFlowValue.first, changeFlowValue.second)
}
val field = viewState.data.fields[fieldId] ?: return
updateState {
copy(
fieldFocusKey = fieldId,
fieldFocusText = field.valueOrAdditionalInfo
)
}
}

fun onFieldValueTextChange(id: String, value: String) {
updateState {
copy(fieldFocusText = value)
}
onFieldValueTextChangeFlow.tryEmit(id to value)
}

private fun setFieldValue(id: String, value: String) {
val field = viewState.data.fields[id]
if (field == null) {
return
Expand Down Expand Up @@ -764,13 +800,13 @@ class ItemDetailsViewModel @Inject constructor(
return field
}

fun saveChanges() {
private fun endEditing() {
if (viewState.snapshot == viewState.data) {
return
}
try {
coroutineScope.launch {
endEditing()
endEditingAsync()
}
} catch (error: Exception) {
Timber.e(error, "ItemDetailStore: can't store changes")
Expand All @@ -780,9 +816,7 @@ class ItemDetailsViewModel @Inject constructor(
}
}

private fun endEditing() {
// updateDateFieldIfNeeded()
// updateAccessedFieldIfNeeded()
private fun endEditingAsync() {
viewModelScope.launch {
val updatedFields: MutableMap<KeyBaseKeyPair, String> = mutableMapOf()
val updatedFieldsMap = viewState.data.fields.toMutableMap()
Expand Down Expand Up @@ -940,8 +974,7 @@ class ItemDetailsViewModel @Inject constructor(

private fun cancelChanges() {
viewModelScope.launch {
val type = viewState.type!!
when (type) {
when (val type = viewState.type) {
is DetailType.duplication -> {
perform(
dbWrapper = dbWrapperMain,
Expand Down Expand Up @@ -1986,7 +2019,7 @@ data class ItemDetailsViewState(
val key: String = "",
val library: Library? = null,
val userId: Long = 0,
val type: DetailType? = null,
val type: DetailType = DetailType.preview(""),
val preScrolledChildKey: String? = null,
val isEditing: Boolean = false,
var error: ItemDetailError? = null,
Expand All @@ -2001,6 +2034,8 @@ data class ItemDetailsViewState(
var isLoadingData: Boolean = false,
var backgroundProcessedItems: Set<String> = emptySet(),
val longPressOptionsHolder: LongPressOptionsHolder? = null,
val fieldFocusKey: String? = null,
val fieldFocusText: String = "",
) : ViewState

sealed class ItemDetailsViewEffect : ViewEffect {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,9 @@ class ItemDetailField(
)
}

val valueOrAdditionalInfo: String get() {
return additionalInfo?.get(AdditionalInfoKey.formattedDate)
?: value
}

}

0 comments on commit 8ab234d

Please sign in to comment.